Dashboard › craft › Distillation
eb249d16-9f49-454a-845f-fe9c7b0860ae["lore_tm_v1_1WyJXFt6XQhb4E5195cJvD6UQro4UzhESesceGpnKSg","lore_tm_v1_6DZS5DBxEoiki0tuB6V6hsgAeEvgwkh_u79uAtBMG6Q","lore_tm_v1_-pFrKg4tJyd0tlLkGkNZLrcyrbj5-VFe-8AKJC3qJGE","lore_tm_v1_1u-RjSl_UsPFod_c66m_qc1V5I61zDVG9sg3jI__sc8","lore_tm_v1_9VgbDXOD6GFOHo0NcWyzFHMfxB26PcBqLkWfZpTYg-c"]
Date: Aug 27, 2026
--workspace (for example, --workspace --dry-run) must never be mistaken for a workspace name.src/index.ts resolves the active workspace before yargs parsing via setActiveWorkspace(extractWorkspaceSelection(argv)), because yargs command builders run before middleware and publish derives --target choices from config.targets; workspace selection precedence is centralized in extractWorkspaceSelection(argv).src/index.ts configures global yargs option workspace as a string, with description “Select a named workspace (release unit) from the configuration. Required when the config defines "workspaces". Env: CRAFT_WORKSPACE”; it is global.src/utils/helpers.ts implements extractWorkspaceSelection(argv, env = process.env): it reads CRAFT_WORKSPACE, calls parseArgs() with options: { workspace: { type: 'string' } }, allowPositionals: true, strict: false, and tokens: true; it iterates workspace option tokens so the last occurrence wins, accepts nonempty values when inline (--workspace=-foo valid) or when non-inline values do not start with -, clears prior CLI selection for a bare/empty final option, and returns the accepted CLI workspace or falls back to CRAFT_WORKSPACE.src/utils/helpers.ts defines MAX_STEP_OUTPUT_BYTES = 64 * 1024; truncateForOutput() leaves values at or below that UTF-8 byte limit unchanged, otherwise safely truncates to account for a notice, removes a trailing U+FFFD if slicing split a multibyte codepoint, and appends either \n\n---\n*Changelog truncated.* or \n\n---\n*Changelog truncated. [View full changelog](${changelogUrl}).*.setGitHubActionsOutput(name, value) writes to GITHUB_OUTPUT only when set, using name=value for single-line values and a randomized EOF_${Date.now()}_${Math.random().toString(36).slice(2)} heredoc delimiter for multiline values. writeGitHubActionsFile(name, content) writes ${name}.md under $RUNNER_TEMP/craft/, emits ${name}_file, and returns the absolute path; it is a no-op if RUNNER_TEMP is unset.disableChangelogMentions(changelog) replaces the exact changelog pattern by @author in with by **author** in using / by @(\S+) in /g, preventing contributor pings in embedded GitHub issue bodies.src/modules/__tests__/details-from-context.js expects legacy issue title publish: getsentry/sentry@21.3.1 with Merge target: custom-branch and checked targets github, npm[@sentry/node], and docker[latest] to parse as { dry_run: "", merge_target: "custom-branch", path: ".", repo: "sentry", targets: ["github", "npm[@sentry/node]", "docker[latest]"], version: "21.3.1" }; (default) merge target parses to merge_target: "".4.2.6+sentry1, human-readable workspace title publish: getsentry/toolkit [workspace: "cli/v2"] @1.2.3, escaped workspace cli [preview] "next", and Unicode workspace cli-日本語; they reject legacy title publish: getsentry/toolkit @1.2.3 with Invalid publish issue title and invalid JSON escape cli\qnext with Invalid publish workspace JSON in title.Workspace names must be nonempty and cannot contain Unicode control, format, or separator characters; it rejects target path getsentry/toolkit/../other@1.2.3 with Invalid publish issue path and missing issue payload with Issue context is not defined.src/modules/__tests__/publish-workflow.js extracts the Set targets shell script from .github/workflows/publish.yml, runs it with CRAFT_PUBLISH_PATH, CRAFT_PUBLISH_REPO, CRAFT_PUBLISH_TARGETS_JSON='["github"]', CRAFT_PUBLISH_VERSION, optional CRAFT_PUBLISH_WORKSPACE, GITHUB_OUTPUT, and GITHUB_WORKSPACE, then verifies state files contain {"published":{"github":true}}.path: ".", repo: "sentry", version: "21.3.1" to use .craft-state/craft/publish-state-getsentry-sentry-c232c383e26f-21.3.1.json; workspace monorepo release path: "./cli", repo: "toolkit", version: "1.2.3", workspace: "cli" must use .craft-state/craft/publish-state-getsentry-toolkit-21cf7beaeda4-workspace-Y2xp-1.2.3.json.src/utils/publishState.ts moves publish-resume state out of repository checkouts because the former .craft-publish-<version>.json in project cwd could be committed or pre-populated by earlier CI steps, causing completed targets to be silently skipped.getCraftStateDir() resolves $XDG_STATE_HOME/craft/ when XDG_STATE_HOME is nonempty, otherwise $HOME/.local/state/craft/; this is workflow-writable and inaccessible to committed repository contents, including in getsentry/publish Docker runs with HOME=/root.getPublishStateFilename(version, githubConfig, cwd = process.cwd(), workspace?) lowercases and filename-sanitizes strings to [a-z0-9._-], uses a 12-character SHA-1 cwd digest with resolved GitHub config (publish-state-<owner>-<repo>-<sha1(cwd)[:12]>-<workspace-prefix><version>.json), and falls back without GitHub config to a 16-character SHA-256 cwd digest (publish-state-<sha256(cwd)[:16]>-<workspace-prefix><version>.json).src/utils/publishState.ts isolates workspace publish-resume state by inserting workspace-${Buffer.from(workspace).toString('base64url')}- before the version; this losslessly encoded workspace prefix prevents independent release units in the same repository and at the same version from sharing completed-target state.