@brainervirus/workit-cli 8.13.0 → 8.14.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 +710 -216
  2. package/package.json +5 -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.13.0",
68
+ version: "8.14.0",
69
69
  private: false,
70
70
  description: "Workit CLI — setup wizard, doctor, and task control for agentic coding workflows",
71
71
  keywords: [
@@ -103,13 +103,14 @@ var init_package = __esm(() => {
103
103
  },
104
104
  dependencies: {
105
105
  "@babel/parser": "7.29.9",
106
- "@brainervirus/workit-core": "^8.13.0",
107
- "@brainervirus/workit-cursor": "^8.13.0",
108
- "@brainervirus/workit-opencode": "^8.13.0",
106
+ "@brainervirus/workit-cursor": "^8.14.0",
109
107
  "@inkjs/ui": "2.0.0",
110
108
  ink: "7.1.1",
111
109
  react: "19.2.8"
112
110
  },
111
+ devDependencies: {
112
+ "@brainervirus/workit-core": "^8.14.0"
113
+ },
113
114
  engines: {
114
115
  node: ">=24"
115
116
  }
@@ -10429,7 +10430,7 @@ var init_paths = __esm(() => {
10429
10430
  });
10430
10431
 
10431
10432
  // packages/workit-core/src/host-session.ts
10432
- import { createHash as createHash3 } from "node:crypto";
10433
+ import { createHash as createHash3, randomBytes as randomBytes2, timingSafeEqual } from "node:crypto";
10433
10434
  import fs6 from "node:fs";
10434
10435
  import path6 from "node:path";
10435
10436
  function hostSessionFromEnv(env) {
@@ -10482,7 +10483,12 @@ function migrateRepoIssued(cwd) {
10482
10483
  const to = path6.join(userIssuedRoot(), lead);
10483
10484
  fs6.mkdirSync(to, { recursive: true, mode: 448 });
10484
10485
  for (const id of fs6.readdirSync(from)) {
10485
- fs6.copyFileSync(path6.join(from, id), path6.join(to, id));
10486
+ try {
10487
+ fs6.copyFileSync(path6.join(from, id), path6.join(to, id), fs6.constants.COPYFILE_EXCL);
10488
+ } catch (error) {
10489
+ if (error.code !== "EEXIST")
10490
+ throw error;
10491
+ }
10486
10492
  fs6.rmSync(path6.join(from, id), { force: true });
10487
10493
  }
10488
10494
  removeIfEmpty(from);
@@ -10490,7 +10496,25 @@ function migrateRepoIssued(cwd) {
10490
10496
  }
10491
10497
  removeIfEmpty(old);
10492
10498
  }
10493
- function sessionClaimRefusal(env, claimed, cwd) {
10499
+ function issuedBinding(cwd, claimed) {
10500
+ const record = issuedRecord(cwd, claimed);
10501
+ const { stored, leadBound } = issuedToken(claimed);
10502
+ if (stored)
10503
+ return "token";
10504
+ if (record === null)
10505
+ return null;
10506
+ return leadBound ? "token" : "legacy";
10507
+ }
10508
+ function issuedTokenMatches(cwd, claimed, token) {
10509
+ migrateRepoIssued(cwd);
10510
+ const { stored } = issuedToken(claimed);
10511
+ if (!stored || !token)
10512
+ return false;
10513
+ const given = Buffer.from(tokenHash(token.trim()));
10514
+ const want = Buffer.from(stored);
10515
+ return given.length === want.length && timingSafeEqual(given, want);
10516
+ }
10517
+ function sessionClaimRefusal(env, claimed, cwd, options = {}) {
10494
10518
  const real = realHostSession(env);
10495
10519
  const host = family(real.host);
10496
10520
  if (real.kind !== "derived" && host !== null && HOST_SET_VARIABLE[host])
@@ -10500,18 +10524,22 @@ function sessionClaimRefusal(env, claimed, cwd) {
10500
10524
  };
10501
10525
  if (real.kind === "none" || !real.session)
10502
10526
  return null;
10503
- let issuedClaim = false;
10504
- if (claimed === real.session) {
10505
- const declaredChild = real.kind === "declared" && host === "claude_code" && claimed.includes(":");
10506
- if (!declaredChild || wasIssued(cwd, leadOf(claimed), claimed))
10507
- return null;
10508
- issuedClaim = true;
10509
- } else if (real.kind === "derived" && claimed.endsWith(`:${real.session}`))
10510
- return null;
10511
- else if (claimed.startsWith(`${real.session}:`)) {
10512
- if (wasIssued(cwd, real.session, claimed))
10527
+ const ownShell = claimed === real.session && !(real.kind === "declared" && claimed.includes(":")) || real.kind === "derived" && claimed.endsWith(`:${real.session}`);
10528
+ if (ownShell)
10529
+ return options.flag ? {
10530
+ error: `session_flag: --session ${claimed} names this shell's own ${real.host} session; on a host only an issued subagent id is passed as --session`,
10531
+ unblock: "drop --session: the shell's own session is already the acting one"
10532
+ } : null;
10533
+ const issuedClaim = claimed === real.session || claimed.startsWith(`${real.session}:`);
10534
+ if (issuedClaim) {
10535
+ const binding = issuedBinding(cwd, claimed);
10536
+ if (binding === "legacy")
10513
10537
  return null;
10514
- issuedClaim = true;
10538
+ if (binding === "token")
10539
+ return issuedTokenMatches(cwd, claimed, options.token) ? null : {
10540
+ error: `unbound_session: ${claimed} was issued to a subagent, and this call did not present the token its SubagentStart hook gave it`,
10541
+ unblock: `only that subagent acts as ${claimed}: it passes --token exactly as its SubagentStart context names it (or WORKIT_SESSION_TOKEN); anyone else spawns their own verifier`
10542
+ };
10515
10543
  }
10516
10544
  const error = `forged_session: ${claimed} is neither this shell's session (${real.session}) nor an id its host issued to a child of it`;
10517
10545
  if (issuedClaim && noIssuedRecord(cwd, leadOf(claimed)) && host !== null && PLUGIN_UPDATE[host])
@@ -10522,10 +10550,10 @@ function sessionClaimRefusal(env, claimed, cwd) {
10522
10550
  const ownChildShell = host !== null && OWN_CHILD_SHELL.has(host);
10523
10551
  return {
10524
10552
  error,
10525
- unblock: ownChildShell ? `record the verdict from the verifier's own ${host === "pi" ? "Pi worker" : "OpenCode child session"} shell, where WORKIT_SESSION_ID is already set; never set WORKIT_SESSION_ID or --session by hand` : "never name a session yourself: spawn a verifier or reviewer subagent and pass exactly the --session its SubagentStart context names, or pass --as verifier"
10553
+ unblock: ownChildShell ? `record the verdict from the verifier's own ${host === "pi" ? "Pi worker" : "OpenCode child session"} shell, where WORKIT_SESSION_ID is already set; never set WORKIT_SESSION_ID or --session by hand` : "never name a session yourself: spawn a verifier or reviewer subagent and pass exactly the --session and --token its SubagentStart context names, or pass --as verifier"
10526
10554
  };
10527
10555
  }
10528
- var HOST_SESSION_VARS, family = (host) => host?.replace(/_(?:cli|desktop)$/, "") ?? null, hash = (value) => createHash3("sha256").update(value).digest("hex").slice(0, 32), userIssuedRoot = () => path6.join(resolveStateDir(), "issued"), safeList = (dir) => {
10556
+ var HOST_SESSION_VARS, family = (host) => host?.replace(/_(?:cli|desktop)$/, "") ?? null, hash = (value) => createHash3("sha256").update(value).digest("hex").slice(0, 32), userIssuedRoot = () => path6.join(resolveStateDir(), "issued"), userTokenRoot = () => path6.join(resolveStateDir(), "issued-tokens"), safeList = (dir) => {
10529
10557
  try {
10530
10558
  return fs6.readdirSync(dir);
10531
10559
  } catch {
@@ -10544,12 +10572,26 @@ var HOST_SESSION_VARS, family = (host) => host?.replace(/_(?:cli|desktop)$/, "")
10544
10572
  } catch {
10545
10573
  return false;
10546
10574
  }
10547
- }, PLUGIN_UPDATE, wasIssued = (cwd, lead, claimed) => {
10575
+ }, PLUGIN_UPDATE, tokenHash = (token) => createHash3("sha256").update(token).digest("hex"), issuedRecord = (cwd, claimed) => {
10576
+ const cut = claimed.lastIndexOf(":");
10577
+ if (cut <= 0)
10578
+ return null;
10548
10579
  migrateRepoIssued(cwd);
10549
10580
  try {
10550
- return fs6.existsSync(path6.join(userIssuedRoot(), hash(lead), hash(claimed)));
10581
+ return fs6.readFileSync(path6.join(userIssuedRoot(), hash(claimed.slice(0, cut)), hash(claimed)), "utf8");
10551
10582
  } catch {
10552
- return false;
10583
+ return null;
10584
+ }
10585
+ }, TOKEN_HASH, issuedToken = (claimed) => {
10586
+ const cut = claimed.lastIndexOf(":");
10587
+ if (cut <= 0)
10588
+ return { stored: null, leadBound: false };
10589
+ const dir = path6.join(userTokenRoot(), hash(claimed.slice(0, cut)));
10590
+ try {
10591
+ const text = fs6.readFileSync(path6.join(dir, hash(claimed)), "utf8");
10592
+ return { stored: TOKEN_HASH.exec(text)?.[1] ?? null, leadBound: true };
10593
+ } catch {
10594
+ return { stored: null, leadBound: safeList(dir).length > 0 };
10553
10595
  }
10554
10596
  }, leadOf = (session) => session.slice(0, session.lastIndexOf(":")), OWN_CHILD_SHELL, HOST_SET_VARIABLE;
10555
10597
  var init_host_session = __esm(() => {
@@ -10567,6 +10609,7 @@ var init_host_session = __esm(() => {
10567
10609
  claude_code: "claude plugin marketplace update workit && claude plugin update workit@workit",
10568
10610
  codex: "codex plugin remove workit@workit && codex plugin add workit@workit"
10569
10611
  };
10612
+ TOKEN_HASH = /^([0-9a-f]{64})$/mu;
10570
10613
  OWN_CHILD_SHELL = new Set(["opencode", "pi"]);
10571
10614
  HOST_SET_VARIABLE = {
10572
10615
  opencode: "OPENCODE_SESSION_ID",
@@ -10599,7 +10642,7 @@ import { spawnSync as spawnSync3 } from "node:child_process";
10599
10642
  import fs7 from "node:fs";
10600
10643
  import { hostname } from "node:os";
10601
10644
  import path8 from "node:path";
10602
- var metadataLockSchema, FOREIGN_LOCK_TTL_MS, UNREADABLE_LOCK_TTL_MS = 30000, RECLAIM_GUARD_TTL_MS = 30000, defaultLockTimeoutMs = 250, defaultLockTimeout = () => defaultLockTimeoutMs, setDefaultLockTimeout = (ms) => {
10645
+ var metadataLockSchema, FOREIGN_LOCK_TTL_MS, UNREADABLE_LOCK_TTL_MS = 30000, RECLAIM_GUARD_TTL_MS = 30000, IN_PROCESS_LOCK_TIMEOUT_MS = 250, defaultLockTimeoutMs, defaultLockTimeout = () => defaultLockTimeoutMs, hostAwareLockTimeout = (cliMs) => defaultLockTimeoutMs > IN_PROCESS_LOCK_TIMEOUT_MS ? cliMs : IN_PROCESS_LOCK_TIMEOUT_MS, setDefaultLockTimeout = (ms) => {
10603
10646
  defaultLockTimeoutMs = ms;
10604
10647
  }, parseMetadataLock = (raw) => {
10605
10648
  let value;
@@ -10789,6 +10832,7 @@ var init_store_lock = __esm(() => {
10789
10832
  externalAction: literal(true).optional()
10790
10833
  }).strict();
10791
10834
  FOREIGN_LOCK_TTL_MS = 10 * 60000;
10835
+ defaultLockTimeoutMs = IN_PROCESS_LOCK_TIMEOUT_MS;
10792
10836
  TASK_STORE_LOCK = { reclaimUnverifiedAfterTtl: true };
10793
10837
  });
10794
10838
 
@@ -13978,23 +14022,79 @@ var nonBlank, branchPreset, commitPreset, workspaceBranchPolicySchema, workspace
13978
14022
  }, resolveRuntimeReleaseTracks = (cwd) => {
13979
14023
  const matched = matchRuntimeWorkspace(cwd);
13980
14024
  return matched ? { workspace: matched.selected.name, releaseTracks: matched.selected.releaseTracks } : null;
13981
- }, workspaceTrailers = (cwd, dir) => {
14025
+ }, inheritedSetting = (cwd, dir, has) => {
13982
14026
  let matched;
13983
14027
  try {
13984
14028
  matched = matchRuntimeWorkspace(cwd, dir);
13985
14029
  } catch {
13986
- return { enabled: true, workspace: null, from: null };
14030
+ return null;
13987
14031
  }
13988
14032
  if (!matched)
13989
- return { enabled: true, workspace: null, from: null };
14033
+ return null;
13990
14034
  const { selected, matches } = matched;
13991
14035
  const enclosing = matches.filter((entry) => entry !== selected).toSorted((a, b) => globSpecificity(b.glob) - globSpecificity(a.glob));
13992
- const source = [selected, ...enclosing].find((entry) => typeof entry.trailers === "boolean");
14036
+ return { workspace: selected.name, source: [selected, ...enclosing].find(has) ?? null };
14037
+ }, workspaceTrailers = (cwd, dir) => {
14038
+ const found = inheritedSetting(cwd, dir, (entry) => typeof entry.trailers === "boolean");
13993
14039
  return {
13994
- enabled: source?.trailers !== false,
13995
- workspace: selected.name,
13996
- from: source?.name ?? null
14040
+ enabled: found?.source?.trailers !== false,
14041
+ workspace: found?.workspace ?? null,
14042
+ from: found?.source?.name ?? null
13997
14043
  };
14044
+ }, hostFamily = (host) => host.replace(/_(?:cli|desktop)$/u, ""), TIER_KEYS, TIER_HOSTS, workspaceTierModelIssues = (cwd, dir) => {
14045
+ let matched;
14046
+ try {
14047
+ matched = matchRuntimeWorkspace(cwd, dir);
14048
+ } catch {
14049
+ return [];
14050
+ }
14051
+ const issues = [];
14052
+ for (const entry of matched?.matches ?? []) {
14053
+ const models = entry.fanout?.tierModels;
14054
+ if (models === undefined)
14055
+ continue;
14056
+ const where = `workspace ${entry.name} fanout.tierModels`;
14057
+ if (!models || typeof models !== "object" || Array.isArray(models)) {
14058
+ issues.push(`${where} is not an object; ignored`);
14059
+ continue;
14060
+ }
14061
+ for (const [tier, value] of Object.entries(models)) {
14062
+ if (!TIER_KEYS.has(tier))
14063
+ issues.push(`${where}.${tier}: unknown tier; ignored`);
14064
+ else if (typeof value === "string") {
14065
+ if (!value.trim())
14066
+ issues.push(`${where}.${tier}: empty model name; ignored`);
14067
+ } else if (!value || typeof value !== "object" || Array.isArray(value))
14068
+ issues.push(`${where}.${tier}: not a model name or a per-host object; ignored`);
14069
+ else
14070
+ for (const [host, model] of Object.entries(value)) {
14071
+ if (!TIER_HOSTS.has(host))
14072
+ issues.push(`${where}.${tier}.${host}: unknown host; ignored`);
14073
+ else if (typeof model !== "string" || !model.trim())
14074
+ issues.push(`${where}.${tier}.${host}: not a model name; ignored`);
14075
+ }
14076
+ }
14077
+ }
14078
+ return issues;
14079
+ }, workspaceTierModel = (cwd, tier, host, dir) => {
14080
+ const pick = (entry) => {
14081
+ const fanout = entry.fanout;
14082
+ const models = fanout?.tierModels;
14083
+ if (!models || typeof models !== "object" || !Object.hasOwn(models, tier))
14084
+ return null;
14085
+ const value = models[tier];
14086
+ if (typeof value === "string")
14087
+ return value.trim() || null;
14088
+ if (!value || typeof value !== "object")
14089
+ return null;
14090
+ const byHost = value;
14091
+ const family = host ? hostFamily(host) : null;
14092
+ const named = (family && Object.hasOwn(byHost, family) ? byHost[family] : undefined) ?? (host && Object.hasOwn(byHost, host) ? byHost[host] : undefined) ?? (Object.hasOwn(byHost, "default") ? byHost.default : undefined);
14093
+ return typeof named === "string" && named.trim() ? named.trim() : null;
14094
+ };
14095
+ const found = inheritedSetting(cwd, dir, (entry) => pick(entry) !== null);
14096
+ const model = found?.source ? pick(found.source) : null;
14097
+ return model && found?.source ? { model, workspace: found.source.name } : null;
13998
14098
  }, resolveRuntimeWorkspaceCandidate = (cwd, kind) => {
13999
14099
  const matched = matchRuntimeWorkspace(cwd);
14000
14100
  if (!matched)
@@ -14146,6 +14246,8 @@ var init_workspaces = __esm(() => {
14146
14246
  defaultEndpoint: unknown().optional(),
14147
14247
  verification: _enum(["self", "independent"]).optional(),
14148
14248
  trailers: boolean2().optional(),
14249
+ liveSessionGuard: boolean2().optional(),
14250
+ fanout: object({ tierModels: unknown().optional() }).passthrough().optional(),
14149
14251
  autonomy: object(Object.fromEntries(["push", "pr", "merge", "release", "rerun"].map((kind) => [
14150
14252
  kind,
14151
14253
  union([boolean2(), literal("verified")]).optional()
@@ -14195,6 +14297,17 @@ var init_workspaces = __esm(() => {
14195
14297
  runtimeWorkspaceIndexSchema = object({
14196
14298
  workspaces: array(object({ name: nonBlank, glob: nonBlank }).passthrough()).optional()
14197
14299
  }).passthrough();
14300
+ TIER_KEYS = new Set(["mundane", "standard", "hard"]);
14301
+ TIER_HOSTS = new Set([
14302
+ "claude_code",
14303
+ "opencode",
14304
+ "codex",
14305
+ "codex_cli",
14306
+ "codex_desktop",
14307
+ "cursor",
14308
+ "pi",
14309
+ "default"
14310
+ ]);
14198
14311
  });
14199
14312
 
14200
14313
  // packages/workit-core/src/core/release-tracks.ts
@@ -14789,7 +14902,7 @@ var init_vcs_config = __esm(() => {
14789
14902
 
14790
14903
  // packages/workit-core/src/ledger.ts
14791
14904
  import { spawnSync as spawnSync9 } from "node:child_process";
14792
- import { createHash as createHash9, randomBytes as randomBytes2 } from "node:crypto";
14905
+ import { createHash as createHash9, randomBytes as randomBytes3 } from "node:crypto";
14793
14906
  import fs12 from "node:fs";
14794
14907
  import path15 from "node:path";
14795
14908
  function resolveCommit(cwd, ref) {
@@ -14878,7 +14991,7 @@ function actorFromEnv(env) {
14878
14991
  agentId: value("WORKIT_AGENT_ID")
14879
14992
  };
14880
14993
  }
14881
- function withLedgerLock(file, fn, waitMs = LOCK_WAIT_MS) {
14994
+ function withLedgerLock(file, fn, waitMs = hostAwareLockTimeout(LOCK_WAIT_MS)) {
14882
14995
  const lock = `${file}.lock`;
14883
14996
  const deadline = Date.now() + waitMs;
14884
14997
  let token = null;
@@ -14902,8 +15015,10 @@ function withLedgerLock(file, fn, waitMs = LOCK_WAIT_MS) {
14902
15015
  }
14903
15016
  function appendLine(file, build, options) {
14904
15017
  const write = () => {
14905
- const fd = fs12.openSync(file, "a+");
15018
+ const fd = fs12.openSync(file, "a+", 384);
14906
15019
  try {
15020
+ if (process.platform !== "win32")
15021
+ tighten(fd);
14907
15022
  const size = fs12.fstatSync(fd).size;
14908
15023
  let fence = "";
14909
15024
  if (size > 0) {
@@ -14982,7 +15097,9 @@ function readLedger(cwd, options = {}) {
14982
15097
  if (!file.ok)
14983
15098
  return file;
14984
15099
  let text = "";
15100
+ let stat = null;
14985
15101
  try {
15102
+ stat = fs12.statSync(file.value);
14986
15103
  text = fs12.readFileSync(file.value, "utf8");
14987
15104
  } catch (error) {
14988
15105
  if (error.code === "ENOENT")
@@ -15002,6 +15119,7 @@ function readLedger(cwd, options = {}) {
15002
15119
  const integrity = { chained: 0, legacy: 0, unverified: [] };
15003
15120
  const earlier = new Set([null]);
15004
15121
  let chainStarted = false;
15122
+ const ids = new Set;
15005
15123
  for (const raw of text.split(`
15006
15124
  `)) {
15007
15125
  const trimmed = raw.trim();
@@ -15035,6 +15153,10 @@ function readLedger(cwd, options = {}) {
15035
15153
  reason = "unsigned";
15036
15154
  else
15037
15155
  rowIntegrity = "legacy";
15156
+ if (options.integrity && !reason && ids.has(parsed.id))
15157
+ reason = "duplicate_id";
15158
+ if (options.integrity)
15159
+ ids.add(parsed.id);
15038
15160
  if (reason)
15039
15161
  rowIntegrity = "unverified";
15040
15162
  const pr = typeof parsed.pr === "number" && Number.isInteger(parsed.pr) ? parsed.pr : undefined;
@@ -15058,7 +15180,8 @@ function readLedger(cwd, options = {}) {
15058
15180
  seq: rows.length + 1,
15059
15181
  superseded: false,
15060
15182
  supersedeIgnored: false,
15061
- ...rowIntegrity ? { integrity: rowIntegrity } : {}
15183
+ ...rowIntegrity ? { integrity: rowIntegrity } : {},
15184
+ ...reason ? { integrityReason: reason } : {}
15062
15185
  };
15063
15186
  rows.push(row);
15064
15187
  if (!options.integrity)
@@ -15086,18 +15209,44 @@ function readLedger(cwd, options = {}) {
15086
15209
  const byId = new Map;
15087
15210
  for (const row of rows) {
15088
15211
  const target = row.supersedes ? byId.get(row.supersedes) : undefined;
15089
- if (target && supersedeAllowed(row, target, renameAwareBranch(scopeOf, row.branch)) === null)
15212
+ if (target && row.integrity !== "unverified" && supersedeAllowed(row, target, renameAwareBranch(scopeOf, row.branch)) === null)
15090
15213
  target.superseded = true;
15091
15214
  else if (row.supersedes)
15092
15215
  row.supersedeIgnored = true;
15093
15216
  if (!byId.has(row.id))
15094
15217
  byId.set(row.id, row);
15095
15218
  }
15219
+ if (options.integrity && stat && Buffer.byteLength(text) === stat.size)
15220
+ tamperCache.set(file.value, {
15221
+ size: stat.size,
15222
+ stamp: fileStamp(stat),
15223
+ breaks: integrity.unverified.filter((row) => TAMPER_REASONS.has(row.reason))
15224
+ });
15096
15225
  return {
15097
15226
  ok: true,
15098
15227
  value: { path: file.value, rows, skipped, integrity: options.integrity ? integrity : null }
15099
15228
  };
15100
15229
  }
15230
+ function ledgerTampering(cwd) {
15231
+ const file = ledgerPath(cwd);
15232
+ if (!file.ok)
15233
+ return [];
15234
+ try {
15235
+ const stat = fs12.statSync(file.value);
15236
+ const cached = tamperCache.get(file.value);
15237
+ if (cached && cached.size === stat.size && cached.stamp === fileStamp(stat))
15238
+ return cached.breaks;
15239
+ } catch {
15240
+ return [];
15241
+ }
15242
+ const read = readLedger(cwd, { integrity: true });
15243
+ return read.ok ? (read.value.integrity?.unverified ?? []).filter((row) => TAMPER_REASONS.has(row.reason)) : [];
15244
+ }
15245
+ function tamperedUnblock(cwd) {
15246
+ const file = ledgerPath(cwd);
15247
+ const where = file.ok ? file.value : "the ledger file";
15248
+ return `workit ledger verify-integrity # lists the edited or missing rows; if the edit is understood, move ${where} aside (mv ${where} ${where}.tampered-<date>) and record the verdicts again`;
15249
+ }
15101
15250
  function filterRows(rows, filter) {
15102
15251
  const matched = rows.filter((row) => (filter.branch === undefined || row.branch === filter.branch) && (filter.pr === undefined || row.pr === filter.pr) && (filter.type === undefined || row.type === filter.type));
15103
15252
  return filter.last === undefined ? matched : matched.slice(Math.max(0, matched.length - filter.last));
@@ -15213,15 +15362,51 @@ function authorSessions(cwd, rows, branch, range = { base: null, head: null }, s
15213
15362
  sessions.add(session);
15214
15363
  return sessions;
15215
15364
  }
15216
- function effectiveOf(rows, authors, sameCode, isCurrent) {
15365
+ function sessionTrust(cwd, row) {
15366
+ const session = row.actor.session;
15367
+ if (!session || row.self === true)
15368
+ return null;
15369
+ const source = typeof row.sessionSource === "string" ? row.sessionSource : "env";
15370
+ const host = row.actor.host;
15371
+ const issuedOnly = source === "flag" ? host !== "cli" : source === "env" && session.includes(":") && !SHELL_VOUCHED_HOSTS.has(host);
15372
+ if (!issuedOnly)
15373
+ return null;
15374
+ const binding = issuedBinding(cwd, session);
15375
+ if (binding === null)
15376
+ return "unissued_session";
15377
+ return binding === "token" && row.sessionBound !== true ? "unbound_session" : null;
15378
+ }
15379
+ function trustReasons(cwd, row) {
15380
+ if (row.integrity === "unverified")
15381
+ return [row.integrityReason ?? "unsigned"];
15382
+ if (row.integrity !== "verified")
15383
+ return ["unsigned"];
15384
+ const session = sessionTrust(cwd, row);
15385
+ return session ? [session] : [];
15386
+ }
15387
+ function withIntegrity(cwd, rows) {
15388
+ if (rows.every((row) => row.integrity !== undefined))
15389
+ return rows;
15390
+ const read = readLedger(cwd, { integrity: true });
15391
+ const bySeq = new Map(read.ok ? read.value.rows.map((row) => [row.seq, row]) : []);
15392
+ return rows.map((row) => {
15393
+ if (row.integrity !== undefined)
15394
+ return row;
15395
+ const fresh = bySeq.get(row.seq);
15396
+ return fresh && fresh.id === row.id && fresh.at === row.at ? fresh : row;
15397
+ });
15398
+ }
15399
+ function effectiveOf(rows, reasonsOf, sameCode, isCurrent) {
15217
15400
  let effective = null;
15218
15401
  for (const row of rows) {
15219
15402
  if (!effective) {
15220
15403
  effective = row;
15221
15404
  continue;
15222
15405
  }
15223
- const rowIndependent = independenceReasons(row, authors).length === 0;
15224
- const effIndependent = independenceReasons(effective, authors).length === 0;
15406
+ if (untrusted(reasonsOf(row)) && !untrusted(reasonsOf(effective)))
15407
+ continue;
15408
+ const rowIndependent = reasonsOf(row).length === 0;
15409
+ const effIndependent = reasonsOf(effective).length === 0;
15225
15410
  if (effIndependent && !rowIndependent && isCurrent(effective))
15226
15411
  continue;
15227
15412
  if (effIndependent && FAILING.has(String(effective.result)) && row.actor.session === effective.actor.session && sameCode(effective, row))
@@ -15235,7 +15420,7 @@ function restackCarries(rows, branch, from, to) {
15235
15420
  return false;
15236
15421
  const edges = new Map;
15237
15422
  for (const row of rows)
15238
- if (row.type === "stack.restacked" && row.observer === "workit_cli" && row.branch === branch && row.patchEqual === true && typeof row.fromHead === "string" && row.head)
15423
+ if (row.type === "stack.restacked" && row.observer === "workit_cli" && row.integrity === "verified" && row.branch === branch && row.patchEqual === true && typeof row.fromHead === "string" && row.head)
15239
15424
  edges.set(row.fromHead, [...edges.get(row.fromHead) ?? [], row.head]);
15240
15425
  const seen = new Set([from]);
15241
15426
  const queue = [from];
@@ -15251,7 +15436,8 @@ function restackCarries(rows, branch, from, to) {
15251
15436
  }
15252
15437
  return false;
15253
15438
  }
15254
- function checkVerdicts(cwd, branch, rows) {
15439
+ function checkVerdicts(cwd, branch, ledgerRows) {
15440
+ const rows = withIntegrity(cwd, ledgerRows);
15255
15441
  const head = branchHead(cwd, branch);
15256
15442
  const fallbackBase = defaultBase(cwd);
15257
15443
  const scope = branchScope(cwd, branch);
@@ -15281,21 +15467,47 @@ function checkVerdicts(cwd, branch, rows) {
15281
15467
  return verdictBasis(failed, { head: row.head, ...keys }) !== "stale" || restackCarries(rows, branch, failed.head, row.head);
15282
15468
  };
15283
15469
  const authors = authorSessions(cwd, rows, branch, { base: fallbackBase, head }, scope);
15470
+ const failureAuthorCache = new Map;
15471
+ const failureAuthors = (row) => {
15472
+ let set = failureAuthorCache.get(row.seq);
15473
+ if (!set) {
15474
+ set = authorSessions(cwd, rows.filter((other) => other.integrity === "verified" && other.seq < row.seq), branch, { base: null, head: null }, scope);
15475
+ failureAuthorCache.set(row.seq, set);
15476
+ }
15477
+ return set;
15478
+ };
15479
+ const reasonCache = new Map;
15480
+ const reasonsOf = (row) => {
15481
+ let reasons = reasonCache.get(row);
15482
+ if (!reasons) {
15483
+ const failing = FAILING.has(String(row.result));
15484
+ reasons = [
15485
+ ...trustReasons(cwd, row),
15486
+ ...independenceReasons(row, failing ? failureAuthors(row) : authors)
15487
+ ];
15488
+ reasonCache.set(row, reasons);
15489
+ }
15490
+ return reasons;
15491
+ };
15492
+ const retired = new Set;
15493
+ for (const row of rows)
15494
+ if (row.type === "verdict" && row.supersedes && !row.supersedeIgnored && trustReasons(cwd, row).length === 0)
15495
+ retired.add(row.supersedes);
15284
15496
  const byKind = new Map;
15285
15497
  for (const row of rows)
15286
- if (isLiveVerdict(row) && scope(row)) {
15498
+ if (isLiveVerdict(row, retired) && scope(row)) {
15287
15499
  const kind = typeof row.kind === "string" ? row.kind : "review";
15288
15500
  byKind.set(kind, [...byKind.get(kind) ?? [], row]);
15289
15501
  }
15290
15502
  const verdicts = [];
15291
15503
  const warnings = [];
15292
15504
  for (const [kind, list] of byKind) {
15293
- const row = effectiveOf(list, authors, sameCode, (candidate) => basisOf(candidate) !== "stale");
15505
+ const row = effectiveOf(list, reasonsOf, sameCode, (candidate) => basisOf(candidate) !== "stale");
15294
15506
  if (!row)
15295
15507
  continue;
15296
15508
  const basis = basisOf(row);
15297
15509
  const current = basis !== "stale";
15298
- const independence = independenceReasons(row, authors);
15510
+ const independence = reasonsOf(row);
15299
15511
  const reasons = [
15300
15512
  ...current ? [] : ["stale"],
15301
15513
  ...PASSING.has(String(row.result)) ? [] : ["not_passing"],
@@ -15312,23 +15524,31 @@ function checkVerdicts(cwd, branch, rows) {
15312
15524
  });
15313
15525
  if (reasons.length === 0) {
15314
15526
  for (const later of list)
15315
- if (later.seq > row.seq && independenceReasons(later, authors).length > 0 && FAILING.has(String(later.result)) && basisOf(later) !== "stale")
15527
+ if (later.seq > row.seq && reasonsOf(later).length > 0 && !untrusted(reasonsOf(later)) && FAILING.has(String(later.result)) && basisOf(later) !== "stale")
15316
15528
  warnings.push(`the author's own (self) ${String(later.result)} ${kind} verdict ${later.id} by ${later.actor.session ?? "no session"} on the current code is newer than the accepted pass ${row.id}: read it before merging`);
15317
15529
  }
15318
15530
  }
15319
15531
  for (const row of rows)
15320
15532
  if (row.integrity === "unverified" && scope(row))
15321
15533
  warnings.push(`ledger row ${row.id} (${row.type}) on ${row.branch ?? branch} is unverified: the workit CLI did not write it or it changed afterwards (workit ledger verify-integrity)`);
15534
+ const tampered = ledgerTampering(cwd);
15535
+ if (tampered.length) {
15536
+ warnings.push(tamperedWarning(cwd, tampered));
15537
+ for (const entry of verdicts) {
15538
+ entry.accepted = false;
15539
+ entry.reasons = [...entry.reasons, "ledger_tampered"];
15540
+ }
15541
+ }
15322
15542
  verdicts.sort((a, b) => a.verdict.seq - b.verdict.seq);
15323
15543
  const newestCurrent = verdicts.findLast((entry) => entry.current) ?? verdicts.at(-1) ?? null;
15324
15544
  const failing = verdicts.find((entry) => entry.current && entry.independent && FAILING.has(String(entry.verdict.result)));
15325
15545
  const newestAccepted = verdicts.findLast((entry) => entry.accepted && STRONG_RESULTS.has(String(entry.verdict.result))) ?? null;
15326
- const accepted = newestAccepted && !failing ? { accepted: true, verdict: newestAccepted.verdict, reasons: [] } : {
15546
+ const accepted = tampered.length ? { accepted: false, verdict: null, reasons: ["ledger_tampered"] } : newestAccepted && !failing ? { accepted: true, verdict: newestAccepted.verdict, reasons: [] } : {
15327
15547
  accepted: false,
15328
15548
  verdict: failing?.verdict ?? null,
15329
15549
  reasons: failing ? ["failing_verdict"] : !newestCurrent ? ["no_verdict"] : newestCurrent.reasons.length ? newestCurrent.reasons : ["type_check_only"]
15330
15550
  };
15331
- const selfEntry = failing ? undefined : verdicts.findLast((entry) => entry.current && !entry.independent && STRONG_RESULTS.has(String(entry.verdict.result)));
15551
+ const selfEntry = failing ? undefined : verdicts.findLast((entry) => entry.current && !entry.independent && !untrusted(entry.reasons) && STRONG_RESULTS.has(String(entry.verdict.result)));
15332
15552
  return {
15333
15553
  branch,
15334
15554
  head,
@@ -15523,6 +15743,7 @@ function recordVerdict(context, input) {
15523
15743
  self: self2,
15524
15744
  selfReason,
15525
15745
  sessionSource: context.sessionSource ?? "env",
15746
+ ...context.sessionBound === true ? { sessionBound: true } : {},
15526
15747
  evidenceRefs: input.evidenceRefs ?? []
15527
15748
  }, { now: context.now });
15528
15749
  }
@@ -15751,7 +15972,7 @@ var LEDGER_VERSION = 1, MAX_LINE_BYTES = 4096, VERDICT_RESULTS, PASSING, FAILING
15751
15972
  } catch {
15752
15973
  return null;
15753
15974
  }
15754
- }, newId2 = () => `${Date.now().toString(36)}-${randomBytes2(6).toString("hex")}`, NETWORK_FS_TYPES, isNetworkFsType = (type) => NETWORK_FS_TYPES.has(type >>> 0), onNetworkFs = (dir) => {
15975
+ }, newId2 = () => `${Date.now().toString(36)}-${randomBytes3(6).toString("hex")}`, NETWORK_FS_TYPES, isNetworkFsType = (type) => NETWORK_FS_TYPES.has(type >>> 0), onNetworkFs = (dir) => {
15755
15976
  if (process.platform !== "linux")
15756
15977
  return false;
15757
15978
  try {
@@ -15804,6 +16025,11 @@ ${body}`), TAIL_BYTES, lastLine = (fd, size) => {
15804
16025
  return text || null;
15805
16026
  }
15806
16027
  return null;
16028
+ }, tighten = (fd) => {
16029
+ try {
16030
+ if ((fs12.fstatSync(fd).mode & 63) !== 0)
16031
+ fs12.fchmodSync(fd, 384);
16032
+ } catch {}
15807
16033
  }, sealed = (row, id, at, previous) => {
15808
16034
  const { prevHash: _prev, rowHash: _row, ...fields } = row;
15809
16035
  const prevHash = previous === null ? null : sha2562(previous);
@@ -15818,7 +16044,7 @@ ${body}`), TAIL_BYTES, lastLine = (fd, size) => {
15818
16044
  session: str2(actor.session),
15819
16045
  agentId: str2(actor.agentId)
15820
16046
  };
15821
- }, isLiveVerdict = (row) => row.type === "verdict" && typeof row.result === "string" && !row.superseded, RENAMED, renameAwareBranch = (scopeOf, branch) => {
16047
+ }, TAMPER_REASONS, tamperCache, fileStamp = (stat) => `${stat.ino}:${stat.mtimeMs}:${stat.ctimeMs}`, tamperedWarning = (cwd, breaks) => `the ledger was edited, or a row was removed or moved (${breaks.slice(0, 3).map((row) => `${row.reason} at row ${row.seq}`).join(", ")}${breaks.length > 3 ? ", …" : ""}): no verdict is accepted until it is repaired. ${tamperedUnblock(cwd)}`, isLiveVerdict = (row, retired) => row.type === "verdict" && typeof row.result === "string" && !retired.has(row.id), RENAMED, renameAwareBranch = (scopeOf, branch) => {
15822
16048
  return (target) => {
15823
16049
  const own = typeof branch === "string" ? branch : null;
15824
16050
  const theirs = typeof target.branch === "string" ? target.branch : null;
@@ -15835,7 +16061,7 @@ ${body}`), TAIL_BYTES, lastLine = (fd, size) => {
15835
16061
  if (derivesFrom(author, session) || derivesFrom(session, author))
15836
16062
  return true;
15837
16063
  return false;
15838
- }, independenceReasons = (row, authors) => {
16064
+ }, TRUST_REASONS, SHELL_VOUCHED_HOSTS, untrusted = (reasons) => reasons.some((reason) => TRUST_REASONS.has(reason)), independenceReasons = (row, authors) => {
15839
16065
  const reasons = [];
15840
16066
  if (!row.actor.session)
15841
16067
  reasons.push("no_session");
@@ -15897,6 +16123,7 @@ ${body}`), TAIL_BYTES, lastLine = (fd, size) => {
15897
16123
  return brief.pr === null ? "workit pr create" : `workit pr status --pr ${brief.pr}`;
15898
16124
  };
15899
16125
  var init_ledger = __esm(() => {
16126
+ init_store_lock();
15900
16127
  init_vcs_config();
15901
16128
  init_rev();
15902
16129
  init_host_session();
@@ -15935,14 +16162,14 @@ var init_ledger = __esm(() => {
15935
16162
  return null;
15936
16163
  throw error;
15937
16164
  }
15938
- const token = `${process.pid}-${randomBytes2(8).toString("hex")}`;
16165
+ const token = `${process.pid}-${randomBytes3(8).toString("hex")}`;
15939
16166
  fs12.writeFileSync(path15.join(lock, LOCK_OWNER), token);
15940
16167
  return token;
15941
16168
  },
15942
16169
  release(lock, token) {
15943
16170
  if (lockToken(lock) !== token)
15944
16171
  return false;
15945
- const tomb = `${lock}.release-${randomBytes2(6).toString("hex")}`;
16172
+ const tomb = `${lock}.release-${randomBytes3(6).toString("hex")}`;
15946
16173
  try {
15947
16174
  fs12.renameSync(lock, tomb);
15948
16175
  } catch {
@@ -15959,7 +16186,7 @@ var init_ledger = __esm(() => {
15959
16186
  },
15960
16187
  token: lockToken,
15961
16188
  reap(lock, observed) {
15962
- const tomb = `${lock}.reap-${randomBytes2(6).toString("hex")}`;
16189
+ const tomb = `${lock}.reap-${randomBytes3(6).toString("hex")}`;
15963
16190
  try {
15964
16191
  fs12.renameSync(lock, tomb);
15965
16192
  } catch {
@@ -15978,7 +16205,24 @@ var init_ledger = __esm(() => {
15978
16205
  }
15979
16206
  };
15980
16207
  TAIL_BYTES = 64 * 1024;
16208
+ TAMPER_REASONS = new Set(["hash_mismatch", "broken_link"]);
16209
+ tamperCache = new Map;
15981
16210
  RENAMED = /^branch: renamed refs\/heads\/(.+) to refs\/heads\/(.+)$/iu;
16211
+ TRUST_REASONS = new Set([
16212
+ "unsigned",
16213
+ "hash_mismatch",
16214
+ "broken_link",
16215
+ "duplicate_id",
16216
+ "unissued_session",
16217
+ "unbound_session"
16218
+ ]);
16219
+ SHELL_VOUCHED_HOSTS = new Set([
16220
+ "cli",
16221
+ "opencode",
16222
+ "pi",
16223
+ "codex_cli",
16224
+ "codex_desktop"
16225
+ ]);
15982
16226
  OBSERVED_ONLY = new Set([
15983
16227
  "check",
15984
16228
  "merge.unverified",
@@ -63713,7 +63957,8 @@ var init_changelog = __esm(() => {
63713
63957
  });
63714
63958
 
63715
63959
  // packages/workit-core/src/core/hygiene.ts
63716
- import { existsSync as existsSync9, readFileSync as readFileSync9, writeFileSync as writeFileSync4 } from "node:fs";
63960
+ import { spawnSync as spawnSync12 } from "node:child_process";
63961
+ import { existsSync as existsSync9, readFileSync as readFileSync9, readdirSync as readdirSync5, writeFileSync as writeFileSync4 } from "node:fs";
63717
63962
  import path26 from "node:path";
63718
63963
  var repoRoot2, templatesDir = () => path26.join(repoRoot2, "templates", "hygiene"), packageJson = (root) => {
63719
63964
  if (!existsSync9(path26.join(root, "package.json")))
@@ -63743,6 +63988,23 @@ var repoRoot2, templatesDir = () => path26.join(repoRoot2, "templates", "hygiene
63743
63988
  }
63744
63989
  }
63745
63990
  return "";
63991
+ }, projectTarget = (dir) => {
63992
+ const start = path26.resolve(dir);
63993
+ const top = spawnSync12("git", ["rev-parse", "--show-toplevel"], { cwd: start, encoding: "utf8" });
63994
+ const root = top.status === 0 ? (top.stdout ?? "").trim() : "";
63995
+ if (root)
63996
+ return { ok: true, root: path26.resolve(root) };
63997
+ let children = [];
63998
+ try {
63999
+ children = readdirSync5(start, { withFileTypes: true }).filter((entry) => entry.isDirectory() && existsSync9(path26.join(start, entry.name, ".git"))).map((entry) => path26.join(start, entry.name)).toSorted();
64000
+ } catch {
64001
+ children = [];
64002
+ }
64003
+ const where = children.length > 0 ? `run it inside one of its repositories: ${children.slice(0, 5).map((child) => `cd ${child}`).join(", ")}${children.length > 5 ? ` (+${children.length - 5} more)` : ""}` : "cd <repo> (or git init here) and run workit init again";
64004
+ return {
64005
+ ok: false,
64006
+ refused: `${start} is not a git repository, so no project files were added there; ${where}`
64007
+ };
63746
64008
  }, planHygieneFiles = (root, opts = {}) => {
63747
64009
  const openSource = opts.includeOpenSource ?? isOpenSource(root);
63748
64010
  const files = ["CHANGELOG.md", "README.md", ".editorconfig", ".gitattributes"];
@@ -63967,13 +64229,13 @@ var init_support_matrix = __esm(() => {
63967
64229
  });
63968
64230
 
63969
64231
  // packages/workit-cli/src/admin/host-install.ts
63970
- import { spawnSync as spawnSync12 } from "node:child_process";
64232
+ import { spawnSync as spawnSync13 } from "node:child_process";
63971
64233
  import {
63972
64234
  accessSync,
63973
64235
  constants as constants2,
63974
64236
  existsSync as existsSync11,
63975
64237
  readFileSync as readFileSync11,
63976
- readdirSync as readdirSync5,
64238
+ readdirSync as readdirSync6,
63977
64239
  realpathSync as realpathSync6,
63978
64240
  statSync as statSync2
63979
64241
  } from "node:fs";
@@ -64016,7 +64278,7 @@ function findHostExecutable(name, options = {}) {
64016
64278
  [path29.join(home, ".nvm", "versions", "node"), "bin"]
64017
64279
  ]) {
64018
64280
  try {
64019
- for (const entry of readdirSync5(base, { withFileTypes: true })) {
64281
+ for (const entry of readdirSync6(base, { withFileTypes: true })) {
64020
64282
  if (entry.isDirectory())
64021
64283
  dirs.push(path29.join(base, entry.name, tail));
64022
64284
  }
@@ -64238,7 +64500,7 @@ function runHostCommand(step, context = {}) {
64238
64500
  stderr: `Cannot safely execute batch shim ${step.command}; resolve its Node.js CLI entrypoint and retry`
64239
64501
  };
64240
64502
  }
64241
- const result = spawnSync12(step.command, step.args, {
64503
+ const result = spawnSync13(step.command, step.args, {
64242
64504
  cwd: step.cwd,
64243
64505
  env: (() => {
64244
64506
  const home = context.home ?? context.env?.HOME ?? os7.homedir();
@@ -64292,6 +64554,40 @@ var resolveWindowsShimScript = (shim) => {
64292
64554
  } catch {
64293
64555
  return false;
64294
64556
  }
64557
+ }, OPENCODE_PLUGIN_SCOPE = "@brainervirus", OPENCODE_PLUGIN_NAME = "workit-opencode", packageVersionAt = (root, name) => {
64558
+ try {
64559
+ const pkg = JSON.parse(readFileSync11(path29.join(root, "package.json"), "utf8"));
64560
+ return pkg.name === name && typeof pkg.version === "string" ? pkg.version : null;
64561
+ } catch {
64562
+ return null;
64563
+ }
64564
+ }, compareVersions = (a, b) => {
64565
+ const pa = a.split(/[.+-]/).map((n) => Number(n) || 0);
64566
+ const pb = b.split(/[.+-]/).map((n) => Number(n) || 0);
64567
+ for (let i = 0;i < Math.max(pa.length, pb.length); i++) {
64568
+ const d = (pa[i] ?? 0) - (pb[i] ?? 0);
64569
+ if (d !== 0)
64570
+ return d;
64571
+ }
64572
+ return 0;
64573
+ }, openCodeCacheDir = (home, env = process.env) => path29.join(env.XDG_CACHE_HOME || path29.join(home, ".cache"), "opencode"), subdirs = (dir) => {
64574
+ try {
64575
+ return readdirSync6(dir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => path29.join(dir, entry.name));
64576
+ } catch {
64577
+ return [];
64578
+ }
64579
+ }, openCodeInstalledPlugin = (home, env = process.env) => {
64580
+ const name = `${OPENCODE_PLUGIN_SCOPE}/${OPENCODE_PLUGIN_NAME}`;
64581
+ const cache = openCodeCacheDir(home, env);
64582
+ const specDirs = (layout) => subdirs(path29.join(cache, layout, OPENCODE_PLUGIN_SCOPE)).filter((dir) => path29.basename(dir) === `${OPENCODE_PLUGIN_NAME}@latest`);
64583
+ const installs = [...specDirs("npm").flatMap(subdirs), ...specDirs("packages")].map((dir) => path29.join(dir, "node_modules", OPENCODE_PLUGIN_SCOPE, OPENCODE_PLUGIN_NAME));
64584
+ let best = null;
64585
+ for (const root of installs) {
64586
+ const version = packageVersionAt(root, name);
64587
+ if (version && (!best || compareVersions(version, best.version) > 0))
64588
+ best = { root, version };
64589
+ }
64590
+ return best;
64295
64591
  }, isCanonicalCodexPackage = (root) => {
64296
64592
  for (const file of [
64297
64593
  path29.join(root, ".codex-plugin", "plugin.json"),
@@ -64311,7 +64607,7 @@ var resolveWindowsShimScript = (shim) => {
64311
64607
  if (isCanonicalCodexPackage(root))
64312
64608
  return true;
64313
64609
  try {
64314
- return readdirSync5(root, { withFileTypes: true }).some((entry) => entry.isDirectory() && isCanonicalCodexPackage(path29.join(root, entry.name)));
64610
+ return readdirSync6(root, { withFileTypes: true }).some((entry) => entry.isDirectory() && isCanonicalCodexPackage(path29.join(root, entry.name)));
64315
64611
  } catch {
64316
64612
  return false;
64317
64613
  }
@@ -64320,7 +64616,7 @@ var resolveWindowsShimScript = (shim) => {
64320
64616
  return true;
64321
64617
  const root = path29.join(codexHome, "plugins", "cache");
64322
64618
  try {
64323
- for (const marketplace of readdirSync5(root, { withFileTypes: true })) {
64619
+ for (const marketplace of readdirSync6(root, { withFileTypes: true })) {
64324
64620
  if (!marketplace.isDirectory())
64325
64621
  continue;
64326
64622
  if (isPackageOrVersionDirectory(path29.join(root, marketplace.name, "workit")))
@@ -64398,9 +64694,9 @@ var init_host_install = __esm(() => {
64398
64694
  });
64399
64695
 
64400
64696
  // packages/workit-core/src/core/skill-manifests.ts
64401
- import { cpSync as cpSync3, existsSync as existsSync12, readFileSync as readFileSync12, readdirSync as readdirSync6, statSync as statSync3, writeFileSync as writeFileSync5 } from "node:fs";
64697
+ import { cpSync as cpSync3, existsSync as existsSync12, readFileSync as readFileSync12, readdirSync as readdirSync7, statSync as statSync3, writeFileSync as writeFileSync5 } from "node:fs";
64402
64698
  import path30 from "node:path";
64403
- var WORKIT_METHOD_SKILLS, skillManifestNames = (root) => existsSync12(root) ? readdirSync6(root).filter((name) => existsSync12(path30.join(root, name, "SKILL.md"))).toSorted() : [], validateSkillManifests = (root, expected, label) => {
64699
+ var WORKIT_METHOD_SKILLS, skillManifestNames = (root) => existsSync12(root) ? readdirSync7(root).filter((name) => existsSync12(path30.join(root, name, "SKILL.md"))).toSorted() : [], validateSkillManifests = (root, expected, label) => {
64404
64700
  const actual = skillManifestNames(root);
64405
64701
  const missing = expected.filter((name) => !actual.includes(name));
64406
64702
  const extra = actual.filter((name) => !expected.includes(name));
@@ -64412,7 +64708,7 @@ var WORKIT_METHOD_SKILLS, skillManifestNames = (root) => existsSync12(root) ? re
64412
64708
  const pending = [path30.join(pluginDir, "skills")];
64413
64709
  while (pending.length > 0) {
64414
64710
  const dir = pending.pop();
64415
- for (const entry of readdirSync6(dir, { withFileTypes: true })) {
64711
+ for (const entry of readdirSync7(dir, { withFileTypes: true })) {
64416
64712
  const file = path30.join(dir, entry.name);
64417
64713
  if (entry.isDirectory())
64418
64714
  pending.push(file);
@@ -64443,7 +64739,7 @@ var init_skill_manifests = __esm(() => {
64443
64739
  });
64444
64740
 
64445
64741
  // packages/workit-core/src/git/session-hook.ts
64446
- import { spawnSync as spawnSync13 } from "node:child_process";
64742
+ import { spawnSync as spawnSync14 } from "node:child_process";
64447
64743
  import {
64448
64744
  chmodSync,
64449
64745
  existsSync as existsSync13,
@@ -64638,7 +64934,7 @@ add_trailer "$(git rev-parse --git-path COMMIT_EDITMSG)"
64638
64934
  [ "$2" != merge ] || add_trailer "$(git rev-parse --git-path MERGE_MSG)"
64639
64935
  exit 0
64640
64936
  `, 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) => {
64641
- const r = spawnSync13("git", args, {
64937
+ const r = spawnSync14("git", args, {
64642
64938
  cwd,
64643
64939
  encoding: "utf8",
64644
64940
  timeout: GIT_TIMEOUTS.local,
@@ -64799,14 +65095,14 @@ ${manualTrailerLine()}
64799
65095
  });
64800
65096
 
64801
65097
  // packages/workit-cli/src/admin/doctor.ts
64802
- import { spawnSync as spawnSync14 } from "node:child_process";
65098
+ import { spawnSync as spawnSync15 } from "node:child_process";
64803
65099
  import { createHash as createHash14 } from "node:crypto";
64804
65100
  import {
64805
65101
  existsSync as existsSync14,
64806
65102
  lstatSync as lstatSync5,
64807
65103
  mkdirSync as mkdirSync6,
64808
65104
  mkdtempSync,
64809
- readdirSync as readdirSync7,
65105
+ readdirSync as readdirSync8,
64810
65106
  readFileSync as readFileSync14,
64811
65107
  readlinkSync as readlinkSync2,
64812
65108
  rmSync as rmSync3,
@@ -64832,7 +65128,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
64832
65128
  const configDir = options.configDir ?? env.WORKFLOW_TOOLKIT_CONFIG ?? env.WORKFLOW_TOOLKIT_CONFIG_DIR ?? path32.join(home, ".config", "workit");
64833
65129
  const stateDir = options.stateDir ?? env.WORKFLOW_TOOLKIT_STATE ?? path32.join(home, ".local", "state", "workit");
64834
65130
  const cwd = options.cwd ?? process.cwd();
64835
- const dev = options.dev ?? env.WORKFLOW_TOOLKIT_DEV ?? findDevFromCwd(cwd);
65131
+ const dev = options.dev?.trim() || env.WORKFLOW_TOOLKIT_DEV?.trim() || findDevFromCwd(cwd);
64836
65132
  return {
64837
65133
  host: options.host ?? "cli",
64838
65134
  home,
@@ -64842,7 +65138,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
64842
65138
  workspaceRoot: options.workspaceRoot ?? env.WORKFLOW_WORKSPACE_ROOT ?? cwd,
64843
65139
  dev,
64844
65140
  opencodeConfig: options.opencodeConfig ?? path32.join(home, ".config", "opencode", "opencode.json"),
64845
- opencodePackageCacheDir: options.opencodePackageCacheDir ?? path32.join(home, ".cache", "opencode", "packages", "@brainervirus", "workit-opencode@latest"),
65141
+ opencodePackageCacheDir: options.opencodePackageCacheDir ?? null,
64846
65142
  cursorSettings: options.cursorSettings ?? path32.join(home, ".cursor", "settings.json"),
64847
65143
  cursorMcp: options.cursorMcp ?? path32.join(home, ".cursor", "mcp.json"),
64848
65144
  cursorPluginDir: options.cursorPluginDir ?? path32.join(home, ".cursor", "plugins", "local", "workit"),
@@ -64888,7 +65184,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
64888
65184
  }
64889
65185
  return null;
64890
65186
  }, versionOf = (bin, env, timeout) => {
64891
- const r = spawnSync14(bin, ["--version"], { encoding: "utf8", env, timeout });
65187
+ const r = spawnSync15(bin, ["--version"], { encoding: "utf8", env, timeout });
64892
65188
  if (r.error)
64893
65189
  return null;
64894
65190
  return (r.stdout ?? "").trim();
@@ -64906,7 +65202,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
64906
65202
  if (env.BUN && existsSync14(env.BUN))
64907
65203
  return env.BUN;
64908
65204
  for (const candidate of [
64909
- path32.join(os8.homedir(), ".bun/bin/bun"),
65205
+ path32.join(env.HOME || os8.homedir(), ".bun/bin/bun"),
64910
65206
  "/usr/local/bin/bun",
64911
65207
  "/usr/bin/bun"
64912
65208
  ]) {
@@ -64915,47 +65211,50 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
64915
65211
  }
64916
65212
  return commandOnPath("bun", env) ? "bun" : null;
64917
65213
  }, checkRuntime = (res) => {
64918
- const node = versionOf("node", res.env);
64919
- const nodeOk = node !== null && semverAtLeast(node, SUPPORT_MATRIX.node.minimum);
65214
+ const running = `v${process.versions.node}`;
65215
+ const runningOk = semverAtLeast(running, SUPPORT_MATRIX.node.minimum);
65216
+ const pathNode = versionOf("node", res.env);
64920
65217
  const bun = resolveBun(res.env);
64921
65218
  const bunVersion = bun ? versionOf(bun, res.env) : null;
64922
65219
  const bunOk = bunVersion !== null;
64923
65220
  const needsBun = res.dev !== null;
64924
- if (!nodeOk) {
65221
+ if (!runningOk) {
64925
65222
  return {
64926
65223
  id: "runtime",
64927
65224
  status: "fail",
64928
- detail: `node ${SUPPORT_MATRIX.node.minimum}+ required (found ${node ?? "none on PATH"})`,
65225
+ detail: `node ${SUPPORT_MATRIX.node.minimum}+ required (workit runs under ${running} at ${process.execPath})`,
64929
65226
  fix: `Install Node ${SUPPORT_MATRIX.node.minimum}+ (declared support: ${SUPPORT_MATRIX.node.minimum}/current)`
64930
65227
  };
64931
65228
  }
64932
- if (!bunOk && needsBun) {
65229
+ const pathNote = pathNode !== null && pathNode !== running ? `; node on PATH is ${pathNode}${semverAtLeast(pathNode, SUPPORT_MATRIX.node.minimum) ? "" : ` (below ${SUPPORT_MATRIX.node.minimum}; it does not run this CLI)`}` : "";
65230
+ if (pathNode === null) {
64933
65231
  return {
64934
65232
  id: "runtime",
64935
- status: "fail",
64936
- detail: `bun not found on PATH (dev checkout requires the pinned toolchain ${SUPPORT_MATRIX.bun})`,
64937
- fix: `Install bun ${SUPPORT_MATRIX.bun} (curl -fsSL https://bun.sh/install | bash)`
65233
+ status: "warn",
65234
+ detail: `workit runs under node ${running}, but no node is on PATH for host hooks`,
65235
+ fix: `Put Node ${SUPPORT_MATRIX.node.minimum}+ on PATH (host hooks launch \`node\`)`
64938
65236
  };
64939
65237
  }
64940
- if (!bunOk) {
65238
+ if (!bunOk && needsBun) {
64941
65239
  return {
64942
65240
  id: "runtime",
64943
- status: "warn",
64944
- detail: "bun not found on PATH — not required for published artifacts",
64945
- fix: "Install bun for development/installer use"
65241
+ status: "fail",
65242
+ detail: `bun not found on PATH (dev checkout requires the pinned toolchain ${SUPPORT_MATRIX.bun})`,
65243
+ fix: `Install bun ${SUPPORT_MATRIX.bun} (curl -fsSL https://bun.sh/install | bash)`
64946
65244
  };
64947
65245
  }
65246
+ const pathOld = !semverAtLeast(pathNode, SUPPORT_MATRIX.node.minimum);
64948
65247
  return {
64949
65248
  id: "runtime",
64950
- status: "pass",
64951
- detail: `node ${node} (>=${SUPPORT_MATRIX.node.minimum}), bun ${bunVersion ?? "n/a"}`
65249
+ status: bunOk && !pathOld ? "pass" : "info",
65250
+ detail: `node ${running} (>=${SUPPORT_MATRIX.node.minimum})${pathNote}, ${bunOk ? `bun ${bunVersion}` : "no bun (needed only for a dev checkout)"}`
64952
65251
  };
64953
65252
  }, checkVersions = (res) => {
64954
65253
  if (!res.dev) {
64955
65254
  return {
64956
65255
  id: "versions",
64957
- status: "warn",
64958
- detail: "no dev checkout found (WORKFLOW_TOOLKIT_DEV) — skipping version parity"
65256
+ status: "info",
65257
+ detail: "installed package, not a dev checkout — version parity applies to checkouts only"
64959
65258
  };
64960
65259
  }
64961
65260
  const corePkg = readJson(path32.join(res.dev, "packages/workit-core/package.json"));
@@ -64969,7 +65268,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
64969
65268
  const refs = new Set;
64970
65269
  for (const name of ["workit-opencode", "workit-cursor", "workit-cli"]) {
64971
65270
  const pkg = readJson(path32.join(res.dev, "packages", name, "package.json"));
64972
- const dep = pkg?.dependencies?.["@brainervirus/workit-core"];
65271
+ const dep = pkg?.dependencies?.["@brainervirus/workit-core"] ?? pkg?.devDependencies?.["@brainervirus/workit-core"];
64973
65272
  if (typeof dep === "string")
64974
65273
  refs.add(dep);
64975
65274
  }
@@ -65066,10 +65365,16 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
65066
65365
  status: "pass",
65067
65366
  detail: `codex CLI ${installed} matches the qualified pin`
65068
65367
  };
65368
+ if (semverAtLeast(installed, qualified))
65369
+ return {
65370
+ id: "codex_pin",
65371
+ status: "info",
65372
+ detail: `codex CLI ${installed} is newer than the qualified ${qualified}`
65373
+ };
65069
65374
  return {
65070
65375
  id: "codex_pin",
65071
65376
  status: "warn",
65072
- detail: `codex CLI ${installed} differs from the qualified ${qualified}`,
65377
+ detail: `codex CLI ${installed} is older than the qualified ${qualified}`,
65073
65378
  fix: `Reinstall the qualified Codex CLI ${qualified} or record fresh qualification evidence`
65074
65379
  };
65075
65380
  }, readTomlTables = (file) => {
@@ -65126,7 +65431,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
65126
65431
  const dir = path32.join(codexHome, "plugins", "cache", marketplace, "workit");
65127
65432
  let versions = [];
65128
65433
  try {
65129
- versions = readdirSync7(dir).filter((v) => existsSync14(path32.join(dir, v, ".codex-plugin")));
65434
+ versions = readdirSync8(dir).filter((v) => existsSync14(path32.join(dir, v, ".codex-plugin")));
65130
65435
  } catch {
65131
65436
  versions = [];
65132
65437
  }
@@ -65235,7 +65540,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
65235
65540
  const installed = [];
65236
65541
  for (const install of installs) {
65237
65542
  const source = install.root ? path32.join(install.root, "agents") : null;
65238
- const files = source && existsSync14(source) ? readdirSync7(source).filter((f) => f.endsWith(".toml")).toSorted() : [];
65543
+ const files = source && existsSync14(source) ? readdirSync8(source).filter((f) => f.endsWith(".toml")).toSorted() : [];
65239
65544
  if (files.length === 0) {
65240
65545
  problems.push(`${install.id} ${install.version ?? "?"} bundles no agents`);
65241
65546
  fixes.push(`codex plugin remove ${install.id} && codex plugin add ${install.id}`);
@@ -65463,8 +65768,8 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
65463
65768
  if (!dev && res.host === "opencode") {
65464
65769
  return {
65465
65770
  id: "assets",
65466
- status: "warn",
65467
- detail: "no dev checkout found (WORKFLOW_TOOLKIT_DEV) — skipping asset check"
65771
+ status: "info",
65772
+ detail: "installed package — OpenCode loads the published assets, no checkout to compare"
65468
65773
  };
65469
65774
  }
65470
65775
  return {
@@ -65499,7 +65804,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
65499
65804
  `)) {
65500
65805
  return false;
65501
65806
  }
65502
- return spawnSync14(runtime, ["--check", entry], { encoding: "utf8", env }).status === 0;
65807
+ return spawnSync15(runtime, ["--check", entry], { encoding: "utf8", env }).status === 0;
65503
65808
  } catch {
65504
65809
  return false;
65505
65810
  }
@@ -65589,8 +65894,8 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
65589
65894
  if (!dev && res.host !== "cursor") {
65590
65895
  return {
65591
65896
  id: "launcher",
65592
- status: "warn",
65593
- detail: "no dev checkout found (WORKFLOW_TOOLKIT_DEV) — skipping non-Cursor launcher checks"
65897
+ status: "info",
65898
+ detail: "installed package — non-Cursor launchers ship inside each host plugin, no checkout to check"
65594
65899
  };
65595
65900
  }
65596
65901
  return {
@@ -65630,7 +65935,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
65630
65935
  fix: "Re-run install-cursor-plugin.sh (or `workit init` with Cursor) to rewrite the hook entries"
65631
65936
  };
65632
65937
  const started = performance.now();
65633
- const probe = spawnSync14("node", [launcher, "--probe", "workit-cursor-hook"], {
65938
+ const probe = spawnSync15("node", [launcher, "--probe", "workit-cursor-hook"], {
65634
65939
  encoding: "utf8",
65635
65940
  env: { ...res.env, WORKIT_CURSOR_HOOK_NPX_OFFLINE: "1" },
65636
65941
  timeout: 40000,
@@ -65699,18 +66004,18 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
65699
66004
  fix: "Install git and ensure it is on PATH"
65700
66005
  };
65701
66006
  }
65702
- if (process.platform !== "win32" && !commandOnPath("flock", res.env)) {
66007
+ if (res.dev && process.platform !== "win32" && !commandOnPath("flock", res.env)) {
65703
66008
  return {
65704
66009
  id: "utility",
65705
66010
  status: "warn",
65706
- detail: "flock (util-linux) not found — sync-runtime requires it for locking",
65707
- fix: "Install util-linux (flock)"
66011
+ detail: "flock not found — the dev checkout's sync-runtime requires it for locking",
66012
+ fix: process.platform === "darwin" ? "brew install flock (Homebrew's util-linux is keg-only and leaves flock off PATH)" : "Install util-linux (flock)"
65708
66013
  };
65709
66014
  }
65710
66015
  return {
65711
66016
  id: "utility",
65712
66017
  status: "pass",
65713
- detail: "git (and flock where required) on PATH"
66018
+ detail: res.dev ? "git and flock on PATH" : "git on PATH"
65714
66019
  };
65715
66020
  }, isFragileCachePin = (entry) => {
65716
66021
  const n = entry.replaceAll("\\", "/").toLowerCase();
@@ -65804,7 +66109,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
65804
66109
  if (!cmd)
65805
66110
  return null;
65806
66111
  try {
65807
- const r = spawnSync14(cmd, ["view", pkgName, "version"], {
66112
+ const r = spawnSync15(cmd, ["view", pkgName, "version"], {
65808
66113
  encoding: "utf8",
65809
66114
  timeout: 20000,
65810
66115
  env: res.env
@@ -65817,9 +66122,18 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
65817
66122
  }, installedPluginVersion = (res) => {
65818
66123
  const pkg = readJson(path32.join(res.cursorPluginDir, "package.json"));
65819
66124
  return typeof pkg?.version === "string" && pkg.version ? pkg.version : null;
65820
- }, installedOpenCodeCacheVersion = (res) => {
65821
- const pkg = readJson(path32.join(res.opencodePackageCacheDir, "node_modules", "@brainervirus", "workit-opencode", "package.json"));
65822
- return typeof pkg?.version === "string" && pkg.version ? pkg.version : null;
66125
+ }, installedOpenCodeCache = (res) => {
66126
+ if (res.opencodePackageCacheDir !== null) {
66127
+ const pkg = readJson(path32.join(res.opencodePackageCacheDir, "node_modules", "@brainervirus", "workit-opencode", "package.json"));
66128
+ return typeof pkg?.version === "string" && pkg.version ? { version: pkg.version, dir: res.opencodePackageCacheDir } : null;
66129
+ }
66130
+ const found = openCodeInstalledPlugin(res.home, res.env);
66131
+ if (!found)
66132
+ return null;
66133
+ let dir = path32.dirname(path32.dirname(path32.dirname(found.root)));
66134
+ if (path32.basename(dir) !== "workit-opencode@latest")
66135
+ dir = path32.dirname(dir);
66136
+ return { version: found.version, dir };
65823
66137
  }, checkOpenCodePackageCache = (res) => {
65824
66138
  if (!existsSync14(res.opencodeConfig)) {
65825
66139
  return {
@@ -65851,8 +66165,9 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
65851
66165
  detail: `opencode pin ${pin} is an exact version — not compared to registry latest`
65852
66166
  };
65853
66167
  }
65854
- const installed = installedOpenCodeCacheVersion(res);
65855
- if (installed === null) {
66168
+ const cache = installedOpenCodeCache(res);
66169
+ const installed = cache?.version ?? null;
66170
+ if (cache === null || installed === null) {
65856
66171
  return {
65857
66172
  id: "stale_install",
65858
66173
  status: "pass",
@@ -65866,7 +66181,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
65866
66181
  status: "warn",
65867
66182
  registryProbed: true,
65868
66183
  detail: "registry_unreachable: cannot compare OpenCode @latest cache against published workit-opencode",
65869
- fix: `Retry when npm is reachable, or remove ${res.opencodePackageCacheDir} and restart OpenCode to re-resolve`
66184
+ fix: `Retry when npm is reachable, or remove ${cache.dir} and restart OpenCode to re-resolve`
65870
66185
  };
65871
66186
  }
65872
66187
  if (!semverAtLeast(installed, expected)) {
@@ -65875,7 +66190,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
65875
66190
  status: "fail",
65876
66191
  registryProbed: true,
65877
66192
  detail: `stale_install: OpenCode @latest cache has workit-opencode ${installed} behind published ${expected}`,
65878
- fix: `Remove ${res.opencodePackageCacheDir} and restart OpenCode — it re-resolves @latest on the next launch`
66193
+ fix: `Remove ${cache.dir} and restart OpenCode — it re-resolves @latest on the next launch`
65879
66194
  };
65880
66195
  }
65881
66196
  return {
@@ -66344,7 +66659,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
66344
66659
  }, defaultIdentityProbes = (env) => ({
66345
66660
  origin: (cwd) => {
66346
66661
  try {
66347
- const out = spawnSync14("git", ["remote", "get-url", "origin"], {
66662
+ const out = spawnSync15("git", ["remote", "get-url", "origin"], {
66348
66663
  cwd,
66349
66664
  encoding: "utf8",
66350
66665
  env
@@ -66356,7 +66671,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
66356
66671
  },
66357
66672
  ghLogin: (e) => {
66358
66673
  try {
66359
- const out = spawnSync14("gh", ["api", "user", "--jq", ".login"], { encoding: "utf8", env: e });
66674
+ const out = spawnSync15("gh", ["api", "user", "--jq", ".login"], { encoding: "utf8", env: e });
66360
66675
  const login = (out.stdout ?? "").trim();
66361
66676
  return out.status === 0 && login ? login : null;
66362
66677
  } catch {
@@ -66365,7 +66680,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
66365
66680
  },
66366
66681
  glabLogin: (e) => {
66367
66682
  try {
66368
- const out = spawnSync14("glab", ["api", "user", "--jq", ".username"], {
66683
+ const out = spawnSync15("glab", ["api", "user", "--jq", ".username"], {
66369
66684
  encoding: "utf8",
66370
66685
  env: e
66371
66686
  });
@@ -66377,7 +66692,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
66377
66692
  },
66378
66693
  sshLogin: (host) => {
66379
66694
  try {
66380
- const out = spawnSync14("ssh", ["-o", "BatchMode=yes", "-o", "ConnectTimeout=5", "-T", `git@${host}`], {
66695
+ const out = spawnSync15("ssh", ["-o", "BatchMode=yes", "-o", "ConnectTimeout=5", "-T", `git@${host}`], {
66381
66696
  encoding: "utf8",
66382
66697
  env
66383
66698
  });
@@ -66534,10 +66849,10 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
66534
66849
  fix: repair,
66535
66850
  registryProbed
66536
66851
  };
66537
- }, HOOK_ISSUED_MARKER = "workit-issued-sessions/2", hookRecordsIssued = (root) => {
66852
+ }, HOOK_ISSUED_MARKER = "workit-issued-sessions/3", hookRecordsIssued = (root) => {
66538
66853
  let files;
66539
66854
  try {
66540
- files = readdirSync7(path32.join(root, "dist")).filter((f) => f.endsWith(".js"));
66855
+ files = readdirSync8(path32.join(root, "dist")).filter((f) => f.endsWith(".js"));
66541
66856
  } catch {
66542
66857
  return null;
66543
66858
  }
@@ -66596,12 +66911,12 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
66596
66911
  if (cached)
66597
66912
  return cached;
66598
66913
  const viaShell = process.platform === "win32" && /\.(?:cmd|bat)$/i.test(bin);
66599
- const r = viaShell ? spawnSync14(`"${bin}" --version`, {
66914
+ const r = viaShell ? spawnSync15(`"${bin}" --version`, {
66600
66915
  encoding: "utf8",
66601
66916
  env,
66602
66917
  timeout: WORKIT_PROBE_TIMEOUT_MS,
66603
66918
  shell: true
66604
- }) : spawnSync14(bin, ["--version"], { encoding: "utf8", env, timeout: WORKIT_PROBE_TIMEOUT_MS });
66919
+ }) : spawnSync15(bin, ["--version"], { encoding: "utf8", env, timeout: WORKIT_PROBE_TIMEOUT_MS });
66605
66920
  const timedOut = r.error !== undefined && "code" in r.error && r.error.code === "ETIMEDOUT";
66606
66921
  const version = r.status === 0 ? (r.stdout ?? "").match(SEMVER)?.[0] ?? null : null;
66607
66922
  const probe = { version: timedOut ? null : version, timedOut };
@@ -66614,7 +66929,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
66614
66929
  version: i.version
66615
66930
  })),
66616
66931
  { label: "Cursor plugin", version: installedPluginVersion(res) },
66617
- { label: "OpenCode plugin", version: installedOpenCodeCacheVersion(res) }
66932
+ { label: "OpenCode plugin", version: installedOpenCodeCache(res)?.version ?? null }
66618
66933
  ].filter((p) => p.version !== null);
66619
66934
  const newest = plugins.reduce((best, p) => best && semverAtLeast(best.version, p.version) ? best : p, null);
66620
66935
  const target = newest?.version ?? "latest";
@@ -66655,7 +66970,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
66655
66970
  } : c) : raw;
66656
66971
  const failed = checks.filter((c) => c.status === "fail").length;
66657
66972
  const warned = checks.filter((c) => c.status === "warn").length;
66658
- const passed = checks.filter((c) => c.status === "pass").length;
66973
+ const passed = checks.filter((c) => c.status === "pass" || c.status === "info").length;
66659
66974
  const exitCode = failed > 0 ? 1 : 0;
66660
66975
  const offline = !raw.some((c) => ("registryProbed" in c) && c.registryProbed);
66661
66976
  const report = {
@@ -66746,13 +67061,14 @@ import {
66746
67061
  mkdirSync as mkdirSync7,
66747
67062
  mkdtempSync as mkdtempSync2,
66748
67063
  readFileSync as readFileSync15,
66749
- readdirSync as readdirSync8,
67064
+ readdirSync as readdirSync9,
66750
67065
  realpathSync as realpathSync7,
66751
67066
  renameSync as renameSync4,
66752
67067
  rmSync as rmSync4,
66753
67068
  statSync as statSync6,
66754
67069
  writeFileSync as writeFileSync8
66755
67070
  } from "node:fs";
67071
+ import { createRequire as createRequire2 } from "node:module";
66756
67072
  import os9 from "node:os";
66757
67073
  import path33 from "node:path";
66758
67074
  import { isDeepStrictEqual as isDeepStrictEqual2 } from "node:util";
@@ -66789,6 +67105,7 @@ function buildSetupPreview(values, opts = {}) {
66789
67105
  const blocked = [];
66790
67106
  const mutations = [];
66791
67107
  const preserved = [];
67108
+ let projectRefused;
66792
67109
  const overrides = activeSetupOverrides(env);
66793
67110
  for (const entry of [state.config, state.youtrack, state.vcs, state.workspaces]) {
66794
67111
  if (entry.status === "malformed")
@@ -66911,8 +67228,11 @@ function buildSetupPreview(values, opts = {}) {
66911
67228
  }
66912
67229
  }
66913
67230
  }
66914
- if (values.applyProject) {
66915
- const root = path33.resolve(opts.cwd ?? process.cwd());
67231
+ const target = values.applyProject ? projectTarget(opts.cwd ?? process.cwd()) : null;
67232
+ if (target && !target.ok)
67233
+ projectRefused = target.refused;
67234
+ if (target?.ok) {
67235
+ const root = target.root;
66916
67236
  const gitignorePath = path33.join(root, ".gitignore");
66917
67237
  const existing = existsSync15(gitignorePath) ? readFileSync15(gitignorePath, "utf8") : "";
66918
67238
  const existingLines = new Set(existing.split(`
@@ -66931,7 +67251,8 @@ function buildSetupPreview(values, opts = {}) {
66931
67251
  overrides,
66932
67252
  preserved,
66933
67253
  platforms: values.platforms ?? [],
66934
- state
67254
+ state,
67255
+ ...projectRefused === undefined ? {} : { projectRefused }
66935
67256
  };
66936
67257
  }
66937
67258
  function resolveApply(preview, options) {
@@ -67114,7 +67435,14 @@ function adapterRoot(platform, res, preferInstalledAdapter = false) {
67114
67435
  if (res.dev) {
67115
67436
  candidates.push(path33.join(res.dev, "packages", `workit-${platform}`));
67116
67437
  } else {
67117
- candidates.push(path33.join(packageRoot(), "..", `workit-${platform}`));
67438
+ candidates.push(...nodeResolvedAdapters(platform));
67439
+ if (platform === "cursor")
67440
+ candidates.push(stagedCursor);
67441
+ if (platform === "opencode") {
67442
+ const cached = openCodeInstalledPlugin(res.home, res.env);
67443
+ if (cached)
67444
+ candidates.push(cached.root);
67445
+ }
67118
67446
  let dir = path33.resolve(res.cwd);
67119
67447
  while (true) {
67120
67448
  candidates.push(path33.join(dir, "packages", `workit-${platform}`));
@@ -67124,17 +67452,14 @@ function adapterRoot(platform, res, preferInstalledAdapter = false) {
67124
67452
  dir = parent;
67125
67453
  }
67126
67454
  }
67127
- candidates.push(path33.join(res.home, ".local", "share", "workit", "packages", `workit-${platform}`));
67128
- if (platform === "cursor")
67129
- candidates.push(stagedCursor);
67130
67455
  for (const candidate of candidates) {
67131
67456
  if (isAdapter(candidate, platform))
67132
- return candidate;
67457
+ return realRoot(candidate);
67133
67458
  }
67134
67459
  return null;
67135
67460
  }
67136
67461
  function applyOpenCode(root, res) {
67137
- const resolvedPin = opencodePin(root, res);
67462
+ const resolvedPin = root === null ? OPENCODE_NPM_PIN : opencodePin(root, res);
67138
67463
  if (!resolvedPin) {
67139
67464
  return {
67140
67465
  platform: "opencode",
@@ -67433,6 +67758,10 @@ function applySetupPreview(preview, options = {}) {
67433
67758
  root = adapterRoot(platform, res, options.preferInstalledAdapter);
67434
67759
  rootFor.set(platform, root);
67435
67760
  }
67761
+ if (root === null && registersNpmPin(platform, res)) {
67762
+ entries.push(applyOpenCode(null, res));
67763
+ continue;
67764
+ }
67436
67765
  if (root === null) {
67437
67766
  entries.push({
67438
67767
  platform,
@@ -67474,12 +67803,20 @@ function applySetupPreview(preview, options = {}) {
67474
67803
  detail: "existing credential preserved"
67475
67804
  });
67476
67805
  }
67806
+ if (preview.projectRefused) {
67807
+ entries.push({
67808
+ platform: "core",
67809
+ file: path33.resolve(res.cwd),
67810
+ status: "Skipped",
67811
+ detail: preview.projectRefused
67812
+ });
67813
+ }
67477
67814
  const doctor = [];
67478
67815
  for (const platform of preview.platforms) {
67479
67816
  if (platform !== "opencode" && platform !== "cursor")
67480
67817
  continue;
67481
67818
  const root = rootFor.get(platform);
67482
- if (root === null || root === undefined)
67819
+ if (root === undefined || root === null && !registersNpmPin(platform, res))
67483
67820
  continue;
67484
67821
  if (!entries.some((e) => e.platform === platform && e.status !== "Failed"))
67485
67822
  continue;
@@ -67608,6 +67945,16 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
67608
67945
  } catch {
67609
67946
  return false;
67610
67947
  }
67948
+ }, nodeResolvedAdapters = (platform) => {
67949
+ const name = `@brainervirus/workit-${platform}`;
67950
+ const require2 = createRequire2(path33.join(packageRoot(), "package.json"));
67951
+ return (require2.resolve.paths(name) ?? []).map((dir) => path33.join(dir, name));
67952
+ }, realRoot = (root) => {
67953
+ try {
67954
+ return realpathSync7(root);
67955
+ } catch {
67956
+ return root;
67957
+ }
67611
67958
  }, isDevOpenCodeAdapterRoot = (root, dev) => {
67612
67959
  if (dev)
67613
67960
  return true;
@@ -67622,7 +67969,7 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
67622
67969
  return `file://${entry}`;
67623
67970
  }
67624
67971
  return null;
67625
- }, opencodePin = (root, res) => resolveOpenCodePin(root, { dev: res.dev }), CURSOR_HOOKS_FILE, localizedCursorHooks = (shipped, pluginDir) => {
67972
+ }, opencodePin = (root, res) => resolveOpenCodePin(root, { dev: res.dev }), registersNpmPin = (platform, res) => platform === "opencode" && !res.dev, CURSOR_HOOKS_FILE, localizedCursorHooks = (shipped, pluginDir) => {
67626
67973
  try {
67627
67974
  const merged = mergeCursorHooks(JSON.parse(shipped.toString("utf8")), { command: cursorHooksEntry(pluginDir).command }, pluginDir);
67628
67975
  return Buffer.from(`${JSON.stringify(merged.config, null, 2)}
@@ -67632,7 +67979,7 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
67632
67979
  }
67633
67980
  }, samePluginContent = (src, dest, pluginDir, relative = "") => {
67634
67981
  try {
67635
- for (const entry of readdirSync8(src, { withFileTypes: true })) {
67982
+ for (const entry of readdirSync9(src, { withFileTypes: true })) {
67636
67983
  if (entry.name === "node_modules")
67637
67984
  continue;
67638
67985
  const source = path33.join(src, entry.name);
@@ -67647,7 +67994,7 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
67647
67994
  return false;
67648
67995
  }
67649
67996
  }
67650
- for (const entry of readdirSync8(dest, { withFileTypes: true })) {
67997
+ for (const entry of readdirSync9(dest, { withFileTypes: true })) {
67651
67998
  if (existsSync15(path33.join(src, entry.name)))
67652
67999
  continue;
67653
68000
  const rel = path33.join(relative, entry.name);
@@ -67666,7 +68013,7 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
67666
68013
  const sourceRules = path33.join(src, "rules");
67667
68014
  const installedRules = path33.join(dest, "rules");
67668
68015
  try {
67669
- for (const entry of readdirSync8(installedRules, { withFileTypes: true })) {
68016
+ for (const entry of readdirSync9(installedRules, { withFileTypes: true })) {
67670
68017
  if (!entry.isFile() || !entry.name.endsWith(".mdc"))
67671
68018
  continue;
67672
68019
  if (existsSync15(path33.join(sourceRules, entry.name)))
@@ -67683,7 +68030,7 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
67683
68030
  if (existsSync15(legacyRules)) {
67684
68031
  try {
67685
68032
  mkdirSync7(path33.join(res.cursorPluginDir, "rules"), { recursive: true });
67686
- for (const entry of readdirSync8(legacyRules, { withFileTypes: true })) {
68033
+ for (const entry of readdirSync9(legacyRules, { withFileTypes: true })) {
67687
68034
  if (!entry.isFile() || !entry.name.endsWith(".mdc"))
67688
68035
  continue;
67689
68036
  const target = path33.join(res.cursorPluginDir, "rules", entry.name);
@@ -67693,7 +68040,7 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
67693
68040
  } catch {}
67694
68041
  }
67695
68042
  rmSync4(legacy, { recursive: true, force: true });
67696
- }, failedDetail = (report) => report.checks.filter((c) => c.status === "fail").map((c) => `${c.id}: ${c.detail}`).join("; "), setupCompletionGuidance = () => [
68043
+ }, failedDetail = (report) => report.checks.filter((c) => c.status === "fail").map((c) => c.detail.startsWith(`${c.id}:`) ? c.detail : `${c.id}: ${c.detail}`).join("; "), setupCompletionGuidance = () => [
67697
68044
  "Run `workit doctor` to verify your installation.",
67698
68045
  "Run /wk-status in OpenCode to review token setup steps."
67699
68046
  ];
@@ -70762,7 +71109,43 @@ function Screen({
70762
71109
  }, undefined, false, undefined, this)
70763
71110
  ]
70764
71111
  }, undefined, true, undefined, this);
70765
- case "project":
71112
+ case "project": {
71113
+ const target = projectTargetFor(resolveBasePath(draft.values));
71114
+ if (!target.ok) {
71115
+ return /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
71116
+ flexDirection: "column",
71117
+ gap: 1,
71118
+ children: [
71119
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
71120
+ bold: true,
71121
+ children: "Step 6 — Project setup"
71122
+ }, undefined, false, undefined, this),
71123
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
71124
+ color: "yellow",
71125
+ children: [
71126
+ "Skipped: ",
71127
+ target.refused
71128
+ ]
71129
+ }, undefined, true, undefined, this),
71130
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(ConfirmInput, {
71131
+ defaultChoice: "confirm",
71132
+ submitOnEnter: false,
71133
+ onConfirm: () => {
71134
+ dispatch({ type: "set", field: "applyProject", value: true });
71135
+ dispatch({ type: "next" });
71136
+ },
71137
+ onCancel: () => {
71138
+ dispatch({ type: "set", field: "applyProject", value: false });
71139
+ dispatch({ type: "next" });
71140
+ }
71141
+ }, undefined, false, undefined, this),
71142
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
71143
+ dimColor: true,
71144
+ children: "y to keep this note in the summary · n to skip it · either adds no project files · b Back · Esc Cancel"
71145
+ }, undefined, false, undefined, this)
71146
+ ]
71147
+ }, undefined, true, undefined, this);
71148
+ }
70766
71149
  return /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
70767
71150
  flexDirection: "column",
70768
71151
  gap: 1,
@@ -70775,7 +71158,7 @@ function Screen({
70775
71158
  dimColor: true,
70776
71159
  children: [
70777
71160
  "Apply gitignore + hygiene in ",
70778
- resolveBasePath(draft.values),
71161
+ target.root,
70779
71162
  "? (Existing files are never overwritten.)"
70780
71163
  ]
70781
71164
  }, undefined, true, undefined, this),
@@ -70797,6 +71180,7 @@ function Screen({
70797
71180
  }, undefined, false, undefined, this)
70798
71181
  ]
70799
71182
  }, undefined, true, undefined, this);
71183
+ }
70800
71184
  case "summary": {
70801
71185
  const policy = effectivePolicy(draft.values);
70802
71186
  const preview = buildSetupPreview(draft.values, { cwd: resolveBasePath(draft.values) });
@@ -70938,8 +71322,15 @@ function Screen({
70938
71322
  }, undefined, true, undefined, this),
70939
71323
  /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
70940
71324
  children: [
70941
- "Project hygiene: ",
70942
- /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
71325
+ "Project hygiene:",
71326
+ " ",
71327
+ preview.projectRefused ? /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
71328
+ color: "yellow",
71329
+ children: [
71330
+ "skipped — ",
71331
+ preview.projectRefused
71332
+ ]
71333
+ }, undefined, true, undefined, this) : /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
70943
71334
  color: "green",
70944
71335
  children: draft.values.applyProject ? "yes" : "no"
70945
71336
  }, undefined, false, undefined, this)
@@ -71028,7 +71419,11 @@ function Screen({
71028
71419
  }, undefined, false, undefined, this);
71029
71420
  }
71030
71421
  }
71031
- var import_react66, jsx_dev_runtime2, PLATFORM_LABELS, BRANCH_PRESETS, BRANCH_PRESET_DESCRIPTIONS, SCREEN_PLACEHOLDERS, VCS_PROVIDERS, LOCALE_PICKER_OPTIONS, ISSUE_TRACKERS, WORKSPACE_ADVANCED_FIELDS, PROFILE_FIELDS, TRACK_FIELDS, enumFieldOptions = (field) => {
71422
+ var import_react66, jsx_dev_runtime2, lastProjectTarget = null, projectTargetFor = (base) => {
71423
+ if (lastProjectTarget?.base !== base)
71424
+ lastProjectTarget = { base, target: projectTarget(base) };
71425
+ return lastProjectTarget.target;
71426
+ }, PLATFORM_LABELS, BRANCH_PRESETS, BRANCH_PRESET_DESCRIPTIONS, SCREEN_PLACEHOLDERS, VCS_PROVIDERS, LOCALE_PICKER_OPTIONS, ISSUE_TRACKERS, WORKSPACE_ADVANCED_FIELDS, PROFILE_FIELDS, TRACK_FIELDS, enumFieldOptions = (field) => {
71032
71427
  if (field === "commitPolicy.preset")
71033
71428
  return [{ label: "Inherit global", value: "inherit" }, ...commitPresetOptions];
71034
71429
  if (field === "branchPolicy.preset")
@@ -71070,6 +71465,7 @@ var init_steps = __esm(async () => {
71070
71465
  init_logic();
71071
71466
  init_workspaces();
71072
71467
  init_branch_policy();
71468
+ init_hygiene();
71073
71469
  init_wizard_state();
71074
71470
  init_detect_hosts();
71075
71471
  await __promiseAll([
@@ -71461,7 +71857,7 @@ var init_init = __esm(() => {
71461
71857
  });
71462
71858
 
71463
71859
  // packages/workit-cli/src/upgrade.ts
71464
- import { spawnSync as spawnSync15 } from "node:child_process";
71860
+ import { spawnSync as spawnSync16 } from "node:child_process";
71465
71861
  import {
71466
71862
  existsSync as existsSync18,
71467
71863
  mkdtempSync as mkdtempSync3,
@@ -71817,7 +72213,7 @@ async function runLaunchCommand(argv, deps = {}) {
71817
72213
  }
71818
72214
  if (deps.run)
71819
72215
  return deps.run(host, hostArgs).status ?? 1;
71820
- return spawnSync15(launch.command, launch.args, {
72216
+ return spawnSync16(launch.command, launch.args, {
71821
72217
  stdio: "inherit",
71822
72218
  env
71823
72219
  }).status ?? 1;
@@ -71999,7 +72395,7 @@ var init_launch = __esm(() => {
71999
72395
  });
72000
72396
 
72001
72397
  // packages/workit-core/src/knowledge.ts
72002
- import { spawnSync as spawnSync16 } from "node:child_process";
72398
+ import { spawnSync as spawnSync17 } from "node:child_process";
72003
72399
  import fs18 from "node:fs";
72004
72400
  import path38 from "node:path";
72005
72401
  function lintKnowledge(root) {
@@ -72120,7 +72516,7 @@ var AGENTS_BYTE_BUDGET, STEERING_FILES, NEED_BASED_FILES, STANDARDS_FILE = "CODI
72120
72516
  return "unreadable";
72121
72517
  }
72122
72518
  }, trackedTopLevel = (root) => {
72123
- const run = spawnSync16("git", ["ls-files", "-z", "--cached"], {
72519
+ const run = spawnSync17("git", ["ls-files", "-z", "--cached"], {
72124
72520
  cwd: root,
72125
72521
  encoding: "utf8",
72126
72522
  maxBuffer: 256 * 1024 * 1024,
@@ -72488,7 +72884,8 @@ var R = "[REDACTED]", TOKEN_PATTERNS, WEBHOOK, URL_USERINFO, CURL_USER, KEY, ASS
72488
72884
  var init_redact = __esm(() => {
72489
72885
  TOKEN_PATTERNS = [
72490
72886
  /\b(?:gh[pousr]_[A-Za-z0-9]{20,}|github_pat_[A-Za-z0-9_]{20,})/gu,
72491
- /\bgl[a-z]{1,8}-[A-Za-z0-9_-]{16,}/gu,
72887
+ /\b(?:glpat|gloas|gldt|glrtr|glrt|glcbt|glptt|glft|glimt|glagent|glwt|glsoat|glffct)-[A-Za-z0-9_-]{20,}/gu,
72888
+ /\b_gitlab_session=[A-Za-z0-9%_-]{16,}/gu,
72492
72889
  /\bnpm_[A-Za-z0-9]{30,}/gu,
72493
72890
  /\bxox[abposr]-[A-Za-z0-9-]{10,}/gu,
72494
72891
  /\b(?:AKIA|ASIA)[A-Z0-9]{16}\b/gu,
@@ -72522,7 +72919,7 @@ var init_redact = __esm(() => {
72522
72919
  });
72523
72920
 
72524
72921
  // packages/workit-core/src/checks.ts
72525
- import { spawn, spawnSync as spawnSync17 } from "node:child_process";
72922
+ import { spawn, spawnSync as spawnSync18 } from "node:child_process";
72526
72923
  import { createHash as createHash16 } from "node:crypto";
72527
72924
  import fs19 from "node:fs";
72528
72925
  import os13 from "node:os";
@@ -72704,7 +73101,7 @@ function runCheckCommand(argv, options) {
72704
73101
  if (!child?.pid)
72705
73102
  return;
72706
73103
  if (windows)
72707
- spawnSync17("taskkill", ["/pid", String(child.pid), "/T", "/F"], {
73104
+ spawnSync18("taskkill", ["/pid", String(child.pid), "/T", "/F"], {
72708
73105
  stdio: "ignore",
72709
73106
  windowsHide: true
72710
73107
  });
@@ -72975,9 +73372,15 @@ function show(argv, io) {
72975
73372
  return emit(io, fail("invalid_input", error instanceof Error ? error.message : String(error)));
72976
73373
  }
72977
73374
  const tracks = releaseTracksReport(io.cwd);
72978
- const shown = tracks.tracks.length || tracks.error ? { ...autonomy, releaseTracks: tracks } : autonomy;
73375
+ const tierModelIssues = workspaceTierModelIssues(io.cwd);
73376
+ const shown = {
73377
+ ...autonomy,
73378
+ ...tracks.tracks.length || tracks.error ? { releaseTracks: tracks } : {},
73379
+ ...tierModelIssues.length ? { tierModelIssues } : {}
73380
+ };
72979
73381
  return emit(io, ok(shown), (data) => [
72980
73382
  ...data.note ? [`note: ${data.note}`] : [],
73383
+ ...tierModelIssues.map((issue) => `note: ${issue}`),
72981
73384
  data.workspace ? `workspace ${data.workspace} (${data.source === "default" ? "D4 defaults" : `from ${data.source}`})` : "no workspace matches this checkout: D4 defaults apply",
72982
73385
  ...describe2(data.grants, data.configured, data, data.verification),
72983
73386
  ...describeReleaseTracks(tracks).map((line) => ` ${line}`),
@@ -73073,6 +73476,7 @@ usage: ${USAGE2}`)), run9 = (argv, io) => runGrant(argv, io);
73073
73476
  var init_grant = __esm(() => {
73074
73477
  init_autonomy();
73075
73478
  init_release_tracks();
73479
+ init_workspaces();
73076
73480
  init_output();
73077
73481
  init_prompt();
73078
73482
  AGENT_ENV = [
@@ -74040,7 +74444,7 @@ var init_check = __esm(() => {
74040
74444
  var success2 = (data) => ({ ok: true, data }), failure3 = (code, error, unblock) => ({ ok: false, code, error, ...unblock ? { unblock } : {} });
74041
74445
 
74042
74446
  // packages/workit-core/src/git/ops.ts
74043
- import { spawnSync as spawnSync18 } from "node:child_process";
74447
+ import { spawnSync as spawnSync19 } from "node:child_process";
74044
74448
  import { existsSync as existsSync19, readFileSync as readFileSync19 } from "node:fs";
74045
74449
  import path42 from "node:path";
74046
74450
  function operationInProgress(cwd) {
@@ -74355,6 +74759,14 @@ function gitCommit(cwd, input) {
74355
74759
  const session = input.actor.session;
74356
74760
  if (session && !SESSION_SAFE.test(session))
74357
74761
  return failure3("invalid_input", "WORKIT_SESSION_ID must be 1-128 characters of [A-Za-z0-9_.:@/+-]");
74762
+ if (session) {
74763
+ const env = input.env ?? process.env;
74764
+ if (issuedBinding(cwd, session) !== null)
74765
+ return failure3("blocked", `judge_session: ${session} was issued to a verifier or reviewer subagent; it records verdicts and never authors commits`, "commit from the implementer's or the lead's own session (unset WORKIT_SESSION_ID back to the shell's)");
74766
+ const refusal = sessionClaimRefusal(env, session, cwd);
74767
+ if (refusal)
74768
+ return failure3("blocked", refusal.error, "commit from the session this shell really is: never set WORKIT_SESSION_ID by hand for a commit (unset it, or use the id the host put in this shell)");
74769
+ }
74358
74770
  const changeRequired = !input.amend && !input.allowEmpty;
74359
74771
  const emptyAmend = previous !== null && git5(cwd, ["rev-parse", "--verify", "-q", `${previous}^{tree}`]).stdout.trim() === git5(cwd, ["rev-parse", "--verify", "-q", `${previous}~1^{tree}`]).stdout.trim();
74360
74772
  const args = ["commit", "--no-edit"];
@@ -74853,7 +75265,7 @@ ${run.stdout}`;
74853
75265
  } : { ok: false, lease: false, error: gitError(run) };
74854
75266
  }
74855
75267
  var COMMIT_TIMEOUT_MS, PUSH_TIMEOUT_MS = 120000, git5 = (cwd, args, options = {}) => {
74856
- const result = spawnSync18("git", args, {
75268
+ const result = spawnSync19("git", args, {
74857
75269
  cwd,
74858
75270
  encoding: "utf8",
74859
75271
  env: { ...options.env ?? process.env, GIT_TERMINAL_PROMPT: "0" },
@@ -74898,6 +75310,7 @@ var init_ops = __esm(() => {
74898
75310
  init_vcs_config();
74899
75311
  init_workspaces();
74900
75312
  init_redact();
75313
+ init_host_session();
74901
75314
  init_ledger();
74902
75315
  init_rev();
74903
75316
  COMMIT_TIMEOUT_MS = 10 * 60000;
@@ -75386,7 +75799,7 @@ var init_report = __esm(() => {
75386
75799
  });
75387
75800
 
75388
75801
  // packages/workit-core/src/forge/pr-ops.ts
75389
- import { spawnSync as spawnSync19 } from "node:child_process";
75802
+ import { spawnSync as spawnSync20 } from "node:child_process";
75390
75803
  function fillFromCommits(cwd, resolved, base) {
75391
75804
  const tracking = `refs/remotes/${resolved.baseRemote}/${base}`;
75392
75805
  if (!base.startsWith("-"))
@@ -75394,7 +75807,7 @@ function fillFromCommits(cwd, resolved, base) {
75394
75807
  const from = resolveRef(cwd, tracking) ?? resolveRef(cwd, `refs/heads/${base}`);
75395
75808
  if (!from)
75396
75809
  return failure3("not_found", `base ${base} is not available locally`, `git fetch ${resolved.baseRemote} ${base}`);
75397
- const log = spawnSync19("git", ["log", "--reverse", "--no-merges", "--format=%s%x1f%b%x1e", `${from}..HEAD`], {
75810
+ const log = spawnSync20("git", ["log", "--reverse", "--no-merges", "--format=%s%x1f%b%x1e", `${from}..HEAD`], {
75398
75811
  cwd,
75399
75812
  encoding: "utf8",
75400
75813
  timeout: GIT_TIMEOUTS.local,
@@ -75591,7 +76004,7 @@ function squashCommitList(cwd, resolved, base, head) {
75591
76004
  const from = resolveRef(cwd, `refs/remotes/${resolved.baseRemote}/${base}`) ?? resolveRef(cwd, `refs/heads/${base}`);
75592
76005
  if (!from)
75593
76006
  return "";
75594
- const log = spawnSync19("git", ["log", "--reverse", "--no-merges", "--format=%B%x1e", `${from}..${head}`], {
76007
+ const log = spawnSync20("git", ["log", "--reverse", "--no-merges", "--format=%B%x1e", `${from}..${head}`], {
75595
76008
  cwd,
75596
76009
  encoding: "utf8",
75597
76010
  timeout: GIT_TIMEOUTS.local,
@@ -75664,7 +76077,7 @@ async function mergePullRequest(cwd, resolved, input, sleep) {
75664
76077
  if (reason)
75665
76078
  return refuse(`protected_branch: --delete-branch would delete ${branch}, which ${reason}; workit never deletes it`, `workit pr merge${input.pr ? ` --pr ${doc.number}` : ""} --method ${input.method} # without --delete-branch`, { reason: "protected_branch" });
75666
76079
  }
75667
- const ledger = readLedger(cwd);
76080
+ const ledger = readLedger(cwd, { integrity: true });
75668
76081
  if (!ledger.ok)
75669
76082
  return ledger;
75670
76083
  const check = checkVerdicts(cwd, branch, ledger.value.rows);
@@ -75696,18 +76109,54 @@ async function mergePullRequest(cwd, resolved, input, sleep) {
75696
76109
  unverified = { reason, recorded: String(recorded.value.id) };
75697
76110
  } else if (check.head !== head)
75698
76111
  return refuse(`head_mismatch: the verdict check reads ${branch} at ${check.head?.slice(0, 12) ?? "(missing)"} but ${label} is at ${head.slice(0, 12)}`, `git fetch && git switch ${branch} && git merge --ff-only @{u} # then re-verify that head`, { reason: "head_mismatch", verdict: summary });
76112
+ else if (!covered && check.accepted.reasons.includes("ledger_tampered"))
76113
+ return refuse(`ledger_tampered: a ledger row was edited, removed or moved, so no verdict for ${label} is accepted until it is repaired`, tamperedUnblock(cwd), { reason: "ledger_tampered", verdict: summary });
75699
76114
  else if (!covered)
75700
76115
  return refuse(`NEEDS_VERDICT: ${label} has no accepted independent verdict for ${head.slice(0, 12)} (${check.accepted.reasons.join(", ")})`, `an independent session verifies the head and runs: workit ledger verdict verified --how "<what was exercised>" --branch ${branch}${grant.allowUnverified ? `; or, only if the user asks to merge unverified: workit pr merge --unverified --reason "<why>"` : ""}`, { reason: "needs_verdict", verdict: summary });
75701
76116
  const squashMessage = squashMessageFor(cwd, resolved, input, doc);
75702
76117
  if (squashMessage && !squashMessage.ok)
75703
76118
  return squashMessage;
76119
+ const intent = appendObserved(cwd, {
76120
+ type: "pr.merge.intent",
76121
+ actor: input.actor,
76122
+ branch,
76123
+ head,
76124
+ pr: doc.number,
76125
+ base: doc.base,
76126
+ method: input.method,
76127
+ verdictId: verdict.verdictId,
76128
+ ...unverified ? { unverified: unverified.recorded } : {},
76129
+ grant: grant.source
76130
+ });
76131
+ if (!intent.ok)
76132
+ return refuse(`intent_unrecorded: the merge intent for ${label} could not be recorded (${intent.error}); nothing was merged`, "fix the ledger (workit ledger check), then merge again", { reason: "intent_unrecorded" });
76133
+ const intentId = String(intent.value.id);
75704
76134
  const merged = resolved.forge.merge(doc.number, {
75705
76135
  sha: head,
75706
76136
  method: input.method,
75707
76137
  ...squashMessage ? { squashMessage: squashMessage.data } : {}
75708
76138
  });
75709
76139
  if (!merged.ok)
75710
- return merged;
76140
+ return {
76141
+ ...merged,
76142
+ error: `${merged.error} (merge intent ${intentId} is recorded: if the forge merged anyway, workit pr status reads it)`
76143
+ };
76144
+ const row = appendObserved(cwd, {
76145
+ type: "pr.merged",
76146
+ actor: input.actor,
76147
+ branch,
76148
+ head,
76149
+ pr: doc.number,
76150
+ base: doc.base,
76151
+ mergeSha: merged.data.mergeSha,
76152
+ method: input.method,
76153
+ verdictId: verdict.verdictId,
76154
+ ...unverified ? { unverified: unverified.recorded } : {},
76155
+ grant: grant.source,
76156
+ intent: intentId,
76157
+ verified: false
76158
+ });
76159
+ const recorded = row.ok ? { id: String(row.value.id) } : { error: row.error };
75711
76160
  let state = "open";
75712
76161
  for (const delay of [0, ...VERIFY_DELAYS_MS]) {
75713
76162
  if (delay)
@@ -75722,9 +76171,21 @@ async function mergePullRequest(cwd, resolved, input, sleep) {
75722
76171
  return {
75723
76172
  ok: false,
75724
76173
  code: "failed",
75725
- error: `merge_unverified: the forge accepted the merge of ${label} but still reports it ${state}`,
75726
- unblock: `workit verify-delivery merged --pr ${doc.number}`
76174
+ error: `merge_unverified: the forge accepted the merge of ${label} but still reports it ${state}${"id" in recorded ? `; recorded as pr.merged ${recorded.id} (verified: false)` : `; the pr.merged row could not be written (${recorded.error})`}`,
76175
+ unblock: `workit verify-delivery merged --pr ${doc.number}`,
76176
+ recorded
75727
76177
  };
76178
+ const confirmation = "id" in recorded ? appendObserved(cwd, {
76179
+ type: "pr.merge.verified",
76180
+ actor: input.actor,
76181
+ branch,
76182
+ head,
76183
+ pr: doc.number,
76184
+ base: doc.base,
76185
+ merged: recorded.id,
76186
+ mergeSha: merged.data.mergeSha
76187
+ }) : null;
76188
+ const confirmed = confirmation === null ? { error: "no pr.merged row to confirm" } : confirmation.ok ? { id: String(confirmation.value.id) } : { error: confirmation.error };
75728
76189
  let deletedBranch = false;
75729
76190
  if (input.deleteBranch) {
75730
76191
  const deleted = deleteRemoteBranch(cwd, resolved.remote, branch, head);
@@ -75732,19 +76193,6 @@ async function mergePullRequest(cwd, resolved, input, sleep) {
75732
76193
  deletedBranch = deleted.ok || gone && gone.ok && gone.sha === null ? true : { error: deleted.error };
75733
76194
  }
75734
76195
  const mergeBack = mergeBackFor(cwd, doc.base, branch);
75735
- const row = appendObserved(cwd, {
75736
- type: "pr.merged",
75737
- actor: input.actor,
75738
- branch,
75739
- head,
75740
- pr: doc.number,
75741
- base: doc.base,
75742
- mergeSha: merged.data.mergeSha,
75743
- method: input.method,
75744
- verdictId: verdict.verdictId,
75745
- ...unverified ? { unverified: unverified.recorded } : {},
75746
- grant: grant.source
75747
- });
75748
76196
  return {
75749
76197
  ok: true,
75750
76198
  data: {
@@ -75759,7 +76207,8 @@ async function mergePullRequest(cwd, resolved, input, sleep) {
75759
76207
  unverified,
75760
76208
  grant: { source: grant.source },
75761
76209
  deletedBranch,
75762
- recorded: row.ok ? { id: String(row.value.id) } : { error: row.error },
76210
+ recorded,
76211
+ confirmed,
75763
76212
  mergeBack: mergeBack.branches,
75764
76213
  mergeBackTrack: mergeBack.track
75765
76214
  }
@@ -75817,8 +76266,8 @@ var init_pr_ops = __esm(() => {
75817
76266
  });
75818
76267
 
75819
76268
  // packages/workit-core/src/stack.ts
75820
- import { spawnSync as spawnSync20 } from "node:child_process";
75821
- import { createHash as createHash17, randomBytes as randomBytes3 } from "node:crypto";
76269
+ import { spawnSync as spawnSync21 } from "node:child_process";
76270
+ import { createHash as createHash17, randomBytes as randomBytes4 } from "node:crypto";
75822
76271
  import fs22 from "node:fs";
75823
76272
  import path44 from "node:path";
75824
76273
  function worktreeOf(cwd, branch) {
@@ -75864,7 +76313,7 @@ function gitRestack(cwd, input) {
75864
76313
  if (!scratch)
75865
76314
  return { ok: false, conflict: false, worktree: cwd, error: "no store root" };
75866
76315
  fs22.mkdirSync(scratch, { recursive: true });
75867
- dir = path44.join(scratch, `${input.branch.replace(/[^A-Za-z0-9._-]+/gu, "_").slice(0, 40)}-${randomBytes3(4).toString("hex")}`);
76316
+ dir = path44.join(scratch, `${input.branch.replace(/[^A-Za-z0-9._-]+/gu, "_").slice(0, 40)}-${randomBytes4(4).toString("hex")}`);
75868
76317
  const added = gitRun3(cwd, ["worktree", "add", "-q", dir, input.branch], GIT_TIMEOUTS.worktree);
75869
76318
  if (!added.ok)
75870
76319
  return { ok: false, conflict: false, worktree: cwd, error: firstLine(added) };
@@ -76073,13 +76522,13 @@ function takeLock(lock) {
76073
76522
  pid: process.pid,
76074
76523
  processStart: processStartOf(process.pid),
76075
76524
  host: localLockHost(),
76076
- nonce: randomBytes3(8).toString("hex")
76525
+ nonce: randomBytes4(8).toString("hex")
76077
76526
  };
76078
76527
  fs22.writeFileSync(path44.join(lock, OWNER), JSON.stringify(owner));
76079
76528
  return owner;
76080
76529
  }
76081
76530
  function reapLock(lock, observed) {
76082
- const tomb = `${lock}.reap-${randomBytes3(6).toString("hex")}`;
76531
+ const tomb = `${lock}.reap-${randomBytes4(6).toString("hex")}`;
76083
76532
  try {
76084
76533
  fs22.renameSync(lock, tomb);
76085
76534
  } catch {
@@ -76100,7 +76549,7 @@ function releaseLock(lock, owner) {
76100
76549
  const { raw } = readOwner(lock);
76101
76550
  if (raw !== JSON.stringify(owner))
76102
76551
  return;
76103
- const tomb = `${lock}.release-${randomBytes3(6).toString("hex")}`;
76552
+ const tomb = `${lock}.release-${randomBytes4(6).toString("hex")}`;
76104
76553
  try {
76105
76554
  fs22.renameSync(lock, tomb);
76106
76555
  fs22.rmSync(tomb, { recursive: true, force: true });
@@ -76330,7 +76779,7 @@ function commitKeys(cwd, range) {
76330
76779
  const patches = new Map;
76331
76780
  const diff = gitRun3(cwd, ["log", "--no-merges", "-p", "--format=commit %H", range]);
76332
76781
  if (diff.ok && diff.stdout.trim()) {
76333
- const ids = spawnSync20("git", ["patch-id", "--stable"], {
76782
+ const ids = spawnSync21("git", ["patch-id", "--stable"], {
76334
76783
  cwd,
76335
76784
  input: diff.stdout,
76336
76785
  encoding: "utf8",
@@ -76423,7 +76872,7 @@ function stackStatus(ctx, stack) {
76423
76872
  const mismatch = repoMismatch(ctx, stack);
76424
76873
  if (mismatch)
76425
76874
  return mismatch;
76426
- const ledger = readLedger(ctx.cwd);
76875
+ const ledger = readLedger(ctx.cwd, { integrity: true });
76427
76876
  if (!ledger.ok)
76428
76877
  return stackFail(ledger.code, ledger.error, ledger.unblock);
76429
76878
  const remote = remoteFor(ctx.cwd, ctx.resolved, stack.trunk);
@@ -76847,7 +77296,7 @@ async function landStack(ctx, stack, options) {
76847
77296
  absorb(synced.data);
76848
77297
  }
76849
77298
  const ledgerRows = () => {
76850
- const ledger = readLedger(ctx.cwd);
77299
+ const ledger = readLedger(ctx.cwd, { integrity: true });
76851
77300
  return ledger.ok ? ledger.value.rows : [];
76852
77301
  };
76853
77302
  const simulated = new Set;
@@ -76954,7 +77403,7 @@ var STACK_VERSION = 1, stackFail = (code, error, unblock, data) => ({
76954
77403
  ...unblock ? { unblock } : {},
76955
77404
  ...data ? { data } : {}
76956
77405
  }), fromForge = (result) => stackFail(result.code, result.error, result.unblock), stackDeps, gitRun3 = (cwd, args, timeoutMs = GIT_TIMEOUTS.local) => {
76957
- const run = spawnSync20("git", args, {
77406
+ const run = spawnSync21("git", args, {
76958
77407
  cwd,
76959
77408
  encoding: "utf8",
76960
77409
  timeout: timeoutMs,
@@ -77035,7 +77484,7 @@ var init_stack = __esm(() => {
77035
77484
  });
77036
77485
 
77037
77486
  // packages/workit-core/src/forge/pr-edit.ts
77038
- import { spawnSync as spawnSync21 } from "node:child_process";
77487
+ import { spawnSync as spawnSync22 } from "node:child_process";
77039
77488
  function openPr(cwd, resolved, pr) {
77040
77489
  const grant = requireGrant(cwd, "pr");
77041
77490
  if (!grant.allowed)
@@ -77200,7 +77649,7 @@ function replyToThread(cwd, resolved, input) {
77200
77649
  });
77201
77650
  }
77202
77651
  var label = (resolved, number) => `${resolved.forge.kind === "github" ? "PR #" : "MR !"}${number}`, git6 = (cwd, args) => {
77203
- const run = spawnSync21("git", args, {
77652
+ const run = spawnSync22("git", args, {
77204
77653
  cwd,
77205
77654
  encoding: "utf8",
77206
77655
  timeout: GIT_TIMEOUTS.local,
@@ -77220,7 +77669,7 @@ var init_pr_edit = __esm(() => {
77220
77669
  });
77221
77670
 
77222
77671
  // packages/workit-core/src/forge/exec.ts
77223
- import { spawnSync as spawnSync22 } from "node:child_process";
77672
+ import { spawnSync as spawnSync23 } from "node:child_process";
77224
77673
  import fs23 from "node:fs";
77225
77674
  import path45 from "node:path";
77226
77675
  function findExecutable(bin, env) {
@@ -77255,7 +77704,7 @@ function systemRunner(kind, apiHost, env = process.env) {
77255
77704
  if (!exe)
77256
77705
  return { status: null, stdout: "", stderr: "", timedOut: false, missing: true };
77257
77706
  const token = options.token ? kind === "github" ? { GH_TOKEN: options.token, GH_ENTERPRISE_TOKEN: options.token } : { GITLAB_TOKEN: options.token } : {};
77258
- const result = spawnSync22(exe, [...args], {
77707
+ const result = spawnSync23(exe, [...args], {
77259
77708
  encoding: "utf8",
77260
77709
  env: { ...childEnv, ...token },
77261
77710
  maxBuffer: MAX_BUFFER2,
@@ -78255,6 +78704,14 @@ function resolveCredential(workspace, derived, run, scope) {
78255
78704
  const explicit = typeof workspaceHost === "string" && workspaceHost.trim().toLowerCase().replace(/^https?:\/\//u, "").replace(/\/.*$/u, "") === apiHost;
78256
78705
  if (derived.via === "host_name" && !explicit)
78257
78706
  return failure3("blocked", `token_host_unverified: push host ${derived.host} only looks like ${kind}; workspace ${workspace?.name ?? "?"} vcs.tokenFile is not sent to it`, `if ${apiHost} is your ${kind} server, set ${kind}.host in ~/.config/workit/vcs.json (or vcs.host for the workspace); otherwise fix the push remote`);
78707
+ if (process.platform !== "win32") {
78708
+ let mode = 0;
78709
+ try {
78710
+ mode = fs24.statSync(tokenFile.trim()).mode;
78711
+ } catch {}
78712
+ if ((mode & 63) !== 0)
78713
+ return failure3("blocked", `workspace ${workspace?.name ?? "?"} vcs.tokenFile is readable by group or other (mode ${(mode & 511).toString(8).padStart(4, "0")})`, `chmod 600 ${tokenFile.trim()}`);
78714
+ }
78258
78715
  let token = "";
78259
78716
  try {
78260
78717
  token = fs24.readFileSync(tokenFile.trim(), "utf8").trim();
@@ -78678,17 +79135,20 @@ async function status(argv, io) {
78678
79135
  });
78679
79136
  }
78680
79137
  function verdictBlock(cwd, branch, doc) {
78681
- const ledger = readLedger(cwd);
79138
+ const ledger = readLedger(cwd, { integrity: true });
78682
79139
  if (!ledger.ok)
78683
79140
  return null;
78684
79141
  const check = checkVerdicts(cwd, branch, ledger.value.rows);
78685
79142
  let landed = null;
78686
79143
  if (doc.state === "merged") {
78687
- const row = ledger.value.rows.findLast((candidate) => candidate.type === "pr.merged" && candidate.observer === "workit_cli" && candidate.pr === doc.number && candidate.base === doc.base);
79144
+ const mine = (type) => ledger.value.rows.findLast((candidate) => candidate.type === type && candidate.observer === "workit_cli" && candidate.integrity !== "unverified" && candidate.pr === doc.number && candidate.base === doc.base);
79145
+ const merged = mine("pr.merged");
79146
+ const row = merged ?? mine("pr.merge.intent");
78688
79147
  landed = row ? {
78689
79148
  head: typeof row.head === "string" ? row.head : null,
78690
79149
  verdictId: typeof row.verdictId === "string" ? row.verdictId : null,
78691
- unverified: row.unverified !== undefined && row.unverified !== null
79150
+ unverified: row.unverified !== undefined && row.unverified !== null,
79151
+ ...merged ? {} : { intentOnly: true }
78692
79152
  } : "untracked";
78693
79153
  }
78694
79154
  return {
@@ -78859,7 +79319,7 @@ async function merge3(argv, io) {
78859
79319
  if (!result.ok)
78860
79320
  return emit(io, fail(result.code, result.error, {
78861
79321
  unblock: result.unblock,
78862
- data: "refusal" in result && result.refusal ? result.refusal : {}
79322
+ data: "refusal" in result && result.refusal ? result.refusal : ("recorded" in result) && result.recorded ? { recorded: result.recorded } : {}
78863
79323
  }));
78864
79324
  return emit(io, ok(result.data), (data) => [
78865
79325
  `merged ${connected.data.forge.kind === "github" ? "PR #" : "MR !"}${data.number} (${data.method}) at head ${data.head.slice(0, 12)}${data.mergeSha ? ` -> ${data.mergeSha.slice(0, 12)}` : ""}`,
@@ -78868,7 +79328,8 @@ async function merge3(argv, io) {
78868
79328
  `merge back: ${data.base} is the ${data.mergeBackTrack} production branch; bring it into ${data.mergeBack.join(", ")}`
78869
79329
  ] : [],
78870
79330
  ...data.deletedBranch === true ? [`deleted ${data.branch}`] : typeof data.deletedBranch === "object" ? [`branch not deleted: ${data.deletedBranch.error}`] : [],
78871
- ..."error" in data.recorded ? [`ledger: not recorded (${data.recorded.error})`] : []
79331
+ ..."error" in data.recorded ? [`ledger: not recorded (${data.recorded.error})`] : [],
79332
+ ..."error" in data.confirmed && !("error" in data.recorded) ? [`ledger: merge not confirmed in the ledger (${data.confirmed.error})`] : []
78872
79333
  ]);
78873
79334
  }
78874
79335
  async function ready(argv, io) {
@@ -79018,7 +79479,7 @@ async function run11(argv, io) {
79018
79479
  return reply(rest, io);
79019
79480
  return usage3(io, sub && !sub.startsWith("-") ? `unknown pr subcommand "${sub}"` : "missing pr subcommand", USAGE4);
79020
79481
  }
79021
- var STATUS_USAGE = "workit pr status [--pr <n> | --branch <b>] [--log-lines 60] [--json]", CREATE_USAGE = "workit pr create [--base <b> | --track <t>] (--title <t> [--body <text> | --body-file <f|->] | --fill) [--label <l>]… [--reviewer <login>]… [--draft] [--json]", MERGE_USAGE = "workit pr merge [--pr <n>] [--method squash|merge|rebase] [--subject <s>] [--body <b> | --body-file <f|->] [--delete-branch] [--unverified --reason <why>] [--json]", READY_USAGE = "workit pr ready [--pr <n>] [--undo] [--json]", EDIT_USAGE = "workit pr edit [--pr <n>] [--title <t>] [--body-file <f|->] [--add-label <l>]… [--remove-label <l>]… [--add-reviewer <login>]… [--base <b>] [--json]", THREADS_USAGE = "workit pr threads [--pr <n>] [--json]", REPLY_USAGE = "workit pr reply [--pr <n>] --thread <id> [--body-file <f|->] [--resolve] [--json]", USAGE4 = "workit pr status|create|merge|ready|edit|threads|reply ... (workit help pr)", prLabel = (kind, number) => `${kind === "github" ? "PR #" : "MR !"}${number}`, mergedVerdictLine = (landed) => landed === "untracked" ? "merged outside workit (no merge record)" : landed.unverified ? `merged unverified at ${(landed.head ?? "?").slice(0, 12)} (recorded bypass)` : `merged with accepted verdict ${landed.verdictId ?? "?"} at ${(landed.head ?? "?").slice(0, 12)}`, METHODS2;
79482
+ var STATUS_USAGE = "workit pr status [--pr <n> | --branch <b>] [--log-lines 60] [--json]", CREATE_USAGE = "workit pr create [--base <b> | --track <t>] (--title <t> [--body <text> | --body-file <f|->] | --fill) [--label <l>]… [--reviewer <login>]… [--draft] [--json]", MERGE_USAGE = "workit pr merge [--pr <n>] [--method squash|merge|rebase] [--subject <s>] [--body <b> | --body-file <f|->] [--delete-branch] [--unverified --reason <why>] [--json]", READY_USAGE = "workit pr ready [--pr <n>] [--undo] [--json]", EDIT_USAGE = "workit pr edit [--pr <n>] [--title <t>] [--body-file <f|->] [--add-label <l>]… [--remove-label <l>]… [--add-reviewer <login>]… [--base <b>] [--json]", THREADS_USAGE = "workit pr threads [--pr <n>] [--json]", REPLY_USAGE = "workit pr reply [--pr <n>] --thread <id> [--body-file <f|->] [--resolve] [--json]", USAGE4 = "workit pr status|create|merge|ready|edit|threads|reply ... (workit help pr)", prLabel = (kind, number) => `${kind === "github" ? "PR #" : "MR !"}${number}`, mergedVerdictLine = (landed) => landed === "untracked" ? "merged outside workit (no merge record)" : landed.unverified ? `merged unverified at ${(landed.head ?? "?").slice(0, 12)} (recorded bypass)` : `merged with accepted verdict ${landed.verdictId ?? "?"} at ${(landed.head ?? "?").slice(0, 12)}${landed.intentOnly ? " (merge intent recorded; the merge call itself failed)" : ""}`, METHODS2;
79022
79483
  var init_pr = __esm(() => {
79023
79484
  init_pr_body();
79024
79485
  init_pr_edit();
@@ -79543,7 +80004,7 @@ var init_git2 = __esm(() => {
79543
80004
  });
79544
80005
 
79545
80006
  // packages/workit-core/src/forge/verify.ts
79546
- import { spawnSync as spawnSync23 } from "node:child_process";
80007
+ import { spawnSync as spawnSync24 } from "node:child_process";
79547
80008
  function finish(cwd, report, actor) {
79548
80009
  const delivered = report.observations.length > 0 && report.observations.every((entry) => entry.ok);
79549
80010
  const out = { ...report, delivered };
@@ -79756,7 +80217,7 @@ var NPM_NAME, SEMVER2, SAFE_ARG, systemNpm = (args) => {
79756
80217
  };
79757
80218
  const found = process.platform === "win32" ? findExecutable("npm.cmd", process.env) : null;
79758
80219
  const npmCmd = found && !/["%!^]/u.test(found) ? `"${found}"` : "npm.cmd";
79759
- const result = process.platform === "win32" ? spawnSync23(`${npmCmd} ${args.join(" ")}`, { ...options, shell: true }) : spawnSync23("npm", [...args], options);
80220
+ const result = process.platform === "win32" ? spawnSync24(`${npmCmd} ${args.join(" ")}`, { ...options, shell: true }) : spawnSync24("npm", [...args], options);
79760
80221
  return { status: result.status, stdout: result.stdout ?? "", stderr: result.stderr ?? "" };
79761
80222
  }, short3 = (sha) => sha ? sha.slice(0, 12) : "(absent)", npmView = (stdout) => {
79762
80223
  try {
@@ -80765,7 +81226,7 @@ var init_stack2 = __esm(() => {
80765
81226
  });
80766
81227
 
80767
81228
  // packages/workit-core/src/fanout.ts
80768
- import { spawnSync as spawnSync24 } from "node:child_process";
81229
+ import { spawnSync as spawnSync25 } from "node:child_process";
80769
81230
  import { createHash as createHash18 } from "node:crypto";
80770
81231
  import fs25 from "node:fs";
80771
81232
  import path48 from "node:path";
@@ -81538,7 +81999,7 @@ var FANOUT_VERSION = 1, TIERS, FAN_IN_MODES, fanoutFail = (code, error, unblock,
81538
81999
  text: edges.map((edge) => `add "${edge.dependsOn}" to "dependsOn" of slice ${edge.slice}`).join("; ")
81539
82000
  };
81540
82001
  }, gitRun4 = (cwd, args, timeoutMs = GIT_TIMEOUTS.local) => {
81541
- const run = spawnSync24("git", args, {
82002
+ const run = spawnSync25("git", args, {
81542
82003
  cwd,
81543
82004
  encoding: "utf8",
81544
82005
  timeout: timeoutMs,
@@ -81576,7 +82037,7 @@ var init_fanout = __esm(() => {
81576
82037
  });
81577
82038
 
81578
82039
  // packages/workit-core/src/fanout-worktree.ts
81579
- import { randomBytes as randomBytes4 } from "node:crypto";
82040
+ import { randomBytes as randomBytes5 } from "node:crypto";
81580
82041
  import fs26 from "node:fs";
81581
82042
  import path49 from "node:path";
81582
82043
  function rowSample(lines) {
@@ -81660,7 +82121,7 @@ function markAdminDir(worktree) {
81660
82121
  const admin = adminDir(worktree);
81661
82122
  if (!admin)
81662
82123
  return null;
81663
- const token = randomBytes4(16).toString("hex");
82124
+ const token = randomBytes5(16).toString("hex");
81664
82125
  try {
81665
82126
  fs26.writeFileSync(path49.join(admin.path, TOKEN_FILE), `${token}
81666
82127
  `);
@@ -81989,6 +82450,7 @@ function renderBrief(cwd, plan, input) {
81989
82450
  what: String(row.what)
81990
82451
  }));
81991
82452
  const identity = identityOf(input.actor.host);
82453
+ const model = workspaceTierModel(cwd, slice.tier, input.actor.host);
81992
82454
  const minted = workerSession(sessionSafe(input.actor.session), slice.id, input.attempt);
81993
82455
  const session = identity === "declared" ? minted : null;
81994
82456
  const fanIn = plan.fanIn === "integration" ? [
@@ -82012,6 +82474,7 @@ function renderBrief(cwd, plan, input) {
82012
82474
  ...slice.acceptance.map((line) => ` - ${line}`),
82013
82475
  `VERIFY: ${slice.verify.join("; ")}`,
82014
82476
  `TIER: ${slice.tier}`,
82477
+ ...model ? [` model: ${model.model} (fanout.tierModels in workspace ${model.workspace})`] : [],
82015
82478
  `TIMEBOX: ${slice.timebox ?? DEFAULT_TIMEBOX}; past it without a new commit you will be replaced`,
82016
82479
  scratchLine,
82017
82480
  `FORBIDDEN: ${slice.forbidden.join("; ")}`,
@@ -82032,6 +82495,7 @@ function renderBrief(cwd, plan, input) {
82032
82495
  branch,
82033
82496
  base: slice.base,
82034
82497
  tier: slice.tier,
82498
+ model: model?.model ?? null,
82035
82499
  scratch,
82036
82500
  session,
82037
82501
  standing,
@@ -82074,6 +82538,7 @@ var DEFAULT_TIMEBOX = "30 minutes", REPORT, identityOf = (host) => {
82074
82538
  ];
82075
82539
  }, sessionSafe = (text) => text.replace(/[^A-Za-z0-9_.:@/+-]/gu, "-"), SESSION_MAX = 128;
82076
82540
  var init_fanout_brief = __esm(() => {
82541
+ init_workspaces();
82077
82542
  init_ledger();
82078
82543
  init_fanout();
82079
82544
  init_fanout_worktree();
@@ -82085,7 +82550,7 @@ var init_fanout_brief = __esm(() => {
82085
82550
  });
82086
82551
 
82087
82552
  // packages/workit-core/src/fanout-landed.ts
82088
- import { spawnSync as spawnSync25 } from "node:child_process";
82553
+ import { spawnSync as spawnSync26 } from "node:child_process";
82089
82554
  function forgeBreaker(resolved) {
82090
82555
  if (!resolved)
82091
82556
  return { forge: null, down: () => null };
@@ -82176,7 +82641,7 @@ function trunkPatchIds(ctx, fork) {
82176
82641
  "--"
82177
82642
  ]);
82178
82643
  if (log.ok && log.stdout.trim()) {
82179
- const run = spawnSync25("git", ["patch-id", "--stable"], {
82644
+ const run = spawnSync26("git", ["patch-id", "--stable"], {
82180
82645
  cwd: ctx.cwd,
82181
82646
  input: log.stdout,
82182
82647
  encoding: "utf8",
@@ -82691,6 +83156,15 @@ function fanoutStatus(cwd, plan, options) {
82691
83156
  if (row.waitsFor.length && !suggested.includes(id))
82692
83157
  row.reasons.push(`waits for ${row.waitsFor.join(", ")}`);
82693
83158
  }
83159
+ const host = options.host === undefined ? actorFromEnv(process.env).host : options.host;
83160
+ const spawnModels = {};
83161
+ for (const id of spawnable) {
83162
+ const tier = plan.slices.find((slice) => slice.id === id)?.tier;
83163
+ const model = tier ? workspaceTierModel(cwd, tier, host) : null;
83164
+ if (model)
83165
+ spawnModels[id] = model.model;
83166
+ }
83167
+ const spawnList = spawnable.map((id) => spawnModels[id] ? `${id} (model ${spawnModels[id]})` : id).join(", ");
82694
83168
  const stuck = order.filter((id) => out.get(id)?.stuck);
82695
83169
  const down = breaker.down();
82696
83170
  if (down)
@@ -82700,7 +83174,7 @@ function fanoutStatus(cwd, plan, options) {
82700
83174
  const row = out.get(id);
82701
83175
  return !row.landed && row.reasons.length === 1 && row.reasons[0] === "no PR";
82702
83176
  });
82703
- const next = stuck.length ? `replace ${stuck.join(", ")}: stop the worker, then workit fanout worktree release ${stuck[0]} (records git status first) and respawn it in MODE: resume` : suggested.length ? online ? `land in this order: ${suggested.join(", ")} (workit fanout check first; workit pr merge each)` : `land in this order: ${suggested.join(", ")} once each has a PR (offline: PRs unchecked; open a missing one with workit git push && workit pr create --fill, then workit fanout status online)` : noPr.length ? `open PRs for ${noPr.join(", ")}: workit git push && workit pr create --fill on each branch` : spawnable.length ? `spawn ${spawnable.join(", ")} (workit fanout worktree create <slice> on hosts without native worktrees)` : order.every((id) => out.get(id)?.landed) ? "every slice has landed" : "wait for workers, then workit fanout status again";
83177
+ const next = stuck.length ? `replace ${stuck.join(", ")}: stop the worker, then workit fanout worktree release ${stuck[0]} (records git status first) and respawn it in MODE: resume` : suggested.length ? online ? `land in this order: ${suggested.join(", ")} (workit fanout check first; workit pr merge each)` : `land in this order: ${suggested.join(", ")} once each has a PR (offline: PRs unchecked; open a missing one with workit git push && workit pr create --fill, then workit fanout status online)` : noPr.length ? `open PRs for ${noPr.join(", ")}: workit git push && workit pr create --fill on each branch` : spawnable.length ? `spawn ${spawnList} (workit fanout worktree create <slice> on hosts without native worktrees)` : order.every((id) => out.get(id)?.landed) ? "every slice has landed" : "wait for workers, then workit fanout status again";
82704
83178
  return {
82705
83179
  ok: true,
82706
83180
  data: {
@@ -82714,6 +83188,7 @@ function fanoutStatus(cwd, plan, options) {
82714
83188
  slices: order.map((id) => out.get(id)),
82715
83189
  landingOrder: suggested,
82716
83190
  spawnable,
83191
+ spawnModels,
82717
83192
  stuck,
82718
83193
  next,
82719
83194
  notes
@@ -82727,6 +83202,7 @@ var DEFAULT_STUCK_MS, isoOf = (seconds) => {
82727
83202
  var init_fanout_status = __esm(() => {
82728
83203
  init_duration();
82729
83204
  init_report();
83205
+ init_workspaces();
82730
83206
  init_ledger();
82731
83207
  init_fanout_check();
82732
83208
  init_fanout_landed();
@@ -83025,7 +83501,7 @@ var exports_ledger = {};
83025
83501
  __export(exports_ledger, {
83026
83502
  run: () => run18
83027
83503
  });
83028
- import { randomBytes as randomBytes5 } from "node:crypto";
83504
+ import { randomBytes as randomBytes6 } from "node:crypto";
83029
83505
  import { parseArgs } from "node:util";
83030
83506
  function targetBranch(io, rows, branch, pr) {
83031
83507
  if (pr !== undefined) {
@@ -83163,10 +83639,12 @@ async function run18(argv, io) {
83163
83639
  if (rest.length !== 1)
83164
83640
  return usage4(io, `ledger verdict takes one result: ${VERDICT_RESULTS.join("|")}`);
83165
83641
  const claimed = values.self === true ? null : claimedSession(acting);
83166
- const refusal = claimed === null ? null : sessionClaimRefusal(io.env, claimed, io.cwd);
83642
+ const token = values.token ?? io.env.WORKIT_SESSION_TOKEN ?? null;
83643
+ const refusal = claimed === null ? null : sessionClaimRefusal(io.env, claimed, io.cwd, { token, flag: acting.source === "flag" });
83167
83644
  if (refusal)
83168
83645
  return emit(io, fail("blocked", refusal.error, { unblock: refusal.unblock }));
83169
- const verdict = await recorded(recordVerdict(context, {
83646
+ const bound = claimed !== null && issuedTokenMatches(io.cwd, claimed, token);
83647
+ const verdict = await recorded(recordVerdict({ ...context, ...bound ? { sessionBound: true } : {} }, {
83170
83648
  result: rest[0],
83171
83649
  kind: values.kind,
83172
83650
  how: values.how,
@@ -83182,7 +83660,12 @@ async function run18(argv, io) {
83182
83660
  if (shadowed)
83183
83661
  io.stderr(`warning: ${shadowed}
83184
83662
  `);
83185
- return fromResult(io, verdict, (row) => `recorded verdict ${row.id}: ${row.result} [${row.kind}] for ${row.branch} @ ${(row.head ?? "").slice(0, 12)} as ${actor.session ?? "no session"}${row.self ? ` (self${row.selfReason === "no_session" ? ": WORKIT_SESSION_ID unset" : ""}; never accepted)` : ""}`);
83663
+ const withGate = verdict.ok ? { ok: true, value: { ...verdict.value, gate: gateReading(io.cwd, verdict.value) } } : verdict;
83664
+ return fromResult(io, withGate, (row) => [
83665
+ `recorded verdict ${row.id}: ${row.result} [${row.kind}] for ${row.branch} @ ${(row.head ?? "").slice(0, 12)} as ${actor.session ?? "no session"}${row.self ? ` (self${row.selfReason === "no_session" ? ": WORKIT_SESSION_ID unset" : ""}; never accepted)` : ""}`,
83666
+ row.gate ? `gate: ${row.branch} ${row.gate.accepted ? `accepted (verdict ${row.gate.verdictId ?? "?"})` : `not accepted (${row.gate.reasons.join(", ")})`}` : "gate: unknown (ledger unreadable)"
83667
+ ].join(`
83668
+ `));
83186
83669
  }
83187
83670
  function standingFanout(io, values) {
83188
83671
  if (values.fanout !== undefined) {
@@ -83253,7 +83736,7 @@ var USAGE10 = "workit ledger decision|ruling|verdict|standing|list|check ... (wo
83253
83736
  return new Error("--as takes a lowercase role, e.g. verifier");
83254
83737
  const prefix = (actor.session ?? actor.host).slice(0, 96);
83255
83738
  return {
83256
- actor: { ...actor, session: `${prefix}:${values.as}:${randomBytes5(4).toString("hex")}` },
83739
+ actor: { ...actor, session: `${prefix}:${values.as}:${randomBytes6(4).toString("hex")}` },
83257
83740
  source: "as",
83258
83741
  derivedFrom: actor.session
83259
83742
  };
@@ -83296,7 +83779,17 @@ var USAGE10 = "workit ledger decision|ruling|verdict|standing|list|check ... (wo
83296
83779
  ] : [
83297
83780
  `${data.unverified_rows.length} unverified row(s) (not written by the workit CLI, or changed afterwards):`,
83298
83781
  ...data.unverified_rows.map((row) => ` #${row.seq} ${row.id} ${row.type}${row.branch ? ` [${row.branch}]` : ""}: ${row.reason}`)
83299
- ];
83782
+ ], gateReading = (cwd, row) => {
83783
+ const ledger = readLedger(cwd, { integrity: true });
83784
+ if (!ledger.ok || !row.branch)
83785
+ return null;
83786
+ const { accepted } = checkVerdicts(cwd, row.branch, ledger.value.rows);
83787
+ return {
83788
+ accepted: accepted.accepted,
83789
+ reasons: accepted.reasons,
83790
+ verdictId: typeof accepted.verdict?.id === "string" ? accepted.verdict.id : null
83791
+ };
83792
+ };
83300
83793
  var init_ledger2 = __esm(() => {
83301
83794
  init_ledger();
83302
83795
  init_fanout();
@@ -83320,6 +83813,7 @@ var init_ledger2 = __esm(() => {
83320
83813
  last: { type: "string" },
83321
83814
  supersedes: { type: "string" },
83322
83815
  session: { type: "string" },
83816
+ token: { type: "string" },
83323
83817
  as: { type: "string" },
83324
83818
  fanout: { type: "string" },
83325
83819
  json: { type: "boolean" }
@@ -99175,11 +99669,11 @@ var init_rules = __esm(() => {
99175
99669
  });
99176
99670
 
99177
99671
  // packages/workit-cli/src/test-audit/audit.ts
99178
- import { spawnSync as spawnSync26 } from "node:child_process";
99179
- import { existsSync as existsSync20, readdirSync as readdirSync9, readFileSync as readFileSync23, statSync as statSync8 } from "node:fs";
99672
+ import { spawnSync as spawnSync27 } from "node:child_process";
99673
+ import { existsSync as existsSync20, readdirSync as readdirSync10, readFileSync as readFileSync23, statSync as statSync8 } from "node:fs";
99180
99674
  import path52 from "node:path";
99181
99675
  function git7(cwd, args) {
99182
- const run = spawnSync26("git", ["-c", "core.quotepath=off", ...args], {
99676
+ const run = spawnSync27("git", ["-c", "core.quotepath=off", ...args], {
99183
99677
  cwd,
99184
99678
  encoding: "utf8",
99185
99679
  maxBuffer: 64 * 1024 * 1024
@@ -99187,7 +99681,7 @@ function git7(cwd, args) {
99187
99681
  return { ok: run.status === 0, stdout: run.stdout ?? "" };
99188
99682
  }
99189
99683
  function walkTests(dir, out) {
99190
- for (const entry of readdirSync9(dir, { withFileTypes: true })) {
99684
+ for (const entry of readdirSync10(dir, { withFileTypes: true })) {
99191
99685
  if (entry.name.startsWith(".") && entry.name !== "." && entry.isDirectory())
99192
99686
  continue;
99193
99687
  const full = path52.join(dir, entry.name);
@@ -99323,7 +99817,7 @@ import {
99323
99817
  lstatSync as lstatSync8,
99324
99818
  mkdirSync as mkdirSync10,
99325
99819
  mkdtempSync as mkdtempSync4,
99326
- readdirSync as readdirSync10,
99820
+ readdirSync as readdirSync11,
99327
99821
  readFileSync as readFileSync24,
99328
99822
  readlinkSync as readlinkSync3,
99329
99823
  realpathSync as realpathSync9,
@@ -99420,7 +99914,7 @@ function removeStaleCopies(tmp = os16.tmpdir()) {
99420
99914
  let removed = 0;
99421
99915
  let names = [];
99422
99916
  try {
99423
- names = readdirSync10(tmp);
99917
+ names = readdirSync11(tmp);
99424
99918
  } catch {
99425
99919
  return 0;
99426
99920
  }
@@ -99449,7 +99943,7 @@ function removeStaleCopies(tmp = os16.tmpdir()) {
99449
99943
  }
99450
99944
  function linkNodeModules(origin, target, repo, copy) {
99451
99945
  mkdirSync10(target, { recursive: true });
99452
- for (const entry of readdirSync10(origin, { withFileTypes: true })) {
99946
+ for (const entry of readdirSync11(origin, { withFileTypes: true })) {
99453
99947
  const from = path53.join(origin, entry.name);
99454
99948
  const to = path53.join(target, entry.name);
99455
99949
  if (entry.name.startsWith("@") && entry.isDirectory()) {
@@ -100586,7 +101080,7 @@ function withSubcommands(entry, options = {}) {
100586
101080
  };
100587
101081
  }
100588
101082
  var VERIFY_OPTIONS = "[--expect pushed|pr|merged|released] [--pr <n> | --branch <b>] [--sha <sha>] [--tag <t>] [--package <name[@version]>]";
100589
- var LEDGER_ACTOR = "[--branch <b> | --pr <n>] [--supersedes <id>] [--session <id> | --as <role>]";
101083
+ var LEDGER_ACTOR = "[--branch <b> | --pr <n>] [--supersedes <id>] [--session <id> [--token <t>] | --as <role>]";
100590
101084
  var VERBS = [
100591
101085
  {
100592
101086
  name: "init",
@@ -100915,7 +101409,7 @@ var VERBS = [
100915
101409
  },
100916
101410
  {
100917
101411
  name: "standing",
100918
- usage: `workit ledger standing add "<order>" | standing list | standing clear [<id>] [--fanout <name>] [--supersedes <id>] [--session <id> | --as <role>]`,
101412
+ usage: `workit ledger standing add "<order>" | standing list | standing clear [<id>] [--fanout <name>] [--supersedes <id>] [--session <id> [--token <t>] | --as <role>]`,
100919
101413
  summary: "The lead's standing orders for a fanout's workers"
100920
101414
  },
100921
101415
  {