Dashboard › craft › Distillation
827960c4-29d3-4fd3-88e9-0f92d5afef6a["lore_tm_v1_TsiFniB3Iz74EmdOhmlSQNG9zFSeSssI9IQdR8wxFcM","lore_tm_v1_FJkmdD56U8uFwrAJp9QeHEUlLY5BaQYK0JwWWWDP4jU","lore_tm_v1_zAQe2Ca6wHMmWKzh1lUUg_vdAZDa22TuZlOJWj7b1mE","lore_tm_v1_zD7Op8uZlMzoCWNODhD5eHMqecBe8xeLk5P0wFx6R3M","lore_tm_v1_16mIGKfzxxMqCDE9MAtuAEOFDNjad2KN5dZNnos2-wc","lore_tm_v1_jhxNv2ZLWOZ6h8aY85sK7dWfF9uPXv93htrMn19LHdk","lore_tm_v1_yYDwbxSP3NWwS4X3ncXC7nJomn8vBBDnfEO8dPN34a4","lore_tm_v1_mLBLFO61JBWbzwXnBD1h0ij0alMnoJxpavQIy-rlNeg","lore_tm_v1_1ntKtmHxXkx-OxreGb0DvV0QQADEki_j-KX6oFkZ4q0","lore_tm_v1_jtJRpHomEI6prE2XYb-GbZMpfMXzZQiPodESH789wBU","lore_tm_v1_AkU37k-r05z3ZUMsoOEn37bzzncPtjmb50MEAwConJ0","lore_tm_v1_icArZAcWfHBKh9ptvMr-rKhZqFBwRpliaNCsdS5kX6Q"]
Date: Aug 25, 2026
ab63572 fix(publish): isolate workspace release state; 086a633 fix(config): address workspace review feedback; c099bbf Merge branch 'master' into feat/workspaces-schema; e5a7f97 fix(deps): bump vulnerable packages and add overrides (#866); 8cc5425 feat(targets): add vercel deploy target (#865).minVersion side.src/config.ts:110-160 fix: resolveWorkspaceConfig(base, workspaceName) sets const workspaces = base.workspaces || {} and rejects selectors not owned by workspaces using Object.hasOwn(workspaces, workspaceName) at lines 114-123, throwing ConfigurationError with Unknown workspace "${workspaceName}" and an available-workspace list. It accesses const workspace = workspaces[workspaceName] only after that guard. It strips workspaces from base config via destructuring at lines 126-127, shallow-merges workspace fields, and shallow-merges github; it retains merged GitHub config only when both owner and repo exist (lines 137-154), otherwise deletes resolved.github to permit getGlobalGitHubConfig() Git-remote fallback.src/config.ts:163-239 behavior: isVersionGteMinVersion(minVersionRaw, requiredVersion) parses and compares configured minVersion and required version after withoutBuildMetadata(), returning false if missing/unparseable. withoutBuildMetadata(version) removes SemVer build metadata because the comparison helper rejects build-bearing versions. applyWorkspaceSelection() requires an explicit workspace when workspaces exist, rejects a selection when none are configured, checks config.minVersion >= WORKSPACES_MIN_VERSION at lines 231-237, then resolves via resolveWorkspaceConfig(config, _activeWorkspaceName) at line 239.src/utils/publishState.ts:58-121 fix: shortCwdHash(cwd) is sha1(cwd).digest('hex').slice(0, 12). getPublishStateFilename(version, githubConfig, cwd = process.cwd(), workspace?) uses workspace ? \workspace-${Buffer.from(workspace).toString('base64url')}-` : ''at lines 88-91. With GitHub config, filename ispublish-state-${sanitisedOwner}-${sanitisedRepo}-${shortCwdHash(cwd)}-${workspacePrefix}${safeVersion}.json; without GitHub config, it is publish-state-${sha256(cwd).slice(0, 16)}-${workspacePrefix}${safeVersion}.json. getPublishStatePath(version, githubConfig, cwd, workspace?)` passes workspace through to filename construction. Comments state lossless workspace encoding prevents same-repository independent release units from sharing completed-target state.src/commands/publish.ts:674-756 behavior: after expandWorkspaceTargets(config.targets || []), publishMain() resolves GitHub config with getGlobalGitHubConfig() and falls back to null on error. It calls getPublishStatePath(newVersion, publishStateGithubConfig, process.cwd(), getActiveWorkspace()) at lines 697-702. It warns but never reads legacy repo-local .craft-publish-${newVersion}.json because repository contents can be attacker-influenced; state is instead in the Craft XDG state path. If the computed state file exists, it parses it, resets targetsToPublish to all target IDs, then deletes each key in publishState.published; otherwise it initializes { published: Object.create(null) }.src/__tests__/config.test.ts:301-316: unknown workspace nope must throw /Unknown workspace "nope"/; parameterized names constructor, toString, and __proto__ each call setActiveWorkspace(workspace) and must throw new RegExp(\Unknown workspace "${workspace}"`). Additional tests show a below-gate minVersion: 2.14.0must throw, while${WORKSPACES_MIN_VERSION}+linuxis accepted and resolves thecli` release branch.src/utils/__tests__/publishState.test.ts:70-108: getPublishStateFilename('1.2.3', { owner: 'o', repo: 'r' }, cwd, 'cli') and the corresponding 'mcp' call must differ; expected suffixes are -workspace-Y2xp-1.2.3.json for cli and -workspace-bWNw-1.2.3.json for mcp. Names CLI, cli, cli/workspace, and cli_workspace must all generate distinct filenames. With no workspace argument, the legacy non-workspace form remains publish-state-o-r-[0-9a-f]{12}-1.2.3.json.@typescript-eslint/no-unused-vars was never used.4.1.8 ran in /home/byk/Code/getsentry/craft-workspaces-schema; 2 test files and 52 tests passed, duration 1.32s. Prettier reported all matched files use code style. ESLint completed with 0 errors and 7 @typescript-eslint/no-unused-vars warnings: src/commands/publish.ts _abortError at 453:14, 470:14, and 498:16; _statusError at 486:16; _diffError at 492:18; src/utils/git.ts _err at 231:12 and 239:12.Object.hasOwn() at src/config.ts:114-124 rejects inherited constructor, toString, and __proto__; assistant assessed that the old const workspace = workspaces[workspaceName]; if (!workspace) implementation would treat inherited values as truthy, so the throw-expecting tests at src/__tests__/config.test.ts:308-316 would fail before the fix and pass now.src/utils/publishState.ts:82-99, passed from getActiveWorkspace() at src/commands/publish.ts:697-702, isolates resume state before the target-skip logic at src/commands/publish.ts:722-742. Assistant assessed that under the old implementation cli and mcp resolved to the same owner/repo/cwd/version state filename, so expect(cli).not.toBe(mcp) at src/utils/__tests__/publishState.test.ts:83 would fail; it passes with the current implementation.tsc --noEmit passed; Prettier passed; ESLint had no errors and only 7 unused-variable warnings. Assistantβs final security decision: MERGE.