@brainervirus/workit-cli 8.8.0 → 8.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +978 -567
  2. package/package.json +4 -4
package/dist/index.js CHANGED
@@ -65,7 +65,7 @@ var package_default;
65
65
  var init_package = __esm(() => {
66
66
  package_default = {
67
67
  name: "@brainervirus/workit-cli",
68
- version: "8.8.0",
68
+ version: "8.9.0",
69
69
  private: false,
70
70
  description: "Workit CLI — setup wizard, doctor, and task control for agentic coding workflows",
71
71
  keywords: [
@@ -103,9 +103,9 @@ var init_package = __esm(() => {
103
103
  },
104
104
  dependencies: {
105
105
  "@babel/parser": "7.29.9",
106
- "@brainervirus/workit-core": "^8.8.0",
107
- "@brainervirus/workit-cursor": "^8.8.0",
108
- "@brainervirus/workit-opencode": "^8.8.0",
106
+ "@brainervirus/workit-core": "^8.9.0",
107
+ "@brainervirus/workit-cursor": "^8.9.0",
108
+ "@brainervirus/workit-opencode": "^8.9.0",
109
109
  "@inkjs/ui": "2.0.0",
110
110
  ink: "7.1.1",
111
111
  react: "19.2.8"
@@ -63938,30 +63938,353 @@ var init_skill_manifests = __esm(() => {
63938
63938
  if (false) {}
63939
63939
  });
63940
63940
 
63941
- // packages/workit-cli/src/admin/doctor.ts
63941
+ // packages/workit-core/src/git/session-hook.ts
63942
63942
  import { spawnSync as spawnSync13 } from "node:child_process";
63943
- import { createHash as createHash13 } from "node:crypto";
63944
63943
  import {
63944
+ chmodSync,
63945
63945
  existsSync as existsSync13,
63946
63946
  lstatSync as lstatSync4,
63947
63947
  mkdirSync as mkdirSync5,
63948
- mkdtempSync,
63949
- readdirSync as readdirSync7,
63950
63948
  readFileSync as readFileSync13,
63951
- readlinkSync as readlinkSync2,
63949
+ renameSync as renameSync3,
63952
63950
  rmSync as rmSync2,
63953
63951
  statSync as statSync4,
63954
- unlinkSync as unlinkSync3,
63955
63952
  writeFileSync as writeFileSync6
63956
63953
  } from "node:fs";
63957
- import os8 from "node:os";
63958
63954
  import path30 from "node:path";
63955
+ function inspectSessionHook(cwd, env = process.env) {
63956
+ const none = { hooksDir: null, hookPath: null, helperPath: null, helperCurrent: false };
63957
+ if (!existsSync13(cwd))
63958
+ return { state: "not_git", ...none };
63959
+ const top = run2(cwd, ["rev-parse", "--show-toplevel"], env);
63960
+ if (!top.ok || !top.out)
63961
+ return { state: "not_git", ...none };
63962
+ const paths = run2(cwd, ["rev-parse", "--path-format=absolute", "--git-common-dir", "--git-path", "hooks"], env);
63963
+ const [commonDir, hooksDir] = paths.out.split(/\r?\n/);
63964
+ if (!paths.ok || !commonDir || !hooksDir)
63965
+ return { state: "not_git", ...none };
63966
+ const hookPath = path30.join(hooksDir, SESSION_HOOK_NAME);
63967
+ const helperPath = path30.join(commonDir, ...HELPER);
63968
+ const helperCurrent = readText(helperPath) === SESSION_TRAILER_SCRIPT;
63969
+ const leftover = leftoverOf(hooksDir);
63970
+ const base = { hooksDir, hookPath, helperPath, helperCurrent, ...leftover ? { leftover } : {} };
63971
+ const blocked = (reason, owner, text = "") => {
63972
+ const old = `${hookPath}.old`;
63973
+ const displaced = readText(old)?.includes(SESSION_HOOK_MARKER) ? old : null;
63974
+ const input = { owner, text, hooksDir, hookPath, top: top.out, displaced };
63975
+ const manualTarget = manualTargetOf(input);
63976
+ const owned = text ? { owner } : {};
63977
+ if (manualInPlace(input, manualTarget))
63978
+ return {
63979
+ state: "manual",
63980
+ ...base,
63981
+ ...owned,
63982
+ manualTarget,
63983
+ via: owner === "other" ? "existing hook" : owner
63984
+ };
63985
+ return {
63986
+ state: "blocked",
63987
+ ...base,
63988
+ ...owned,
63989
+ reason: displaced ? `${reason} (Workit's earlier hook was moved to ${old})` : reason,
63990
+ manual: manualFor(input),
63991
+ manualTarget
63992
+ };
63993
+ };
63994
+ if (!inside2(hooksDir, commonDir) && !inside2(hooksDir, top.out))
63995
+ return blocked(`core.hooksPath ${hooksDir} is outside the repository; a hook there runs in every repository that uses it`, "other");
63996
+ const text = exists(hookPath) ? readText(hookPath) ?? "" : null;
63997
+ if (text !== null) {
63998
+ if (text === SESSION_HOOK_SCRIPT)
63999
+ return { state: helperCurrent ? "installed" : "outdated", ...base };
64000
+ if (text.includes(SESSION_HOOK_MARKER))
64001
+ return { state: "outdated", ...base };
64002
+ const owner = ownerOf(text, hooksDir, top.out);
64003
+ return blocked(`${hookPath} belongs to ${owner === "other" ? "another hook" : owner}; Workit never replaces it`, owner, text);
64004
+ }
64005
+ if (!inside2(hooksDir, commonDir)) {
64006
+ const rel = path30.relative(top.out, hookPath).split(path30.sep).join("/");
64007
+ if (!run2(top.out, ["check-ignore", "-q", "--", rel], env).ok)
64008
+ return blocked(`${hooksDir} is in the working tree and not ignored; the hook would show up as a new file`, "other");
64009
+ }
64010
+ return { state: "missing", ...base };
64011
+ }
64012
+ function installSessionHook(cwd, env = process.env) {
64013
+ const status = inspectSessionHook(cwd, env);
64014
+ if (status.state === "not_git")
64015
+ return {
64016
+ action: "skipped",
64017
+ helperWritten: false,
64018
+ status,
64019
+ detail: "not inside a git work tree"
64020
+ };
64021
+ const helperWritten = !status.helperCurrent;
64022
+ if (helperWritten)
64023
+ writeExecutable(status.helperPath, SESSION_TRAILER_SCRIPT);
64024
+ const helper = helperWritten ? `; wrote ${status.helperPath}` : "";
64025
+ if (status.state === "installed")
64026
+ return {
64027
+ action: "unchanged",
64028
+ helperWritten,
64029
+ status,
64030
+ detail: `hook already at ${status.hookPath}`
64031
+ };
64032
+ if (status.state === "manual")
64033
+ return {
64034
+ action: "unchanged",
64035
+ helperWritten,
64036
+ status: inspectSessionHook(cwd, env),
64037
+ detail: `${status.manualTarget} already runs the helper (via ${status.via})${helper}`
64038
+ };
64039
+ if (status.state === "blocked")
64040
+ return {
64041
+ action: "skipped",
64042
+ helperWritten,
64043
+ status: inspectSessionHook(cwd, env),
64044
+ detail: `${status.reason}${helper}`
64045
+ };
64046
+ const fresh = status.state === "missing";
64047
+ const slotCurrent = readText(status.hookPath) === SESSION_HOOK_SCRIPT;
64048
+ if (!slotCurrent)
64049
+ writeExecutable(status.hookPath, SESSION_HOOK_SCRIPT);
64050
+ const verb = fresh ? "installed" : "updated";
64051
+ return {
64052
+ action: verb,
64053
+ helperWritten,
64054
+ status: inspectSessionHook(cwd, env),
64055
+ detail: `${verb} the Workit ${SESSION_HOOK_NAME} hook at ${status.hookPath}${helper}`
64056
+ };
64057
+ }
64058
+ var SESSION_HOOK_NAME = "prepare-commit-msg", SESSION_HOOK_MARKER = "# workit-session-trailer-hook", HELPER, LEGACY_CHAINED = "commit-msg.workit-chained", SESSION_TRAILER_SCRIPT = `#!/bin/sh
64059
+ # Workit (https://github.com/BrainerVirus/workit) wrote this file with
64060
+ # \`workit doctor --fix\`. A prepare-commit-msg hook runs it with its own
64061
+ # arguments to add a Workit-Session trailer to commits made in an agent session.
64062
+ # Not a hook itself; delete it together with the line that runs it.
64063
+ # lefthook passes a missing argument as its literal placeholder.
64064
+ case "\${2-}" in "" | "{2}" | template) exit 0 ;; esac
64065
+ gitdir=$(git rev-parse --git-dir) || exit 0
64066
+ if [ -d "$gitdir/rebase-merge" ] || [ -d "$gitdir/rebase-apply" ] || [ -f "$gitdir/CHERRY_PICK_HEAD" ]; then
64067
+ exit 0
64068
+ fi
64069
+ trim() { printf '%s' "$1" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//'; }
64070
+ inner=$(trim "\${OPENCODE_SESSION_ID-}"); inner_host=opencode
64071
+ if [ -z "$inner" ]; then inner=$(trim "\${PI_SESSION_ID-}"); inner_host=pi; fi
64072
+ if [ -z "$inner" ]; then inner=$(trim "\${CODEX_THREAD_ID-}"); inner_host=codex; fi
64073
+ [ -n "$inner" ] || inner_host=
64074
+ declared=$(trim "\${WORKIT_HOST-}")
64075
+ family=$(printf '%s' "$declared" | sed 's/_cli$//;s/_desktop$//')
64076
+ session=$inner
64077
+ if [ "\${WORKIT_SESSION_ID+set}" = set ]; then
64078
+ if [ -z "$inner" ] || [ -z "$declared" ] || [ "$family" = "$inner_host" ]; then
64079
+ session=$(trim "$WORKIT_SESSION_ID")
64080
+ fi
64081
+ fi
64082
+ [ -n "$session" ] || exit 0
64083
+ [ \${#session} -le 128 ] || exit 0
64084
+ case "$session" in *[!A-Za-z0-9_.:@/+-]*) exit 0 ;; esac
64085
+ add_trailer() {
64086
+ [ -f "$1" ] && [ -r "$1" ] || return 0
64087
+ body=$(sed '/^# -\\{24\\} >8 -\\{24\\}$/,$d' "$1" | git stripspace --strip-comments)
64088
+ [ -n "$body" ] || return 0
64089
+ # A merge message has no final newline; interpret-trailers would glue the
64090
+ # trailer to the subject line.
64091
+ [ -z "$(tail -c 1 "$1")" ] || printf '\\n' >> "$1"
64092
+ git -c trailer.separators=: -c trailer.where=end interpret-trailers --in-place \\
64093
+ --no-divider --if-exists addIfDifferent --trailer "Workit-Session: $session" "$1" || return 0
64094
+ }
64095
+ # $1 is the message file. lefthook cannot quote a path it pastes in, so its
64096
+ # job passes '' and the file is found here: git hands the hook COMMIT_EDITMSG,
64097
+ # except \`git merge\`, which hands it MERGE_MSG. With source "merge" both are
64098
+ # updated: the one git did not hand over is stale or removed after the commit.
64099
+ case "\${1-}" in "" | "{1}") ;; *) add_trailer "$1"; exit 0 ;; esac
64100
+ add_trailer "$(git rev-parse --git-path COMMIT_EDITMSG)"
64101
+ [ "$2" != merge ] || add_trailer "$(git rev-parse --git-path MERGE_MSG)"
64102
+ exit 0
64103
+ `, manualTrailerLine = () => `h="$(git rev-parse --git-common-dir 2>/dev/null)/${HELPER.join("/")}"; [ ! -f "$h" ] || sh "$h" "$@" || true`, lefthookTrailerRun = () => `set -f; IFS=; h=$(git rev-parse --git-common-dir 2>/dev/null)/${HELPER.join("/")}; [ ! -f $h ] || sh $h '' {2} {3} || true`, HELPER_REF, SESSION_HOOK_SCRIPT, run2 = (cwd, args, env) => {
64104
+ const r = spawnSync13("git", args, {
64105
+ cwd,
64106
+ encoding: "utf8",
64107
+ timeout: GIT_TIMEOUTS.local,
64108
+ windowsHide: true,
64109
+ stdio: ["ignore", "pipe", "pipe"],
64110
+ env: { ...env, GIT_TERMINAL_PROMPT: "0" }
64111
+ });
64112
+ return { ok: r.status === 0, out: (r.stdout ?? "").trim() };
64113
+ }, inside2 = (child, parent) => {
64114
+ const rel = path30.relative(path30.resolve(parent), path30.resolve(child));
64115
+ return rel === "" || !rel.startsWith("..") && !path30.isAbsolute(rel);
64116
+ }, readText = (file) => {
64117
+ try {
64118
+ return readFileSync13(file, "utf8");
64119
+ } catch {
64120
+ return null;
64121
+ }
64122
+ }, exists = (file) => {
64123
+ try {
64124
+ lstatSync4(file);
64125
+ return true;
64126
+ } catch {
64127
+ return false;
64128
+ }
64129
+ }, LEFTHOOK_CONFIGS, lefthookConfig = (top) => LEFTHOOK_CONFIGS.map((name) => path30.join(top, name)).find((file) => existsSync13(file)) ?? null, isComment = (line) => /^\s*#/.test(line), COMMAND_SH, DIRECT_CALL, VAR_CALL, runsHelperText = (text) => {
64130
+ const lines = text.split(/\r?\n/).filter((line) => !isComment(line));
64131
+ const assigned = lines.some((line) => /(?:^|[\s;])h=/.test(line) && line.includes(HELPER_REF));
64132
+ return lines.some((line) => DIRECT_CALL.test(line) || assigned && VAR_CALL.test(line));
64133
+ }, LEFTHOOK_YAML, indentOf = (line) => line.length - line.trimStart().length, lefthookRunsHelper = (text) => {
64134
+ const lines = text.split(/\r?\n/);
64135
+ const start = lines.findIndex((line) => /^prepare-commit-msg:\s*(?:#.*)?$/.test(line));
64136
+ if (start < 0)
64137
+ return false;
64138
+ const block = [];
64139
+ for (const line of lines.slice(start + 1)) {
64140
+ if (line.trim() && !isComment(line) && indentOf(line) === 0)
64141
+ break;
64142
+ block.push(line);
64143
+ }
64144
+ return block.some((line, i) => {
64145
+ if (isComment(line))
64146
+ return false;
64147
+ const runKey = /^(\s*)(?:-\s+)?run:\s*(.*)$/.exec(line);
64148
+ if (!runKey)
64149
+ return false;
64150
+ let value = runKey[2] ?? "";
64151
+ if (/^[|>][-+]?\s*$/.test(value)) {
64152
+ const body = [];
64153
+ for (const next of block.slice(i + 1)) {
64154
+ if (next.trim() && indentOf(next) <= indentOf(line))
64155
+ break;
64156
+ body.push(next);
64157
+ }
64158
+ value = body.join(`
64159
+ `);
64160
+ }
64161
+ return runsHelperText(value);
64162
+ });
64163
+ }, isExecutable = (file) => {
64164
+ if (process.platform === "win32")
64165
+ return true;
64166
+ try {
64167
+ return (statSync4(file).mode & 73) !== 0;
64168
+ } catch {
64169
+ return false;
64170
+ }
64171
+ }, manualInPlace = (input, target) => {
64172
+ if (input.owner === "lefthook")
64173
+ return LEFTHOOK_YAML.some((name) => {
64174
+ const text = readText(path30.join(input.top, name));
64175
+ return text !== null && lefthookRunsHelper(text);
64176
+ });
64177
+ const text = readText(target);
64178
+ if (text === null || !runsHelperText(text))
64179
+ return false;
64180
+ return input.owner === "husky" && target !== input.hookPath || isExecutable(target);
64181
+ }, isHuskyV9 = (text, hooksDir) => /\$\(dirname (?:-- )?"\$0"\)\/h"/.test(text) && existsSync13(path30.join(hooksDir, "h")), ownerOf = (text, hooksDir, top) => {
64182
+ if (text.includes("husky.sh") || isHuskyV9(text, hooksDir))
64183
+ return "husky";
64184
+ if (/lefthook/i.test(text) || lefthookConfig(top))
64185
+ return "lefthook";
64186
+ return "other";
64187
+ }, manualTargetOf = ({ owner, text, hooksDir, hookPath, top }) => {
64188
+ if (owner === "husky" && isHuskyV9(text, hooksDir))
64189
+ return path30.join(path30.dirname(hooksDir), SESSION_HOOK_NAME);
64190
+ if (owner === "lefthook")
64191
+ return lefthookConfig(top) ?? path30.join(top, "lefthook.yml");
64192
+ return hookPath;
64193
+ }, manualFor = (input) => {
64194
+ const { owner, displaced } = input;
64195
+ const target = manualTargetOf(input);
64196
+ const stale = displaced ? `; delete the stale ${displaced} (nothing runs it)` : "";
64197
+ if (owner === "husky")
64198
+ return `add this line to ${target} (create it if missing; husky runs it)${stale}: ${manualTrailerLine()}`;
64199
+ if (owner === "lefthook")
64200
+ return [
64201
+ `merge this job into ${target} (add it to an existing \`${SESSION_HOOK_NAME}:\` \`jobs:\` list rather than a second \`${SESSION_HOOK_NAME}:\` key), then run \`lefthook install\`${stale}:`,
64202
+ `${SESSION_HOOK_NAME}:`,
64203
+ " jobs:",
64204
+ " - name: workit-session",
64205
+ ` run: ${lefthookTrailerRun()}`
64206
+ ].join(`
64207
+ `);
64208
+ return `add this line to ${target} (a new file needs \`#!/bin/sh\` as its first line and \`chmod +x\`)${stale}: ${manualTrailerLine()}`;
64209
+ }, leftoverOf = (hooksDir) => {
64210
+ const chained = path30.join(hooksDir, LEGACY_CHAINED);
64211
+ const commitMsg = path30.join(hooksDir, "commit-msg");
64212
+ const oldOurs = readText(commitMsg)?.includes(SESSION_HOOK_MARKER) ?? false;
64213
+ if (exists(chained))
64214
+ return oldOurs ? `${chained} was left by an earlier Workit build: move it back to ${commitMsg} (replacing Workit's old hook there)` : `${chained} was left by an earlier Workit build and nothing runs it: if it is your original commit-msg hook, move it back to ${commitMsg}; otherwise delete it`;
64215
+ if (oldOurs)
64216
+ return `${commitMsg} is a hook from an earlier Workit build; delete it (the trailer now comes from ${SESSION_HOOK_NAME})`;
64217
+ return;
64218
+ }, writeExecutable = (file, content) => {
64219
+ mkdirSync5(path30.dirname(file), { recursive: true });
64220
+ const staged = `${file}.workit-new`;
64221
+ try {
64222
+ writeFileSync6(staged, content, { mode: 493 });
64223
+ chmodSync(staged, 493);
64224
+ renameSync3(staged, file);
64225
+ } finally {
64226
+ rmSync2(staged, { force: true });
64227
+ }
64228
+ };
64229
+ var init_session_hook = __esm(() => {
64230
+ init_rev();
64231
+ HELPER = ["workit", "session-trailer.sh"];
64232
+ HELPER_REF = HELPER.join("/");
64233
+ SESSION_HOOK_SCRIPT = `#!/bin/sh
64234
+ ${SESSION_HOOK_MARKER} v4
64235
+ # Workit (https://github.com/BrainerVirus/workit) installed this hook with
64236
+ # \`workit doctor --fix\`: it runs Workit's session-trailer helper, which adds a
64237
+ # Workit-Session trailer to commits made in an agent session. To remove it,
64238
+ # delete this file.
64239
+ ${manualTrailerLine()}
64240
+ `;
64241
+ LEFTHOOK_CONFIGS = [
64242
+ "lefthook.yml",
64243
+ "lefthook.yaml",
64244
+ ".lefthook.yml",
64245
+ ".lefthook.yaml",
64246
+ "lefthook.json",
64247
+ "lefthook.toml"
64248
+ ];
64249
+ COMMAND_SH = String.raw`(?:^|[;&|(!]|\b(?:then|do|else)\s)\s*sh\s+`;
64250
+ DIRECT_CALL = new RegExp(String.raw`${COMMAND_SH}(?:"[^"]*|\S*)${HELPER_REF.replaceAll(".", String.raw`\.`)}`);
64251
+ VAR_CALL = new RegExp(String.raw`${COMMAND_SH}"?\$h\b`);
64252
+ LEFTHOOK_YAML = [
64253
+ "lefthook.yml",
64254
+ "lefthook.yaml",
64255
+ ".lefthook.yml",
64256
+ ".lefthook.yaml",
64257
+ "lefthook-local.yml",
64258
+ "lefthook-local.yaml",
64259
+ ".lefthook-local.yml",
64260
+ ".lefthook-local.yaml"
64261
+ ];
64262
+ });
64263
+
64264
+ // packages/workit-cli/src/admin/doctor.ts
64265
+ import { spawnSync as spawnSync14 } from "node:child_process";
64266
+ import { createHash as createHash13 } from "node:crypto";
64267
+ import {
64268
+ existsSync as existsSync14,
64269
+ lstatSync as lstatSync5,
64270
+ mkdirSync as mkdirSync6,
64271
+ mkdtempSync,
64272
+ readdirSync as readdirSync7,
64273
+ readFileSync as readFileSync14,
64274
+ readlinkSync as readlinkSync2,
64275
+ rmSync as rmSync3,
64276
+ statSync as statSync5,
64277
+ unlinkSync as unlinkSync3,
64278
+ writeFileSync as writeFileSync7
64279
+ } from "node:fs";
64280
+ import os8 from "node:os";
64281
+ import path31 from "node:path";
63959
64282
  var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
63960
- let dir = path30.resolve(cwd);
64283
+ let dir = path31.resolve(cwd);
63961
64284
  while (true) {
63962
- if (existsSync13(path30.join(dir, "packages", "workit-core", "package.json")))
64285
+ if (existsSync14(path31.join(dir, "packages", "workit-core", "package.json")))
63963
64286
  return dir;
63964
- const parent = path30.dirname(dir);
64287
+ const parent = path31.dirname(dir);
63965
64288
  if (parent === dir)
63966
64289
  return null;
63967
64290
  dir = parent;
@@ -63969,8 +64292,8 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
63969
64292
  }, resolve = (options) => {
63970
64293
  const env = options.env ?? process.env;
63971
64294
  const home = options.home ?? env.HOME ?? os8.homedir();
63972
- const configDir = options.configDir ?? env.WORKFLOW_TOOLKIT_CONFIG ?? env.WORKFLOW_TOOLKIT_CONFIG_DIR ?? path30.join(home, ".config", "workit");
63973
- const stateDir = options.stateDir ?? env.WORKFLOW_TOOLKIT_STATE ?? path30.join(home, ".local", "state", "workit");
64295
+ const configDir = options.configDir ?? env.WORKFLOW_TOOLKIT_CONFIG ?? env.WORKFLOW_TOOLKIT_CONFIG_DIR ?? path31.join(home, ".config", "workit");
64296
+ const stateDir = options.stateDir ?? env.WORKFLOW_TOOLKIT_STATE ?? path31.join(home, ".local", "state", "workit");
63974
64297
  const cwd = options.cwd ?? process.cwd();
63975
64298
  const dev = options.dev ?? env.WORKFLOW_TOOLKIT_DEV ?? findDevFromCwd(cwd);
63976
64299
  return {
@@ -63981,11 +64304,11 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
63981
64304
  cwd,
63982
64305
  workspaceRoot: options.workspaceRoot ?? env.WORKFLOW_WORKSPACE_ROOT ?? cwd,
63983
64306
  dev,
63984
- opencodeConfig: options.opencodeConfig ?? path30.join(home, ".config", "opencode", "opencode.json"),
63985
- opencodePackageCacheDir: options.opencodePackageCacheDir ?? path30.join(home, ".cache", "opencode", "packages", "@brainervirus", "workit-opencode@latest"),
63986
- cursorSettings: options.cursorSettings ?? path30.join(home, ".cursor", "settings.json"),
63987
- cursorMcp: options.cursorMcp ?? path30.join(home, ".cursor", "mcp.json"),
63988
- cursorPluginDir: options.cursorPluginDir ?? path30.join(home, ".cursor", "plugins", "local", "workit"),
64307
+ opencodeConfig: options.opencodeConfig ?? path31.join(home, ".config", "opencode", "opencode.json"),
64308
+ opencodePackageCacheDir: options.opencodePackageCacheDir ?? path31.join(home, ".cache", "opencode", "packages", "@brainervirus", "workit-opencode@latest"),
64309
+ cursorSettings: options.cursorSettings ?? path31.join(home, ".cursor", "settings.json"),
64310
+ cursorMcp: options.cursorMcp ?? path31.join(home, ".cursor", "mcp.json"),
64311
+ cursorPluginDir: options.cursorPluginDir ?? path31.join(home, ".cursor", "plugins", "local", "workit"),
63989
64312
  cursorHeartbeatDir: options.stateDir ?? (env.WORKFLOW_TOOLKIT_STATE || resolveStateDir()),
63990
64313
  codexHome: options.codexHome,
63991
64314
  piAgentDir: options.piAgentDir,
@@ -63995,14 +64318,14 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
63995
64318
  };
63996
64319
  }, readJson = (p) => {
63997
64320
  try {
63998
- const parsed = JSON.parse(readFileSync13(p, "utf8"));
64321
+ const parsed = JSON.parse(readFileSync14(p, "utf8"));
63999
64322
  return parsed !== null && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
64000
64323
  } catch {
64001
64324
  return null;
64002
64325
  }
64003
64326
  }, parsesAsConfigObject = (p) => {
64004
64327
  try {
64005
- return isConfigObject(JSON.parse(readFileSync13(p, "utf8")));
64328
+ return isConfigObject(JSON.parse(readFileSync14(p, "utf8")));
64006
64329
  } catch {
64007
64330
  return false;
64008
64331
  }
@@ -64012,14 +64335,14 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
64012
64335
  ...new Set(entries.filter((entry) => typeof entry === "string" && isWorkitPlugin(entry)))
64013
64336
  ];
64014
64337
  }, commandOnPath = (name, env) => findOnPath(process.platform === "win32" ? [name, `${name}.exe`] : [name], env) !== null, pathextNames = (name, env) => process.platform === "win32" ? (env.PATHEXT ?? process.env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean).map((ext) => `${name}${ext.toLowerCase()}`) : [name], findOnPath = (names, env) => {
64015
- const dirs = (env.PATH ?? process.env.PATH ?? "").split(path30.delimiter);
64338
+ const dirs = (env.PATH ?? process.env.PATH ?? "").split(path31.delimiter);
64016
64339
  for (const dir of dirs) {
64017
64340
  if (!dir)
64018
64341
  continue;
64019
64342
  for (const candidateName of names) {
64020
- const candidate = path30.join(dir, candidateName);
64343
+ const candidate = path31.join(dir, candidateName);
64021
64344
  try {
64022
- const st = statSync4(candidate);
64345
+ const st = statSync5(candidate);
64023
64346
  if (process.platform !== "win32" && (st.mode & 73) === 0)
64024
64347
  continue;
64025
64348
  return candidate;
@@ -64028,7 +64351,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
64028
64351
  }
64029
64352
  return null;
64030
64353
  }, versionOf = (bin, env, timeout) => {
64031
- const r = spawnSync13(bin, ["--version"], { encoding: "utf8", env, timeout });
64354
+ const r = spawnSync14(bin, ["--version"], { encoding: "utf8", env, timeout });
64032
64355
  if (r.error)
64033
64356
  return null;
64034
64357
  return (r.stdout ?? "").trim();
@@ -64043,14 +64366,14 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
64043
64366
  }
64044
64367
  return true;
64045
64368
  }, resolveBun = (env) => {
64046
- if (env.BUN && existsSync13(env.BUN))
64369
+ if (env.BUN && existsSync14(env.BUN))
64047
64370
  return env.BUN;
64048
64371
  for (const candidate of [
64049
- path30.join(os8.homedir(), ".bun/bin/bun"),
64372
+ path31.join(os8.homedir(), ".bun/bin/bun"),
64050
64373
  "/usr/local/bin/bun",
64051
64374
  "/usr/bin/bun"
64052
64375
  ]) {
64053
- if (existsSync13(candidate))
64376
+ if (existsSync14(candidate))
64054
64377
  return candidate;
64055
64378
  }
64056
64379
  return commandOnPath("bun", env) ? "bun" : null;
@@ -64098,7 +64421,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
64098
64421
  detail: "no dev checkout found (WORKFLOW_TOOLKIT_DEV) — skipping version parity"
64099
64422
  };
64100
64423
  }
64101
- const corePkg = readJson(path30.join(res.dev, "packages/workit-core/package.json"));
64424
+ const corePkg = readJson(path31.join(res.dev, "packages/workit-core/package.json"));
64102
64425
  if (!corePkg) {
64103
64426
  return {
64104
64427
  id: "versions",
@@ -64108,7 +64431,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
64108
64431
  }
64109
64432
  const refs = new Set;
64110
64433
  for (const name of ["workit-opencode", "workit-cursor", "workit-cli"]) {
64111
- const pkg = readJson(path30.join(res.dev, "packages", name, "package.json"));
64434
+ const pkg = readJson(path31.join(res.dev, "packages", name, "package.json"));
64112
64435
  const dep = pkg?.dependencies?.["@brainervirus/workit-core"];
64113
64436
  if (typeof dep === "string")
64114
64437
  refs.add(dep);
@@ -64124,7 +64447,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
64124
64447
  if (refs.size > 1) {
64125
64448
  problems.push(`adapters pin different core versions: ${[...refs].join(", ")}`);
64126
64449
  }
64127
- const opencodePkg = readJson(path30.join(res.dev, "packages/workit-opencode/package.json"));
64450
+ const opencodePkg = readJson(path31.join(res.dev, "packages/workit-opencode/package.json"));
64128
64451
  const sdk = opencodePkg?.dependencies?.["@opencode/plugin"] ?? opencodePkg?.devDependencies?.["@opencode/plugin"];
64129
64452
  const sdkVersion = typeof sdk === "string" ? (sdk.match(/^\d+(?:\.\d+){0,2}/) ?? [])[0] : null;
64130
64453
  if (sdkVersion && !semverAtLeast(sdkVersion, SUPPORT_MATRIX.opencode.minimum)) {
@@ -64151,17 +64474,17 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
64151
64474
  status: "pass",
64152
64475
  detail: "opencode CLI not on PATH — skipping version check"
64153
64476
  };
64154
- const scratch = mkdtempSync(path30.join(os8.tmpdir(), "workit-doctor-opencode-"));
64477
+ const scratch = mkdtempSync(path31.join(os8.tmpdir(), "workit-doctor-opencode-"));
64155
64478
  let raw;
64156
64479
  try {
64157
64480
  raw = versionOf("opencode", {
64158
64481
  ...res.env,
64159
- XDG_DATA_HOME: path30.join(scratch, "data"),
64160
- XDG_STATE_HOME: path30.join(scratch, "state"),
64161
- XDG_CACHE_HOME: path30.join(scratch, "cache")
64482
+ XDG_DATA_HOME: path31.join(scratch, "data"),
64483
+ XDG_STATE_HOME: path31.join(scratch, "state"),
64484
+ XDG_CACHE_HOME: path31.join(scratch, "cache")
64162
64485
  }, 5000);
64163
64486
  } finally {
64164
- rmSync2(scratch, { recursive: true, force: true });
64487
+ rmSync3(scratch, { recursive: true, force: true });
64165
64488
  }
64166
64489
  const installed = raw ? (raw.match(/\d+\.\d+\.\d+/) ?? [])[0] ?? null : null;
64167
64490
  if (installed === null)
@@ -64216,7 +64539,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
64216
64539
  const tables = new Map;
64217
64540
  let text;
64218
64541
  try {
64219
- text = readFileSync13(file, "utf8");
64542
+ text = readFileSync14(file, "utf8");
64220
64543
  } catch {
64221
64544
  return tables;
64222
64545
  }
@@ -64254,19 +64577,19 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
64254
64577
  current[unquote(pair[1])] = value === "true" ? true : value === "false" ? false : unquote(value);
64255
64578
  }
64256
64579
  return tables;
64257
- }, codexHomeOf = (res) => res.codexHome ?? (res.env.CODEX_HOME || path30.join(res.home, ".codex")), codexWorkitInstalls = (res) => {
64580
+ }, codexHomeOf = (res) => res.codexHome ?? (res.env.CODEX_HOME || path31.join(res.home, ".codex")), codexWorkitInstalls = (res) => {
64258
64581
  const codexHome = codexHomeOf(res);
64259
- const configFile = path30.join(codexHome, "config.toml");
64582
+ const configFile = path31.join(codexHome, "config.toml");
64260
64583
  const installs = [];
64261
64584
  for (const [key, table] of readTomlTables(configFile)) {
64262
64585
  const [kind, id, ...rest] = key.split("\x00");
64263
64586
  if (kind !== "plugins" || rest.length > 0 || !id?.startsWith("workit@") || table.enabled === false)
64264
64587
  continue;
64265
64588
  const marketplace = id.slice("workit@".length);
64266
- const dir = path30.join(codexHome, "plugins", "cache", marketplace, "workit");
64589
+ const dir = path31.join(codexHome, "plugins", "cache", marketplace, "workit");
64267
64590
  let versions = [];
64268
64591
  try {
64269
- versions = readdirSync7(dir).filter((v) => existsSync13(path30.join(dir, v, ".codex-plugin")));
64592
+ versions = readdirSync7(dir).filter((v) => existsSync14(path31.join(dir, v, ".codex-plugin")));
64270
64593
  } catch {
64271
64594
  versions = [];
64272
64595
  }
@@ -64274,7 +64597,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
64274
64597
  installs.push({
64275
64598
  id,
64276
64599
  marketplace,
64277
- root: version ? path30.join(dir, version) : null,
64600
+ root: version ? path31.join(dir, version) : null,
64278
64601
  version,
64279
64602
  configFile
64280
64603
  });
@@ -64296,7 +64619,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
64296
64619
  };
64297
64620
  return `sha256:${createHash13("sha256").update(JSON.stringify(body)).digest("hex")}`;
64298
64621
  }, codexHookTrust = (install, tables) => {
64299
- const hooks = install.root ? readJson(path30.join(install.root, "hooks", "hooks.json"))?.hooks : null;
64622
+ const hooks = install.root ? readJson(path31.join(install.root, "hooks", "hooks.json"))?.hooks : null;
64300
64623
  if (!hooks || typeof hooks !== "object")
64301
64624
  return null;
64302
64625
  const result = [];
@@ -64369,28 +64692,28 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
64369
64692
  status: "pass",
64370
64693
  detail: "no Workit Codex plugin enabled — skipping"
64371
64694
  };
64372
- const agentsDir = path30.join(codexHomeOf(res), "agents");
64695
+ const agentsDir = path31.join(codexHomeOf(res), "agents");
64373
64696
  const problems = [];
64374
64697
  const fixes = [];
64375
64698
  const installed = [];
64376
64699
  for (const install of installs) {
64377
- const source = install.root ? path30.join(install.root, "agents") : null;
64378
- const files = source && existsSync13(source) ? readdirSync7(source).filter((f) => f.endsWith(".toml")).toSorted() : [];
64700
+ const source = install.root ? path31.join(install.root, "agents") : null;
64701
+ const files = source && existsSync14(source) ? readdirSync7(source).filter((f) => f.endsWith(".toml")).toSorted() : [];
64379
64702
  if (files.length === 0) {
64380
64703
  problems.push(`${install.id} ${install.version ?? "?"} bundles no agents`);
64381
64704
  fixes.push(`codex plugin remove ${install.id} && codex plugin add ${install.id}`);
64382
64705
  continue;
64383
64706
  }
64384
- const install_fix = `node ${JSON.stringify(path30.join(install.root, "dist", "launch-mcp.js"))} --install-agents, then start a new Codex session`;
64385
- const pluginVersion = readJson(path30.join(install.root, "package.json"))?.version;
64707
+ const install_fix = `node ${JSON.stringify(path31.join(install.root, "dist", "launch-mcp.js"))} --install-agents, then start a new Codex session`;
64708
+ const pluginVersion = readJson(path31.join(install.root, "package.json"))?.version;
64386
64709
  const version = typeof pluginVersion === "string" ? pluginVersion.match(SEMVER)?.[0] ?? null : null;
64387
64710
  let stale = false;
64388
64711
  for (const file of files) {
64389
- const dest = path30.join(agentsDir, file);
64390
- const want = stampCodexAgent(readFileSync13(path30.join(source, file), "utf8"), version);
64712
+ const dest = path31.join(agentsDir, file);
64713
+ const want = stampCodexAgent(readFileSync14(path31.join(source, file), "utf8"), version);
64391
64714
  let link = false;
64392
64715
  try {
64393
- link = lstatSync4(dest).isSymbolicLink();
64716
+ link = lstatSync5(dest).isSymbolicLink();
64394
64717
  } catch {
64395
64718
  link = false;
64396
64719
  }
@@ -64401,7 +64724,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
64401
64724
  }
64402
64725
  let have = null;
64403
64726
  try {
64404
- have = readFileSync13(dest, "utf8");
64727
+ have = readFileSync14(dest, "utf8");
64405
64728
  } catch {
64406
64729
  have = null;
64407
64730
  }
@@ -64440,7 +64763,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
64440
64763
  const env = res.env.PI_CODING_AGENT_DIR;
64441
64764
  if (env)
64442
64765
  return env === "~" ? res.home : env.replace(/^~(?=\/|\\)/, res.home);
64443
- return path30.join(res.home, ".pi", "agent");
64766
+ return path31.join(res.home, ".pi", "agent");
64444
64767
  }, npmSpecName = (spec) => {
64445
64768
  const at = spec.indexOf("@", spec.startsWith("@") ? 1 : 0);
64446
64769
  return at > 0 ? { name: spec.slice(0, at), pinned: true } : { name: spec, pinned: false };
@@ -64448,10 +64771,10 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
64448
64771
  const scopes = [
64449
64772
  {
64450
64773
  scope: "project",
64451
- settingsFile: path30.join(res.cwd, ".pi", "settings.json"),
64452
- base: path30.join(res.cwd, ".pi")
64774
+ settingsFile: path31.join(res.cwd, ".pi", "settings.json"),
64775
+ base: path31.join(res.cwd, ".pi")
64453
64776
  },
64454
- { scope: "user", settingsFile: path30.join(agentDir, "settings.json"), base: agentDir }
64777
+ { scope: "user", settingsFile: path31.join(agentDir, "settings.json"), base: agentDir }
64455
64778
  ];
64456
64779
  for (const { scope, settingsFile, base } of scopes) {
64457
64780
  const packages = readJson(settingsFile)?.packages;
@@ -64466,13 +64789,13 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
64466
64789
  const spec = npmSpecName(source.slice(4).trim());
64467
64790
  if (spec.name !== PI_PACKAGE)
64468
64791
  continue;
64469
- const root = path30.join(base, "npm", "node_modules", ...PI_PACKAGE.split("/"));
64792
+ const root = path31.join(base, "npm", "node_modules", ...PI_PACKAGE.split("/"));
64470
64793
  return { scope, settingsFile, source, filter, root, npm: { pinned: spec.pinned } };
64471
64794
  }
64472
64795
  if (/^(git:|https?:|ssh:|git@)/.test(source))
64473
64796
  continue;
64474
- const local = path30.resolve(base, source.replace(/^~(?=\/|\\)/, res.home));
64475
- if (readJson(path30.join(local, "package.json"))?.name === PI_PACKAGE)
64797
+ const local = path31.resolve(base, source.replace(/^~(?=\/|\\)/, res.home));
64798
+ if (readJson(path31.join(local, "package.json"))?.name === PI_PACKAGE)
64476
64799
  return { scope, settingsFile, source, filter, root: local, npm: null };
64477
64800
  }
64478
64801
  }
@@ -64483,7 +64806,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
64483
64806
  const list = patterns.filter((p) => typeof p === "string");
64484
64807
  if (list.length === 0)
64485
64808
  return false;
64486
- const name = path30.posix.basename(file);
64809
+ const name = path31.posix.basename(file);
64487
64810
  const matches = (p) => {
64488
64811
  const re = globToRegExp3(p);
64489
64812
  return re.test(file) || re.test(name);
@@ -64500,7 +64823,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
64500
64823
  return kept;
64501
64824
  }, checkPiExtension = (res) => {
64502
64825
  const agentDir = piAgentDirOf(res);
64503
- if (!existsSync13(agentDir) && !commandOnPath("pi", res.env))
64826
+ if (!existsSync14(agentDir) && !commandOnPath("pi", res.env))
64504
64827
  return { id: "pi_extension", status: "pass", detail: "Pi not installed — skipping" };
64505
64828
  const installCmd = (scope, spec = `npm:${PI_PACKAGE}`) => `pi install ${spec}${scope === "project" ? " -l" : ""}`;
64506
64829
  const entry = findPiEntry(res, agentDir);
@@ -64508,12 +64831,12 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
64508
64831
  return {
64509
64832
  id: "pi_extension",
64510
64833
  status: "warn",
64511
- detail: `Workit Pi extension missing: no ${PI_PACKAGE} entry in ${path30.join(agentDir, "settings.json")} or ${path30.join(res.cwd, ".pi", "settings.json")}`,
64834
+ detail: `Workit Pi extension missing: no ${PI_PACKAGE} entry in ${path31.join(agentDir, "settings.json")} or ${path31.join(res.cwd, ".pi", "settings.json")}`,
64512
64835
  fix: installCmd("user")
64513
64836
  };
64514
64837
  const where = `${entry.source} (${entry.scope}, ${entry.settingsFile})`;
64515
64838
  const rebuild = `cd ${JSON.stringify(entry.root)} && bun run build`;
64516
- const pkg = readJson(path30.join(entry.root, "package.json"));
64839
+ const pkg = readJson(path31.join(entry.root, "package.json"));
64517
64840
  if (!pkg)
64518
64841
  return {
64519
64842
  id: "pi_extension",
@@ -64522,7 +64845,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
64522
64845
  fix: entry.npm ? installCmd(entry.scope, entry.source) : `restore ${entry.root}, then ${rebuild}`
64523
64846
  };
64524
64847
  const declared = Array.isArray(pkg.pi?.extensions) ? pkg.pi.extensions.some((e) => typeof e === "string" && e.replace(/^\.\//, "") === PI_EXTENSION) : false;
64525
- if (!declared || !existsSync13(path30.join(entry.root, PI_EXTENSION)))
64848
+ if (!declared || !existsSync14(path31.join(entry.root, PI_EXTENSION)))
64526
64849
  return {
64527
64850
  id: "pi_extension",
64528
64851
  status: "warn",
@@ -64575,25 +64898,25 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
64575
64898
  detail: `Workit Pi extension ${version ?? "?"} from ${where} loads ${PI_EXTENSION}`
64576
64899
  };
64577
64900
  }, assetPathsFor = (host, dev) => {
64578
- const pkg = path30.join(dev, "packages", `workit-${host}`);
64901
+ const pkg = path31.join(dev, "packages", `workit-${host}`);
64579
64902
  switch (host) {
64580
64903
  case "opencode": {
64581
- const packaged = path30.join(pkg, "assets", "skills");
64582
- const root = existsSync13(packaged) ? packaged : path30.join(dev, "packages", "workit-core", "skills");
64583
- return WORKIT_METHOD_SKILLS.map((skill) => path30.join(root, skill, "SKILL.md"));
64904
+ const packaged = path31.join(pkg, "assets", "skills");
64905
+ const root = existsSync14(packaged) ? packaged : path31.join(dev, "packages", "workit-core", "skills");
64906
+ return WORKIT_METHOD_SKILLS.map((skill) => path31.join(root, skill, "SKILL.md"));
64584
64907
  }
64585
64908
  case "cursor":
64586
64909
  return [
64587
- path30.join(pkg, "assets", "templates", "workit-contract.md"),
64588
- path30.join(pkg, "mcp.json"),
64589
- path30.join(pkg, ".cursor-plugin")
64910
+ path31.join(pkg, "assets", "templates", "workit-contract.md"),
64911
+ path31.join(pkg, "mcp.json"),
64912
+ path31.join(pkg, ".cursor-plugin")
64590
64913
  ];
64591
64914
  case "cli":
64592
- return [path30.join(pkg, "assets", "templates", "spec-template.md")];
64915
+ return [path31.join(pkg, "assets", "templates", "spec-template.md")];
64593
64916
  }
64594
64917
  }, hostsFor = (host) => host === "cli" ? ["opencode", "cursor", "cli"] : [host], checkAssets = (res) => {
64595
64918
  const dev = res.dev;
64596
- const missing = dev ? hostsFor(res.host).flatMap((h) => assetPathsFor(h, dev).filter((p) => !existsSync13(p)).map((p) => `${h}: ${p}`)) : [];
64919
+ const missing = dev ? hostsFor(res.host).flatMap((h) => assetPathsFor(h, dev).filter((p) => !existsSync14(p)).map((p) => `${h}: ${p}`)) : [];
64597
64920
  if (res.host === "cursor" || res.host === "cli") {
64598
64921
  const cursorError = validateCursorSkills(res.cursorPluginDir, WORKIT_METHOD_SKILLS);
64599
64922
  if (cursorError)
@@ -64620,31 +64943,31 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
64620
64943
  fix: "Reinstall or rebuild the workit package (missing assets under packages/workit-<host>)"
64621
64944
  };
64622
64945
  }, launcherSlotsFor = (host, dev) => {
64623
- const pkg = path30.join(dev, "packages", `workit-${host}`);
64946
+ const pkg = path31.join(dev, "packages", `workit-${host}`);
64624
64947
  switch (host) {
64625
64948
  case "opencode":
64626
- return [[path30.join(pkg, "src", "plugin.ts"), path30.join(pkg, "dist", "plugin.js")]];
64949
+ return [[path31.join(pkg, "src", "plugin.ts"), path31.join(pkg, "dist", "plugin.js")]];
64627
64950
  case "cursor":
64628
64951
  return [
64629
- [path30.join(pkg, "dist", "mcp-server.js")],
64630
- [path30.join(pkg, "dist", "cursor-session-start.js")]
64952
+ [path31.join(pkg, "dist", "mcp-server.js")],
64953
+ [path31.join(pkg, "dist", "cursor-session-start.js")]
64631
64954
  ];
64632
64955
  case "cli":
64633
- return [[path30.join(pkg, "src", "index.tsx"), path30.join(pkg, "dist", "index.js")]];
64956
+ return [[path31.join(pkg, "src", "index.tsx"), path31.join(pkg, "dist", "index.js")]];
64634
64957
  }
64635
64958
  }, validNodeEntry = (entry, runtime, env) => {
64636
64959
  try {
64637
- const stat = statSync4(entry);
64638
- if (!stat.isFile() || stat.size === 0 || !readFileSync13(entry, "utf8").startsWith(`#!/usr/bin/env node
64960
+ const stat = statSync5(entry);
64961
+ if (!stat.isFile() || stat.size === 0 || !readFileSync14(entry, "utf8").startsWith(`#!/usr/bin/env node
64639
64962
  `)) {
64640
64963
  return false;
64641
64964
  }
64642
- return spawnSync13(runtime, ["--check", entry], { encoding: "utf8", env }).status === 0;
64965
+ return spawnSync14(runtime, ["--check", entry], { encoding: "utf8", env }).status === 0;
64643
64966
  } catch {
64644
64967
  return false;
64645
64968
  }
64646
64969
  }, registeredCursorLauncher = (res) => {
64647
- if (!existsSync13(res.cursorMcp))
64970
+ if (!existsSync14(res.cursorMcp))
64648
64971
  return "invalid";
64649
64972
  const config = readJson(res.cursorMcp);
64650
64973
  if (!config)
@@ -64657,7 +64980,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
64657
64980
  if (typeof command !== "string" || !Array.isArray(args) || typeof args[0] !== "string") {
64658
64981
  return "invalid";
64659
64982
  }
64660
- const executable = path30.basename(command).toLowerCase();
64983
+ const executable = path31.basename(command).toLowerCase();
64661
64984
  const canonical = cursorMcpServerEntry("").args;
64662
64985
  if (executable === "npx" || executable === "npx.exe" || executable === "npx.cmd") {
64663
64986
  if (args.length !== canonical.length || args.some((a, i) => a !== canonical[i]))
@@ -64669,11 +64992,11 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
64669
64992
  return {
64670
64993
  kind: "node",
64671
64994
  runtime: command,
64672
- entry: path30.isAbsolute(args[0]) ? args[0] : path30.resolve(path30.dirname(res.cursorMcp), args[0])
64995
+ entry: path31.isAbsolute(args[0]) ? args[0] : path31.resolve(path31.dirname(res.cursorMcp), args[0])
64673
64996
  };
64674
64997
  }, canonicalCursorHook, isCanonicalCursorHook = (command, res) => command === canonicalCursorHook || command === cursorHooksEntry(res.cursorPluginDir).command, registeredCursorHook = (res) => {
64675
- const hooksFile = path30.join(res.cursorPluginDir, "hooks", "hooks-cursor.json");
64676
- if (!existsSync13(hooksFile))
64998
+ const hooksFile = path31.join(res.cursorPluginDir, "hooks", "hooks-cursor.json");
64999
+ if (!existsSync14(hooksFile))
64677
65000
  return "invalid";
64678
65001
  const config = readJson(hooksFile);
64679
65002
  if (!config)
@@ -64690,9 +65013,9 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
64690
65013
  if (!m)
64691
65014
  return false;
64692
65015
  const entry = m[1].trim();
64693
- if (!path30.isAbsolute(entry))
65016
+ if (!path31.isAbsolute(entry))
64694
65017
  return false;
64695
- if (path30.resolve(entry) !== path30.resolve(path30.join(res.cursorPluginDir, "dist", "cursor-session-start.js"))) {
65018
+ if (path31.resolve(entry) !== path31.resolve(path31.join(res.cursorPluginDir, "dist", "cursor-session-start.js"))) {
64696
65019
  return false;
64697
65020
  }
64698
65021
  return validNodeEntry(entry, "node", res.env);
@@ -64701,7 +65024,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
64701
65024
  const hosts = hostsFor(res.host);
64702
65025
  const registered = hosts.includes("cursor") ? registeredCursorLauncher(res) : null;
64703
65026
  const runtime = registered && registered !== "invalid" && registered.kind === "node" ? registered.runtime : "node";
64704
- const missing = hosts.includes("cursor") ? ["dist/mcp-server.js", "dist/cursor-session-start.js"].map((rel) => path30.join(res.cursorPluginDir, rel)).filter((p) => !validNodeEntry(p, runtime, res.env)).map((p) => `cursor: ${p}`) : [];
65027
+ const missing = hosts.includes("cursor") ? ["dist/mcp-server.js", "dist/cursor-session-start.js"].map((rel) => path31.join(res.cursorPluginDir, rel)).filter((p) => !validNodeEntry(p, runtime, res.env)).map((p) => `cursor: ${p}`) : [];
64705
65028
  if (hosts.includes("cursor")) {
64706
65029
  if (registered === "invalid") {
64707
65030
  missing.push(`cursor: canonical workit MCP launcher in ${res.cursorMcp}`);
@@ -64710,13 +65033,13 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
64710
65033
  }
64711
65034
  const hook = registeredCursorHook(res);
64712
65035
  if (hook === "invalid") {
64713
- missing.push(`cursor: canonical session-start hook in ${path30.join(res.cursorPluginDir, "hooks", "hooks-cursor.json")}`);
65036
+ missing.push(`cursor: canonical session-start hook in ${path31.join(res.cursorPluginDir, "hooks", "hooks-cursor.json")}`);
64714
65037
  } else if (hook !== null && !isCanonicalCursorHook(hook, res) && !validLocalDistHook(hook, res)) {
64715
- missing.push(`cursor: canonical session-start hook in ${path30.join(res.cursorPluginDir, "hooks", "hooks-cursor.json")} (registered ${hook})`);
65038
+ missing.push(`cursor: canonical session-start hook in ${path31.join(res.cursorPluginDir, "hooks", "hooks-cursor.json")} (registered ${hook})`);
64716
65039
  }
64717
65040
  }
64718
65041
  if (dev) {
64719
- missing.push(...hosts.filter((h) => h !== "cursor").flatMap((h) => launcherSlotsFor(h, dev).filter((slot) => !slot.some((p) => existsSync13(p))).map((slot) => `${h}: ${slot.join(" or ")}`)));
65042
+ missing.push(...hosts.filter((h) => h !== "cursor").flatMap((h) => launcherSlotsFor(h, dev).filter((slot) => !slot.some((p) => existsSync14(p))).map((slot) => `${h}: ${slot.join(" or ")}`)));
64720
65043
  }
64721
65044
  if (missing.length > 0) {
64722
65045
  return {
@@ -64741,21 +65064,21 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
64741
65064
  }, CURSOR_HOOK_FIX = "Run `workit init` and select Cursor to install the bundled hook", checkCursorHook = (res) => {
64742
65065
  if (!hostsFor(res.host).includes("cursor"))
64743
65066
  return { id: "cursor_hook", status: "pass", detail: "cursor hook not inspected on this host" };
64744
- if (!existsSync13(res.cursorPluginDir))
65067
+ if (!existsSync14(res.cursorPluginDir))
64745
65068
  return {
64746
65069
  id: "cursor_hook",
64747
65070
  status: "pass",
64748
65071
  detail: "no Cursor plugin install — hook launcher not inspected"
64749
65072
  };
64750
- const launcher = path30.join(res.cursorPluginDir, "hooks", "launch.mjs");
64751
- if (!existsSync13(launcher))
65073
+ const launcher = path31.join(res.cursorPluginDir, "hooks", "launch.mjs");
65074
+ if (!existsSync14(launcher))
64752
65075
  return {
64753
65076
  id: "cursor_hook",
64754
65077
  status: "warn",
64755
65078
  detail: `cursor hook launcher mode: missing — ${launcher} is absent (an install from before the pinned launcher)`,
64756
65079
  fix: CURSOR_HOOK_FIX
64757
65080
  };
64758
- const hooksFile = path30.join(res.cursorPluginDir, "hooks", "hooks-cursor.json");
65081
+ const hooksFile = path31.join(res.cursorPluginDir, "hooks", "hooks-cursor.json");
64759
65082
  const registered = readJson(hooksFile);
64760
65083
  const sessionCommand = registered?.hooks?.sessionStart?.[0]?.command;
64761
65084
  const offLauncher = [
@@ -64770,7 +65093,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
64770
65093
  fix: "Re-run install-cursor-plugin.sh (or `workit init` with Cursor) to rewrite the hook entries"
64771
65094
  };
64772
65095
  const started = performance.now();
64773
- const probe = spawnSync13("node", [launcher, "--probe", "workit-cursor-hook"], {
65096
+ const probe = spawnSync14("node", [launcher, "--probe", "workit-cursor-hook"], {
64774
65097
  encoding: "utf8",
64775
65098
  env: { ...res.env, WORKIT_CURSOR_HOOK_NPX_OFFLINE: "1" },
64776
65099
  timeout: 40000,
@@ -64817,15 +65140,15 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
64817
65140
  return { id: "cursor_hook", status: "pass", detail: `${label}; probe ${ms} ms` };
64818
65141
  }, SILENT_HOOK_GRACE_MS, mtimeMs = (file) => {
64819
65142
  try {
64820
- return statSync4(file).mtimeMs;
65143
+ return statSync5(file).mtimeMs;
64821
65144
  } catch {
64822
65145
  return null;
64823
65146
  }
64824
65147
  }, silentCursorHooks = (res) => {
64825
- const session = mtimeMs(path30.join(res.cursorHeartbeatDir, "cursor-session-last-start"));
65148
+ const session = mtimeMs(path31.join(res.cursorHeartbeatDir, "cursor-session-last-start"));
64826
65149
  if (session === null || Date.now() - session < SILENT_HOOK_GRACE_MS)
64827
65150
  return null;
64828
- const hook = mtimeMs(path30.join(res.cursorHeartbeatDir, "cursor-hook-last-run"));
65151
+ const hook = mtimeMs(path31.join(res.cursorHeartbeatDir, "cursor-hook-last-run"));
64829
65152
  if (hook !== null && hook >= session)
64830
65153
  return null;
64831
65154
  return `Cursor started the Workit MCP server at ${new Date(session).toISOString()} but no Workit hook has run since${hook === null ? " (none ever)" : ""} — if the agent ran in that window, Cursor is not running the plugin hooks and Workit enforcement is off`;
@@ -64866,7 +65189,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
64866
65189
  return "fragile-cache";
64867
65190
  if (entry.startsWith("file:")) {
64868
65191
  const target = entry.replace(/^file:\/\//, "").replace(/^file:/, "");
64869
- return existsSync13(target) ? "ok" : "missing-file";
65192
+ return existsSync14(target) ? "ok" : "missing-file";
64870
65193
  }
64871
65194
  return "ok";
64872
65195
  }, checkStalePin = (res) => {
@@ -64877,7 +65200,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
64877
65200
  detail: "opencode pin not inspected on the cursor host"
64878
65201
  };
64879
65202
  }
64880
- if (!existsSync13(res.opencodeConfig)) {
65203
+ if (!existsSync14(res.opencodeConfig)) {
64881
65204
  return {
64882
65205
  id: "stale_pin",
64883
65206
  status: "pass",
@@ -64921,8 +65244,8 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
64921
65244
  }
64922
65245
  return { id: "stale_pin", status: "pass", detail: "opencode pin resolves" };
64923
65246
  }, pluginMcpSelectors = (res) => {
64924
- const p = path30.join(res.cursorPluginDir, "mcp.json");
64925
- if (!existsSync13(p))
65247
+ const p = path31.join(res.cursorPluginDir, "mcp.json");
65248
+ if (!existsSync14(p))
64926
65249
  return null;
64927
65250
  const cfg = readJson(p);
64928
65251
  const server = cfg?.mcpServers?.workit;
@@ -64944,7 +65267,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
64944
65267
  if (!cmd)
64945
65268
  return null;
64946
65269
  try {
64947
- const r = spawnSync13(cmd, ["view", pkgName, "version"], {
65270
+ const r = spawnSync14(cmd, ["view", pkgName, "version"], {
64948
65271
  encoding: "utf8",
64949
65272
  timeout: 20000,
64950
65273
  env: res.env
@@ -64955,13 +65278,13 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
64955
65278
  return null;
64956
65279
  }
64957
65280
  }, installedPluginVersion = (res) => {
64958
- const pkg = readJson(path30.join(res.cursorPluginDir, "package.json"));
65281
+ const pkg = readJson(path31.join(res.cursorPluginDir, "package.json"));
64959
65282
  return typeof pkg?.version === "string" && pkg.version ? pkg.version : null;
64960
65283
  }, installedOpenCodeCacheVersion = (res) => {
64961
- const pkg = readJson(path30.join(res.opencodePackageCacheDir, "node_modules", "@brainervirus", "workit-opencode", "package.json"));
65284
+ const pkg = readJson(path31.join(res.opencodePackageCacheDir, "node_modules", "@brainervirus", "workit-opencode", "package.json"));
64962
65285
  return typeof pkg?.version === "string" && pkg.version ? pkg.version : null;
64963
65286
  }, checkOpenCodePackageCache = (res) => {
64964
- if (!existsSync13(res.opencodeConfig)) {
65287
+ if (!existsSync14(res.opencodeConfig)) {
64965
65288
  return {
64966
65289
  id: "stale_install",
64967
65290
  status: "pass",
@@ -65035,7 +65358,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
65035
65358
  detail: "cursor plugin not inspected on this host"
65036
65359
  };
65037
65360
  }
65038
- if (existsSync13(res.cursorPluginDir) && lstatSync4(res.cursorPluginDir).isSymbolicLink()) {
65361
+ if (existsSync14(res.cursorPluginDir) && lstatSync5(res.cursorPluginDir).isSymbolicLink()) {
65039
65362
  let target = "";
65040
65363
  try {
65041
65364
  target = readlinkSync2(res.cursorPluginDir);
@@ -65061,7 +65384,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
65061
65384
  fix: "Re-run install-cursor-plugin.sh — it rewrites the workit MCP entry to the canonical @latest selector"
65062
65385
  };
65063
65386
  }
65064
- const hooksFile = path30.join(res.cursorPluginDir, "hooks", "hooks-cursor.json");
65387
+ const hooksFile = path31.join(res.cursorPluginDir, "hooks", "hooks-cursor.json");
65065
65388
  const hookCmd = readJson(hooksFile)?.hooks?.sessionStart?.[0]?.command ?? null;
65066
65389
  const canonicalHook = canonicalCursorHook;
65067
65390
  const staleHook = hookCmd !== null && !isCanonicalCursorHook(hookCmd, res) && !hookCmd.startsWith("node ") && hookCmd.includes("@brainervirus/workit-cursor@");
@@ -65073,7 +65396,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
65073
65396
  fix: "Re-run install-cursor-plugin.sh — it rewrites the sessionStart hook to the canonical pinned launcher"
65074
65397
  };
65075
65398
  }
65076
- const hookDrift = existsSync13(hooksFile) ? cursorHookDrift(readJson(hooksFile), res.cursorPluginDir) : [];
65399
+ const hookDrift = existsSync14(hooksFile) ? cursorHookDrift(readJson(hooksFile), res.cursorPluginDir) : [];
65077
65400
  if (hookDrift.length > 0) {
65078
65401
  return {
65079
65402
  id: "stale_install",
@@ -65083,7 +65406,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
65083
65406
  };
65084
65407
  }
65085
65408
  const installed = installedPluginVersion(res);
65086
- const source = res.dev ? readJson(path30.join(res.dev, "packages/workit-cursor/package.json"))?.version ?? null : readJson(path30.join(packageRoot(), "package.json"))?.version ?? null;
65409
+ const source = res.dev ? readJson(path31.join(res.dev, "packages/workit-cursor/package.json"))?.version ?? null : readJson(path31.join(packageRoot(), "package.json"))?.version ?? null;
65087
65410
  const localDist = mcpSelectors === null && hookCmd !== null && !isCanonicalCursorHook(hookCmd, res) && hookCmd.startsWith("node ");
65088
65411
  if (localDist && installed !== null && source !== null && !semverAtLeast(installed, source)) {
65089
65412
  return {
@@ -65095,7 +65418,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
65095
65418
  }
65096
65419
  if (localDist && installed !== null && source !== null && res.dev) {
65097
65420
  const entry = /^node\s+(.+)$/.exec((hookCmd ?? "").trim())?.[1]?.trim() ?? "";
65098
- const sourceBundle = entry && path30.isAbsolute(entry) ? path30.join(res.dev, "packages", "workit-cursor", "dist", path30.basename(entry)) : "";
65421
+ const sourceBundle = entry && path31.isAbsolute(entry) ? path31.join(res.dev, "packages", "workit-cursor", "dist", path31.basename(entry)) : "";
65099
65422
  if (entry && sourceBundle) {
65100
65423
  const installedHash = bundleHashOfFile(entry);
65101
65424
  const sourceHash = bundleHashOfFile(sourceBundle);
@@ -65103,7 +65426,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
65103
65426
  return {
65104
65427
  id: "stale_install",
65105
65428
  status: "fail",
65106
- detail: `stale_install: installed workit-cursor ${installed} runs different bytes than the current runtime build (${path30.basename(entry)} hash mismatch)`,
65429
+ detail: `stale_install: installed workit-cursor ${installed} runs different bytes than the current runtime build (${path31.basename(entry)} hash mismatch)`,
65107
65430
  fix: "Re-run install-cursor-plugin.sh — it refreshes the plugin directory with the current build"
65108
65431
  };
65109
65432
  }
@@ -65157,13 +65480,13 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
65157
65480
  const problems = [];
65158
65481
  const opencodeHost = res.host !== "cursor";
65159
65482
  const cursorHost = res.host !== "opencode";
65160
- if (opencodeHost && existsSync13(res.opencodeConfig)) {
65483
+ if (opencodeHost && existsSync14(res.opencodeConfig)) {
65161
65484
  const cfg = readJson(res.opencodeConfig);
65162
65485
  const entries = pluginEntries(cfg);
65163
65486
  if (entries.length > 1)
65164
65487
  problems.push(`opencode registers ${entries.length} workit plugin entries`);
65165
65488
  }
65166
- if (cursorHost && existsSync13(res.cursorSettings)) {
65489
+ if (cursorHost && existsSync14(res.cursorSettings)) {
65167
65490
  const settings = readJson(res.cursorSettings);
65168
65491
  const enabled = settings?.enabled_plugins;
65169
65492
  if (enabled && typeof enabled === "object") {
@@ -65178,7 +65501,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
65178
65501
  if (dirs.length > 1)
65179
65502
  problems.push(`cursor plugin_dirs has ${dirs.length} workit entries`);
65180
65503
  }
65181
- if (cursorHost && existsSync13(res.cursorMcp)) {
65504
+ if (cursorHost && existsSync14(res.cursorMcp)) {
65182
65505
  const mcp = readJson(res.cursorMcp);
65183
65506
  const servers = mcp?.mcpServers ?? {};
65184
65507
  if (servers && typeof servers === "object") {
@@ -65203,17 +65526,17 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
65203
65526
  }, checkMalformedConfig = (res) => {
65204
65527
  const files = [];
65205
65528
  for (const name of ["config.json", "youtrack.json", "vcs.json", "workspaces.json"]) {
65206
- const p = path30.join(res.configDir, name);
65207
- if (existsSync13(p))
65529
+ const p = path31.join(res.configDir, name);
65530
+ if (existsSync14(p))
65208
65531
  files.push(p);
65209
65532
  }
65210
65533
  const opencodeHost = res.host !== "cursor";
65211
65534
  const cursorHost = res.host !== "opencode";
65212
- if (opencodeHost && existsSync13(res.opencodeConfig))
65535
+ if (opencodeHost && existsSync14(res.opencodeConfig))
65213
65536
  files.push(res.opencodeConfig);
65214
- if (cursorHost && existsSync13(res.cursorSettings))
65537
+ if (cursorHost && existsSync14(res.cursorSettings))
65215
65538
  files.push(res.cursorSettings);
65216
- if (cursorHost && existsSync13(res.cursorMcp))
65539
+ if (cursorHost && existsSync14(res.cursorMcp))
65217
65540
  files.push(res.cursorMcp);
65218
65541
  const bad = files.filter((p) => !parsesAsConfigObject(p));
65219
65542
  if (bad.length === 0)
@@ -65292,19 +65615,90 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
65292
65615
  detail: `current directory ${res.cwd} does not match any configured workspace`,
65293
65616
  fix: `Add a workspace glob matching this directory to ${file} or run /wk-init`
65294
65617
  };
65618
+ }, matchedWorkspace = (res) => {
65619
+ try {
65620
+ return resolveWorkspaceFrom(res.cwd, res.configDir, res.env.WORKFLOW_WORKSPACE_NAME?.trim() || undefined);
65621
+ } catch {
65622
+ return null;
65623
+ }
65624
+ }, SESSION_HOOK_FIX = "workit doctor --fix", sessionHookFinding = (hook) => {
65625
+ const slot = `${SESSION_HOOK_NAME} hook`;
65626
+ switch (hook.state) {
65627
+ case "not_git":
65628
+ return { status: "pass", detail: `not inside a git work tree — skipping the ${slot}` };
65629
+ case "installed":
65630
+ return {
65631
+ status: "pass",
65632
+ detail: `${slot} ${hook.hookPath} adds the Workit-Session trailer to plain git commits`
65633
+ };
65634
+ case "manual":
65635
+ return hook.helperCurrent ? {
65636
+ status: "pass",
65637
+ detail: `${hook.manualTarget} adds the Workit-Session trailer to plain git commits (via ${hook.via})`
65638
+ } : {
65639
+ status: "warn",
65640
+ detail: `${hook.manualTarget} runs the Workit helper (via ${hook.via}), but ${hook.helperPath} is missing or an older version`,
65641
+ fix: SESSION_HOOK_FIX
65642
+ };
65643
+ case "missing":
65644
+ return {
65645
+ status: "warn",
65646
+ detail: `no ${slot} at ${hook.hookPath}: plain git commits from an agent session get no Workit-Session trailer`,
65647
+ fix: SESSION_HOOK_FIX
65648
+ };
65649
+ case "outdated":
65650
+ return {
65651
+ status: "warn",
65652
+ detail: `the Workit ${slot} at ${hook.hookPath} or its helper ${hook.helperPath} is missing or an older version`,
65653
+ fix: SESSION_HOOK_FIX
65654
+ };
65655
+ case "blocked":
65656
+ return {
65657
+ status: "warn",
65658
+ detail: `plain git commits get no Workit-Session trailer and --fix will not install the ${slot}: ${hook.reason}`,
65659
+ fix: hook.helperCurrent ? hook.manual : `${SESSION_HOOK_FIX} (writes ${hook.helperPath}), then ${hook.manual}`
65660
+ };
65661
+ }
65662
+ }, checkSessionHook = (res) => {
65663
+ if (!matchedWorkspace(res))
65664
+ return {
65665
+ id: "session_hook",
65666
+ status: "pass",
65667
+ detail: `not in a Workit workspace — skipping the ${SESSION_HOOK_NAME} session hook`
65668
+ };
65669
+ const hook = inspectSessionHook(res.cwd, res.env);
65670
+ const finding = sessionHookFinding(hook);
65671
+ if (!hook.leftover)
65672
+ return { id: "session_hook", ...finding };
65673
+ return {
65674
+ id: "session_hook",
65675
+ status: "warn",
65676
+ detail: `${finding.detail}; ${hook.leftover}`,
65677
+ fix: finding.fix ? `${finding.fix}; ${hook.leftover}` : hook.leftover
65678
+ };
65679
+ }, fixSessionHook = (options = {}) => {
65680
+ const res = resolve(options);
65681
+ const workspace = matchedWorkspace(res);
65682
+ if (!workspace)
65683
+ return {
65684
+ action: "skipped",
65685
+ detail: `${res.cwd} is not in a Workit workspace; no hook installed`,
65686
+ workspace: null
65687
+ };
65688
+ return { ...installSessionHook(res.cwd, res.env), workspace: workspace.name };
65295
65689
  }, isPlaceholder = (p) => {
65296
65690
  try {
65297
- return readFileSync13(p, "utf8").trim() === TOKEN_PLACEHOLDER2;
65691
+ return readFileSync14(p, "utf8").trim() === TOKEN_PLACEHOLDER2;
65298
65692
  } catch {
65299
65693
  return false;
65300
65694
  }
65301
65695
  }, checkCredentialMetadata = (res) => {
65302
65696
  const tokenPaths = [];
65303
- const youtrackJson = readJson(path30.join(res.configDir, "youtrack.json"));
65697
+ const youtrackJson = readJson(path31.join(res.configDir, "youtrack.json"));
65304
65698
  if (youtrackJson) {
65305
- tokenPaths.push(typeof youtrackJson.tokenFile === "string" ? youtrackJson.tokenFile : path30.join(res.configDir, "youtrack.token"));
65306
- } else if (existsSync13(path30.join(res.configDir, "youtrack.token"))) {
65307
- tokenPaths.push(path30.join(res.configDir, "youtrack.token"));
65699
+ tokenPaths.push(typeof youtrackJson.tokenFile === "string" ? youtrackJson.tokenFile : path31.join(res.configDir, "youtrack.token"));
65700
+ } else if (existsSync14(path31.join(res.configDir, "youtrack.token"))) {
65701
+ tokenPaths.push(path31.join(res.configDir, "youtrack.token"));
65308
65702
  }
65309
65703
  if (tokenPaths.length === 0) {
65310
65704
  return {
@@ -65315,13 +65709,13 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
65315
65709
  }
65316
65710
  const problems = [];
65317
65711
  for (const raw of tokenPaths) {
65318
- const p = path30.isAbsolute(raw) ? raw : path30.resolve(res.configDir, raw);
65319
- if (!existsSync13(p)) {
65712
+ const p = path31.isAbsolute(raw) ? raw : path31.resolve(res.configDir, raw);
65713
+ if (!existsSync14(p)) {
65320
65714
  problems.push(`${p} is missing`);
65321
65715
  continue;
65322
65716
  }
65323
65717
  if (process.platform !== "win32") {
65324
- const mode = statSync4(p).mode & 511;
65718
+ const mode = statSync5(p).mode & 511;
65325
65719
  if (mode !== 384)
65326
65720
  problems.push(`${p} must be mode 0600 (found ${mode.toString(8)})`);
65327
65721
  }
@@ -65383,7 +65777,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
65383
65777
  }, defaultIdentityProbes = (env) => ({
65384
65778
  origin: (cwd) => {
65385
65779
  try {
65386
- const out = spawnSync13("git", ["remote", "get-url", "origin"], {
65780
+ const out = spawnSync14("git", ["remote", "get-url", "origin"], {
65387
65781
  cwd,
65388
65782
  encoding: "utf8",
65389
65783
  env
@@ -65395,7 +65789,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
65395
65789
  },
65396
65790
  ghLogin: (e) => {
65397
65791
  try {
65398
- const out = spawnSync13("gh", ["api", "user", "--jq", ".login"], { encoding: "utf8", env: e });
65792
+ const out = spawnSync14("gh", ["api", "user", "--jq", ".login"], { encoding: "utf8", env: e });
65399
65793
  const login = (out.stdout ?? "").trim();
65400
65794
  return out.status === 0 && login ? login : null;
65401
65795
  } catch {
@@ -65404,7 +65798,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
65404
65798
  },
65405
65799
  glabLogin: (e) => {
65406
65800
  try {
65407
- const out = spawnSync13("glab", ["api", "user", "--jq", ".username"], {
65801
+ const out = spawnSync14("glab", ["api", "user", "--jq", ".username"], {
65408
65802
  encoding: "utf8",
65409
65803
  env: e
65410
65804
  });
@@ -65416,7 +65810,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
65416
65810
  },
65417
65811
  sshLogin: (host) => {
65418
65812
  try {
65419
- const out = spawnSync13("ssh", ["-o", "BatchMode=yes", "-o", "ConnectTimeout=5", "-T", `git@${host}`], {
65813
+ const out = spawnSync14("ssh", ["-o", "BatchMode=yes", "-o", "ConnectTimeout=5", "-T", `git@${host}`], {
65420
65814
  encoding: "utf8",
65421
65815
  env
65422
65816
  });
@@ -65431,7 +65825,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
65431
65825
  const remoteHost = githubHostFromRemote(probes.origin(res.cwd) ?? "");
65432
65826
  if (!remoteHost)
65433
65827
  return { id: "github_identity", status: "pass", detail: "no GitHub remote configured" };
65434
- const vcsJson = readJson(res.env.WORKFLOW_VCS_CONFIG ?? path30.join(res.configDir, "vcs.json"));
65828
+ const vcsJson = readJson(res.env.WORKFLOW_VCS_CONFIG ?? path31.join(res.configDir, "vcs.json"));
65435
65829
  const workspace = workspaceProviderForIdentity(res.cwd, res.configDir, res.env);
65436
65830
  if (workspace.error)
65437
65831
  return {
@@ -65459,7 +65853,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
65459
65853
  const remoteHost = githubHostFromRemote(probes.origin(res.cwd) ?? "");
65460
65854
  if (!remoteHost)
65461
65855
  return { id: "gitlab_identity", status: "pass", detail: "no GitLab remote configured" };
65462
- const vcsJson = readJson(res.env.WORKFLOW_VCS_CONFIG ?? path30.join(res.configDir, "vcs.json"));
65856
+ const vcsJson = readJson(res.env.WORKFLOW_VCS_CONFIG ?? path31.join(res.configDir, "vcs.json"));
65463
65857
  const workspace = workspaceProviderForIdentity(res.cwd, res.configDir, res.env);
65464
65858
  if (workspace.error)
65465
65859
  return {
@@ -65485,11 +65879,11 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
65485
65879
  { surface: "SSH", login: probes.sshLogin(remoteHost) }
65486
65880
  ]);
65487
65881
  }, checkLogWritable = (res) => {
65488
- const logsDir = path30.join(res.stateDir, "logs");
65489
- const probe = path30.join(logsDir, "doctor-probe.tmp");
65882
+ const logsDir = path31.join(res.stateDir, "logs");
65883
+ const probe = path31.join(logsDir, "doctor-probe.tmp");
65490
65884
  try {
65491
- mkdirSync5(logsDir, { recursive: true, mode: 448 });
65492
- writeFileSync6(probe, `{"probe":true}
65885
+ mkdirSync6(logsDir, { recursive: true, mode: 448 });
65886
+ writeFileSync7(probe, `{"probe":true}
65493
65887
  `, { mode: 384 });
65494
65888
  return {
65495
65889
  id: "log_writable",
@@ -65576,7 +65970,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
65576
65970
  }, CLI_PACKAGE = "@brainervirus/workit-cli", SEMVER, WORKIT_PROBE_TIMEOUT_MS = 1e4, workitVersions, workitVersionAt = (bin, env) => {
65577
65971
  let key;
65578
65972
  try {
65579
- const st = statSync4(bin);
65973
+ const st = statSync5(bin);
65580
65974
  key = `${bin}:${st.ino}:${st.size}:${st.mtimeMs}`;
65581
65975
  } catch {
65582
65976
  return { version: null, timedOut: false };
@@ -65585,12 +65979,12 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
65585
65979
  if (cached)
65586
65980
  return cached;
65587
65981
  const viaShell = process.platform === "win32" && /\.(?:cmd|bat)$/i.test(bin);
65588
- const r = viaShell ? spawnSync13(`"${bin}" --version`, {
65982
+ const r = viaShell ? spawnSync14(`"${bin}" --version`, {
65589
65983
  encoding: "utf8",
65590
65984
  env,
65591
65985
  timeout: WORKIT_PROBE_TIMEOUT_MS,
65592
65986
  shell: true
65593
- }) : spawnSync13(bin, ["--version"], { encoding: "utf8", env, timeout: WORKIT_PROBE_TIMEOUT_MS });
65987
+ }) : spawnSync14(bin, ["--version"], { encoding: "utf8", env, timeout: WORKIT_PROBE_TIMEOUT_MS });
65594
65988
  const timedOut = r.error !== undefined && "code" in r.error && r.error.code === "ETIMEDOUT";
65595
65989
  const version = r.status === 0 ? (r.stdout ?? "").match(SEMVER)?.[0] ?? null : null;
65596
65990
  const probe = { version: timedOut ? null : version, timedOut };
@@ -65680,6 +66074,7 @@ var init_doctor = __esm(() => {
65680
66074
  init_workspaces();
65681
66075
  init_host_install();
65682
66076
  init_skill_manifests();
66077
+ init_session_hook();
65683
66078
  OPENCODE_V1_FIX = `OpenCode < ${SUPPORT_MATRIX.opencode.minimum} cannot load Workit 3 (V2 plugin API only): upgrade OpenCode to ${SUPPORT_MATRIX.opencode.minimum}+, or stay on Workit 2.x by pinning "@brainervirus/workit-opencode@2" in the opencode.json "plugin" array`;
65684
66079
  AGENT_MARKER_VERSION = /^# Generated by Workit (\d+\.\d+\.\d+)\b/;
65685
66080
  canonicalCursorHook = cursorHooksEntry().command;
@@ -65706,6 +66101,7 @@ var init_doctor = __esm(() => {
65706
66101
  checkMalformedConfig,
65707
66102
  checkWorkspaceMismatch,
65708
66103
  checkWorkspaceLock,
66104
+ checkSessionHook,
65709
66105
  checkCredentialMetadata,
65710
66106
  checkGithubIdentity,
65711
66107
  checkGitLabIdentity,
@@ -65727,20 +66123,20 @@ var init_doctor = __esm(() => {
65727
66123
  import {
65728
66124
  copyFileSync as copyFileSync4,
65729
66125
  cpSync as cpSync4,
65730
- existsSync as existsSync14,
65731
- lstatSync as lstatSync5,
65732
- mkdirSync as mkdirSync6,
66126
+ existsSync as existsSync15,
66127
+ lstatSync as lstatSync6,
66128
+ mkdirSync as mkdirSync7,
65733
66129
  mkdtempSync as mkdtempSync2,
65734
- readFileSync as readFileSync14,
66130
+ readFileSync as readFileSync15,
65735
66131
  readdirSync as readdirSync8,
65736
66132
  realpathSync as realpathSync7,
65737
- renameSync as renameSync3,
65738
- rmSync as rmSync3,
65739
- statSync as statSync5,
65740
- writeFileSync as writeFileSync7
66133
+ renameSync as renameSync4,
66134
+ rmSync as rmSync4,
66135
+ statSync as statSync6,
66136
+ writeFileSync as writeFileSync8
65741
66137
  } from "node:fs";
65742
66138
  import os9 from "node:os";
65743
- import path31 from "node:path";
66139
+ import path32 from "node:path";
65744
66140
  import { isDeepStrictEqual as isDeepStrictEqual2 } from "node:util";
65745
66141
  function parseList(raw) {
65746
66142
  return raw.split(",").map((s) => s.trim()).filter(Boolean);
@@ -65784,7 +66180,7 @@ function buildSetupPreview(values, opts = {}) {
65784
66180
  const current = readConfigFromDir(state.configDir);
65785
66181
  mutations.push({
65786
66182
  type: "merge-json",
65787
- path: path31.join(state.configDir, "config.json"),
66183
+ path: path32.join(state.configDir, "config.json"),
65788
66184
  value: {
65789
66185
  locale: values.locale,
65790
66186
  localeOptions: current.localeOptions,
@@ -65810,17 +66206,17 @@ function buildSetupPreview(values, opts = {}) {
65810
66206
  if (blocked.length === 0) {
65811
66207
  mutations.push({
65812
66208
  type: "update-workspaces",
65813
- path: path31.join(state.configDir, "workspaces.json"),
66209
+ path: path32.join(state.configDir, "workspaces.json"),
65814
66210
  entries: values.workspaces,
65815
66211
  expectedRevision: diskWorkspaceResult.revision
65816
66212
  });
65817
66213
  }
65818
66214
  }
65819
66215
  if (values.baseUrl.trim()) {
65820
- const ytPath = path31.join(state.configDir, "youtrack.json");
66216
+ const ytPath = path32.join(state.configDir, "youtrack.json");
65821
66217
  const ytExisting = readConfigRecord(ytPath);
65822
66218
  const ytConfigured = configuredTokenPath(ytExisting, "tokenFile");
65823
- const tokenPath = resolveTokenPath(ytConfigured, path31.join(state.configDir, "youtrack.token"), values.tokenPaths?.youtrack);
66219
+ const tokenPath = resolveTokenPath(ytConfigured, path32.join(state.configDir, "youtrack.token"), values.tokenPaths?.youtrack);
65824
66220
  const draft = youtrackDraft(values, tokenPath);
65825
66221
  if (ytConfigured !== null && tokenPath !== ytConfigured) {
65826
66222
  delete draft.tokenFile;
@@ -65836,7 +66232,7 @@ function buildSetupPreview(values, opts = {}) {
65836
66232
  path: ytPath,
65837
66233
  value: draft
65838
66234
  });
65839
- if (existsSync14(tokenPath))
66235
+ if (existsSync15(tokenPath))
65840
66236
  preserved.push(tokenPath);
65841
66237
  else
65842
66238
  mutations.push({
@@ -65848,7 +66244,7 @@ function buildSetupPreview(values, opts = {}) {
65848
66244
  });
65849
66245
  }
65850
66246
  if (values.vcsProvider !== "skip") {
65851
- const vcsPath = path31.join(state.configDir, "vcs.json");
66247
+ const vcsPath = path32.join(state.configDir, "vcs.json");
65852
66248
  mutations.push({
65853
66249
  type: "merge-json",
65854
66250
  path: vcsPath,
@@ -65877,7 +66273,7 @@ function buildSetupPreview(values, opts = {}) {
65877
66273
  mutations.push({
65878
66274
  type: "install-host",
65879
66275
  platform: "cursor",
65880
- path: path31.join(paths.home, ".cursor", "plugins", "local", ".workit-package-bootstrap"),
66276
+ path: path32.join(paths.home, ".cursor", "plugins", "local", ".workit-package-bootstrap"),
65881
66277
  commands
65882
66278
  });
65883
66279
  }
@@ -65890,7 +66286,7 @@ function buildSetupPreview(values, opts = {}) {
65890
66286
  mutations.push({
65891
66287
  type: "install-host",
65892
66288
  platform,
65893
- path: platform === "claude-code" ? claudeInstallRecord(paths.home, env) : platform === "codex" ? path31.join(env.CODEX_HOME ?? path31.join(paths.home, ".codex"), "plugins", "cache", "workflow-toolkit", "workit") : path31.join(env.PI_CODING_AGENT_DIR ?? path31.join(paths.home, ".pi", "agent"), "settings.json"),
66289
+ path: platform === "claude-code" ? claudeInstallRecord(paths.home, env) : platform === "codex" ? path32.join(env.CODEX_HOME ?? path32.join(paths.home, ".codex"), "plugins", "cache", "workflow-toolkit", "workit") : path32.join(env.PI_CODING_AGENT_DIR ?? path32.join(paths.home, ".pi", "agent"), "settings.json"),
65894
66290
  commands
65895
66291
  });
65896
66292
  }
@@ -65898,9 +66294,9 @@ function buildSetupPreview(values, opts = {}) {
65898
66294
  }
65899
66295
  }
65900
66296
  if (values.applyProject) {
65901
- const root = path31.resolve(opts.cwd ?? process.cwd());
65902
- const gitignorePath = path31.join(root, ".gitignore");
65903
- const existing = existsSync14(gitignorePath) ? readFileSync14(gitignorePath, "utf8") : "";
66297
+ const root = path32.resolve(opts.cwd ?? process.cwd());
66298
+ const gitignorePath = path32.join(root, ".gitignore");
66299
+ const existing = existsSync15(gitignorePath) ? readFileSync15(gitignorePath, "utf8") : "";
65904
66300
  const existingLines = new Set(existing.split(`
65905
66301
  `).map((l) => l.trim()).filter(Boolean));
65906
66302
  const entries = GITIGNORE_ENTRIES.filter((e) => e.trim() !== "" && !existingLines.has(e.trim()));
@@ -65936,10 +66332,10 @@ function deepMerge(base, patch) {
65936
66332
  return out;
65937
66333
  }
65938
66334
  function applyMutation(m) {
65939
- const dir = path31.dirname(m.path);
66335
+ const dir = path32.dirname(m.path);
65940
66336
  switch (m.type) {
65941
66337
  case "create-file": {
65942
- mkdirSync6(dir, { recursive: true });
66338
+ mkdirSync7(dir, { recursive: true });
65943
66339
  const res = writeFileExclusive(m.path, m.content, m.mode);
65944
66340
  return res === "created" ? { platform: "core", file: m.path, status: "Installed" } : {
65945
66341
  platform: "core",
@@ -65962,8 +66358,8 @@ function applyMutation(m) {
65962
66358
  if (existing.kind === "record" && JSON.stringify(existing.value) === JSON.stringify(merged)) {
65963
66359
  return { platform: "core", file: m.path, status: "Skipped", detail: "already configured" };
65964
66360
  }
65965
- mkdirSync6(dir, { recursive: true });
65966
- writeFileSync7(m.path, JSON.stringify(merged, null, 2) + `
66361
+ mkdirSync7(dir, { recursive: true });
66362
+ writeFileSync8(m.path, JSON.stringify(merged, null, 2) + `
65967
66363
  `, "utf8");
65968
66364
  return existing.kind === "record" ? { platform: "core", file: m.path, status: "Configured" } : { platform: "core", file: m.path, status: "Installed" };
65969
66365
  }
@@ -66004,12 +66400,12 @@ function applyMutation(m) {
66004
66400
  `;
66005
66401
  if (prev === next)
66006
66402
  return { platform: "core", file: m.path, status: "Skipped", detail: "already configured" };
66007
- mkdirSync6(dir, { recursive: true });
66403
+ mkdirSync7(dir, { recursive: true });
66008
66404
  const tmp = `${m.path}.${process.pid}.tmp`;
66009
66405
  try {
66010
- writeFileSync7(tmp, next, "utf8");
66406
+ writeFileSync8(tmp, next, "utf8");
66011
66407
  if (workspacesRevision(readFileSafe(m.path)) !== m.expectedRevision) {
66012
- rmSync3(tmp, { force: true });
66408
+ rmSync4(tmp, { force: true });
66013
66409
  return {
66014
66410
  platform: "core",
66015
66411
  file: m.path,
@@ -66017,9 +66413,9 @@ function applyMutation(m) {
66017
66413
  detail: "workspace config changed while applying the preview; rebuild and review it"
66018
66414
  };
66019
66415
  }
66020
- renameSync3(tmp, m.path);
66416
+ renameSync4(tmp, m.path);
66021
66417
  } catch (error) {
66022
- rmSync3(tmp, { force: true });
66418
+ rmSync4(tmp, { force: true });
66023
66419
  return {
66024
66420
  platform: "core",
66025
66421
  file: m.path,
@@ -66042,11 +66438,11 @@ function applyMutation(m) {
66042
66438
  detail: "all entries already present"
66043
66439
  };
66044
66440
  }
66045
- mkdirSync6(dir, { recursive: true });
66441
+ mkdirSync7(dir, { recursive: true });
66046
66442
  const separator = existing && !existing.endsWith(`
66047
66443
  `) ? `
66048
66444
  ` : "";
66049
- writeFileSync7(m.path, existing + separator + (existing ? `
66445
+ writeFileSync8(m.path, existing + separator + (existing ? `
66050
66446
  ` : "") + add.join(`
66051
66447
  `) + `
66052
66448
  `, "utf8");
@@ -66085,8 +66481,8 @@ function applyMutation(m) {
66085
66481
  detail: "already configured"
66086
66482
  };
66087
66483
  }
66088
- mkdirSync6(path31.dirname(m.path), { recursive: true });
66089
- writeFileSync7(m.path, JSON.stringify(merged, null, 2) + `
66484
+ mkdirSync7(path32.dirname(m.path), { recursive: true });
66485
+ writeFileSync8(m.path, JSON.stringify(merged, null, 2) + `
66090
66486
  `, "utf8");
66091
66487
  return existing.kind === "record" ? { platform: "core", file: m.path, status: "Configured" } : { platform: "core", file: m.path, status: "Installed" };
66092
66488
  }
@@ -66094,23 +66490,23 @@ function applyMutation(m) {
66094
66490
  }
66095
66491
  function adapterRoot(platform, res, preferInstalledAdapter = false) {
66096
66492
  const candidates = [];
66097
- const stagedCursor = path31.join(res.home, ".cursor", "plugins", "local", ".workit-package-bootstrap", "node_modules", "@brainervirus", "workit-cursor");
66493
+ const stagedCursor = path32.join(res.home, ".cursor", "plugins", "local", ".workit-package-bootstrap", "node_modules", "@brainervirus", "workit-cursor");
66098
66494
  if (platform === "cursor" && preferInstalledAdapter)
66099
66495
  candidates.push(stagedCursor);
66100
66496
  if (res.dev) {
66101
- candidates.push(path31.join(res.dev, "packages", `workit-${platform}`));
66497
+ candidates.push(path32.join(res.dev, "packages", `workit-${platform}`));
66102
66498
  } else {
66103
- candidates.push(path31.join(packageRoot(), "..", `workit-${platform}`));
66104
- let dir = path31.resolve(res.cwd);
66499
+ candidates.push(path32.join(packageRoot(), "..", `workit-${platform}`));
66500
+ let dir = path32.resolve(res.cwd);
66105
66501
  while (true) {
66106
- candidates.push(path31.join(dir, "packages", `workit-${platform}`));
66107
- const parent = path31.dirname(dir);
66502
+ candidates.push(path32.join(dir, "packages", `workit-${platform}`));
66503
+ const parent = path32.dirname(dir);
66108
66504
  if (parent === dir)
66109
66505
  break;
66110
66506
  dir = parent;
66111
66507
  }
66112
66508
  }
66113
- candidates.push(path31.join(res.home, ".local", "share", "workit", "packages", `workit-${platform}`));
66509
+ candidates.push(path32.join(res.home, ".local", "share", "workit", "packages", `workit-${platform}`));
66114
66510
  if (platform === "cursor")
66115
66511
  candidates.push(stagedCursor);
66116
66512
  for (const candidate of candidates) {
@@ -66129,7 +66525,7 @@ function applyOpenCode(root, res) {
66129
66525
  detail: "workit-opencode package has no loadable plugin entry (src/plugin.ts or dist/plugin.js)"
66130
66526
  };
66131
66527
  }
66132
- mkdirSync6(path31.dirname(res.opencodeConfig), { recursive: true });
66528
+ mkdirSync7(path32.dirname(res.opencodeConfig), { recursive: true });
66133
66529
  const existing = readExisting(res.opencodeConfig);
66134
66530
  if (existing.kind === "malformed") {
66135
66531
  return {
@@ -66158,7 +66554,7 @@ function applyOpenCode(root, res) {
66158
66554
  detail: "already registered"
66159
66555
  };
66160
66556
  }
66161
- writeFileSync7(res.opencodeConfig, JSON.stringify(merged.config, null, 2) + `
66557
+ writeFileSync8(res.opencodeConfig, JSON.stringify(merged.config, null, 2) + `
66162
66558
  `, "utf8");
66163
66559
  return existing.kind === "record" ? {
66164
66560
  platform: "opencode",
@@ -66174,54 +66570,54 @@ function applyOpenCode(root, res) {
66174
66570
  }
66175
66571
  function copyPluginDir(src, dest) {
66176
66572
  const realSrc = realpathSync7(src);
66177
- const marker = path31.join(dest, ".workit-root");
66178
- const destIsLink = existsSync14(dest) && lstatSync5(dest).isSymbolicLink();
66573
+ const marker = path32.join(dest, ".workit-root");
66574
+ const destIsLink = existsSync15(dest) && lstatSync6(dest).isSymbolicLink();
66179
66575
  const synced = !destIsLink && readFileSafe(marker)?.trim() === realSrc && samePluginContent(realSrc, dest, dest);
66180
66576
  if (synced)
66181
66577
  return "Skipped";
66182
- const hadDir = existsSync14(dest);
66578
+ const hadDir = existsSync15(dest);
66183
66579
  const rules = preservedCursorRules(realSrc, dest);
66184
- const parent = path31.dirname(dest);
66185
- mkdirSync6(parent, { recursive: true });
66186
- const swap = mkdtempSync2(path31.join(parent, `.${path31.basename(dest)}.swap-`));
66187
- const stage = path31.join(swap, "stage");
66188
- const backup = path31.join(swap, "backup");
66580
+ const parent = path32.dirname(dest);
66581
+ mkdirSync7(parent, { recursive: true });
66582
+ const swap = mkdtempSync2(path32.join(parent, `.${path32.basename(dest)}.swap-`));
66583
+ const stage = path32.join(swap, "stage");
66584
+ const backup = path32.join(swap, "backup");
66189
66585
  try {
66190
66586
  cpSync4(realSrc, stage, {
66191
66587
  recursive: true,
66192
- filter: (entry) => !path31.relative(realSrc, entry).split(path31.sep).includes("node_modules")
66588
+ filter: (entry) => !path32.relative(realSrc, entry).split(path32.sep).includes("node_modules")
66193
66589
  });
66194
- const stagedHooks = path31.join(stage, CURSOR_HOOKS_FILE);
66195
- if (existsSync14(stagedHooks))
66196
- writeFileSync7(stagedHooks, localizedCursorHooks(readFileSync14(stagedHooks), dest));
66590
+ const stagedHooks = path32.join(stage, CURSOR_HOOKS_FILE);
66591
+ if (existsSync15(stagedHooks))
66592
+ writeFileSync8(stagedHooks, localizedCursorHooks(readFileSync15(stagedHooks), dest));
66197
66593
  for (const [name, content] of rules) {
66198
- mkdirSync6(path31.join(stage, "rules"), { recursive: true });
66199
- writeFileSync7(path31.join(stage, "rules", name), content);
66594
+ mkdirSync7(path32.join(stage, "rules"), { recursive: true });
66595
+ writeFileSync8(path32.join(stage, "rules", name), content);
66200
66596
  }
66201
- writeFileSync7(path31.join(stage, ".workit-root"), realSrc + `
66597
+ writeFileSync8(path32.join(stage, ".workit-root"), realSrc + `
66202
66598
  `, "utf8");
66203
66599
  if (!samePluginContent(realSrc, stage, dest))
66204
66600
  throw new Error("staged adapter content is incomplete");
66205
- if (lstatSync5(stage).isSymbolicLink()) {
66601
+ if (lstatSync6(stage).isSymbolicLink()) {
66206
66602
  throw new Error("staged adapter resolved to a symlink — refusing fragile cache install");
66207
66603
  }
66208
66604
  if (hadDir)
66209
- renameSync3(dest, backup);
66605
+ renameSync4(dest, backup);
66210
66606
  try {
66211
- renameSync3(stage, dest);
66607
+ renameSync4(stage, dest);
66212
66608
  } catch (error) {
66213
- if (hadDir && !existsSync14(dest))
66214
- renameSync3(backup, dest);
66609
+ if (hadDir && !existsSync15(dest))
66610
+ renameSync4(backup, dest);
66215
66611
  throw error;
66216
66612
  }
66217
- rmSync3(backup, { recursive: true, force: true });
66613
+ rmSync4(backup, { recursive: true, force: true });
66218
66614
  } finally {
66219
- rmSync3(swap, { recursive: true, force: true });
66615
+ rmSync4(swap, { recursive: true, force: true });
66220
66616
  }
66221
66617
  return hadDir ? "Configured" : "Installed";
66222
66618
  }
66223
66619
  function applyCursorSettings(root, res) {
66224
- mkdirSync6(path31.dirname(res.cursorSettings), { recursive: true });
66620
+ mkdirSync7(path32.dirname(res.cursorSettings), { recursive: true });
66225
66621
  const settingsExisting = readExisting(res.cursorSettings);
66226
66622
  if (settingsExisting.kind === "malformed") {
66227
66623
  return {
@@ -66240,7 +66636,7 @@ function applyCursorSettings(root, res) {
66240
66636
  detail: "already registered"
66241
66637
  };
66242
66638
  }
66243
- writeFileSync7(res.cursorSettings, JSON.stringify(settings.config, null, 2) + `
66639
+ writeFileSync8(res.cursorSettings, JSON.stringify(settings.config, null, 2) + `
66244
66640
  `, "utf8");
66245
66641
  return {
66246
66642
  platform: "cursor",
@@ -66249,7 +66645,7 @@ function applyCursorSettings(root, res) {
66249
66645
  };
66250
66646
  }
66251
66647
  function applyCursorMcp(root, res) {
66252
- mkdirSync6(path31.dirname(res.cursorMcp), { recursive: true });
66648
+ mkdirSync7(path32.dirname(res.cursorMcp), { recursive: true });
66253
66649
  const mcpExisting = readExisting(res.cursorMcp);
66254
66650
  if (mcpExisting.kind === "malformed") {
66255
66651
  return {
@@ -66279,7 +66675,7 @@ function applyCursorMcp(root, res) {
66279
66675
  detail: "already registered"
66280
66676
  };
66281
66677
  }
66282
- writeFileSync7(res.cursorMcp, JSON.stringify(mcp.config, null, 2) + `
66678
+ writeFileSync8(res.cursorMcp, JSON.stringify(mcp.config, null, 2) + `
66283
66679
  `, "utf8");
66284
66680
  return {
66285
66681
  platform: "cursor",
@@ -66288,9 +66684,9 @@ function applyCursorMcp(root, res) {
66288
66684
  };
66289
66685
  }
66290
66686
  function verifyPlatform(platform, res) {
66291
- if (platform === "opencode" && !existsSync14(res.opencodeConfig))
66687
+ if (platform === "opencode" && !existsSync15(res.opencodeConfig))
66292
66688
  return null;
66293
- if (platform === "cursor" && !existsSync14(res.cursorSettings) && !existsSync14(res.cursorMcp)) {
66689
+ if (platform === "cursor" && !existsSync15(res.cursorSettings) && !existsSync15(res.cursorMcp)) {
66294
66690
  return null;
66295
66691
  }
66296
66692
  return runDoctor({
@@ -66355,7 +66751,7 @@ function applySetupPreview(preview, options = {}) {
66355
66751
  let cursorCopyOk = false;
66356
66752
  for (const mutation of preview.mutations) {
66357
66753
  if (mutation.type === "install-host") {
66358
- const expectedPath = mutation.platform === "cursor" ? path31.join(res.home, ".cursor", "plugins", "local", ".workit-package-bootstrap") : mutation.platform === "codex" ? path31.join(res.env.CODEX_HOME ?? path31.join(res.home, ".codex"), "plugins", "cache", "workflow-toolkit", "workit") : mutation.platform === "pi" ? path31.join(res.env.PI_CODING_AGENT_DIR ?? path31.join(res.home, ".pi", "agent"), "settings.json") : mutation.platform === "claude-code" ? claudeInstallRecord(res.home, res.env) : "";
66754
+ const expectedPath = mutation.platform === "cursor" ? path32.join(res.home, ".cursor", "plugins", "local", ".workit-package-bootstrap") : mutation.platform === "codex" ? path32.join(res.env.CODEX_HOME ?? path32.join(res.home, ".codex"), "plugins", "cache", "workflow-toolkit", "workit") : mutation.platform === "pi" ? path32.join(res.env.PI_CODING_AGENT_DIR ?? path32.join(res.home, ".pi", "agent"), "settings.json") : mutation.platform === "claude-code" ? claudeInstallRecord(res.home, res.env) : "";
66359
66755
  if (mutation.path !== expectedPath) {
66360
66756
  entries.push({
66361
66757
  platform: mutation.platform,
@@ -66536,12 +66932,12 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
66536
66932
  return configured ?? fallback;
66537
66933
  }, readConfigRecord = (file) => {
66538
66934
  try {
66539
- const value = JSON.parse(readFileSync14(file, "utf8"));
66935
+ const value = JSON.parse(readFileSync15(file, "utf8"));
66540
66936
  return isRecord5(value) ? value : null;
66541
66937
  } catch {
66542
66938
  return null;
66543
66939
  }
66544
- }, claudeInstallRecord = (home, env) => path31.join(claudeConfigDir(home, env), "plugins", "installed_plugins.json"), resolveSetupPaths = (options, resolvedConfigDir) => {
66940
+ }, claudeInstallRecord = (home, env) => path32.join(claudeConfigDir(home, env), "plugins", "installed_plugins.json"), resolveSetupPaths = (options, resolvedConfigDir) => {
66545
66941
  const env = options.env ?? process.env;
66546
66942
  const home = options.home ?? env.HOME ?? os9.homedir();
66547
66943
  return {
@@ -66549,17 +66945,17 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
66549
66945
  configDir: resolvedConfigDir,
66550
66946
  cwd: options.cwd ?? process.cwd(),
66551
66947
  env,
66552
- opencodeConfig: options.opencodeConfig ?? path31.join(home, ".config", "opencode", "opencode.json"),
66553
- cursorSettings: options.cursorSettings ?? path31.join(home, ".cursor", "settings.json"),
66554
- cursorMcp: options.cursorMcp ?? path31.join(home, ".cursor", "mcp.json"),
66555
- cursorPluginDir: options.cursorPluginDir ?? path31.join(home, ".cursor", "plugins", "local", "workit")
66948
+ opencodeConfig: options.opencodeConfig ?? path32.join(home, ".config", "opencode", "opencode.json"),
66949
+ cursorSettings: options.cursorSettings ?? path32.join(home, ".cursor", "settings.json"),
66950
+ cursorMcp: options.cursorMcp ?? path32.join(home, ".cursor", "mcp.json"),
66951
+ cursorPluginDir: options.cursorPluginDir ?? path32.join(home, ".cursor", "plugins", "local", "workit")
66556
66952
  };
66557
66953
  }, isRecord5 = (v) => v !== null && typeof v === "object" && !Array.isArray(v), readExisting = (p) => {
66558
66954
  let raw;
66559
66955
  try {
66560
- raw = readFileSync14(p, "utf8");
66956
+ raw = readFileSync15(p, "utf8");
66561
66957
  } catch {
66562
- if (existsSync14(p))
66958
+ if (existsSync15(p))
66563
66959
  return { kind: "malformed", error: `${p} is not readable` };
66564
66960
  return { kind: "missing" };
66565
66961
  }
@@ -66574,7 +66970,7 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
66574
66970
  return { kind: "malformed", error: `${p} is not a JSON object` };
66575
66971
  }, readFileSafe = (p) => {
66576
66972
  try {
66577
- return readFileSync14(p, "utf8");
66973
+ return readFileSync15(p, "utf8");
66578
66974
  } catch {
66579
66975
  return null;
66580
66976
  }
@@ -66589,7 +66985,7 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
66589
66985
  }
66590
66986
  }, isAdapter = (root, platform) => {
66591
66987
  try {
66592
- const pkg = JSON.parse(readFileSync14(path31.join(root, "package.json"), "utf8"));
66988
+ const pkg = JSON.parse(readFileSync15(path32.join(root, "package.json"), "utf8"));
66593
66989
  return pkg.name === `@brainervirus/workit-${platform}`;
66594
66990
  } catch {
66595
66991
  return false;
@@ -66603,8 +66999,8 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
66603
66999
  if (!isDevOpenCodeAdapterRoot(root, opts.dev))
66604
67000
  return OPENCODE_NPM_PIN;
66605
67001
  for (const rel of ["src/plugin.ts", "dist/plugin.js"]) {
66606
- const entry = path31.join(root, rel);
66607
- if (existsSync14(entry))
67002
+ const entry = path32.join(root, rel);
67003
+ if (existsSync15(entry))
66608
67004
  return `file://${entry}`;
66609
67005
  }
66610
67006
  return null;
@@ -66621,22 +67017,22 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
66621
67017
  for (const entry of readdirSync8(src, { withFileTypes: true })) {
66622
67018
  if (entry.name === "node_modules")
66623
67019
  continue;
66624
- const source = path31.join(src, entry.name);
66625
- const installed = path31.join(dest, entry.name);
66626
- const rel = path31.join(relative, entry.name);
67020
+ const source = path32.join(src, entry.name);
67021
+ const installed = path32.join(dest, entry.name);
67022
+ const rel = path32.join(relative, entry.name);
66627
67023
  if (entry.isDirectory()) {
66628
- if (!statSync5(installed).isDirectory() || !samePluginContent(source, installed, pluginDir, rel))
67024
+ if (!statSync6(installed).isDirectory() || !samePluginContent(source, installed, pluginDir, rel))
66629
67025
  return false;
66630
67026
  } else {
66631
- const expected = rel === CURSOR_HOOKS_FILE ? localizedCursorHooks(readFileSync14(source), pluginDir) : readFileSync14(source);
66632
- if (!expected.equals(readFileSync14(installed)))
67027
+ const expected = rel === CURSOR_HOOKS_FILE ? localizedCursorHooks(readFileSync15(source), pluginDir) : readFileSync15(source);
67028
+ if (!expected.equals(readFileSync15(installed)))
66633
67029
  return false;
66634
67030
  }
66635
67031
  }
66636
67032
  for (const entry of readdirSync8(dest, { withFileTypes: true })) {
66637
- if (existsSync14(path31.join(src, entry.name)))
67033
+ if (existsSync15(path32.join(src, entry.name)))
66638
67034
  continue;
66639
- const rel = path31.join(relative, entry.name);
67035
+ const rel = path32.join(relative, entry.name);
66640
67036
  if (rel === ".workit-root")
66641
67037
  continue;
66642
67038
  if (relative === "rules" && entry.isFile() && entry.name.endsWith(".mdc"))
@@ -66649,36 +67045,36 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
66649
67045
  }
66650
67046
  }, preservedCursorRules = (src, dest) => {
66651
67047
  const preserved = new Map;
66652
- const sourceRules = path31.join(src, "rules");
66653
- const installedRules = path31.join(dest, "rules");
67048
+ const sourceRules = path32.join(src, "rules");
67049
+ const installedRules = path32.join(dest, "rules");
66654
67050
  try {
66655
67051
  for (const entry of readdirSync8(installedRules, { withFileTypes: true })) {
66656
67052
  if (!entry.isFile() || !entry.name.endsWith(".mdc"))
66657
67053
  continue;
66658
- if (existsSync14(path31.join(sourceRules, entry.name)))
67054
+ if (existsSync15(path32.join(sourceRules, entry.name)))
66659
67055
  continue;
66660
- preserved.set(entry.name, readFileSync14(path31.join(installedRules, entry.name)));
67056
+ preserved.set(entry.name, readFileSync15(path32.join(installedRules, entry.name)));
66661
67057
  }
66662
67058
  } catch {}
66663
67059
  return preserved;
66664
67060
  }, removeLegacyCursorDir = (res) => {
66665
- const legacy = path31.join(res.home, ".cursor", "plugins", "local", "workflow-toolkit");
66666
- if (legacy === res.cursorPluginDir || !existsSync14(legacy))
67061
+ const legacy = path32.join(res.home, ".cursor", "plugins", "local", "workflow-toolkit");
67062
+ if (legacy === res.cursorPluginDir || !existsSync15(legacy))
66667
67063
  return;
66668
- const legacyRules = path31.join(legacy, "rules");
66669
- if (existsSync14(legacyRules)) {
67064
+ const legacyRules = path32.join(legacy, "rules");
67065
+ if (existsSync15(legacyRules)) {
66670
67066
  try {
66671
- mkdirSync6(path31.join(res.cursorPluginDir, "rules"), { recursive: true });
67067
+ mkdirSync7(path32.join(res.cursorPluginDir, "rules"), { recursive: true });
66672
67068
  for (const entry of readdirSync8(legacyRules, { withFileTypes: true })) {
66673
67069
  if (!entry.isFile() || !entry.name.endsWith(".mdc"))
66674
67070
  continue;
66675
- const target = path31.join(res.cursorPluginDir, "rules", entry.name);
66676
- if (!existsSync14(target))
66677
- copyFileSync4(path31.join(legacyRules, entry.name), target);
67071
+ const target = path32.join(res.cursorPluginDir, "rules", entry.name);
67072
+ if (!existsSync15(target))
67073
+ copyFileSync4(path32.join(legacyRules, entry.name), target);
66678
67074
  }
66679
67075
  } catch {}
66680
67076
  }
66681
- rmSync3(legacy, { recursive: true, force: true });
67077
+ rmSync4(legacy, { recursive: true, force: true });
66682
67078
  }, failedDetail = (report) => report.checks.filter((c) => c.status === "fail").map((c) => `${c.id}: ${c.detail}`).join("; "), setupCompletionGuidance = () => [
66683
67079
  "Run `workit doctor` to verify your installation.",
66684
67080
  "Run /wk-status in OpenCode to review token setup steps."
@@ -66708,16 +67104,16 @@ var init_setup = __esm(() => {
66708
67104
  { envKey: "WORKFLOW_GITHUB_HOST", affects: "vcs.json github.host" }
66709
67105
  ];
66710
67106
  SETUP_OVERRIDES = [...YT_OVERRIDES, ...VCS_OVERRIDES];
66711
- CURSOR_HOOKS_FILE = path31.join("hooks", "hooks-cursor.json");
67107
+ CURSOR_HOOKS_FILE = path32.join("hooks", "hooks-cursor.json");
66712
67108
  });
66713
67109
 
66714
67110
  // packages/workit-core/src/core/workspace-branch-policy.ts
66715
- import { mkdirSync as mkdirSync7, readFileSync as readFileSync15, renameSync as renameSync4, rmSync as rmSync4, writeFileSync as writeFileSync8 } from "node:fs";
66716
- import path32 from "node:path";
67111
+ import { mkdirSync as mkdirSync8, readFileSync as readFileSync16, renameSync as renameSync5, rmSync as rmSync5, writeFileSync as writeFileSync9 } from "node:fs";
67112
+ import path33 from "node:path";
66717
67113
  import { isDeepStrictEqual as isDeepStrictEqual3 } from "node:util";
66718
67114
  function applyWorkspaceBranchPolicy(opts) {
66719
67115
  const { workspace_root, env = process.env } = opts;
66720
- const dir = path32.join(env.WORKFLOW_TOOLKIT_CONFIG ?? configDir());
67116
+ const dir = path33.join(env.WORKFLOW_TOOLKIT_CONFIG ?? configDir());
66721
67117
  const {
66722
67118
  status,
66723
67119
  path: wsPath,
@@ -66729,7 +67125,7 @@ function applyWorkspaceBranchPolicy(opts) {
66729
67125
  if (status === "malformed" || status === "invalid")
66730
67126
  return { ok: false, error: workspacesError ?? `invalid workspaces.json: ${wsPath}` };
66731
67127
  const detection = detectBranchPolicy(workspace_root);
66732
- const name = String(env.WORKFLOW_BP_NAME ?? path32.basename(workspace_root));
67128
+ const name = String(env.WORKFLOW_BP_NAME ?? path33.basename(workspace_root));
66733
67129
  const integration = env.WORKFLOW_BP_INTEGRATION ?? detection.integration;
66734
67130
  const policy = {
66735
67131
  preset: detection.preset,
@@ -66778,22 +67174,22 @@ function applyWorkspaceBranchPolicy(opts) {
66778
67174
  ok: false,
66779
67175
  error: `workspaces.json changed while applying the branch policy: ${wsPath}`
66780
67176
  };
66781
- mkdirSync7(path32.dirname(wsPath), { recursive: true });
67177
+ mkdirSync8(path33.dirname(wsPath), { recursive: true });
66782
67178
  const tmp = `${wsPath}.${process.pid}.tmp`;
66783
67179
  try {
66784
- writeFileSync8(tmp, JSON.stringify({ ...document2, workspaces: next }, null, 2) + `
67180
+ writeFileSync9(tmp, JSON.stringify({ ...document2, workspaces: next }, null, 2) + `
66785
67181
  `, "utf8");
66786
67182
  if (workspacesRevision(readFileSafe2(wsPath)) !== revision) {
66787
- rmSync4(tmp, { force: true });
67183
+ rmSync5(tmp, { force: true });
66788
67184
  return {
66789
67185
  ok: false,
66790
67186
  error: `workspaces.json changed while applying the branch policy: ${wsPath}`
66791
67187
  };
66792
67188
  }
66793
- renameSync4(tmp, wsPath);
67189
+ renameSync5(tmp, wsPath);
66794
67190
  } catch (error) {
66795
67191
  try {
66796
- rmSync4(tmp, { force: true });
67192
+ rmSync5(tmp, { force: true });
66797
67193
  } catch {}
66798
67194
  return {
66799
67195
  ok: false,
@@ -66810,7 +67206,7 @@ function applyWorkspaceBranchPolicy(opts) {
66810
67206
  }
66811
67207
  var readFileSafe2 = (p) => {
66812
67208
  try {
66813
- return readFileSync15(p, "utf8");
67209
+ return readFileSync16(p, "utf8");
66814
67210
  } catch {
66815
67211
  return null;
66816
67212
  }
@@ -67062,8 +67458,8 @@ var init_logic = __esm(() => {
67062
67458
  });
67063
67459
 
67064
67460
  // packages/workit-cli/src/wizard-state.ts
67065
- import { existsSync as existsSync15, statSync as statSync6 } from "node:fs";
67066
- import path33 from "node:path";
67461
+ import { existsSync as existsSync16, statSync as statSync7 } from "node:fs";
67462
+ import path34 from "node:path";
67067
67463
  import { isDeepStrictEqual as isDeepStrictEqual4 } from "node:util";
67068
67464
  function resolveBasePath(values, env = process.env) {
67069
67465
  return env.WORKFLOW_WORKSPACE_ROOT?.trim() || values.basePath.trim();
@@ -67582,7 +67978,7 @@ function workspaceDraftText(draft, field, value) {
67582
67978
  }
67583
67979
  var NEXT, PREV, skipsCustomBranch = (screen, preset) => (screen === "branchAllowed" || screen === "branchProtected") && preset !== "custom", skipsYoutrack = (screen, tracker) => screen === "youtrack" && tracker !== "youtrack", skipsBasePath = (screen, basePath) => screen === "basePath" && basePath !== "", isDirectory = (p) => {
67584
67980
  try {
67585
- return statSync6(p).isDirectory();
67981
+ return statSync7(p).isDirectory();
67586
67982
  } catch {
67587
67983
  return false;
67588
67984
  }
@@ -67590,8 +67986,8 @@ var NEXT, PREV, skipsCustomBranch = (screen, preset) => (screen === "branchAllow
67590
67986
  const p = value.trim();
67591
67987
  if (!p)
67592
67988
  return "workspace root path is required";
67593
- return !path33.isAbsolute(p) || !isDirectory(p) ? `invalid workspace root "${p}" — enter an existing absolute directory` : null;
67594
- }, skipsBranchPolicy = (screen, basePath) => (screen === "branchPolicy" || screen === "branchPolicyDevelop") && !existsSync15(path33.join(basePath, ".git")), decodeBranchPreset = (value, fallback) => value === "gitflow" || value === "github-flow" || value === "trunk-based" || value === "custom" ? value : fallback, decodeVcsProvider = (value, fallback) => value === "gitlab" || value === "github" || value === "skip" ? value : fallback, decodeIssueTracker = (value, fallback) => value === "youtrack" || value === "github" || value === "gitlab" || value === "none" ? value : fallback, GITHUB_ISSUES, withGithubIssues = (draft, tracker) => tracker === "github" ? { ...draft, issues: { ...GITHUB_ISSUES } } : draft;
67989
+ return !path34.isAbsolute(p) || !isDirectory(p) ? `invalid workspace root "${p}" — enter an existing absolute directory` : null;
67990
+ }, skipsBranchPolicy = (screen, basePath) => (screen === "branchPolicy" || screen === "branchPolicyDevelop") && !existsSync16(path34.join(basePath, ".git")), decodeBranchPreset = (value, fallback) => value === "gitflow" || value === "github-flow" || value === "trunk-based" || value === "custom" ? value : fallback, decodeVcsProvider = (value, fallback) => value === "gitlab" || value === "github" || value === "skip" ? value : fallback, decodeIssueTracker = (value, fallback) => value === "youtrack" || value === "github" || value === "gitlab" || value === "none" ? value : fallback, GITHUB_ISSUES, withGithubIssues = (draft, tracker) => tracker === "github" ? { ...draft, issues: { ...GITHUB_ISSUES } } : draft;
67595
67991
  var init_wizard_state = __esm(() => {
67596
67992
  init_config();
67597
67993
  init_workspaces();
@@ -67650,9 +68046,9 @@ var init_wizard_state = __esm(() => {
67650
68046
  });
67651
68047
 
67652
68048
  // packages/workit-cli/src/admin/uninstall.ts
67653
- import { existsSync as existsSync16, readFileSync as readFileSync16, realpathSync as realpathSync8, rmSync as rmSync5, writeFileSync as writeFileSync9 } from "node:fs";
68049
+ import { existsSync as existsSync17, readFileSync as readFileSync17, realpathSync as realpathSync8, rmSync as rmSync6, writeFileSync as writeFileSync10 } from "node:fs";
67654
68050
  import os10 from "node:os";
67655
- import path34 from "node:path";
68051
+ import path35 from "node:path";
67656
68052
  function cleanCursorSettings(settings, pluginDir) {
67657
68053
  const next = { ...settings };
67658
68054
  let changed = false;
@@ -67752,7 +68148,7 @@ function planUninstall(paths = {}) {
67752
68148
  const mcpExisting = readJsonRecord(res.cursorMcp);
67753
68149
  const settingsDirty = settingsExisting.kind === "malformed" || settingsExisting.kind === "record" && cleanCursorSettings(settingsExisting.value, res.cursorPluginDir).changed;
67754
68150
  const mcpDirty = mcpExisting.kind === "malformed" || mcpExisting.kind === "record" && cleanCursorMcp(mcpExisting.value).changed;
67755
- const dirExists = existsSync16(res.cursorPluginDir);
68151
+ const dirExists = existsSync17(res.cursorPluginDir);
67756
68152
  const actions = [];
67757
68153
  if (settingsDirty) {
67758
68154
  actions.push({
@@ -67780,7 +68176,7 @@ function planUninstall(paths = {}) {
67780
68176
  installed: settingsDirty || mcpDirty || dirExists,
67781
68177
  actions
67782
68178
  };
67783
- const codexInstalled = existsSync16(res.codexPluginDir);
68179
+ const codexInstalled = existsSync17(res.codexPluginDir);
67784
68180
  const codex = {
67785
68181
  host: "codex",
67786
68182
  installed: codexInstalled,
@@ -67827,17 +68223,17 @@ function applyUninstall(plan, paths = {}) {
67827
68223
  status = outcome.status;
67828
68224
  detail = outcome.detail;
67829
68225
  } else if (action.kind === "remove-dir") {
67830
- const resolved = path34.resolve(action.path);
67831
- const allowed = canonicalRemoveDirAllowed(resolved, res) || resolved === path34.resolve(res.codexPluginDir) && path34.basename(resolved) === "workit" && path34.basename(path34.dirname(resolved)) === "plugins";
68226
+ const resolved = path35.resolve(action.path);
68227
+ const allowed = canonicalRemoveDirAllowed(resolved, res) || resolved === path35.resolve(res.codexPluginDir) && path35.basename(resolved) === "workit" && path35.basename(path35.dirname(resolved)) === "plugins";
67832
68228
  if (!allowed) {
67833
68229
  status = "failed";
67834
68230
  detail = `refusing to remove non-canonical plugin directory: ${resolved}`;
67835
- } else if (!existsSync16(resolved)) {
68231
+ } else if (!existsSync17(resolved)) {
67836
68232
  status = "skipped";
67837
68233
  detail = "directory already absent";
67838
68234
  } else {
67839
68235
  try {
67840
- rmSync5(resolved, { recursive: true, force: true });
68236
+ rmSync6(resolved, { recursive: true, force: true });
67841
68237
  status = "removed";
67842
68238
  } catch (error) {
67843
68239
  status = "failed";
@@ -67863,19 +68259,19 @@ function applyUninstall(plan, paths = {}) {
67863
68259
  var resolveUninstallPaths = (options = {}) => {
67864
68260
  const home = options.home ?? options.env?.HOME ?? os10.homedir();
67865
68261
  return {
67866
- opencodeConfig: options.opencodeConfig ?? path34.join(home, ".config", "opencode", "opencode.json"),
67867
- cursorSettings: options.cursorSettings ?? path34.join(home, ".cursor", "settings.json"),
67868
- cursorMcp: options.cursorMcp ?? path34.join(home, ".cursor", "mcp.json"),
67869
- cursorPluginDir: options.cursorPluginDir ?? path34.join(home, ".cursor", "plugins", "local", "workit"),
67870
- codexPluginDir: path34.join(home, ".codex", "plugins", "workit"),
67871
- piConfig: path34.join(home, ".pi", "config.json")
68262
+ opencodeConfig: options.opencodeConfig ?? path35.join(home, ".config", "opencode", "opencode.json"),
68263
+ cursorSettings: options.cursorSettings ?? path35.join(home, ".cursor", "settings.json"),
68264
+ cursorMcp: options.cursorMcp ?? path35.join(home, ".cursor", "mcp.json"),
68265
+ cursorPluginDir: options.cursorPluginDir ?? path35.join(home, ".cursor", "plugins", "local", "workit"),
68266
+ codexPluginDir: path35.join(home, ".codex", "plugins", "workit"),
68267
+ piConfig: path35.join(home, ".pi", "config.json")
67872
68268
  };
67873
68269
  }, isRecord6 = (v) => v !== null && typeof v === "object" && !Array.isArray(v), readJsonRecord = (file) => {
67874
68270
  let raw;
67875
68271
  try {
67876
- raw = readFileSync16(file, "utf8");
68272
+ raw = readFileSync17(file, "utf8");
67877
68273
  } catch {
67878
- if (existsSync16(file))
68274
+ if (existsSync17(file))
67879
68275
  return { kind: "malformed", error: `${file} is not readable` };
67880
68276
  return { kind: "missing" };
67881
68277
  }
@@ -67886,8 +68282,8 @@ var resolveUninstallPaths = (options = {}) => {
67886
68282
  return { kind: "malformed", error: `${file} is not valid JSON` };
67887
68283
  }
67888
68284
  }, stripTrailingSep = (p) => {
67889
- const j = path34.join(p);
67890
- return path34.dirname(j) === j ? j : j.replace(/[\\/]+$/, "");
68285
+ const j = path35.join(p);
68286
+ return path35.dirname(j) === j ? j : j.replace(/[\\/]+$/, "");
67891
68287
  }, CURSOR_LEGACY_IDENTITIES, jsonCleanerFor = (target, res) => {
67892
68288
  if (target === res.opencodeConfig)
67893
68289
  return cleanOpenCodeConfig;
@@ -67899,8 +68295,8 @@ var resolveUninstallPaths = (options = {}) => {
67899
68295
  return cleanPiConfig;
67900
68296
  return null;
67901
68297
  }, canonicalRemoveDirAllowed = (actionPath, res) => {
67902
- const expected = path34.resolve(res.cursorPluginDir);
67903
- if (!(actionPath === expected && path34.basename(expected) === "workit" && path34.basename(path34.dirname(expected)) === "local" && path34.basename(path34.dirname(path34.dirname(expected))) === "plugins")) {
68298
+ const expected = path35.resolve(res.cursorPluginDir);
68299
+ if (!(actionPath === expected && path35.basename(expected) === "workit" && path35.basename(path35.dirname(expected)) === "local" && path35.basename(path35.dirname(path35.dirname(expected))) === "plugins")) {
67904
68300
  return false;
67905
68301
  }
67906
68302
  try {
@@ -67923,7 +68319,7 @@ var resolveUninstallPaths = (options = {}) => {
67923
68319
  `;
67924
68320
  let current;
67925
68321
  try {
67926
- current = readFileSync16(target, "utf8");
68322
+ current = readFileSync17(target, "utf8");
67927
68323
  } catch (error) {
67928
68324
  return {
67929
68325
  status: "failed",
@@ -67934,7 +68330,7 @@ var resolveUninstallPaths = (options = {}) => {
67934
68330
  return { status: "skipped", detail: "already clean" };
67935
68331
  }
67936
68332
  try {
67937
- writeFileSync9(target, serialized, "utf8");
68333
+ writeFileSync10(target, serialized, "utf8");
67938
68334
  } catch (error) {
67939
68335
  return {
67940
68336
  status: "failed",
@@ -67952,7 +68348,7 @@ var resolveUninstallPaths = (options = {}) => {
67952
68348
  };
67953
68349
  const home = paths.home ?? paths.env?.HOME ?? os10.homedir();
67954
68350
  const env = paths.env ?? process.env;
67955
- const recorded = claudeWorkitInstalls(home, env, action.cwd).some((install) => install.id === id && install.scope === scope && (install.projectPath === null ? action.cwd === null : path34.resolve(install.projectPath) === path34.resolve(action.cwd ?? "")));
68351
+ const recorded = claudeWorkitInstalls(home, env, action.cwd).some((install) => install.id === id && install.scope === scope && (install.projectPath === null ? action.cwd === null : path35.resolve(install.projectPath) === path35.resolve(action.cwd ?? "")));
67956
68352
  if (!recorded)
67957
68353
  return { status: "skipped", detail: `${id} (${scope} scope) is no longer installed` };
67958
68354
  const executable = findHostExecutable("claude", { home, env });
@@ -70431,9 +70827,9 @@ var init_src2 = __esm(async () => {
70431
70827
  // packages/workit-cli/src/verbs/init.ts
70432
70828
  var exports_init = {};
70433
70829
  __export(exports_init, {
70434
- run: () => run2
70830
+ run: () => run3
70435
70831
  });
70436
- async function run2(_argv, io) {
70832
+ async function run3(_argv, io) {
70437
70833
  if (io.json)
70438
70834
  return emit(io, fail("invalid_input", "workit init is an interactive wizard and has no --json output", {
70439
70835
  unblock: "run `workit init` in a terminal without --json"
@@ -70447,19 +70843,19 @@ var init_init = __esm(() => {
70447
70843
  });
70448
70844
 
70449
70845
  // packages/workit-cli/src/upgrade.ts
70450
- import { spawnSync as spawnSync14 } from "node:child_process";
70846
+ import { spawnSync as spawnSync15 } from "node:child_process";
70451
70847
  import {
70452
- existsSync as existsSync17,
70848
+ existsSync as existsSync18,
70453
70849
  mkdtempSync as mkdtempSync3,
70454
- rmSync as rmSync6,
70455
- readFileSync as readFileSync17,
70456
- mkdirSync as mkdirSync8,
70850
+ rmSync as rmSync7,
70851
+ readFileSync as readFileSync18,
70852
+ mkdirSync as mkdirSync9,
70457
70853
  copyFileSync as copyFileSync5,
70458
- chmodSync,
70854
+ chmodSync as chmodSync2,
70459
70855
  cpSync as cpSync5,
70460
- lstatSync as lstatSync6
70856
+ lstatSync as lstatSync7
70461
70857
  } from "node:fs";
70462
- import path35 from "node:path";
70858
+ import path36 from "node:path";
70463
70859
  import os12 from "node:os";
70464
70860
  import { createHash as createHash14 } from "node:crypto";
70465
70861
  function previewUpgrade(hosts = HOSTS2, deps = {}) {
@@ -70483,9 +70879,9 @@ function previewUpgrade(hosts = HOSTS2, deps = {}) {
70483
70879
  for (const file of [
70484
70880
  paths.opencodeConfig,
70485
70881
  paths.opencodeConfig + "c",
70486
- path35.join(home, ".cursor/settings.json"),
70487
- path35.join(home, ".cursor/mcp.json"),
70488
- path35.join(home, ".cursor/plugins/local/workit/package.json"),
70882
+ path36.join(home, ".cursor/settings.json"),
70883
+ path36.join(home, ".cursor/mcp.json"),
70884
+ path36.join(home, ".cursor/plugins/local/workit/package.json"),
70489
70885
  paths.codexConfig,
70490
70886
  paths.piSettings
70491
70887
  ])
@@ -70500,20 +70896,20 @@ function previewUpgrade(hosts = HOSTS2, deps = {}) {
70500
70896
  });
70501
70897
  const installedSources = sources(paths, run, hosts);
70502
70898
  if (installedSources.some((source) => source.host === "opencode")) {
70503
- const scratch = mkdtempSync3(path35.join(os12.tmpdir(), "workit-upgrade-opencode-"));
70899
+ const scratch = mkdtempSync3(path36.join(os12.tmpdir(), "workit-upgrade-opencode-"));
70504
70900
  let probe;
70505
70901
  try {
70506
70902
  probe = runner({
70507
70903
  ...deps,
70508
70904
  env: {
70509
70905
  ...deps.env,
70510
- XDG_DATA_HOME: path35.join(scratch, "data"),
70511
- XDG_STATE_HOME: path35.join(scratch, "state"),
70512
- XDG_CACHE_HOME: path35.join(scratch, "cache")
70906
+ XDG_DATA_HOME: path36.join(scratch, "data"),
70907
+ XDG_STATE_HOME: path36.join(scratch, "state"),
70908
+ XDG_CACHE_HOME: path36.join(scratch, "cache")
70513
70909
  }
70514
70910
  })("opencode", ["--version"]);
70515
70911
  } finally {
70516
- rmSync6(scratch, { recursive: true, force: true });
70912
+ rmSync7(scratch, { recursive: true, force: true });
70517
70913
  }
70518
70914
  const installed = probe.status === 0 ? probe.stdout.match(/\d+\.\d+\.\d+/)?.[0] : undefined;
70519
70915
  if (installed && !versionAtLeast(installed, SUPPORT_MATRIX.opencode.minimum))
@@ -70555,7 +70951,7 @@ function previewUpgrade(hosts = HOSTS2, deps = {}) {
70555
70951
  env: deps.env,
70556
70952
  cwd: home,
70557
70953
  packageVersion: latest.stdout.trim(),
70558
- targetDir: path35.join(home, ".cursor/plugins/local/workit")
70954
+ targetDir: path36.join(home, ".cursor/plugins/local/workit")
70559
70955
  });
70560
70956
  plan.entries.push({
70561
70957
  host: source.host,
@@ -70585,13 +70981,13 @@ function applyUpgrade(plan, deps = {}) {
70585
70981
  ok: false,
70586
70982
  error: "Stop the selected running hosts before upgrading their loaded plugins"
70587
70983
  };
70588
- const backup = path35.join(home, ".local/state/workit/upgrades", new Date().toISOString().replaceAll(":", "-"));
70589
- mkdirSync8(backup, { recursive: true, mode: 448 });
70984
+ const backup = path36.join(home, ".local/state/workit/upgrades", new Date().toISOString().replaceAll(":", "-"));
70985
+ mkdirSync9(backup, { recursive: true, mode: 448 });
70590
70986
  for (const file of Object.keys(plan.configDigests))
70591
- if (existsSync17(file)) {
70592
- const target = path35.join(backup, createHash14("sha256").update(file).digest("hex").slice(0, 12) + "-" + path35.basename(file));
70987
+ if (existsSync18(file)) {
70988
+ const target = path36.join(backup, createHash14("sha256").update(file).digest("hex").slice(0, 12) + "-" + path36.basename(file));
70593
70989
  copyFileSync5(file, target);
70594
- chmodSync(target, 384);
70990
+ chmodSync2(target, 384);
70595
70991
  }
70596
70992
  for (const migration of plan.migrations) {
70597
70993
  const value = object2(migration.file);
@@ -70606,9 +71002,9 @@ function applyUpgrade(plan, deps = {}) {
70606
71002
  `, 384);
70607
71003
  }
70608
71004
  const run = runner(deps);
70609
- const cursorRoot = path35.join(home, ".cursor/plugins/local/workit");
70610
- if (plan.entries.some((entry) => entry.host === "cursor") && existsSync17(cursorRoot))
70611
- cpSync5(cursorRoot, path35.join(backup, "cursor-package"), { recursive: true });
71005
+ const cursorRoot = path36.join(home, ".cursor/plugins/local/workit");
71006
+ if (plan.entries.some((entry) => entry.host === "cursor") && existsSync18(cursorRoot))
71007
+ cpSync5(cursorRoot, path36.join(backup, "cursor-package"), { recursive: true });
70612
71008
  for (const entry of plan.entries) {
70613
71009
  if (entry.host === "opencode")
70614
71010
  return {
@@ -70628,7 +71024,7 @@ function applyUpgrade(plan, deps = {}) {
70628
71024
  {
70629
71025
  type: "install-host",
70630
71026
  platform: "cursor",
70631
- path: path35.join(home, ".cursor/plugins/local/.workit-package-bootstrap"),
71027
+ path: path36.join(home, ".cursor/plugins/local/.workit-package-bootstrap"),
70632
71028
  commands: entry.commands.map((command) => ({
70633
71029
  ...command,
70634
71030
  purpose: command.purpose ?? "Upgrade Cursor"
@@ -70637,7 +71033,7 @@ function applyUpgrade(plan, deps = {}) {
70637
71033
  {
70638
71034
  type: "install-adapter",
70639
71035
  platform: "cursor",
70640
- path: path35.join(home, ".cursor/plugins/local/workit")
71036
+ path: path36.join(home, ".cursor/plugins/local/workit")
70641
71037
  }
70642
71038
  ]
70643
71039
  };
@@ -70651,7 +71047,7 @@ function applyUpgrade(plan, deps = {}) {
70651
71047
  return { exitCode: outcome.status ?? 1, stdout: outcome.stdout, stderr: "" };
70652
71048
  }
70653
71049
  });
70654
- const pkg = object2(path35.join(home, ".cursor/plugins/local/workit/package.json"));
71050
+ const pkg = object2(path36.join(home, ".cursor/plugins/local/workit/package.json"));
70655
71051
  if (!result.ok || pkg?.version !== entry.latest)
70656
71052
  return {
70657
71053
  ok: false,
@@ -70685,15 +71081,15 @@ function applyUpgrade(plan, deps = {}) {
70685
71081
  const currentRoot = run("npm", ["root", "--global"]);
70686
71082
  if (currentRoot.status !== 0 || currentRoot.stdout.trim() !== plan.cli.root)
70687
71083
  return { ok: false, backup, error: "Global npm location changed; preview again" };
70688
- const cliBackup = path35.join(backup, "cli-package");
70689
- cpSync5(path35.join(plan.cli.root, "@brainervirus/workit-cli"), cliBackup, { recursive: true });
71084
+ const cliBackup = path36.join(backup, "cli-package");
71085
+ cpSync5(path36.join(plan.cli.root, "@brainervirus/workit-cli"), cliBackup, { recursive: true });
70690
71086
  if (run("npm", ["install", "--global", `@brainervirus/workit-cli@${plan.cli.latest}`]).status !== 0)
70691
71087
  return {
70692
71088
  ok: false,
70693
71089
  backup,
70694
- error: `CLI update failed; preserved package at ${cliBackup}; use npm to repair or run node ${path35.join(cliBackup, "dist/index.js")}`
71090
+ error: `CLI update failed; preserved package at ${cliBackup}; use npm to repair or run node ${path36.join(cliBackup, "dist/index.js")}`
70695
71091
  };
70696
- const installed = object2(path35.join(plan.cli.root, "@brainervirus/workit-cli/package.json"));
71092
+ const installed = object2(path36.join(plan.cli.root, "@brainervirus/workit-cli/package.json"));
70697
71093
  if (installed?.name !== "@brainervirus/workit-cli" || installed.version !== plan.cli.latest)
70698
71094
  return {
70699
71095
  ok: false,
@@ -70718,12 +71114,12 @@ async function runUpgradeCommand(argv, deps = {}) {
70718
71114
  if (flags.has("--cli")) {
70719
71115
  const run = runner(deps);
70720
71116
  const root = run("npm", ["root", "--global"]);
70721
- if (root.status !== 0 || !path35.isAbsolute(root.stdout.trim())) {
71117
+ if (root.status !== 0 || !path36.isAbsolute(root.stdout.trim())) {
70722
71118
  plan.blocked.push("Global npm location could not be verified");
70723
71119
  } else {
70724
- const packageFile = path35.join(root.stdout.trim(), "@brainervirus/workit-cli/package.json");
71120
+ const packageFile = path36.join(root.stdout.trim(), "@brainervirus/workit-cli/package.json");
70725
71121
  const pkg = object2(packageFile);
70726
- if (pkg?.name !== "@brainervirus/workit-cli" || lstatSync6(path35.dirname(packageFile)).isSymbolicLink()) {
71122
+ if (pkg?.name !== "@brainervirus/workit-cli" || lstatSync7(path36.dirname(packageFile)).isSymbolicLink()) {
70727
71123
  plan.skipped.push({
70728
71124
  host: "cli",
70729
71125
  reason: "No managed global CLI install (local links preserved); use npx @brainervirus/workit-cli@latest"
@@ -70803,7 +71199,7 @@ async function runLaunchCommand(argv, deps = {}) {
70803
71199
  }
70804
71200
  if (deps.run)
70805
71201
  return deps.run(host, hostArgs).status ?? 1;
70806
- return spawnSync14(launch.command, launch.args, {
71202
+ return spawnSync15(launch.command, launch.args, {
70807
71203
  stdio: "inherit",
70808
71204
  env
70809
71205
  }).status ?? 1;
@@ -70814,37 +71210,37 @@ var HOSTS2, upgradePaths = (deps) => {
70814
71210
  ...process.env,
70815
71211
  ...deps.home || deps.env?.HOME ? {
70816
71212
  HOME: home,
70817
- CODEX_HOME: path35.join(home, ".codex"),
70818
- PI_CODING_AGENT_DIR: path35.join(home, ".pi/agent"),
70819
- XDG_CONFIG_HOME: path35.join(home, ".config"),
71213
+ CODEX_HOME: path36.join(home, ".codex"),
71214
+ PI_CODING_AGENT_DIR: path36.join(home, ".pi/agent"),
71215
+ XDG_CONFIG_HOME: path36.join(home, ".config"),
70820
71216
  WORKFLOW_TOOLKIT_CONFIG: undefined,
70821
71217
  WORKFLOW_TOOLKIT_CONFIG_DIR: undefined
70822
71218
  } : {},
70823
71219
  ...deps.env,
70824
71220
  HOME: home
70825
71221
  };
70826
- const xdg = env.XDG_CONFIG_HOME || path35.join(home, ".config");
71222
+ const xdg = env.XDG_CONFIG_HOME || path36.join(home, ".config");
70827
71223
  return {
70828
71224
  home,
70829
71225
  env,
70830
- configDir: env.WORKFLOW_TOOLKIT_CONFIG ?? env.WORKFLOW_TOOLKIT_CONFIG_DIR ?? path35.join(xdg, "workit"),
70831
- opencodeConfig: path35.join(xdg, "opencode/opencode.json"),
70832
- piSettings: path35.join(env.PI_CODING_AGENT_DIR ?? path35.join(home, ".pi/agent"), "settings.json"),
70833
- codexConfig: path35.join(env.CODEX_HOME ?? path35.join(home, ".codex"), "config.toml")
71226
+ configDir: env.WORKFLOW_TOOLKIT_CONFIG ?? env.WORKFLOW_TOOLKIT_CONFIG_DIR ?? path36.join(xdg, "workit"),
71227
+ opencodeConfig: path36.join(xdg, "opencode/opencode.json"),
71228
+ piSettings: path36.join(env.PI_CODING_AGENT_DIR ?? path36.join(home, ".pi/agent"), "settings.json"),
71229
+ codexConfig: path36.join(env.CODEX_HOME ?? path36.join(home, ".codex"), "config.toml")
70834
71230
  };
70835
71231
  }, object2 = (file) => {
70836
- if (!existsSync17(file))
71232
+ if (!existsSync18(file))
70837
71233
  return null;
70838
71234
  let data;
70839
71235
  try {
70840
- data = JSON.parse(readFileSync17(file, "utf8"));
71236
+ data = JSON.parse(readFileSync18(file, "utf8"));
70841
71237
  } catch {
70842
71238
  throw new Error(`${file} is not valid JSON; use the native host to inspect JSONC settings`);
70843
71239
  }
70844
71240
  if (!data || typeof data !== "object" || Array.isArray(data))
70845
71241
  throw new Error(`${file} is not a configuration object`);
70846
71242
  return data;
70847
- }, digest2 = (file) => existsSync17(file) ? createHash14("sha256").update(readFileSync17(file)).digest("hex") : "missing", runner = (deps) => deps.run ?? ((command, args) => {
71243
+ }, digest2 = (file) => existsSync18(file) ? createHash14("sha256").update(readFileSync18(file)).digest("hex") : "missing", runner = (deps) => deps.run ?? ((command, args) => {
70848
71244
  const { home, env } = upgradePaths(deps);
70849
71245
  let step;
70850
71246
  try {
@@ -70861,7 +71257,7 @@ var HOSTS2, upgradePaths = (deps) => {
70861
71257
  }), sources = (paths, run, hosts) => {
70862
71258
  const { home, opencodeConfig, piSettings } = paths;
70863
71259
  const result = [];
70864
- if (hosts.includes("opencode") && existsSync17(opencodeConfig + "c"))
71260
+ if (hosts.includes("opencode") && existsSync18(opencodeConfig + "c"))
70865
71261
  throw new Error("OpenCode JSONC config is present; inspect effective native configuration before updating");
70866
71262
  const oc = hosts.includes("opencode") ? object2(opencodeConfig) : null;
70867
71263
  if (oc && [oc.plugins, oc.plugin].some((value) => value !== undefined && !Array.isArray(value)))
@@ -70870,9 +71266,9 @@ var HOSTS2, upgradePaths = (deps) => {
70870
71266
  for (const pin of plugins)
70871
71267
  if (typeof pin === "string" && isWorkitPlugin(pin))
70872
71268
  result.push(classify("opencode", pin));
70873
- const cursor = hosts.includes("cursor") ? object2(path35.join(home, ".cursor/plugins/local/workit/package.json")) : null;
71269
+ const cursor = hosts.includes("cursor") ? object2(path36.join(home, ".cursor/plugins/local/workit/package.json")) : null;
70874
71270
  if (cursor?.name === "@brainervirus/workit-cursor") {
70875
- const mcp = object2(path35.join(home, ".cursor/mcp.json"));
71271
+ const mcp = object2(path36.join(home, ".cursor/mcp.json"));
70876
71272
  const args = mcp?.mcpServers?.workit?.args ?? [];
70877
71273
  const selector = args.find((arg) => typeof arg === "string" && arg.startsWith("--package="));
70878
71274
  result.push(classify("cursor", typeof selector === "string" ? selector.slice(10) : "local"));
@@ -70885,7 +71281,7 @@ var HOSTS2, upgradePaths = (deps) => {
70885
71281
  if (typeof source !== "string")
70886
71282
  continue;
70887
71283
  const npm = /^(?:npm:)?@brainervirus\/workit-pi(?:@[^/]+)?$/.test(source);
70888
- const local = path35.isAbsolute(source) && source.replaceAll("\\", "/").endsWith("/packages/workit-pi") && object2(path35.join(source, "package.json"))?.name === "@brainervirus/workit-pi";
71284
+ const local = path36.isAbsolute(source) && source.replaceAll("\\", "/").endsWith("/packages/workit-pi") && object2(path36.join(source, "package.json"))?.name === "@brainervirus/workit-pi";
70889
71285
  if (npm || local)
70890
71286
  result.push(classify("pi", source));
70891
71287
  }
@@ -70896,7 +71292,7 @@ var HOSTS2, upgradePaths = (deps) => {
70896
71292
  hostCommand("codex", [], { home, env: paths.env });
70897
71293
  available = true;
70898
71294
  } catch {}
70899
- if (available || existsSync17(paths.codexConfig))
71295
+ if (available || existsSync18(paths.codexConfig))
70900
71296
  throw new Error("Codex plugin inventory failed; inspect the native host before upgrading");
70901
71297
  }
70902
71298
  if (listing.status === 0) {
@@ -70932,9 +71328,9 @@ var HOSTS2, upgradePaths = (deps) => {
70932
71328
  }, piInstalledVersion = (listing, selector) => {
70933
71329
  const lines = listing.split(/\r?\n/).map((line) => line.trim());
70934
71330
  const index = lines.indexOf(selector);
70935
- if (index < 0 || !lines[index + 1] || !path35.isAbsolute(lines[index + 1]))
71331
+ if (index < 0 || !lines[index + 1] || !path36.isAbsolute(lines[index + 1]))
70936
71332
  return;
70937
- const pkg = object2(path35.join(lines[index + 1], "package.json"));
71333
+ const pkg = object2(path36.join(lines[index + 1], "package.json"));
70938
71334
  return pkg?.name === "@brainervirus/workit-pi" ? pkg.version : undefined;
70939
71335
  }, versionAtLeast = (installed, latest) => {
70940
71336
  if (!/^\d+\.\d+\.\d+$/.test(installed))
@@ -70967,9 +71363,9 @@ var init_upgrade = __esm(() => {
70967
71363
  // packages/workit-cli/src/verbs/upgrade.ts
70968
71364
  var exports_upgrade = {};
70969
71365
  __export(exports_upgrade, {
70970
- run: () => run3
71366
+ run: () => run4
70971
71367
  });
70972
- var run3 = (argv) => runUpgradeCommand(argv);
71368
+ var run4 = (argv) => runUpgradeCommand(argv);
70973
71369
  var init_upgrade2 = __esm(() => {
70974
71370
  init_upgrade();
70975
71371
  });
@@ -70977,17 +71373,17 @@ var init_upgrade2 = __esm(() => {
70977
71373
  // packages/workit-cli/src/verbs/launch.ts
70978
71374
  var exports_launch = {};
70979
71375
  __export(exports_launch, {
70980
- run: () => run4
71376
+ run: () => run5
70981
71377
  });
70982
- var run4 = (argv) => runLaunchCommand(argv);
71378
+ var run5 = (argv) => runLaunchCommand(argv);
70983
71379
  var init_launch = __esm(() => {
70984
71380
  init_upgrade();
70985
71381
  });
70986
71382
 
70987
71383
  // packages/workit-core/src/knowledge.ts
70988
- import { spawnSync as spawnSync15 } from "node:child_process";
71384
+ import { spawnSync as spawnSync16 } from "node:child_process";
70989
71385
  import fs17 from "node:fs";
70990
- import path36 from "node:path";
71386
+ import path37 from "node:path";
70991
71387
  function lintKnowledge(root) {
70992
71388
  const seen = new Set;
70993
71389
  const unreadable = [];
@@ -71091,7 +71487,7 @@ var AGENTS_BYTE_BUDGET, STEERING_FILES, NEED_BASED_FILES, STANDARDS_FILE = "CODI
71091
71487
  const end = lines.indexOf("---", 1);
71092
71488
  return end === -1 ? lines : [...lines.slice(0, end + 1).map(() => ""), ...lines.slice(end + 1)];
71093
71489
  }, read = (root, file) => {
71094
- const full = path36.join(root, file);
71490
+ const full = path37.join(root, file);
71095
71491
  try {
71096
71492
  fs17.lstatSync(full);
71097
71493
  } catch {
@@ -71106,7 +71502,7 @@ var AGENTS_BYTE_BUDGET, STEERING_FILES, NEED_BASED_FILES, STANDARDS_FILE = "CODI
71106
71502
  return "unreadable";
71107
71503
  }
71108
71504
  }, trackedTopLevel = (root) => {
71109
- const run = spawnSync15("git", ["ls-files", "-z", "--cached"], {
71505
+ const run = spawnSync16("git", ["ls-files", "-z", "--cached"], {
71110
71506
  cwd: root,
71111
71507
  encoding: "utf8",
71112
71508
  maxBuffer: 256 * 1024 * 1024,
@@ -71116,7 +71512,7 @@ var AGENTS_BYTE_BUDGET, STEERING_FILES, NEED_BASED_FILES, STANDARDS_FILE = "CODI
71116
71512
  if (run.status !== 0)
71117
71513
  return null;
71118
71514
  return new Set(run.stdout.split("\x00").filter(Boolean).map((file) => file.split("/")[0]));
71119
- }, exists = (target) => {
71515
+ }, exists2 = (target) => {
71120
71516
  try {
71121
71517
  fs17.statSync(target);
71122
71518
  return true;
@@ -71132,7 +71528,7 @@ var AGENTS_BYTE_BUDGET, STEERING_FILES, NEED_BASED_FILES, STANDARDS_FILE = "CODI
71132
71528
  }
71133
71529
  }, brokenLinks = (root, doc, tracked) => {
71134
71530
  const findings = [];
71135
- const base = path36.dirname(path36.join(root, doc.file));
71531
+ const base = path37.dirname(path37.join(root, doc.file));
71136
71532
  const missing = (target, line, how) => findings.push({
71137
71533
  rule: "broken-link",
71138
71534
  file: doc.file,
@@ -71151,8 +71547,8 @@ var AGENTS_BYTE_BUDGET, STEERING_FILES, NEED_BASED_FILES, STANDARDS_FILE = "CODI
71151
71547
  const local = localTarget(target);
71152
71548
  if (!local)
71153
71549
  continue;
71154
- const resolved = local.startsWith("/") ? path36.join(root, local) : path36.resolve(base, local);
71155
- if (!exists(resolved))
71550
+ const resolved = local.startsWith("/") ? path37.join(root, local) : path37.resolve(base, local);
71551
+ if (!exists2(resolved))
71156
71552
  missing(target, index + 1, "link");
71157
71553
  }
71158
71554
  for (const [, span] of text.matchAll(CODE_SPAN)) {
@@ -71161,10 +71557,10 @@ var AGENTS_BYTE_BUDGET, STEERING_FILES, NEED_BASED_FILES, STANDARDS_FILE = "CODI
71161
71557
  continue;
71162
71558
  const relative = /^\.\.?\//.test(candidate);
71163
71559
  const first = candidate.split("/")[0];
71164
- if (!relative && !(tracked ? tracked.has(first) : exists(path36.join(root, first))))
71560
+ if (!relative && !(tracked ? tracked.has(first) : exists2(path37.join(root, first))))
71165
71561
  continue;
71166
- const resolved = relative ? path36.resolve(base, candidate) : path36.join(root, candidate);
71167
- if (!exists(resolved))
71562
+ const resolved = relative ? path37.resolve(base, candidate) : path37.join(root, candidate);
71563
+ if (!exists2(resolved))
71168
71564
  missing(span, index + 1, "pointer");
71169
71565
  }
71170
71566
  }
@@ -71289,7 +71685,7 @@ var init_prompt = () => {};
71289
71685
  // packages/workit-cli/src/verbs/doctor.ts
71290
71686
  var exports_doctor = {};
71291
71687
  __export(exports_doctor, {
71292
- run: () => run5
71688
+ run: () => run6
71293
71689
  });
71294
71690
  async function confirmForcedLockClear(root, args, io) {
71295
71691
  const lock = inspectMetadataLock(root);
@@ -71312,7 +71708,7 @@ async function confirmForcedLockClear(root, args, io) {
71312
71708
  return "cancelled";
71313
71709
  return /^y(es)?$/i.test(answer.trim());
71314
71710
  }
71315
- async function run5(argv, io) {
71711
+ async function run6(argv, io) {
71316
71712
  const root = workspaceRootFor();
71317
71713
  const force = argv.includes("--force");
71318
71714
  let fixLock = null;
@@ -71330,6 +71726,18 @@ async function run5(argv, io) {
71330
71726
  }
71331
71727
  fixLock = clearStaleMetadataLock(root, { force });
71332
71728
  }
71729
+ let sessionHook = null;
71730
+ if (argv.includes("--fix")) {
71731
+ try {
71732
+ const fixed = fixSessionHook({ host: "cli", cwd: io.cwd, workspaceRoot: root });
71733
+ sessionHook = { action: fixed.action, detail: fixed.detail };
71734
+ } catch (error) {
71735
+ sessionHook = {
71736
+ action: "failed",
71737
+ detail: error instanceof Error ? error.message : String(error)
71738
+ };
71739
+ }
71740
+ }
71333
71741
  const report = runDoctor({
71334
71742
  host: "cli",
71335
71743
  cwd: io.cwd,
@@ -71352,7 +71760,7 @@ async function run5(argv, io) {
71352
71760
  budget: knowledge.budget,
71353
71761
  findings: knowledge.findings.length
71354
71762
  } : { unavailable: true };
71355
- io.stdout(`${JSON.stringify({ ...report, ...fixLock ? { fixLock } : {}, knowledge: summary }, null, 2)}
71763
+ io.stdout(`${JSON.stringify({ ...report, ...fixLock ? { fixLock } : {}, ...sessionHook ? { sessionHook } : {}, knowledge: summary }, null, 2)}
71356
71764
  `);
71357
71765
  return report.exitCode;
71358
71766
  }
@@ -71361,6 +71769,9 @@ async function run5(argv, io) {
71361
71769
  io.stdout(`fix-lock: ${what}${fixLock.guardCleared ? "; removed abandoned reclaim guard" : ""}
71362
71770
  `);
71363
71771
  }
71772
+ if (sessionHook)
71773
+ io.stdout(`fix: session hook ${sessionHook.action}: ${sessionHook.detail}
71774
+ `);
71364
71775
  io.stdout(`workit doctor — ${report.ok ? "healthy" : "problems found"} (${report.offline ? "offline" : "online"})
71365
71776
  `);
71366
71777
  for (const check of report.checks) {
@@ -71493,11 +71904,11 @@ var init_redact = __esm(() => {
71493
71904
  });
71494
71905
 
71495
71906
  // packages/workit-core/src/checks.ts
71496
- import { spawn, spawnSync as spawnSync16 } from "node:child_process";
71907
+ import { spawn, spawnSync as spawnSync17 } from "node:child_process";
71497
71908
  import { createHash as createHash15 } from "node:crypto";
71498
71909
  import fs18 from "node:fs";
71499
71910
  import os13 from "node:os";
71500
- import path37 from "node:path";
71911
+ import path38 from "node:path";
71501
71912
  import { StringDecoder } from "node:string_decoder";
71502
71913
  function tailLines(text, lines = TAIL_LINES) {
71503
71914
  const all = text.replace(/\r\n?/gu, `
@@ -71617,7 +72028,7 @@ function planSpawn(argv, options) {
71617
72028
  return { file: argv[0], args: [], verbatim: false, shell: true };
71618
72029
  if (options.platform !== "win32")
71619
72030
  return { file: argv[0], args: argv.slice(1), verbatim: false, shell: false };
71620
- const win = path37.win32;
72031
+ const win = path38.win32;
71621
72032
  const isFile = options.isFile ?? ((file) => {
71622
72033
  try {
71623
72034
  return fs18.statSync(file).isFile();
@@ -71672,7 +72083,7 @@ function runCheckCommand(argv, options) {
71672
72083
  if (!child?.pid)
71673
72084
  return;
71674
72085
  if (windows)
71675
- spawnSync16("taskkill", ["/pid", String(child.pid), "/T", "/F"], {
72086
+ spawnSync17("taskkill", ["/pid", String(child.pid), "/T", "/F"], {
71676
72087
  stdio: "ignore",
71677
72088
  windowsHide: true
71678
72089
  });
@@ -71774,10 +72185,10 @@ function runCheckCommand(argv, options) {
71774
72185
  function storeLog(storeRoot, log) {
71775
72186
  const digest = logDigest(log);
71776
72187
  const ref = `blobs/logs/${digest.slice("sha256:".length)}.log`;
71777
- const file = path37.join(storeRoot, ref);
72188
+ const file = path38.join(storeRoot, ref);
71778
72189
  try {
71779
72190
  if (!fs18.existsSync(file)) {
71780
- fs18.mkdirSync(path37.dirname(file), { recursive: true });
72191
+ fs18.mkdirSync(path38.dirname(file), { recursive: true });
71781
72192
  const temp = `${file}.${process.pid}.${Date.now()}.tmp`;
71782
72193
  fs18.writeFileSync(temp, log, { mode: 384 });
71783
72194
  fs18.renameSync(temp, file);
@@ -71790,7 +72201,7 @@ function storeLog(storeRoot, log) {
71790
72201
  function pruneCheckLogs(storeRoot, options = {}) {
71791
72202
  const limits = { ...LOG_RETENTION, ...options.retention };
71792
72203
  const now = options.now ?? Date.now();
71793
- const dir = path37.join(storeRoot, "blobs", "logs");
72204
+ const dir = path38.join(storeRoot, "blobs", "logs");
71794
72205
  const report = { removed: 0, removedBytes: 0, kept: 0 };
71795
72206
  let names;
71796
72207
  try {
@@ -71800,7 +72211,7 @@ function pruneCheckLogs(storeRoot, options = {}) {
71800
72211
  }
71801
72212
  const files = names.flatMap((name) => {
71802
72213
  try {
71803
- const stat = fs18.statSync(path37.join(dir, name));
72214
+ const stat = fs18.statSync(path38.join(dir, name));
71804
72215
  return stat.isFile() ? [{ name, size: stat.size, mtimeMs: stat.mtimeMs }] : [];
71805
72216
  } catch {
71806
72217
  return [];
@@ -71819,7 +72230,7 @@ function pruneCheckLogs(storeRoot, options = {}) {
71819
72230
  continue;
71820
72231
  if (!options.dryRun)
71821
72232
  try {
71822
- fs18.rmSync(path37.join(dir, file.name), { force: true });
72233
+ fs18.rmSync(path38.join(dir, file.name), { force: true });
71823
72234
  } catch {
71824
72235
  continue;
71825
72236
  }
@@ -71850,9 +72261,9 @@ var init_checks3 = __esm(() => {
71850
72261
  // packages/workit-cli/src/verbs/gc.ts
71851
72262
  var exports_gc = {};
71852
72263
  __export(exports_gc, {
71853
- run: () => run6
72264
+ run: () => run7
71854
72265
  });
71855
- async function run6(argv, io) {
72266
+ async function run7(argv, io) {
71856
72267
  const dryRun = argv.includes("--dry-run");
71857
72268
  const pruneRecovery = argv.includes("--prune-recovery");
71858
72269
  if (pruneRecovery && !dryRun && !argv.includes("--yes"))
@@ -71896,9 +72307,9 @@ var init_gc = __esm(() => {
71896
72307
  // packages/workit-cli/src/verbs/uninstall.ts
71897
72308
  var exports_uninstall = {};
71898
72309
  __export(exports_uninstall, {
71899
- run: () => run7
72310
+ run: () => run8
71900
72311
  });
71901
- async function run7(_argv, io) {
72312
+ async function run8(_argv, io) {
71902
72313
  if (io.json)
71903
72314
  return emit(io, fail("invalid_input", "workit uninstall is interactive and has no --json output", {
71904
72315
  unblock: "run `workit uninstall` in a terminal without --json"
@@ -71914,7 +72325,7 @@ var init_uninstall2 = __esm(() => {
71914
72325
  // packages/workit-cli/src/verbs/grant.ts
71915
72326
  var exports_grant = {};
71916
72327
  __export(exports_grant, {
71917
- run: () => run8,
72328
+ run: () => run9,
71918
72329
  runGrant: () => runGrant
71919
72330
  });
71920
72331
  function show(argv, io) {
@@ -72035,7 +72446,7 @@ var USAGE2 = "workit grant show [<workspace>] [--all] | grant set <workspace> <k
72035
72446
  ...endpoint.endpointIssue ? [` note: ${endpoint.endpointIssue}`] : [],
72036
72447
  ` verification: ${verification} (${verification === "independent" ? "a normal-risk behavior change needs a non-author verdict" : "a normal-risk behavior change needs a passing check and the author's --self verdict, shown as self-reviewed"})`
72037
72448
  ], usage2 = (io, message) => emit(io, fail("invalid_input", `${message}
72038
- usage: ${USAGE2}`)), run8 = (argv, io) => runGrant(argv, io);
72449
+ usage: ${USAGE2}`)), run9 = (argv, io) => runGrant(argv, io);
72039
72450
  var init_grant = __esm(() => {
72040
72451
  init_autonomy();
72041
72452
  init_release_tracks();
@@ -72064,9 +72475,9 @@ var init_grant = __esm(() => {
72064
72475
  // packages/workit-cli/src/verbs/check.ts
72065
72476
  var exports_check = {};
72066
72477
  __export(exports_check, {
72067
- run: () => run9
72478
+ run: () => run10
72068
72479
  });
72069
- import path38 from "node:path";
72480
+ import path39 from "node:path";
72070
72481
  function parse5(argv) {
72071
72482
  const split = argv.indexOf("--");
72072
72483
  const head = split >= 0 ? argv.slice(0, split) : [...argv];
@@ -72215,7 +72626,7 @@ function boundedArgv(argv) {
72215
72626
  const truncated = cut.length !== argv.length || cut.some((item, index) => item !== argv[index]);
72216
72627
  return { argv: cut, truncated };
72217
72628
  }
72218
- async function run9(argv, io) {
72629
+ async function run10(argv, io) {
72219
72630
  const options = parse5(argv);
72220
72631
  if (options instanceof Error)
72221
72632
  return emit(io, fail("invalid_input", options.message, { unblock: USAGE3 }));
@@ -72249,7 +72660,7 @@ async function run9(argv, io) {
72249
72660
  if (options.shell && command.length !== 1)
72250
72661
  return emit(io, fail("invalid_input", '--shell takes the command as one string: workit check --shell -- "<cmd>"'));
72251
72662
  }
72252
- const relCwd = posix(path38.relative(top, runCwd));
72663
+ const relCwd = posix(path39.relative(top, runCwd));
72253
72664
  const configured = !options.shell && matchesNamedCheck(config, name, command, relCwd);
72254
72665
  const actor = actorFromEnv(io.env);
72255
72666
  const branchKey = codeKey(io.cwd, { base: options.base });
@@ -72373,7 +72784,7 @@ async function run9(argv, io) {
72373
72784
  return recordError.code === "busy" ? 4 : recordError.code === "invalid_input" ? 2 : 5;
72374
72785
  return 0;
72375
72786
  }
72376
- var USAGE3 = "workit check <name> | workit check [--name <n>] [--shell] [--timeout <s>] [--task <id>] [--json] -- <cmd…>", RECORD_TAIL_LINES = 20, RECORD_TAIL_CHARS = 200, posix = (value) => value.split(path38.sep).join("/") || ".", ENGINE_CODES2, FINGERPRINT_VARS;
72787
+ var USAGE3 = "workit check <name> | workit check [--name <n>] [--shell] [--timeout <s>] [--task <id>] [--json] -- <cmd…>", RECORD_TAIL_LINES = 20, RECORD_TAIL_CHARS = 200, posix = (value) => value.split(path39.sep).join("/") || ".", ENGINE_CODES2, FINGERPRINT_VARS;
72377
72788
  var init_check = __esm(() => {
72378
72789
  init_check_config();
72379
72790
  init_checks3();
@@ -72395,9 +72806,9 @@ var init_check = __esm(() => {
72395
72806
  var success2 = (data) => ({ ok: true, data }), failure3 = (code, error, unblock) => ({ ok: false, code, error, ...unblock ? { unblock } : {} });
72396
72807
 
72397
72808
  // packages/workit-core/src/git/ops.ts
72398
- import { spawnSync as spawnSync17 } from "node:child_process";
72399
- import { existsSync as existsSync18, readFileSync as readFileSync18 } from "node:fs";
72400
- import path39 from "node:path";
72809
+ import { spawnSync as spawnSync18 } from "node:child_process";
72810
+ import { existsSync as existsSync19, readFileSync as readFileSync19 } from "node:fs";
72811
+ import path40 from "node:path";
72401
72812
  function operationInProgress(cwd) {
72402
72813
  const markers = [
72403
72814
  ["rebase-merge", "rebase"],
@@ -72410,18 +72821,18 @@ function operationInProgress(cwd) {
72410
72821
  if (!run.ok)
72411
72822
  return null;
72412
72823
  const found = run.stdout.split(`
72413
- `).map((line) => path39.resolve(cwd, line.trim()));
72824
+ `).map((line) => path40.resolve(cwd, line.trim()));
72414
72825
  const conflicted = () => git5(cwd, ["ls-files", "-u"]).stdout.trim() !== "";
72415
72826
  for (const [index, [, operation]] of markers.entries()) {
72416
72827
  const marker = found[index];
72417
- if (!marker || !existsSync18(marker))
72828
+ if (!marker || !existsSync19(marker))
72418
72829
  continue;
72419
- if (index === 1 && existsSync18(path39.join(marker, "applying")))
72830
+ if (index === 1 && existsSync19(path40.join(marker, "applying")))
72420
72831
  return { operation: "am", commitAllowed: false, branch: null };
72421
- if (index === 0 && existsSync18(path39.join(marker, "amend")) && !conflicted()) {
72832
+ if (index === 0 && existsSync19(path40.join(marker, "amend")) && !conflicted()) {
72422
72833
  let headName = "";
72423
72834
  try {
72424
- headName = readFileSync18(path39.join(marker, "head-name"), "utf8").trim();
72835
+ headName = readFileSync19(path40.join(marker, "head-name"), "utf8").trim();
72425
72836
  } catch {}
72426
72837
  const branch = headName.startsWith("refs/heads/") ? headName.slice("refs/heads/".length) : null;
72427
72838
  return { operation, commitAllowed: branch !== null, branch };
@@ -72671,7 +73082,7 @@ function gitCommit(cwd, input) {
72671
73082
  if (paths.some((value) => value.startsWith("-") || !value.trim()))
72672
73083
  return failure3("invalid_input", "paths must not be empty or start with -");
72673
73084
  const tracked = new Set(nulList(git5(cwd, ["ls-files", "-z", "--", ...paths]).stdout));
72674
- const addable = paths.filter((value) => existsSync18(path39.resolve(cwd, value)) || [...tracked].some((file) => file === value || file.startsWith(`${value}/`)));
73085
+ const addable = paths.filter((value) => existsSync19(path40.resolve(cwd, value)) || [...tracked].some((file) => file === value || file.startsWith(`${value}/`)));
72675
73086
  if (addable.length) {
72676
73087
  const added = git5(cwd, ["add", "-A", "--", ...addable]);
72677
73088
  if (!added.ok)
@@ -72950,7 +73361,7 @@ ${run.stdout}`;
72950
73361
  } : { ok: false, lease: false, error: gitError(run) };
72951
73362
  }
72952
73363
  var COMMIT_TIMEOUT_MS, PUSH_TIMEOUT_MS = 120000, git5 = (cwd, args, options = {}) => {
72953
- const result = spawnSync17("git", args, {
73364
+ const result = spawnSync18("git", args, {
72954
73365
  cwd,
72955
73366
  encoding: "utf8",
72956
73367
  env: { ...options.env ?? process.env, GIT_TERMINAL_PROMPT: "0" },
@@ -73004,10 +73415,10 @@ var init_ops = __esm(() => {
73004
73415
 
73005
73416
  // packages/workit-core/src/forge/reruns.ts
73006
73417
  import fs19 from "node:fs";
73007
- import path40 from "node:path";
73418
+ import path41 from "node:path";
73008
73419
  function rerunLogPath(cwd) {
73009
73420
  const common = gitCommonDir(cwd);
73010
- return common ? path40.join(common, "workit", "ci-reruns.jsonl") : null;
73421
+ return common ? path41.join(common, "workit", "ci-reruns.jsonl") : null;
73011
73422
  }
73012
73423
  function rerunCounts(cwd, key) {
73013
73424
  const counts = new Map;
@@ -73042,7 +73453,7 @@ function recordReruns(cwd, rows) {
73042
73453
  if (!file)
73043
73454
  return false;
73044
73455
  try {
73045
- fs19.mkdirSync(path40.dirname(file), { recursive: true });
73456
+ fs19.mkdirSync(path41.dirname(file), { recursive: true });
73046
73457
  fs19.appendFileSync(file, rows.map((row) => `${JSON.stringify(row)}
73047
73458
  `).join(""));
73048
73459
  return true;
@@ -73055,7 +73466,7 @@ function withRerunLock(cwd, fn) {
73055
73466
  if (!file)
73056
73467
  return fn();
73057
73468
  const lock = `${file.slice(0, -".jsonl".length)}.lock`;
73058
- fs19.mkdirSync(path40.dirname(lock), { recursive: true });
73469
+ fs19.mkdirSync(path41.dirname(lock), { recursive: true });
73059
73470
  const until = Date.now() + LOCK_WAIT_MS2;
73060
73471
  for (;; ) {
73061
73472
  try {
@@ -73478,7 +73889,7 @@ var init_report = __esm(() => {
73478
73889
  });
73479
73890
 
73480
73891
  // packages/workit-core/src/forge/pr-ops.ts
73481
- import { spawnSync as spawnSync18 } from "node:child_process";
73892
+ import { spawnSync as spawnSync19 } from "node:child_process";
73482
73893
  function fillFromCommits(cwd, resolved, base) {
73483
73894
  const tracking = `refs/remotes/${resolved.baseRemote}/${base}`;
73484
73895
  if (!base.startsWith("-"))
@@ -73486,7 +73897,7 @@ function fillFromCommits(cwd, resolved, base) {
73486
73897
  const from = resolveRef(cwd, tracking) ?? resolveRef(cwd, `refs/heads/${base}`);
73487
73898
  if (!from)
73488
73899
  return failure3("not_found", `base ${base} is not available locally`, `git fetch ${resolved.baseRemote} ${base}`);
73489
- const log = spawnSync18("git", ["log", "--reverse", "--no-merges", "--format=%s%x1f%b%x1e", `${from}..HEAD`], {
73900
+ const log = spawnSync19("git", ["log", "--reverse", "--no-merges", "--format=%s%x1f%b%x1e", `${from}..HEAD`], {
73490
73901
  cwd,
73491
73902
  encoding: "utf8",
73492
73903
  timeout: GIT_TIMEOUTS.local,
@@ -73842,10 +74253,10 @@ var init_pr_ops = __esm(() => {
73842
74253
  });
73843
74254
 
73844
74255
  // packages/workit-core/src/stack.ts
73845
- import { spawnSync as spawnSync19 } from "node:child_process";
74256
+ import { spawnSync as spawnSync20 } from "node:child_process";
73846
74257
  import { createHash as createHash16, randomBytes as randomBytes3 } from "node:crypto";
73847
74258
  import fs20 from "node:fs";
73848
- import path41 from "node:path";
74259
+ import path42 from "node:path";
73849
74260
  function worktreeOf(cwd, branch) {
73850
74261
  const list = gitRun3(cwd, ["worktree", "list", "--porcelain"]);
73851
74262
  if (!list.ok)
@@ -73889,7 +74300,7 @@ function gitRestack(cwd, input) {
73889
74300
  if (!scratch)
73890
74301
  return { ok: false, conflict: false, worktree: cwd, error: "no store root" };
73891
74302
  fs20.mkdirSync(scratch, { recursive: true });
73892
- dir = path41.join(scratch, `${input.branch.replace(/[^A-Za-z0-9._-]+/gu, "_").slice(0, 40)}-${randomBytes3(4).toString("hex")}`);
74303
+ dir = path42.join(scratch, `${input.branch.replace(/[^A-Za-z0-9._-]+/gu, "_").slice(0, 40)}-${randomBytes3(4).toString("hex")}`);
73893
74304
  const added = gitRun3(cwd, ["worktree", "add", "-q", dir, input.branch], GIT_TIMEOUTS.worktree);
73894
74305
  if (!added.ok)
73895
74306
  return { ok: false, conflict: false, worktree: cwd, error: firstLine(added) };
@@ -73930,7 +74341,7 @@ function pruneScratch(cwd) {
73930
74341
  if (!scratch || !fs20.existsSync(scratch))
73931
74342
  return;
73932
74343
  for (const name of fs20.readdirSync(scratch)) {
73933
- const dir = path41.join(scratch, name);
74344
+ const dir = path42.join(scratch, name);
73934
74345
  if (!rebaseInProgress(dir) && !trackedDirt(dir))
73935
74346
  gitRun3(cwd, ["worktree", "remove", "--force", dir]);
73936
74347
  }
@@ -73940,7 +74351,7 @@ function stacksDir(cwd) {
73940
74351
  const root = storeRoot(cwd);
73941
74352
  if (!root.ok)
73942
74353
  return stackFail(root.code, root.error, root.unblock);
73943
- return { ok: true, data: path41.join(root.value.root, "stacks") };
74354
+ return { ok: true, data: path42.join(root.value.root, "stacks") };
73944
74355
  }
73945
74356
  function parseStack(raw) {
73946
74357
  if (!isRecord7(raw) || !Array.isArray(raw.branches))
@@ -73992,7 +74403,7 @@ function readStack(cwd, name) {
73992
74403
  const dir = stacksDir(cwd);
73993
74404
  if (!dir.ok)
73994
74405
  return dir;
73995
- const file = path41.join(dir.data, fileFor(name));
74406
+ const file = path42.join(dir.data, fileFor(name));
73996
74407
  let text;
73997
74408
  try {
73998
74409
  text = fs20.readFileSync(file, "utf8");
@@ -74013,7 +74424,7 @@ function writeStack(cwd, stack, now = new Date) {
74013
74424
  const dir = stacksDir(cwd);
74014
74425
  if (!dir.ok)
74015
74426
  return dir;
74016
- const file = path41.join(dir.data, fileFor(stack.name));
74427
+ const file = path42.join(dir.data, fileFor(stack.name));
74017
74428
  const temp = `${file}.${process.pid}.tmp`;
74018
74429
  try {
74019
74430
  fs20.mkdirSync(dir.data, { recursive: true });
@@ -74041,7 +74452,7 @@ function listStacks(cwd) {
74041
74452
  for (const name of names) {
74042
74453
  let parsed = null;
74043
74454
  try {
74044
- parsed = parseStack(JSON.parse(fs20.readFileSync(path41.join(dir.data, name), "utf8")));
74455
+ parsed = parseStack(JSON.parse(fs20.readFileSync(path42.join(dir.data, name), "utf8")));
74045
74456
  } catch {
74046
74457
  parsed = null;
74047
74458
  }
@@ -74100,7 +74511,7 @@ function takeLock(lock) {
74100
74511
  host: localLockHost(),
74101
74512
  nonce: randomBytes3(8).toString("hex")
74102
74513
  };
74103
- fs20.writeFileSync(path41.join(lock, OWNER), JSON.stringify(owner));
74514
+ fs20.writeFileSync(path42.join(lock, OWNER), JSON.stringify(owner));
74104
74515
  return owner;
74105
74516
  }
74106
74517
  function reapLock(lock, observed) {
@@ -74137,7 +74548,7 @@ async function withStackLock(cwd, name, fn, waitMs = LOCK_WAIT_MS3) {
74137
74548
  return dir;
74138
74549
  if (!validName(name))
74139
74550
  return stackFail("invalid_input", "a stack name must be 1-200 printable characters");
74140
- const lock = path41.join(dir.data, `${fileFor(name)}.lock`);
74551
+ const lock = path42.join(dir.data, `${fileFor(name)}.lock`);
74141
74552
  try {
74142
74553
  fs20.mkdirSync(dir.data, { recursive: true });
74143
74554
  } catch (error) {
@@ -74167,7 +74578,7 @@ async function withStackLock(cwd, name, fn, waitMs = LOCK_WAIT_MS3) {
74167
74578
  const touch = () => {
74168
74579
  try {
74169
74580
  const now = new Date;
74170
- fs20.utimesSync(path41.join(lock, OWNER), now, now);
74581
+ fs20.utimesSync(path42.join(lock, OWNER), now, now);
74171
74582
  } catch {}
74172
74583
  };
74173
74584
  const beat = setInterval(touch, HEARTBEAT_MS);
@@ -74355,7 +74766,7 @@ function commitKeys(cwd, range) {
74355
74766
  const patches = new Map;
74356
74767
  const diff = gitRun3(cwd, ["log", "--no-merges", "-p", "--format=commit %H", range]);
74357
74768
  if (diff.ok && diff.stdout.trim()) {
74358
- const ids = spawnSync19("git", ["patch-id", "--stable"], {
74769
+ const ids = spawnSync20("git", ["patch-id", "--stable"], {
74359
74770
  cwd,
74360
74771
  input: diff.stdout,
74361
74772
  encoding: "utf8",
@@ -74979,7 +75390,7 @@ var STACK_VERSION = 1, stackFail = (code, error, unblock, data) => ({
74979
75390
  ...unblock ? { unblock } : {},
74980
75391
  ...data ? { data } : {}
74981
75392
  }), fromForge = (result) => stackFail(result.code, result.error, result.unblock), stackDeps, gitRun3 = (cwd, args, timeoutMs = GIT_TIMEOUTS.local) => {
74982
- const run = spawnSync19("git", args, {
75393
+ const run = spawnSync20("git", args, {
74983
75394
  cwd,
74984
75395
  encoding: "utf8",
74985
75396
  timeout: timeoutMs,
@@ -75007,7 +75418,7 @@ var STACK_VERSION = 1, stackFail = (code, error, unblock, data) => ({
75007
75418
  return !status.ok || status.stdout.trim() !== "";
75008
75419
  }, scratchDir = (cwd) => {
75009
75420
  const dir = stacksDir(cwd);
75010
- return dir.ok ? path41.join(dir.data, "worktrees") : null;
75421
+ return dir.ok ? path42.join(dir.data, "worktrees") : null;
75011
75422
  }, firstLine = (run) => (`${run.stderr}
75012
75423
  ${run.stdout}`.split(`
75013
75424
  `).find((line) => line.trim()) ?? "git failed").trim().slice(0, 300), stackFileName = (name) => `${name.replace(/[^A-Za-z0-9._-]+/gu, "_").replace(/^[._]+/u, "").slice(0, 48).toLowerCase()}-${createHash16("sha256").update(name).digest("hex").slice(0, 12)}.json`, fileFor, validName = (name) => {
@@ -75022,12 +75433,12 @@ ${run.stdout}`.split(`
75022
75433
  }, isRecord7 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), str3 = (value) => typeof value === "string" && value ? value : null, LOCK_WAIT_MS3 = 2000, HEARTBEAT_MS = 20000, HEARTBEAT_STALE_MS, OWNERLESS_STALE_MS = 30000, OWNER = "owner", readOwner = (lock) => {
75023
75434
  let raw = null;
75024
75435
  try {
75025
- raw = fs20.readFileSync(path41.join(lock, OWNER), "utf8");
75436
+ raw = fs20.readFileSync(path42.join(lock, OWNER), "utf8");
75026
75437
  } catch {
75027
75438
  raw = null;
75028
75439
  }
75029
75440
  let age = null;
75030
- for (const target of [path41.join(lock, OWNER), lock])
75441
+ for (const target of [path42.join(lock, OWNER), lock])
75031
75442
  try {
75032
75443
  age = Date.now() - fs20.statSync(target).mtimeMs;
75033
75444
  break;
@@ -75060,7 +75471,7 @@ var init_stack = __esm(() => {
75060
75471
  });
75061
75472
 
75062
75473
  // packages/workit-core/src/forge/pr-edit.ts
75063
- import { spawnSync as spawnSync20 } from "node:child_process";
75474
+ import { spawnSync as spawnSync21 } from "node:child_process";
75064
75475
  function openPr(cwd, resolved, pr) {
75065
75476
  const grant = requireGrant(cwd, "pr");
75066
75477
  if (!grant.allowed)
@@ -75225,7 +75636,7 @@ function replyToThread(cwd, resolved, input) {
75225
75636
  });
75226
75637
  }
75227
75638
  var label = (resolved, number) => `${resolved.forge.kind === "github" ? "PR #" : "MR !"}${number}`, git6 = (cwd, args) => {
75228
- const run = spawnSync20("git", args, {
75639
+ const run = spawnSync21("git", args, {
75229
75640
  cwd,
75230
75641
  encoding: "utf8",
75231
75642
  timeout: GIT_TIMEOUTS.local,
@@ -75245,15 +75656,15 @@ var init_pr_edit = __esm(() => {
75245
75656
  });
75246
75657
 
75247
75658
  // packages/workit-core/src/forge/exec.ts
75248
- import { spawnSync as spawnSync21 } from "node:child_process";
75659
+ import { spawnSync as spawnSync22 } from "node:child_process";
75249
75660
  import fs21 from "node:fs";
75250
- import path42 from "node:path";
75661
+ import path43 from "node:path";
75251
75662
  function findExecutable(bin, env) {
75252
- const dirs = (env.PATH ?? env.Path ?? "").split(path42.delimiter).filter(Boolean);
75663
+ const dirs = (env.PATH ?? env.Path ?? "").split(path43.delimiter).filter(Boolean);
75253
75664
  const exts = process.platform === "win32" ? [".exe"] : [""];
75254
75665
  for (const dir of dirs)
75255
75666
  for (const ext of exts) {
75256
- const candidate = path42.join(dir, `${bin}${ext}`);
75667
+ const candidate = path43.join(dir, `${bin}${ext}`);
75257
75668
  try {
75258
75669
  const stat = fs21.statSync(candidate);
75259
75670
  if (stat.isFile())
@@ -75280,7 +75691,7 @@ function systemRunner(kind, apiHost, env = process.env) {
75280
75691
  if (!exe)
75281
75692
  return { status: null, stdout: "", stderr: "", timedOut: false, missing: true };
75282
75693
  const token = options.token ? kind === "github" ? { GH_TOKEN: options.token, GH_ENTERPRISE_TOKEN: options.token } : { GITLAB_TOKEN: options.token } : {};
75283
- const result = spawnSync21(exe, [...args], {
75694
+ const result = spawnSync22(exe, [...args], {
75284
75695
  encoding: "utf8",
75285
75696
  env: { ...childEnv, ...token },
75286
75697
  maxBuffer: MAX_BUFFER2,
@@ -76444,7 +76855,7 @@ var init_duration = __esm(() => {
76444
76855
  });
76445
76856
 
76446
76857
  // packages/workit-cli/src/verbs/forge-common.ts
76447
- import { readFileSync as readFileSync19 } from "node:fs";
76858
+ import { readFileSync as readFileSync20 } from "node:fs";
76448
76859
  function parseFlags(argv, spec) {
76449
76860
  const parsed = { values: {}, booleans: new Set, lists: {}, positionals: [] };
76450
76861
  for (let index = 0;index < argv.length; index += 1) {
@@ -76588,7 +76999,7 @@ var init_forge_common = __esm(() => {
76588
76999
  forgeDeps = {
76589
77000
  runner: undefined,
76590
77001
  npm: undefined,
76591
- readStdin: () => readFileSync19(0, "utf8"),
77002
+ readStdin: () => readFileSync20(0, "utf8"),
76592
77003
  sleep: (ms) => new Promise((resolve) => setTimeout(resolve, ms)),
76593
77004
  now: () => Date.now()
76594
77005
  };
@@ -76597,14 +77008,14 @@ var init_forge_common = __esm(() => {
76597
77008
  // packages/workit-cli/src/verbs/pr.ts
76598
77009
  var exports_pr = {};
76599
77010
  __export(exports_pr, {
76600
- run: () => run10
77011
+ run: () => run11
76601
77012
  });
76602
- import { readFileSync as readFileSync20 } from "node:fs";
76603
- import path43 from "node:path";
77013
+ import { readFileSync as readFileSync21 } from "node:fs";
77014
+ import path44 from "node:path";
76604
77015
  function readBodyFile(io, file) {
76605
77016
  try {
76606
77017
  return {
76607
- body: file === "-" ? forgeDeps.readStdin() : readFileSync20(path43.resolve(io.cwd, file), "utf8")
77018
+ body: file === "-" ? forgeDeps.readStdin() : readFileSync21(path44.resolve(io.cwd, file), "utf8")
76608
77019
  };
76609
77020
  } catch {
76610
77021
  return `cannot read --body-file ${file}`;
@@ -76931,7 +77342,7 @@ async function reply(argv, io) {
76931
77342
  `${[data.replied ? "replied to" : null, data.resolved ? "resolved" : null].filter(Boolean).join(" and ")} thread ${data.thread} on ${prLabel(kind, data.number)}${data.replyUrl ? ` ${data.replyUrl}` : ""}`
76932
77343
  ]);
76933
77344
  }
76934
- async function run10(argv, io) {
77345
+ async function run11(argv, io) {
76935
77346
  const [sub, ...rest] = argv;
76936
77347
  if (sub === "status")
76937
77348
  return status(rest, io);
@@ -76966,7 +77377,7 @@ var init_pr = __esm(() => {
76966
77377
  // packages/workit-cli/src/verbs/ci.ts
76967
77378
  var exports_ci = {};
76968
77379
  __export(exports_ci, {
76969
- run: () => run11
77380
+ run: () => run12
76970
77381
  });
76971
77382
  async function wait(argv, io) {
76972
77383
  const flags = parseFlags(argv, {
@@ -77135,7 +77546,7 @@ async function rerun(argv, io) {
77135
77546
  "next: workit ci wait"
77136
77547
  ]);
77137
77548
  }
77138
- async function run11(argv, io) {
77549
+ async function run12(argv, io) {
77139
77550
  const [sub, ...rest] = argv;
77140
77551
  if (sub === "wait")
77141
77552
  return wait(rest, io);
@@ -77183,10 +77594,10 @@ var init_implicit_task = __esm(() => {
77183
77594
  // packages/workit-cli/src/verbs/git.ts
77184
77595
  var exports_git = {};
77185
77596
  __export(exports_git, {
77186
- run: () => run12
77597
+ run: () => run13
77187
77598
  });
77188
- import { readFileSync as readFileSync21 } from "node:fs";
77189
- import path44 from "node:path";
77599
+ import { readFileSync as readFileSync22 } from "node:fs";
77600
+ import path45 from "node:path";
77190
77601
  async function branch(argv, io) {
77191
77602
  const flags = parseFlags(argv, {
77192
77603
  base: "value",
@@ -77277,7 +77688,7 @@ function commitMessage(parsed, io) {
77277
77688
 
77278
77689
  `);
77279
77690
  try {
77280
- return file === "-" ? readFileSync21(0, "utf8") : readFileSync21(path44.resolve(io.cwd, file), "utf8");
77691
+ return file === "-" ? readFileSync22(0, "utf8") : readFileSync22(path45.resolve(io.cwd, file), "utf8");
77281
77692
  } catch (error) {
77282
77693
  return {
77283
77694
  error: `cannot read -F ${file}: ${error instanceof Error ? error.message : String(error)}`
@@ -77380,7 +77791,7 @@ async function push(argv, io) {
77380
77791
  ...data.upstream ? [`upstream: ${data.remote}/${data.branch}`] : []
77381
77792
  ]);
77382
77793
  }
77383
- async function run12(argv, io) {
77794
+ async function run13(argv, io) {
77384
77795
  const [sub, ...rest] = argv;
77385
77796
  if (sub === "branch")
77386
77797
  return branch(rest, io);
@@ -77408,7 +77819,7 @@ var init_git2 = __esm(() => {
77408
77819
  });
77409
77820
 
77410
77821
  // packages/workit-core/src/forge/verify.ts
77411
- import { spawnSync as spawnSync22 } from "node:child_process";
77822
+ import { spawnSync as spawnSync23 } from "node:child_process";
77412
77823
  function finish(cwd, report, actor) {
77413
77824
  const delivered = report.observations.length > 0 && report.observations.every((entry) => entry.ok);
77414
77825
  const out = { ...report, delivered };
@@ -77621,7 +78032,7 @@ var NPM_NAME, SEMVER2, SAFE_ARG, systemNpm = (args) => {
77621
78032
  };
77622
78033
  const found = process.platform === "win32" ? findExecutable("npm.cmd", process.env) : null;
77623
78034
  const npmCmd = found && !/["%!^]/u.test(found) ? `"${found}"` : "npm.cmd";
77624
- const result = process.platform === "win32" ? spawnSync22(`${npmCmd} ${args.join(" ")}`, { ...options, shell: true }) : spawnSync22("npm", [...args], options);
78035
+ const result = process.platform === "win32" ? spawnSync23(`${npmCmd} ${args.join(" ")}`, { ...options, shell: true }) : spawnSync23("npm", [...args], options);
77625
78036
  return { status: result.status, stdout: result.stdout ?? "", stderr: result.stderr ?? "" };
77626
78037
  }, short3 = (sha) => sha ? sha.slice(0, 12) : "(absent)", npmView = (stdout) => {
77627
78038
  try {
@@ -77646,9 +78057,9 @@ var init_verify = __esm(() => {
77646
78057
  // packages/workit-cli/src/verbs/verify-delivery.ts
77647
78058
  var exports_verify_delivery = {};
77648
78059
  __export(exports_verify_delivery, {
77649
- run: () => run13
78060
+ run: () => run14
77650
78061
  });
77651
- async function run13(argv, io) {
78062
+ async function run14(argv, io) {
77652
78063
  const flags = parseFlags(argv, {
77653
78064
  expect: "value",
77654
78065
  branch: "value",
@@ -77730,7 +78141,7 @@ var init_verify_delivery = __esm(() => {
77730
78141
  // packages/workit-cli/src/verbs/stack.ts
77731
78142
  var exports_stack = {};
77732
78143
  __export(exports_stack, {
77733
- run: () => run14
78144
+ run: () => run15
77734
78145
  });
77735
78146
  async function plan(argv, io) {
77736
78147
  const flags = parseFlags(argv, { name: "value", trunk: "value", track: "value" });
@@ -77912,7 +78323,7 @@ async function land(argv, io) {
77912
78323
  unblock: ${data.stoppedAt.unblock}` : data.complete ? "stack complete" : ""
77913
78324
  ].filter(Boolean));
77914
78325
  }
77915
- async function run14(argv, io) {
78326
+ async function run15(argv, io) {
77916
78327
  const [sub, ...rest] = argv.filter((arg) => arg !== "--json");
77917
78328
  if (sub === "plan")
77918
78329
  return plan(rest, io);
@@ -77942,10 +78353,10 @@ var init_stack2 = __esm(() => {
77942
78353
  });
77943
78354
 
77944
78355
  // packages/workit-core/src/fanout.ts
77945
- import { spawnSync as spawnSync23 } from "node:child_process";
78356
+ import { spawnSync as spawnSync24 } from "node:child_process";
77946
78357
  import { createHash as createHash17 } from "node:crypto";
77947
78358
  import fs23 from "node:fs";
77948
- import path45 from "node:path";
78359
+ import path46 from "node:path";
77949
78360
  function expandBraces(pattern, limit = 64) {
77950
78361
  for (let index = 0;index < pattern.length; index += 1) {
77951
78362
  if (pattern[index] === "\\") {
@@ -78179,7 +78590,7 @@ function parsePlan(raw, defaults, name) {
78179
78590
  id,
78180
78591
  branch,
78181
78592
  base: optional("base") ?? "",
78182
- worktree: path45.resolve(defaults.root, optional("worktree") ?? path45.join(defaults.worktreeRoot, id)),
78593
+ worktree: path46.resolve(defaults.root, optional("worktree") ?? path46.join(defaults.worktreeRoot, id)),
78183
78594
  tier,
78184
78595
  dependsOn: [...new Set(dependsOn ?? [])],
78185
78596
  scope,
@@ -78408,11 +78819,11 @@ function defaultTrunk(cwd) {
78408
78819
  }
78409
78820
  function mainCheckout(cwd) {
78410
78821
  const common = gitCommonDir(cwd);
78411
- return common && path45.basename(common) === ".git" ? path45.dirname(common) : path45.resolve(cwd);
78822
+ return common && path46.basename(common) === ".git" ? path46.dirname(common) : path46.resolve(cwd);
78412
78823
  }
78413
78824
  function worktreeRoot(cwd) {
78414
78825
  const main = mainCheckout(cwd);
78415
- return path45.join(path45.dirname(main), `${path45.basename(main)}-wt`);
78826
+ return path46.join(path46.dirname(main), `${path46.basename(main)}-wt`);
78416
78827
  }
78417
78828
  function sliceHash(slice) {
78418
78829
  const {
@@ -78430,7 +78841,7 @@ function fanoutsDir(cwd) {
78430
78841
  const root = storeRoot(cwd);
78431
78842
  if (!root.ok)
78432
78843
  return fanoutFail(root.code, root.error, root.unblock);
78433
- return { ok: true, data: path45.join(root.value.root, "fanouts") };
78844
+ return { ok: true, data: path46.join(root.value.root, "fanouts") };
78434
78845
  }
78435
78846
  function parseStored(raw) {
78436
78847
  if (!isRecord8(raw) || typeof raw.name !== "string" || typeof raw.trunk !== "string")
@@ -78496,7 +78907,7 @@ function readFanout(cwd, name) {
78496
78907
  const dir = fanoutsDir(cwd);
78497
78908
  if (!dir.ok)
78498
78909
  return dir;
78499
- const file = path45.join(dir.data, stackFileName(name));
78910
+ const file = path46.join(dir.data, stackFileName(name));
78500
78911
  let parsed = null;
78501
78912
  try {
78502
78913
  parsed = parseStored(JSON.parse(fs23.readFileSync(file, "utf8")));
@@ -78521,7 +78932,7 @@ function listFanouts(cwd) {
78521
78932
  for (const entry of names) {
78522
78933
  let parsed = null;
78523
78934
  try {
78524
- parsed = parseStored(JSON.parse(fs23.readFileSync(path45.join(dir.data, entry), "utf8")));
78935
+ parsed = parseStored(JSON.parse(fs23.readFileSync(path46.join(dir.data, entry), "utf8")));
78525
78936
  } catch {
78526
78937
  parsed = null;
78527
78938
  }
@@ -78551,7 +78962,7 @@ function writeFanout(cwd, plan) {
78551
78962
  const dir = fanoutsDir(cwd);
78552
78963
  if (!dir.ok)
78553
78964
  return dir;
78554
- const file = path45.join(dir.data, stackFileName(plan.name));
78965
+ const file = path46.join(dir.data, stackFileName(plan.name));
78555
78966
  const temp = `${file}.${process.pid}.tmp`;
78556
78967
  try {
78557
78968
  fs23.mkdirSync(dir.data, { recursive: true });
@@ -78715,7 +79126,7 @@ var FANOUT_VERSION = 1, TIERS, FAN_IN_MODES, fanoutFail = (code, error, unblock,
78715
79126
  text: edges.map((edge) => `add "${edge.dependsOn}" to "dependsOn" of slice ${edge.slice}`).join("; ")
78716
79127
  };
78717
79128
  }, gitRun4 = (cwd, args, timeoutMs = GIT_TIMEOUTS.local) => {
78718
- const run = spawnSync23("git", args, {
79129
+ const run = spawnSync24("git", args, {
78719
79130
  cwd,
78720
79131
  encoding: "utf8",
78721
79132
  timeout: timeoutMs,
@@ -78755,7 +79166,7 @@ var init_fanout = __esm(() => {
78755
79166
  // packages/workit-core/src/fanout-worktree.ts
78756
79167
  import { randomBytes as randomBytes4 } from "node:crypto";
78757
79168
  import fs24 from "node:fs";
78758
- import path46 from "node:path";
79169
+ import path47 from "node:path";
78759
79170
  function rowSample(lines) {
78760
79171
  const out = [];
78761
79172
  let bytes = 0;
@@ -78815,7 +79226,7 @@ function adminDir(worktree) {
78815
79226
  const file = dir.stdout.trim();
78816
79227
  let token = null;
78817
79228
  try {
78818
- token = fs24.readFileSync(path46.join(file, TOKEN_FILE), "utf8").trim() || null;
79229
+ token = fs24.readFileSync(path47.join(file, TOKEN_FILE), "utf8").trim() || null;
78819
79230
  } catch {
78820
79231
  token = null;
78821
79232
  }
@@ -78823,7 +79234,7 @@ function adminDir(worktree) {
78823
79234
  const stat = worktreeDeps.stat(file);
78824
79235
  return {
78825
79236
  path: file,
78826
- id: path46.basename(file),
79237
+ id: path47.basename(file),
78827
79238
  ino: stat.ino.toString(),
78828
79239
  token,
78829
79240
  birthMs: stat.birthtimeNs > 0n ? Number(stat.birthtimeMs) : null,
@@ -78839,7 +79250,7 @@ function markAdminDir(worktree) {
78839
79250
  return null;
78840
79251
  const token = randomBytes4(16).toString("hex");
78841
79252
  try {
78842
- fs24.writeFileSync(path46.join(admin.path, TOKEN_FILE), `${token}
79253
+ fs24.writeFileSync(path47.join(admin.path, TOKEN_FILE), `${token}
78843
79254
  `);
78844
79255
  } catch {
78845
79256
  return null;
@@ -78854,7 +79265,7 @@ function excludeScratch(cwd) {
78854
79265
  const common = gitCommonDir(cwd);
78855
79266
  if (!common)
78856
79267
  return;
78857
- const file = path46.join(common, "info", "exclude");
79268
+ const file = path47.join(common, "info", "exclude");
78858
79269
  let text = "";
78859
79270
  try {
78860
79271
  text = fs24.readFileSync(file, "utf8");
@@ -78863,7 +79274,7 @@ function excludeScratch(cwd) {
78863
79274
  }
78864
79275
  if (text.split(/\r?\n/u).includes(EXCLUDE_LINE))
78865
79276
  return;
78866
- fs24.mkdirSync(path46.dirname(file), { recursive: true });
79277
+ fs24.mkdirSync(path47.dirname(file), { recursive: true });
78867
79278
  fs24.appendFileSync(file, `${text && !text.endsWith(`
78868
79279
  `) ? `
78869
79280
  ` : ""}# workit fanout: per-worker scratch dirs
@@ -78871,7 +79282,7 @@ ${EXCLUDE_LINE}
78871
79282
  `);
78872
79283
  }
78873
79284
  function ensureScratch(worktree) {
78874
- const scratch = path46.join(worktree, SCRATCH_DIR);
79285
+ const scratch = path47.join(worktree, SCRATCH_DIR);
78875
79286
  fs24.mkdirSync(scratch, { recursive: true });
78876
79287
  return scratch;
78877
79288
  }
@@ -79007,7 +79418,7 @@ function releaseSliceWorktree(cwd, plan, input) {
79007
79418
  const entry = worktrees[index];
79008
79419
  if (index === 0)
79009
79420
  return fanoutFail("blocked", `${target} is the main checkout; it is never released`);
79010
- if (inside2(cwd, entry.path))
79421
+ if (inside3(cwd, entry.path))
79011
79422
  return fanoutFail("blocked", `this command runs inside ${entry.path}`, `run it from the main checkout: workit --cwd <main checkout> fanout worktree release ${slice.id}`);
79012
79423
  if (entry.branch !== null && entry.branch !== `refs/heads/${slice.branch}`)
79013
79424
  return fanoutFail("blocked", `${entry.path} is on ${entry.branch.replace(/^refs\/heads\//u, "")}, not slice ${slice.id}'s ${slice.branch}; nothing was removed`);
@@ -79089,7 +79500,7 @@ function unpushedCount(cwd, branch) {
79089
79500
  return count.ok ? Number(count.stdout.trim()) : null;
79090
79501
  }
79091
79502
  function removeScratch(worktree) {
79092
- const scratch = path46.join(worktree, SCRATCH_DIR);
79503
+ const scratch = path47.join(worktree, SCRATCH_DIR);
79093
79504
  let stat;
79094
79505
  try {
79095
79506
  stat = fs24.lstatSync(scratch);
@@ -79105,16 +79516,16 @@ var SLOW, SCRATCH_DIR = ".workit-scratch", EXCLUDE_LINE, DIRTY_ROW_BYTES = 2000,
79105
79516
  try {
79106
79517
  return fs24.realpathSync.native(target);
79107
79518
  } catch {
79108
- return path46.resolve(target);
79519
+ return path47.resolve(target);
79109
79520
  }
79110
79521
  }, samePath = (a, b) => {
79111
79522
  const left = canonical2(a);
79112
79523
  const right = canonical2(b);
79113
79524
  return process.platform === "win32" || process.platform === "darwin" ? left.toLowerCase() === right.toLowerCase() : left === right;
79114
- }, inside2 = (child, parent) => {
79115
- const relative = path46.relative(canonical2(parent), canonical2(child));
79116
- return relative === "" || !relative.startsWith("..") && !path46.isAbsolute(relative);
79117
- }, slicePath = (cwd, slice) => path46.isAbsolute(slice.worktree) ? slice.worktree : path46.resolve(mainCheckout(cwd), slice.worktree), CLOCK_SLACK_MS = 2000, TOKEN_FILE = "workit-fanout-token", worktreeDeps, worktreeFailed = (stderr) => fanoutFail("failed", `git worktree add failed: ${stderr.trim().split(`
79525
+ }, inside3 = (child, parent) => {
79526
+ const relative = path47.relative(canonical2(parent), canonical2(child));
79527
+ return relative === "" || !relative.startsWith("..") && !path47.isAbsolute(relative);
79528
+ }, slicePath = (cwd, slice) => path47.isAbsolute(slice.worktree) ? slice.worktree : path47.resolve(mainCheckout(cwd), slice.worktree), CLOCK_SLACK_MS = 2000, TOKEN_FILE = "workit-fanout-token", worktreeDeps, worktreeFailed = (stderr) => fanoutFail("failed", `git worktree add failed: ${stderr.trim().split(`
79118
79529
  `)[0] || "unknown error"}`);
79119
79530
  var init_fanout_worktree = __esm(() => {
79120
79531
  init_ops();
@@ -79235,7 +79646,7 @@ var init_fanout_brief = __esm(() => {
79235
79646
  });
79236
79647
 
79237
79648
  // packages/workit-core/src/fanout-landed.ts
79238
- import { spawnSync as spawnSync24 } from "node:child_process";
79649
+ import { spawnSync as spawnSync25 } from "node:child_process";
79239
79650
  function forgeBreaker(resolved) {
79240
79651
  if (!resolved)
79241
79652
  return { forge: null, down: () => null };
@@ -79326,7 +79737,7 @@ function trunkPatchIds(ctx, fork) {
79326
79737
  "--"
79327
79738
  ]);
79328
79739
  if (log.ok && log.stdout.trim()) {
79329
- const run = spawnSync24("git", ["patch-id", "--stable"], {
79740
+ const run = spawnSync25("git", ["patch-id", "--stable"], {
79330
79741
  cwd: ctx.cwd,
79331
79742
  input: log.stdout,
79332
79743
  encoding: "utf8",
@@ -79887,10 +80298,10 @@ var init_fanout_status = __esm(() => {
79887
80298
  // packages/workit-cli/src/verbs/fanout.ts
79888
80299
  var exports_fanout = {};
79889
80300
  __export(exports_fanout, {
79890
- run: () => run15
80301
+ run: () => run16
79891
80302
  });
79892
80303
  import fs25 from "node:fs";
79893
- import path47 from "node:path";
80304
+ import path48 from "node:path";
79894
80305
  function forgeFor(io, offline) {
79895
80306
  if (offline)
79896
80307
  return { forge: null, error: "--offline" };
@@ -79951,7 +80362,7 @@ function plan2(argv, io) {
79951
80362
  return usage3(io, "pass --trunk or --track, not both (--track picks the trunk)", PLAN_USAGE2);
79952
80363
  if (flags.positionals.length !== 1)
79953
80364
  return usage3(io, flags.positionals.length ? `unexpected argument ${flags.positionals[1]}` : "missing <plan.json>", PLAN_USAGE2);
79954
- const file = path47.resolve(io.cwd, flags.positionals[0]);
80365
+ const file = path48.resolve(io.cwd, flags.positionals[0]);
79955
80366
  let raw;
79956
80367
  try {
79957
80368
  raw = JSON.parse(fs25.readFileSync(file, "utf8"));
@@ -80107,7 +80518,7 @@ function worktree(argv, io) {
80107
80518
  ...data.notes.map((note) => `note: ${note}`)
80108
80519
  ]);
80109
80520
  }
80110
- async function run15(argv, io) {
80521
+ async function run16(argv, io) {
80111
80522
  const [sub, ...rest] = argv.filter((arg) => arg !== "--json");
80112
80523
  if (sub === "plan")
80113
80524
  return plan2(rest, io);
@@ -80173,7 +80584,7 @@ var init_fanout2 = __esm(() => {
80173
80584
  // packages/workit-cli/src/verbs/ledger.ts
80174
80585
  var exports_ledger = {};
80175
80586
  __export(exports_ledger, {
80176
- run: () => run16
80587
+ run: () => run17
80177
80588
  });
80178
80589
  import { randomBytes as randomBytes5 } from "node:crypto";
80179
80590
  import { parseArgs } from "node:util";
@@ -80197,7 +80608,7 @@ function targetBranch(io, rows, branch, pr) {
80197
80608
  }
80198
80609
  return { ok: true, value: branch ?? null };
80199
80610
  }
80200
- async function run16(argv, io) {
80611
+ async function run17(argv, io) {
80201
80612
  let parsed;
80202
80613
  try {
80203
80614
  parsed = parseArgs({ args: argv, options: OPTIONS, allowPositionals: true, strict: true });
@@ -95434,7 +95845,7 @@ var init_ast = __esm(() => {
95434
95845
 
95435
95846
  // packages/workit-cli/src/test-audit/rules.ts
95436
95847
  import { builtinModules } from "node:module";
95437
- import path48 from "node:path";
95848
+ import path49 from "node:path";
95438
95849
  function testCallee(call) {
95439
95850
  let callee = call.callee;
95440
95851
  if (callee.type === "CallExpression")
@@ -95927,12 +96338,12 @@ function checkConstantsOnly(ctx, emit) {
95927
96338
  }
95928
96339
  function checkOverMocking(ctx, emit) {
95929
96340
  const { program } = ctx.parsed;
95930
- const unit = path48.basename(ctx.file).replace(/\.(?:[cm]?[jt]sx?)$/, "").replace(/\.(?:test|spec)$/, "");
96341
+ const unit = path49.basename(ctx.file).replace(/\.(?:[cm]?[jt]sx?)$/, "").replace(/\.(?:test|spec)$/, "");
95931
96342
  const mocked = find2(program, (node) => node.type === "CallExpression" && MODULE_MOCK.test(calleeName(node.callee) ?? "") && node.arguments[0]?.type === "StringLiteral");
95932
96343
  const internal = mocked.filter((call) => /^(?:\.|@\/|~\/)/.test(call.arguments[0].value));
95933
96344
  for (const call of mocked) {
95934
96345
  const spec = call.arguments[0].value;
95935
- const base = path48.basename(spec.replace(/\/index(?:\.[cm]?[jt]sx?)?$/, "")).replace(/\.(?:[cm]?[jt]sx?)$/, "");
96346
+ const base = path49.basename(spec.replace(/\/index(?:\.[cm]?[jt]sx?)?$/, "")).replace(/\.(?:[cm]?[jt]sx?)$/, "");
95936
96347
  if (base === unit)
95937
96348
  emit({
95938
96349
  rule: "over-mocking",
@@ -96320,11 +96731,11 @@ var init_rules = __esm(() => {
96320
96731
  });
96321
96732
 
96322
96733
  // packages/workit-cli/src/test-audit/audit.ts
96323
- import { spawnSync as spawnSync25 } from "node:child_process";
96324
- import { existsSync as existsSync19, readdirSync as readdirSync9, readFileSync as readFileSync22, statSync as statSync7 } from "node:fs";
96325
- import path49 from "node:path";
96734
+ import { spawnSync as spawnSync26 } from "node:child_process";
96735
+ import { existsSync as existsSync20, readdirSync as readdirSync9, readFileSync as readFileSync23, statSync as statSync8 } from "node:fs";
96736
+ import path50 from "node:path";
96326
96737
  function git7(cwd, args) {
96327
- const run = spawnSync25("git", ["-c", "core.quotepath=off", ...args], {
96738
+ const run = spawnSync26("git", ["-c", "core.quotepath=off", ...args], {
96328
96739
  cwd,
96329
96740
  encoding: "utf8",
96330
96741
  maxBuffer: 64 * 1024 * 1024
@@ -96335,7 +96746,7 @@ function walkTests(dir, out) {
96335
96746
  for (const entry of readdirSync9(dir, { withFileTypes: true })) {
96336
96747
  if (entry.name.startsWith(".") && entry.name !== "." && entry.isDirectory())
96337
96748
  continue;
96338
- const full = path49.join(dir, entry.name);
96749
+ const full = path50.join(dir, entry.name);
96339
96750
  if (entry.isDirectory()) {
96340
96751
  if (!SKIP_DIRS.has(entry.name))
96341
96752
  walkTests(full, out);
@@ -96347,10 +96758,10 @@ function expandPaths(cwd, inputs) {
96347
96758
  const files = [];
96348
96759
  const missing = [];
96349
96760
  for (const input of inputs.length > 0 ? inputs : ["."]) {
96350
- const full = path49.resolve(cwd, input);
96351
- if (!existsSync19(full))
96761
+ const full = path50.resolve(cwd, input);
96762
+ if (!existsSync20(full))
96352
96763
  missing.push(input);
96353
- else if (statSync7(full).isDirectory())
96764
+ else if (statSync8(full).isDirectory())
96354
96765
  walkTests(full, files);
96355
96766
  else
96356
96767
  files.push(full);
@@ -96384,11 +96795,11 @@ function changedLines(cwd, base) {
96384
96795
  for (let offset = 0;offset < count; offset += 1)
96385
96796
  lines.add(start + offset);
96386
96797
  }
96387
- changed.set(path49.join(root, file), lines);
96798
+ changed.set(path50.join(root, file), lines);
96388
96799
  }
96389
96800
  const untracked = git7(root, ["ls-files", "--others", "--exclude-standard", "-z"]);
96390
96801
  for (const file of untracked.stdout.split("\x00").filter(Boolean))
96391
- changed.set(path49.join(root, file), "all");
96802
+ changed.set(path50.join(root, file), "all");
96392
96803
  return changed;
96393
96804
  }
96394
96805
  function auditFiles(files, display) {
@@ -96401,7 +96812,7 @@ function auditFiles(files, display) {
96401
96812
  const shown = display(file);
96402
96813
  let parsed;
96403
96814
  try {
96404
- parsed = parseSource(readFileSync22(file, "utf8"), file);
96815
+ parsed = parseSource(readFileSync23(file, "utf8"), file);
96405
96816
  } catch (error) {
96406
96817
  parseErrors.push({
96407
96818
  file: shown,
@@ -96450,7 +96861,7 @@ function auditFiles(files, display) {
96450
96861
  durationMs: Math.round(performance.now() - started)
96451
96862
  };
96452
96863
  }
96453
- var TEST_FILE, CODE_FILE, SKIP_DIRS, toPosix = (file) => file.split(path49.sep).join("/"), SEVERITY_ORDER, ruleIds;
96864
+ var TEST_FILE, CODE_FILE, SKIP_DIRS, toPosix = (file) => file.split(path50.sep).join("/"), SEVERITY_ORDER, ruleIds;
96454
96865
  var init_audit = __esm(() => {
96455
96866
  init_ast();
96456
96867
  init_rules();
@@ -96464,23 +96875,23 @@ var init_audit = __esm(() => {
96464
96875
  // packages/workit-cli/src/test-audit/mutate.ts
96465
96876
  import { spawn as spawn2 } from "node:child_process";
96466
96877
  import {
96467
- existsSync as existsSync20,
96468
- lstatSync as lstatSync7,
96469
- mkdirSync as mkdirSync9,
96878
+ existsSync as existsSync21,
96879
+ lstatSync as lstatSync8,
96880
+ mkdirSync as mkdirSync10,
96470
96881
  mkdtempSync as mkdtempSync4,
96471
96882
  readdirSync as readdirSync10,
96472
- readFileSync as readFileSync23,
96883
+ readFileSync as readFileSync24,
96473
96884
  readlinkSync as readlinkSync3,
96474
96885
  realpathSync as realpathSync9,
96475
- renameSync as renameSync5,
96476
- rmSync as rmSync7,
96477
- statSync as statSync8,
96886
+ renameSync as renameSync6,
96887
+ rmSync as rmSync8,
96888
+ statSync as statSync9,
96478
96889
  symlinkSync,
96479
- writeFileSync as writeFileSync10,
96890
+ writeFileSync as writeFileSync11,
96480
96891
  copyFileSync as copyFileSync6
96481
96892
  } from "node:fs";
96482
96893
  import os14 from "node:os";
96483
- import path50 from "node:path";
96894
+ import path51 from "node:path";
96484
96895
  function mutantsFor(source, file, lines) {
96485
96896
  const parsed = parseSource(source, file);
96486
96897
  const out = [];
@@ -96553,7 +96964,7 @@ function relatedTests(source, testFiles) {
96553
96964
  for (const match of text.matchAll(SPECIFIER)) {
96554
96965
  const spec = match[1];
96555
96966
  if (spec.startsWith(".")) {
96556
- if (stripExt(path50.posix.join(path50.posix.dirname(file), spec)) === target)
96967
+ if (stripExt(path51.posix.join(path51.posix.dirname(file), spec)) === target)
96557
96968
  return true;
96558
96969
  } else if (spec.includes("/") && stripExt(spec).split("/").slice(-2).join("/") === tail)
96559
96970
  return true;
@@ -96573,12 +96984,12 @@ function removeStaleCopies(tmp = os14.tmpdir()) {
96573
96984
  for (const name of names) {
96574
96985
  if (!name.startsWith(TEMP_PREFIX))
96575
96986
  continue;
96576
- const dir = path50.join(tmp, name);
96987
+ const dir = path51.join(tmp, name);
96577
96988
  try {
96578
- const stat = lstatSync7(dir);
96989
+ const stat = lstatSync8(dir);
96579
96990
  if (!stat.isDirectory() || uid !== undefined && stat.uid !== uid)
96580
96991
  continue;
96581
- const pid = Number(readFileSync23(path50.join(dir, PID_FILE), "utf8"));
96992
+ const pid = Number(readFileSync24(path51.join(dir, PID_FILE), "utf8"));
96582
96993
  if (Number.isInteger(pid) && pid > 0 && alive(pid))
96583
96994
  continue;
96584
96995
  } catch (error) {
@@ -96586,23 +96997,23 @@ function removeStaleCopies(tmp = os14.tmpdir()) {
96586
96997
  continue;
96587
96998
  }
96588
96999
  try {
96589
- rmSync7(dir, { recursive: true, force: true });
97000
+ rmSync8(dir, { recursive: true, force: true });
96590
97001
  removed += 1;
96591
97002
  } catch {}
96592
97003
  }
96593
97004
  return removed;
96594
97005
  }
96595
97006
  function linkNodeModules(origin, target, repo, copy) {
96596
- mkdirSync9(target, { recursive: true });
97007
+ mkdirSync10(target, { recursive: true });
96597
97008
  for (const entry of readdirSync10(origin, { withFileTypes: true })) {
96598
- const from = path50.join(origin, entry.name);
96599
- const to = path50.join(target, entry.name);
97009
+ const from = path51.join(origin, entry.name);
97010
+ const to = path51.join(target, entry.name);
96600
97011
  if (entry.name.startsWith("@") && entry.isDirectory()) {
96601
97012
  linkNodeModules(from, to, repo, copy);
96602
97013
  continue;
96603
97014
  }
96604
97015
  if (entry.name.startsWith(".") && entry.name !== ".bin" && entry.isDirectory()) {
96605
- mkdirSync9(to, { recursive: true });
97016
+ mkdirSync10(to, { recursive: true });
96606
97017
  continue;
96607
97018
  }
96608
97019
  if (entry.isSymbolicLink()) {
@@ -96612,9 +97023,9 @@ function linkNodeModules(origin, target, repo, copy) {
96612
97023
  } catch {
96613
97024
  continue;
96614
97025
  }
96615
- const relative = path50.relative(repo, real);
96616
- if (!relative.startsWith("..") && !path50.isAbsolute(relative) && !relative.split(path50.sep).includes("node_modules")) {
96617
- symlinkSync(path50.join(copy, relative), to, "junction");
97026
+ const relative = path51.relative(repo, real);
97027
+ if (!relative.startsWith("..") && !path51.isAbsolute(relative) && !relative.split(path51.sep).includes("node_modules")) {
97028
+ symlinkSync(path51.join(copy, relative), to, "junction");
96618
97029
  continue;
96619
97030
  }
96620
97031
  }
@@ -96629,33 +97040,33 @@ function copySymlink(repo, tree, from, to) {
96629
97040
  real = null;
96630
97041
  }
96631
97042
  const realRepo = realpathSync9(repo);
96632
- if (real && inside3(realRepo, real)) {
96633
- symlinkSync(path50.relative(path50.dirname(to), path50.join(tree, path50.relative(realRepo, real))), to);
97043
+ if (real && inside4(realRepo, real)) {
97044
+ symlinkSync(path51.relative(path51.dirname(to), path51.join(tree, path51.relative(realRepo, real))), to);
96634
97045
  return;
96635
97046
  }
96636
- if (real && statSync8(real).isFile())
97047
+ if (real && statSync9(real).isFile())
96637
97048
  copyFileSync6(real, to);
96638
97049
  else
96639
97050
  symlinkSync(readlinkSync3(from), to);
96640
97051
  }
96641
97052
  function writeInside(copy, file, content) {
96642
- const target = path50.join(copy, file);
97053
+ const target = path51.join(copy, file);
96643
97054
  try {
96644
- const stat = lstatSync7(target);
96645
- if (!stat.isFile() || !inside3(realpathSync9(copy), realpathSync9(path50.dirname(target))))
97055
+ const stat = lstatSync8(target);
97056
+ if (!stat.isFile() || !inside4(realpathSync9(copy), realpathSync9(path51.dirname(target))))
96646
97057
  return false;
96647
97058
  } catch {
96648
97059
  return false;
96649
97060
  }
96650
97061
  const temp = `${target}.workit-mutant-${process.pid}`;
96651
- writeFileSync10(temp, content);
96652
- renameSync5(temp, target);
97062
+ writeFileSync11(temp, content);
97063
+ renameSync6(temp, target);
96653
97064
  return true;
96654
97065
  }
96655
97066
  function copyWorkingTree(repo) {
96656
- const dir = mkdtempSync4(path50.join(os14.tmpdir(), TEMP_PREFIX));
96657
- writeFileSync10(path50.join(dir, PID_FILE), String(process.pid));
96658
- const tree = path50.join(dir, "tree");
97067
+ const dir = mkdtempSync4(path51.join(os14.tmpdir(), TEMP_PREFIX));
97068
+ writeFileSync11(path51.join(dir, PID_FILE), String(process.pid));
97069
+ const tree = path51.join(dir, "tree");
96659
97070
  const head = git7(repo, ["rev-parse", "--verify", "--quiet", "HEAD"]).stdout.trim();
96660
97071
  if (head && git7(dir, ["clone", "-q", "--shared", "--no-checkout", repo, tree]).ok) {
96661
97072
  const branch = git7(repo, ["symbolic-ref", "--quiet", "--short", "HEAD"]).stdout.trim();
@@ -96666,35 +97077,35 @@ function copyWorkingTree(repo) {
96666
97077
  git7(tree, ["update-ref", "--no-deref", "HEAD", head]);
96667
97078
  git7(tree, ["reset", "-q"]);
96668
97079
  } else
96669
- mkdirSync9(tree, { recursive: true });
97080
+ mkdirSync10(tree, { recursive: true });
96670
97081
  const listed = git7(repo, ["ls-files", "-co", "--exclude-standard", "-z"]).stdout.split("\x00");
96671
97082
  const dirs = new Set([""]);
96672
97083
  for (const relative of listed) {
96673
97084
  if (!relative)
96674
97085
  continue;
96675
- const from = path50.join(repo, relative);
97086
+ const from = path51.join(repo, relative);
96676
97087
  let stat;
96677
97088
  try {
96678
- stat = lstatSync7(from);
97089
+ stat = lstatSync8(from);
96679
97090
  } catch {
96680
97091
  continue;
96681
97092
  }
96682
- const to = path50.join(tree, relative);
96683
- mkdirSync9(path50.dirname(to), { recursive: true });
97093
+ const to = path51.join(tree, relative);
97094
+ mkdirSync10(path51.dirname(to), { recursive: true });
96684
97095
  if (stat.isSymbolicLink())
96685
97096
  copySymlink(repo, tree, from, to);
96686
97097
  else if (stat.isFile())
96687
97098
  copyFileSync6(from, to);
96688
- let parent = path50.dirname(relative);
97099
+ let parent = path51.dirname(relative);
96689
97100
  while (parent !== "." && !dirs.has(parent)) {
96690
97101
  dirs.add(parent);
96691
- parent = path50.dirname(parent);
97102
+ parent = path51.dirname(parent);
96692
97103
  }
96693
97104
  }
96694
97105
  for (const parent of dirs) {
96695
- const modules = path50.join(repo, parent, "node_modules");
96696
- if (existsSync20(modules) && !existsSync20(path50.join(tree, parent, "node_modules")))
96697
- linkNodeModules(modules, path50.join(tree, parent, "node_modules"), repo, tree);
97106
+ const modules = path51.join(repo, parent, "node_modules");
97107
+ if (existsSync21(modules) && !existsSync21(path51.join(tree, parent, "node_modules")))
97108
+ linkNodeModules(modules, path51.join(tree, parent, "node_modules"), repo, tree);
96698
97109
  }
96699
97110
  return { dir, tree };
96700
97111
  }
@@ -96733,20 +97144,20 @@ async function runMutation(options) {
96733
97144
  const tracked = git7(repo, ["ls-files", "-co", "--exclude-standard", "-z"]).stdout.split("\x00").filter(Boolean);
96734
97145
  const testFiles = tracked.filter((file) => TEST_FILE.test(file)).map((file) => {
96735
97146
  try {
96736
- return { file, text: readFileSync23(path50.join(repo, file), "utf8") };
97147
+ return { file, text: readFileSync24(path51.join(repo, file), "utf8") };
96737
97148
  } catch {
96738
97149
  return { file, text: "" };
96739
97150
  }
96740
97151
  });
96741
97152
  const candidates = [];
96742
97153
  for (const [absolute, lines] of [...options.changed].toSorted(([a], [b]) => a.localeCompare(b))) {
96743
- const relative = toPosix(path50.relative(repo, absolute));
97154
+ const relative = toPosix(path51.relative(repo, absolute));
96744
97155
  if (!CODE_FILE.test(relative) || TEST_FILE.test(relative) || relative.endsWith(".d.ts"))
96745
97156
  continue;
96746
- if (NOT_SOURCE.test(relative) || !existsSync20(absolute))
97157
+ if (NOT_SOURCE.test(relative) || !existsSync21(absolute))
96747
97158
  continue;
96748
97159
  try {
96749
- candidates.push(...mutantsFor(readFileSync23(absolute, "utf8"), relative, lines));
97160
+ candidates.push(...mutantsFor(readFileSync24(absolute, "utf8"), relative, lines));
96750
97161
  } catch {}
96751
97162
  }
96752
97163
  const mutants = candidates.map((mutant, index) => ({ ...mutant, id: index + 1 }));
@@ -96754,9 +97165,9 @@ async function runMutation(options) {
96754
97165
  for (const mutant of mutants)
96755
97166
  if (!related.has(mutant.file))
96756
97167
  related.set(mutant.file, relatedTests(mutant.file, testFiles));
96757
- const cwdRelative = path50.relative(repo, options.cwd);
97168
+ const cwdRelative = path51.relative(repo, options.cwd);
96758
97169
  const asArg = (file) => {
96759
- const relative = toPosix(path50.relative(cwdRelative, file));
97170
+ const relative = toPosix(path51.relative(cwdRelative, file));
96760
97171
  return shellQuote(relative.startsWith(".") ? relative : `./${relative}`);
96761
97172
  };
96762
97173
  const commandFor = (tests) => options.command.replaceAll("{files}", () => tests.map(asArg).join(" "));
@@ -96791,7 +97202,7 @@ async function runMutation(options) {
96791
97202
  return finish2(options, 0, results, counts, started);
96792
97203
  removeStaleCopies();
96793
97204
  const { dir: copyDir, tree: copy } = copyWorkingTree(repo);
96794
- const copyCwd = path50.join(copy, cwdRelative);
97205
+ const copyCwd = path51.join(copy, cwdRelative);
96795
97206
  let current = null;
96796
97207
  const restore = () => {
96797
97208
  if (current)
@@ -96802,7 +97213,7 @@ async function runMutation(options) {
96802
97213
  for (const child of active)
96803
97214
  killTree(child);
96804
97215
  restore();
96805
- rmSync7(copyDir, { recursive: true, force: true });
97216
+ rmSync8(copyDir, { recursive: true, force: true });
96806
97217
  };
96807
97218
  const onSignal = (signal) => {
96808
97219
  cleanup();
@@ -96826,7 +97237,7 @@ async function runMutation(options) {
96826
97237
  record({ ...mutant, status: "skipped", durationMs: 0, tests, reason: "budget" });
96827
97238
  continue;
96828
97239
  }
96829
- const original = readFileSync23(path50.join(copy, mutant.file), "utf8");
97240
+ const original = readFileSync24(path51.join(copy, mutant.file), "utf8");
96830
97241
  const mutated = original.slice(0, mutant.start) + mutant.replacement + original.slice(mutant.end);
96831
97242
  current = { file: mutant.file, original };
96832
97243
  if (!writeInside(copy, mutant.file, mutated)) {
@@ -96882,9 +97293,9 @@ var NOT_SOURCE, FLIPS, isStringy = (node) => node.type === "StringLiteral" || no
96882
97293
  } catch (error) {
96883
97294
  return error.code === "EPERM";
96884
97295
  }
96885
- }, inside3 = (root, file) => {
96886
- const relative = path50.relative(root, file);
96887
- return relative === "" || !relative.startsWith("..") && !path50.isAbsolute(relative);
97296
+ }, inside4 = (root, file) => {
97297
+ const relative = path51.relative(root, file);
97298
+ return relative === "" || !relative.startsWith("..") && !path51.isAbsolute(relative);
96888
97299
  }, active, killTree = (child) => {
96889
97300
  try {
96890
97301
  if (child.pid && process.platform !== "win32")
@@ -96930,10 +97341,10 @@ var init_mutate = __esm(() => {
96930
97341
  // packages/workit-cli/src/verbs/test-audit.ts
96931
97342
  var exports_test_audit = {};
96932
97343
  __export(exports_test_audit, {
96933
- run: () => run17
97344
+ run: () => run18
96934
97345
  });
96935
- import { existsSync as existsSync21 } from "node:fs";
96936
- import path51 from "node:path";
97346
+ import { existsSync as existsSync22 } from "node:fs";
97347
+ import path52 from "node:path";
96937
97348
  function parse7(argv) {
96938
97349
  const options = {
96939
97350
  paths: [],
@@ -97031,14 +97442,14 @@ function human(data) {
97031
97442
  }
97032
97443
  return lines;
97033
97444
  }
97034
- async function run17(argv, io) {
97445
+ async function run18(argv, io) {
97035
97446
  const options = parse7(argv);
97036
97447
  if (typeof options === "string")
97037
97448
  return emit(io, fail("invalid_input", `${options}
97038
97449
  usage: ${USAGE10}`));
97039
97450
  const top = git7(io.cwd, ["rev-parse", "--show-toplevel"]);
97040
- const repo = top.ok ? path51.resolve(top.stdout.trim()) : null;
97041
- const display = (file) => toPosix(path51.relative(io.cwd, file) || file);
97451
+ const repo = top.ok ? path52.resolve(top.stdout.trim()) : null;
97452
+ const display = (file) => toPosix(path52.relative(io.cwd, file) || file);
97042
97453
  let base = null;
97043
97454
  let changed = null;
97044
97455
  if (options.diff || options.mutate) {
@@ -97055,7 +97466,7 @@ usage: ${USAGE10}`));
97055
97466
  }
97056
97467
  let files;
97057
97468
  if (options.diff && changed)
97058
- files = [...changed.keys()].filter((file) => TEST_FILE.test(toPosix(file)) && existsSync21(file)).toSorted();
97469
+ files = [...changed.keys()].filter((file) => TEST_FILE.test(toPosix(file)) && existsSync22(file)).toSorted();
97059
97470
  else {
97060
97471
  const expanded = expandPaths(io.cwd, options.paths);
97061
97472
  if (expanded.missing.length > 0)
@@ -97142,9 +97553,9 @@ var init_test_audit = __esm(() => {
97142
97553
  // packages/workit-cli/src/verbs/knowledge.ts
97143
97554
  var exports_knowledge = {};
97144
97555
  __export(exports_knowledge, {
97145
- run: () => run18
97556
+ run: () => run19
97146
97557
  });
97147
- async function run18(argv, io) {
97558
+ async function run19(argv, io) {
97148
97559
  const [sub, ...rest] = argv.filter((arg) => arg !== "--json");
97149
97560
  if (sub !== "lint" || rest.length > 0)
97150
97561
  return emit(io, fail("invalid_input", `usage: ${USAGE11}`));
@@ -97278,11 +97689,11 @@ var init_youtrack_writes = __esm(() => {
97278
97689
  // packages/workit-cli/src/verbs/youtrack.ts
97279
97690
  var exports_youtrack = {};
97280
97691
  __export(exports_youtrack, {
97281
- run: () => run19
97692
+ run: () => run20
97282
97693
  });
97283
- import { readFileSync as readFileSync24 } from "node:fs";
97284
- import path52 from "node:path";
97285
- async function run19(argv, io) {
97694
+ import { readFileSync as readFileSync25 } from "node:fs";
97695
+ import path53 from "node:path";
97696
+ async function run20(argv, io) {
97286
97697
  const [sub, ...rest] = argv;
97287
97698
  if (sub !== "note" && sub !== "time" && sub !== "meeting")
97288
97699
  return usage3(io, `unknown subcommand "${sub ?? ""}"`, USAGE12);
@@ -97327,7 +97738,7 @@ async function run19(argv, io) {
97327
97738
  let markdown = flags.values.markdown ?? "";
97328
97739
  if (flags.values.file)
97329
97740
  try {
97330
- markdown = readFileSync24(path52.resolve(io.cwd, flags.values.file), "utf8");
97741
+ markdown = readFileSync25(path53.resolve(io.cwd, flags.values.file), "utf8");
97331
97742
  } catch (error) {
97332
97743
  return usage3(io, `cannot read ${flags.values.file}: ${String(error)}`, USAGE12);
97333
97744
  }
@@ -97393,11 +97804,11 @@ var init_youtrack2 = __esm(() => {
97393
97804
  // packages/workit-cli/src/verbs/changelog.ts
97394
97805
  var exports_changelog = {};
97395
97806
  __export(exports_changelog, {
97396
- run: () => run20
97807
+ run: () => run21
97397
97808
  });
97398
- import { readFileSync as readFileSync25 } from "node:fs";
97399
- import path53 from "node:path";
97400
- async function run20(argv, io) {
97809
+ import { readFileSync as readFileSync26 } from "node:fs";
97810
+ import path54 from "node:path";
97811
+ async function run21(argv, io) {
97401
97812
  const [sub, ...rest] = argv;
97402
97813
  if (sub !== "apply")
97403
97814
  return usage3(io, `unknown subcommand "${sub ?? ""}"`, USAGE13);
@@ -97442,7 +97853,7 @@ async function run20(argv, io) {
97442
97853
  ]);
97443
97854
  }
97444
97855
  var USAGE13 = "workit changelog apply (--entries <JSON|@file|-> | --normalize-only) [--path CHANGELOG.md] [--preview]", readEntries = (raw, cwd) => {
97445
- const text = raw === "-" ? readFileSync25(0, "utf8") : raw.startsWith("@") ? readFileSync25(path53.resolve(cwd, raw.slice(1)), "utf8") : raw;
97856
+ const text = raw === "-" ? readFileSync26(0, "utf8") : raw.startsWith("@") ? readFileSync26(path54.resolve(cwd, raw.slice(1)), "utf8") : raw;
97446
97857
  return JSON.parse(text);
97447
97858
  };
97448
97859
  var init_changelog2 = __esm(() => {
@@ -97454,7 +97865,7 @@ var init_changelog2 = __esm(() => {
97454
97865
  // packages/workit-cli/src/verbs/handoff.ts
97455
97866
  var exports_handoff = {};
97456
97867
  __export(exports_handoff, {
97457
- run: () => run21
97868
+ run: () => run22
97458
97869
  });
97459
97870
  import { parseArgs as parseArgs2 } from "node:util";
97460
97871
  function human2(brief) {
@@ -97524,7 +97935,7 @@ async function resumeBrief(argv, io) {
97524
97935
  }
97525
97936
  return emit(io, ok({ ...data, recorded }), human2);
97526
97937
  }
97527
- async function run21(argv, io) {
97938
+ async function run22(argv, io) {
97528
97939
  if (!argv.some((arg) => arg === "--task" || arg.startsWith("--task=")))
97529
97940
  return resumeBrief(argv, io);
97530
97941
  await Promise.resolve().then(() => init_task());
@@ -97538,7 +97949,7 @@ var init_handoff = __esm(() => {
97538
97949
 
97539
97950
  // packages/workit-cli/src/main.ts
97540
97951
  init_package();
97541
- import path54 from "node:path";
97952
+ import path55 from "node:path";
97542
97953
 
97543
97954
  // packages/workit-cli/src/help.ts
97544
97955
  var HELP_FLAGS = new Set(["--help", "-h"]);
@@ -97757,8 +98168,8 @@ var VERBS = [
97757
98168
  {
97758
98169
  name: "doctor",
97759
98170
  group: "setup",
97760
- usage: "workit doctor [--fix-lock [--force [--yes]]]",
97761
- summary: "Verify the offline installation health (--fix-lock clears a stale workit store lock)",
98171
+ usage: "workit doctor [--fix] [--fix-lock [--force [--yes]]]",
98172
+ summary: "Verify the offline installation health (--fix installs the session trailer hook; --fix-lock clears a stale workit store lock)",
97762
98173
  load: () => Promise.resolve().then(() => (init_doctor2(), exports_doctor))
97763
98174
  },
97764
98175
  {
@@ -98184,7 +98595,7 @@ var defaultIo = (json) => ({
98184
98595
  });
98185
98596
  async function main(argv, overrides = {}, options = {}) {
98186
98597
  const parsed = parseGlobals(argv);
98187
- const cwd = path54.resolve(overrides.cwd ?? process.cwd(), parsed.cwd ?? ".");
98598
+ const cwd = path55.resolve(overrides.cwd ?? process.cwd(), parsed.cwd ?? ".");
98188
98599
  const io = { ...defaultIo(parsed.json), ...overrides, json: parsed.json, cwd };
98189
98600
  if (parsed.error)
98190
98601
  return emit(io, fail("invalid_input", parsed.error));