@brainervirus/workit-claude-code 8.35.1 → 8.35.2

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.
package/dist/workit.js CHANGED
@@ -6401,9 +6401,16 @@ function workspaceDefaultTarget(cwd, globalDefault) {
6401
6401
  }
6402
6402
  var nonBlank, branchPreset, commitPreset, workspaceBranchPolicySchema, workspaceCommitPolicySchema, workspaceProfileSchema, versionSourceSchema, releaseTrackSchema, workspaceConfigSchema, workspacesFileSchema, workspacesRevision = (contents) => createHash("sha256").update(contents ?? "<missing>").digest("hex"), validateWorkspacesDocument = (parsed, file) => {
6403
6403
  if (!isConfigObject(parsed)) {
6404
- return { status: "malformed", path: file, entries: [], error: `${file} is not a JSON object` };
6404
+ return {
6405
+ status: "malformed",
6406
+ path: file,
6407
+ entries: [],
6408
+ error: `${file} is not a JSON object`
6409
+ };
6405
6410
  }
6406
- const validated = workspacesFileSchema.safeParse(parsed, { reportInput: true });
6411
+ const validated = workspacesFileSchema.safeParse(parsed, {
6412
+ reportInput: true
6413
+ });
6407
6414
  if (!validated.success) {
6408
6415
  const detail = validated.error.issues.map((issue) => {
6409
6416
  const field = String(issue.path[issue.path.length - 1] ?? "");
@@ -6442,7 +6449,12 @@ var nonBlank, branchPreset, commitPreset, workspaceBranchPolicySchema, workspace
6442
6449
  raw = readFileSync2(file, "utf8");
6443
6450
  } catch (error) {
6444
6451
  if (error.code === "ENOENT")
6445
- return { status: "missing", path: file, entries: [], revision: workspacesRevision(null) };
6452
+ return {
6453
+ status: "missing",
6454
+ path: file,
6455
+ entries: [],
6456
+ revision: workspacesRevision(null)
6457
+ };
6446
6458
  return {
6447
6459
  status: "malformed",
6448
6460
  path: file,
@@ -6462,7 +6474,10 @@ var nonBlank, branchPreset, commitPreset, workspaceBranchPolicySchema, workspace
6462
6474
  error: `${file} is not valid JSON`
6463
6475
  };
6464
6476
  }
6465
- return { ...validateWorkspacesDocument(parsed, file), revision: workspacesRevision(raw) };
6477
+ return {
6478
+ ...validateWorkspacesDocument(parsed, file),
6479
+ revision: workspacesRevision(raw)
6480
+ };
6466
6481
  }, loadWorkspacesFrom = (dir) => readWorkspacesResult(dir).entries, globToRegExp = (glob) => {
6467
6482
  let out = "";
6468
6483
  for (let i = 0;i < glob.length; i++) {
@@ -6591,7 +6606,7 @@ var nonBlank, branchPreset, commitPreset, workspaceBranchPolicySchema, workspace
6591
6606
  for (const b of entries.slice(i + 1)) {
6592
6607
  const aInB = matchWorkspace(b.glob, globRoot(a.glob));
6593
6608
  const bInA = matchWorkspace(a.glob, globRoot(b.glob));
6594
- if (!aInB && !bInA)
6609
+ if (!aInB && !bInA && !globsMayOverlap(a.glob, b.glob))
6595
6610
  continue;
6596
6611
  const [inner, outer] = aInB && !bInA ? [a, b] : bInA && !aInB ? [b, a] : globSpecificity(a.glob) >= globSpecificity(b.glob) ? [a, b] : [b, a];
6597
6612
  const si = globSpecificity(inner.glob);
@@ -6681,7 +6696,10 @@ var nonBlank, branchPreset, commitPreset, workspaceBranchPolicySchema, workspace
6681
6696
  return selected ? { file, selected, matches } : null;
6682
6697
  }, resolveRuntimeReleaseTracks = (cwd) => {
6683
6698
  const matched = matchRuntimeWorkspace(cwd);
6684
- return matched ? { workspace: matched.selected.name, releaseTracks: matched.selected.releaseTracks } : null;
6699
+ return matched ? {
6700
+ workspace: matched.selected.name,
6701
+ releaseTracks: matched.selected.releaseTracks
6702
+ } : null;
6685
6703
  }, inheritedSetting = (cwd, dir, has) => {
6686
6704
  let matched;
6687
6705
  try {
@@ -6693,7 +6711,10 @@ var nonBlank, branchPreset, commitPreset, workspaceBranchPolicySchema, workspace
6693
6711
  return null;
6694
6712
  const { selected, matches } = matched;
6695
6713
  const enclosing = matches.filter((entry) => entry !== selected).toSorted((a, b) => globSpecificity(b.glob) - globSpecificity(a.glob));
6696
- return { workspace: selected.name, source: [selected, ...enclosing].find(has) ?? null };
6714
+ return {
6715
+ workspace: selected.name,
6716
+ source: [selected, ...enclosing].find(has) ?? null
6717
+ };
6697
6718
  }, workspaceDeleteBranch = (cwd, dir) => inheritedSetting(cwd, dir, (entry) => typeof entry.deleteBranch === "boolean")?.source?.deleteBranch !== false, workspaceTrailers = (cwd, dir) => {
6698
6719
  const found = inheritedSetting(cwd, dir, (entry) => typeof entry.trailers === "boolean");
6699
6720
  return {
@@ -6821,7 +6842,10 @@ var nonBlank, branchPreset, commitPreset, workspaceBranchPolicySchema, workspace
6821
6842
  status: "resolved",
6822
6843
  profileName: null,
6823
6844
  workspace: null,
6824
- provenance: { branchPolicy: "user-default", commitPolicy: "user-default" }
6845
+ provenance: {
6846
+ branchPolicy: "user-default",
6847
+ commitPolicy: "user-default"
6848
+ }
6825
6849
  };
6826
6850
  if (selected.status === "invalid")
6827
6851
  return selected;
@@ -6892,7 +6916,11 @@ var init_workspaces = __esm(() => {
6892
6916
  ["requiredChecks", track.requiredChecks ?? []]
6893
6917
  ]) {
6894
6918
  if (new Set(values).size !== values.length) {
6895
- context.addIssue({ code: "custom", path: [field], message: "entries must be unique" });
6919
+ context.addIssue({
6920
+ code: "custom",
6921
+ path: [field],
6922
+ message: "entries must be unique"
6923
+ });
6896
6924
  }
6897
6925
  }
6898
6926
  if (track.versionSource?.kind === "package-json" && (path2.posix.isAbsolute(track.versionSource.path.replaceAll("\\", "/")) || /^[A-Za-z]:\//u.test(track.versionSource.path.replaceAll("\\", "/")) || track.versionSource.path.replaceAll("\\", "/").split("/").includes(".."))) {
@@ -6925,7 +6953,10 @@ var init_workspaces = __esm(() => {
6925
6953
  kind,
6926
6954
  union([boolean2(), literal("verified")]).optional()
6927
6955
  ]))).passthrough().optional(),
6928
- youtrack: object({ baseUrl: nonBlank.optional(), link_issues: boolean2().optional() }).passthrough().optional(),
6956
+ youtrack: object({
6957
+ baseUrl: nonBlank.optional(),
6958
+ link_issues: boolean2().optional()
6959
+ }).passthrough().optional(),
6929
6960
  issues: object({
6930
6961
  provider: _enum(["github", "gitlab", "youtrack"]).optional(),
6931
6962
  link: boolean2().optional(),
@@ -9286,7 +9317,7 @@ var package_default;
9286
9317
  var init_package = __esm(() => {
9287
9318
  package_default = {
9288
9319
  name: "@brainervirus/workit-cli",
9289
- version: "8.35.1",
9320
+ version: "8.35.2",
9290
9321
  private: false,
9291
9322
  description: "Workit CLI — setup wizard, doctor, and task control for agentic coding workflows",
9292
9323
  keywords: [
@@ -9324,13 +9355,13 @@ var init_package = __esm(() => {
9324
9355
  },
9325
9356
  dependencies: {
9326
9357
  "@babel/parser": "7.29.9",
9327
- "@brainervirus/workit-cursor": "^8.35.1",
9358
+ "@brainervirus/workit-cursor": "^8.35.2",
9328
9359
  "@inkjs/ui": "2.0.0",
9329
9360
  ink: "7.1.1",
9330
9361
  react: "19.2.8"
9331
9362
  },
9332
9363
  devDependencies: {
9333
- "@brainervirus/workit-core": "^8.35.1"
9364
+ "@brainervirus/workit-core": "^8.35.2"
9334
9365
  },
9335
9366
  engines: {
9336
9367
  node: ">=24"
@@ -14889,7 +14920,12 @@ function readLedger(cwd, options = {}) {
14889
14920
  });
14890
14921
  return {
14891
14922
  ok: true,
14892
- value: { path: file.value, rows, skipped, integrity: options.integrity ? integrity : null }
14923
+ value: {
14924
+ path: file.value,
14925
+ rows,
14926
+ skipped,
14927
+ integrity: options.integrity ? integrity : null
14928
+ }
14893
14929
  };
14894
14930
  }
14895
14931
  function ledgerTampering(cwd) {
@@ -15014,7 +15050,10 @@ function branchScope(cwd, branch) {
15014
15050
  return at >= since && at <= until;
15015
15051
  };
15016
15052
  }
15017
- function authorSessions(cwd, rows, branch, range = { base: null, head: null }, scope = branchScope(cwd, branch)) {
15053
+ function authorSessions(cwd, rows, branch, range = {
15054
+ base: null,
15055
+ head: null
15056
+ }, scope = branchScope(cwd, branch)) {
15018
15057
  const sessions = new Set;
15019
15058
  for (const row of rows) {
15020
15059
  if (!scope(row) || row.type !== "commit.recorded" && row.type !== "task.opened")
@@ -15089,12 +15128,13 @@ function restackCarries(exactIn, rows, branch, from, to) {
15089
15128
  const cwd = exactIn;
15090
15129
  let known = restackExact.get(row);
15091
15130
  if (known === undefined) {
15092
- known = typeof row.fromBase === "string" && typeof row.toBase === "string" && sameOwnChange(cwd, {
15131
+ const range = typeof row.fromBase === "string" && typeof row.toBase === "string" ? {
15093
15132
  from: fromHead,
15094
15133
  to: head,
15095
15134
  fromBase: row.fromBase,
15096
15135
  toBase: row.toBase
15097
- });
15136
+ } : null;
15137
+ known = range !== null && (sameOwnChange(cwd, range) || cleanRebase(cwd, range));
15098
15138
  restackExact.set(row, known);
15099
15139
  }
15100
15140
  return known;
@@ -15129,7 +15169,10 @@ function checkVerdicts(cwd, branch, ledgerRows) {
15129
15169
  const cacheKey = `${base}\x00${at}`;
15130
15170
  let key = keyCache.get(cacheKey);
15131
15171
  if (!key) {
15132
- key = { patchId: patchId(cwd, base, at), diffHash: diffHash(cwd, base, at) };
15172
+ key = {
15173
+ patchId: patchId(cwd, base, at),
15174
+ diffHash: diffHash(cwd, base, at)
15175
+ };
15133
15176
  keyCache.set(cacheKey, key);
15134
15177
  }
15135
15178
  return key;
@@ -15169,7 +15212,10 @@ function checkVerdicts(cwd, branch, ledgerRows) {
15169
15212
  };
15170
15213
  const exactCarry = (row) => FAILING.has(String(row.result)) || exactMatch(row) !== null;
15171
15214
  const keyBasis = (row) => {
15172
- const basis = verdictBasis(row, { head, ...keyFor(row.base ?? fallbackBase) });
15215
+ const basis = verdictBasis(row, {
15216
+ head,
15217
+ ...keyFor(row.base ?? fallbackBase)
15218
+ });
15173
15219
  return basis === "carried" && !exactCarry(row) ? "stale" : basis;
15174
15220
  };
15175
15221
  const rebaseNote = (row) => row.head && head && row.head !== head && !FAILING.has(String(row.result)) && keyBasis(row) === "carried" && exactMatch(row) === "rebase" ? { rule: "rebase", since: row.head, files: [] } : null;
@@ -15274,7 +15320,11 @@ function checkVerdicts(cwd, branch, ledgerRows) {
15274
15320
  const newestCurrent = verdicts.findLast((entry) => entry.current) ?? verdicts.at(-1) ?? null;
15275
15321
  const failing = verdicts.find((entry) => entry.current && entry.independent && FAILING.has(String(entry.verdict.result)));
15276
15322
  const newestAccepted = verdicts.findLast((entry) => entry.accepted && STRONG_RESULTS.has(String(entry.verdict.result))) ?? null;
15277
- const accepted = tampered.length ? { accepted: false, verdict: null, reasons: ["ledger_tampered"] } : newestAccepted && !failing ? { accepted: true, verdict: newestAccepted.verdict, reasons: [] } : {
15323
+ const accepted = tampered.length ? {
15324
+ accepted: false,
15325
+ verdict: null,
15326
+ reasons: ["ledger_tampered"]
15327
+ } : newestAccepted && !failing ? { accepted: true, verdict: newestAccepted.verdict, reasons: [] } : {
15278
15328
  accepted: false,
15279
15329
  verdict: failing?.verdict ?? null,
15280
15330
  reasons: failing ? ["failing_verdict"] : !newestCurrent ? ["no_verdict"] : newestCurrent.reasons.length ? newestCurrent.reasons : ["type_check_only"]
@@ -15292,7 +15342,10 @@ function checkVerdicts(cwd, branch, ledgerRows) {
15292
15342
  selfVerdict: accepted.accepted ? null : selfEntry?.verdict ?? null,
15293
15343
  base: newestCurrent?.verdict.base ?? fallbackBase,
15294
15344
  patchId: keyFor(newestCurrent?.verdict.base ?? fallbackBase).patchId,
15295
- current: { basis: newestCurrent?.basis ?? "none", verdict: newestCurrent?.verdict ?? null },
15345
+ current: {
15346
+ basis: newestCurrent?.basis ?? "none",
15347
+ verdict: newestCurrent?.verdict ?? null
15348
+ },
15296
15349
  carry: carryEntry?.carry ?? null,
15297
15350
  reverify,
15298
15351
  accepted,
@@ -15531,10 +15584,18 @@ function recordVerdict(context, input) {
15531
15584
  }
15532
15585
  function untrackedField(cwd) {
15533
15586
  const files = untrackedFiles2(cwd);
15534
- return files.length ? { untracked: files.slice(0, MAX_UNTRACKED_LISTED), untrackedCount: files.length } : {};
15587
+ return files.length ? {
15588
+ untracked: files.slice(0, MAX_UNTRACKED_LISTED),
15589
+ untrackedCount: files.length
15590
+ } : {};
15535
15591
  }
15536
15592
  function recordHandoff(context, input) {
15537
- return appendRow(context.cwd, { ...common(context, noteKey(context)), type: "handoff", note: input.note, next: input.next }, { now: context.now });
15593
+ return appendRow(context.cwd, {
15594
+ ...common(context, noteKey(context)),
15595
+ type: "handoff",
15596
+ note: input.note,
15597
+ next: input.next
15598
+ }, { now: context.now });
15538
15599
  }
15539
15600
  function rowLabels(row) {
15540
15601
  const labels = [];
@@ -15689,7 +15750,11 @@ function buildHandoff(cwd, options = {}) {
15689
15750
  }));
15690
15751
  const lastHandoffRow = mine.findLast((row) => row.type === "handoff");
15691
15752
  const partial = {
15692
- store: { root: store.value.root, shared: store.value.shared, ledger: ledger.path },
15753
+ store: {
15754
+ root: store.value.root,
15755
+ shared: store.value.shared,
15756
+ ledger: ledger.path
15757
+ },
15693
15758
  branch,
15694
15759
  head,
15695
15760
  subject: head ? git4(cwd, ["log", "-1", "--format=%s", head]) : null,
@@ -15722,7 +15787,11 @@ function buildHandoff(cwd, options = {}) {
15722
15787
  const nextCommand = nextCommandFor(partial);
15723
15788
  return {
15724
15789
  ok: true,
15725
- value: { ...partial, nextCommand, next: options.next?.trim() || nextCommand }
15790
+ value: {
15791
+ ...partial,
15792
+ nextCommand,
15793
+ next: options.next?.trim() || nextCommand
15794
+ }
15726
15795
  };
15727
15796
  }
15728
15797
  var LEDGER_VERSION = 1, MAX_LINE_BYTES = 4096, VERDICT_RESULTS, PASSING, FAILING, STRONG_RESULTS, VERDICT_KINDS, VERDICT_SURFACES, PR_ROW_TYPES, err = (code, error, unblock) => ({
@@ -15887,7 +15956,11 @@ ${body}`), TAIL_BYTES, lastLine = (fd, size) => {
15887
15956
  if (entry[0] === "R" || entry[0] === "C")
15888
15957
  index += 1;
15889
15958
  }
15890
- return { dirty: paths.length > 0, files: paths.length, paths: paths.slice(0, MAX_DIRTY_PATHS) };
15959
+ return {
15960
+ dirty: paths.length > 0,
15961
+ files: paths.length,
15962
+ paths: paths.slice(0, MAX_DIRTY_PATHS)
15963
+ };
15891
15964
  }, nextCommandFor = (brief) => {
15892
15965
  const branchFlag = brief.branch ? ` --branch ${brief.branch}` : "";
15893
15966
  const verify = `workit ledger verdict verified${branchFlag} --how "<method and evidence>" (from a session that did not author the branch, with WORKIT_SESSION_ID set)`;
@@ -80569,12 +80642,22 @@ function gitRestack(cwd, input) {
80569
80642
  if (!dir) {
80570
80643
  const scratch = scratchDir(cwd);
80571
80644
  if (!scratch)
80572
- return { ok: false, conflict: false, worktree: cwd, error: "no store root" };
80645
+ return {
80646
+ ok: false,
80647
+ conflict: false,
80648
+ worktree: cwd,
80649
+ error: "no store root"
80650
+ };
80573
80651
  fs28.mkdirSync(scratch, { recursive: true });
80574
80652
  dir = path56.join(scratch, `${input.branch.replace(/[^A-Za-z0-9._-]+/gu, "_").slice(0, 40)}-${randomBytes4(4).toString("hex")}`);
80575
80653
  const added = gitRun3(cwd, ["worktree", "add", "-q", dir, input.branch], GIT_TIMEOUTS.worktree);
80576
80654
  if (!added.ok)
80577
- return { ok: false, conflict: false, worktree: cwd, error: firstLine(added) };
80655
+ return {
80656
+ ok: false,
80657
+ conflict: false,
80658
+ worktree: cwd,
80659
+ error: firstLine(added)
80660
+ };
80578
80661
  }
80579
80662
  const run = gitRun3(dir, [
80580
80663
  "-c",
@@ -80597,7 +80680,12 @@ function gitRestack(cwd, input) {
80597
80680
  error: `git rebase did not finish within ${stackDeps.rebaseTimeoutMs} ms`
80598
80681
  };
80599
80682
  if (rebaseInProgress(dir))
80600
- return { ok: false, conflict: true, worktree: dir, error: firstLine(run) };
80683
+ return {
80684
+ ok: false,
80685
+ conflict: true,
80686
+ worktree: dir,
80687
+ error: firstLine(run)
80688
+ };
80601
80689
  if (!owner)
80602
80690
  gitRun3(cwd, ["worktree", "remove", "--force", dir]);
80603
80691
  return { ok: false, conflict: false, worktree: dir, error: firstLine(run) };
@@ -80605,7 +80693,12 @@ function gitRestack(cwd, input) {
80605
80693
  if (!owner)
80606
80694
  gitRun3(cwd, ["worktree", "remove", "--force", dir]);
80607
80695
  const head = branchTip(cwd, input.branch);
80608
- return head ? { ok: true, head } : { ok: false, conflict: false, worktree: dir, error: `${input.branch} vanished` };
80696
+ return head ? { ok: true, head } : {
80697
+ ok: false,
80698
+ conflict: false,
80699
+ worktree: dir,
80700
+ error: `${input.branch} vanished`
80701
+ };
80609
80702
  }
80610
80703
  function pruneScratch(cwd) {
80611
80704
  const scratch = scratchDir(cwd);
@@ -80730,7 +80823,10 @@ function listStacks(cwd) {
80730
80823
  if (parsed && fileFor(parsed.name) === name)
80731
80824
  out.push(parsed);
80732
80825
  }
80733
- return { ok: true, data: out.toSorted((a, b) => a.name.localeCompare(b.name)) };
80826
+ return {
80827
+ ok: true,
80828
+ data: out.toSorted((a, b) => a.name.localeCompare(b.name))
80829
+ };
80734
80830
  }
80735
80831
  function selectStack(cwd, name) {
80736
80832
  if (name !== null && !validName(name))
@@ -81075,7 +81171,10 @@ function statusDoc(ctx, pr) {
81075
81171
  const status = ctx.resolved.forge.prStatus(pr);
81076
81172
  if (!status.ok)
81077
81173
  return status;
81078
- return buildStatusDoc(ctx.cwd, ctx.resolved, status.data, { logLines: 0, behind: false });
81174
+ return buildStatusDoc(ctx.cwd, ctx.resolved, status.data, {
81175
+ logLines: 0,
81176
+ behind: false
81177
+ });
81079
81178
  }
81080
81179
  function prBinding(ctx, entry, doc) {
81081
81180
  const label = noun2(ctx.resolved, entry.pr);
@@ -81095,7 +81194,10 @@ function prBinding(ctx, entry, doc) {
81095
81194
  function repoMismatch(ctx, stack) {
81096
81195
  const { kind, repo } = ctx.resolved.forge;
81097
81196
  if (stack.repo && stack.repo !== repo || stack.forge && stack.forge !== kind)
81098
- return stackFail("blocked", `repo_mismatch: stack ${stack.name} was planned on ${stack.forge ?? "?"} ${stack.repo ?? "?"}, but this checkout resolves to ${kind} ${repo}`, `workit stack plan --name ${stack.name} <branch…> # re-plan it here, or run from the right checkout`, { planned: { forge: stack.forge, repo: stack.repo }, resolved: { forge: kind, repo } });
81197
+ return stackFail("blocked", `repo_mismatch: stack ${stack.name} was planned on ${stack.forge ?? "?"} ${stack.repo ?? "?"}, but this checkout resolves to ${kind} ${repo}`, `workit stack plan --name ${stack.name} <branch…> # re-plan it here, or run from the right checkout`, {
81198
+ planned: { forge: stack.forge, repo: stack.repo },
81199
+ resolved: { forge: kind, repo }
81200
+ });
81099
81201
  return null;
81100
81202
  }
81101
81203
  function qualify(ctx, stack, entry, doc, verdict, grant, binding = null, bypass = false) {
@@ -81236,7 +81338,11 @@ function detectMerged(ctx, cwd, stack, trunkSha, state) {
81236
81338
  merged = tip !== null && hasOwnCommits(cwd, tip, entry.lastParentHead) && isAncestor2(cwd, tip, trunkSha);
81237
81339
  }
81238
81340
  if (merged) {
81239
- entry.merged = { pr: entry.pr, mergeSha: null, at: new Date().toISOString() };
81341
+ entry.merged = {
81342
+ pr: entry.pr,
81343
+ mergeSha: null,
81344
+ at: new Date().toISOString()
81345
+ };
81240
81346
  newly.push({ branch: entry.branch, pr: entry.pr });
81241
81347
  }
81242
81348
  }
@@ -81250,18 +81356,31 @@ function pushBranch(cwd, actor, branch, priorTip) {
81250
81356
  if (!remote.ok)
81251
81357
  return stackFail(remote.code, remote.error);
81252
81358
  if (remote.sha === plan.data.sha)
81253
- return { ok: true, data: { pushed: false, forced: false, sha: plan.data.sha } };
81359
+ return {
81360
+ ok: true,
81361
+ data: { pushed: false, forced: false, sha: plan.data.sha }
81362
+ };
81254
81363
  const grant = requireGrant(cwd, "push", { forge: !plan.data.local });
81255
81364
  if (!grant.allowed)
81256
- return stackFail("blocked", grant.error, grant.unblock, { reason: grant.reason });
81365
+ return stackFail("blocked", grant.error, grant.unblock, {
81366
+ reason: grant.reason
81367
+ });
81257
81368
  const force = remote.sha !== null && !isAncestor2(cwd, remote.sha, plan.data.sha);
81258
81369
  const expect = !force ? null : remote.sha === priorTip ? priorTip : recordedRemoteTip(cwd, plan.data) ?? null;
81259
- const pushed = executePush(cwd, plan.data, { forceWithLease: force, expect, actor });
81370
+ const pushed = executePush(cwd, plan.data, {
81371
+ forceWithLease: force,
81372
+ expect,
81373
+ actor
81374
+ });
81260
81375
  if (!pushed.ok)
81261
81376
  return { ...fromForge(pushed), data: { branch } };
81262
81377
  return {
81263
81378
  ok: true,
81264
- data: { pushed: pushed.data.pushed, forced: pushed.data.forced, sha: plan.data.sha }
81379
+ data: {
81380
+ pushed: pushed.data.pushed,
81381
+ forced: pushed.data.forced,
81382
+ sha: plan.data.sha
81383
+ }
81265
81384
  };
81266
81385
  }
81267
81386
  function syncStack(cwd, ctx, stack, options, actor) {
@@ -81371,7 +81490,11 @@ function syncStack(cwd, ctx, stack, options, actor) {
81371
81490
  worktree: rebased.worktree,
81372
81491
  progress: outcome
81373
81492
  });
81374
- return rebased.conflict ? stackFail("blocked", `conflict restacking ${entry.branch} onto ${parent.name}: ${rebased.error}`, `resolve the conflicts in ${rebased.worktree}, git rebase --continue, then workit stack sync # or git rebase --abort`, { conflict: entry.branch, worktree: rebased.worktree, progress: outcome }) : stackFail("failed", `restacking ${entry.branch} failed: ${rebased.error}`, undefined, {
81493
+ return rebased.conflict ? stackFail("blocked", `conflict restacking ${entry.branch} onto ${parent.name}: ${rebased.error}`, `resolve the conflicts in ${rebased.worktree}, git rebase --continue, then workit stack sync # or git rebase --abort`, {
81494
+ conflict: entry.branch,
81495
+ worktree: rebased.worktree,
81496
+ progress: outcome
81497
+ }) : stackFail("failed", `restacking ${entry.branch} failed: ${rebased.error}`, undefined, {
81375
81498
  branch: entry.branch,
81376
81499
  progress: outcome
81377
81500
  });
@@ -81431,8 +81554,16 @@ function syncStack(cwd, ctx, stack, options, actor) {
81431
81554
  p: patchId(cwd, fromBase, fromHead),
81432
81555
  d: diffHash(cwd, fromBase, fromHead)
81433
81556
  };
81434
- const after = { p: patchId(cwd, parentTip, newTip), d: diffHash(cwd, parentTip, newTip) };
81435
- const equal = before.d !== null && before.d === after.d && before.p !== null && before.p === after.p && sameOwnChange(cwd, { from: fromHead, to: newTip, fromBase, toBase: parentTip });
81557
+ const after = {
81558
+ p: patchId(cwd, parentTip, newTip),
81559
+ d: diffHash(cwd, parentTip, newTip)
81560
+ };
81561
+ const equal = before.d !== null && before.d === after.d && before.p !== null && before.p === after.p && sameOwnChange(cwd, {
81562
+ from: fromHead,
81563
+ to: newTip,
81564
+ fromBase,
81565
+ toBase: parentTip
81566
+ });
81436
81567
  appendObserved(cwd, {
81437
81568
  type: "stack.restacked",
81438
81569
  actor,
@@ -81450,7 +81581,12 @@ function syncStack(cwd, ctx, stack, options, actor) {
81450
81581
  if (step.restack)
81451
81582
  step.restack.carried = equal;
81452
81583
  else
81453
- step.restack = { from: fromBase, onto: parentTip, head: newTip, carried: equal };
81584
+ step.restack = {
81585
+ from: fromBase,
81586
+ onto: parentTip,
81587
+ head: newTip,
81588
+ carried: equal
81589
+ };
81454
81590
  }
81455
81591
  if (options.publish) {
81456
81592
  touchStackLock();
@@ -81479,7 +81615,10 @@ function syncStack(cwd, ctx, stack, options, actor) {
81479
81615
  });
81480
81616
  const updated = ctx.resolved.forge.updateBase(entry.pr, parent.name);
81481
81617
  if (!updated.ok)
81482
- return { ...fromForge(updated), data: { branch: entry.branch, progress: outcome } };
81618
+ return {
81619
+ ...fromForge(updated),
81620
+ data: { branch: entry.branch, progress: outcome }
81621
+ };
81483
81622
  appendObserved(cwd, {
81484
81623
  type: "pr.retargeted",
81485
81624
  actor,
@@ -81554,7 +81693,9 @@ async function landStack(ctx, stack, options) {
81554
81693
  if (bypass) {
81555
81694
  const grant = requireGrant(ctx.cwd, "merge");
81556
81695
  if (!grant.allowed)
81557
- return failWith(stackFail("blocked", grant.error, grant.unblock, { reason: "grant_required" }));
81696
+ return failWith(stackFail("blocked", grant.error, grant.unblock, {
81697
+ reason: "grant_required"
81698
+ }));
81558
81699
  if (!grant.allowUnverified)
81559
81700
  return failWith(stackFail("blocked", `unverified_refused: workspace ${grant.workspace ? `"${grant.workspace}"` : "(none)"} grants merge: "verified", which never lands without an accepted independent verdict`, "a non-author session verifies each head (workit-review), then land without --unverified", { reason: "unverified_refused" }));
81560
81701
  }
@@ -81627,7 +81768,8 @@ async function landStack(ctx, stack, options) {
81627
81768
  deleteBranch: false,
81628
81769
  actor: ctx.actor,
81629
81770
  expect: { base: stack.trunk, branch: entry.branch },
81630
- ...bypass && !verdict.satisfied ? { unverified: bypass } : {}
81771
+ ...bypass && !verdict.satisfied ? { unverified: bypass } : {},
81772
+ ...options.baseRedOk ? { baseRedOk: options.baseRedOk } : {}
81631
81773
  }, ctx.sleep);
81632
81774
  if (!merged.ok) {
81633
81775
  if (merged.code === "blocked" && "refusal" in merged && merged.refusal) {
@@ -81649,7 +81791,11 @@ async function landStack(ctx, stack, options) {
81649
81791
  mergeSha: merged.data.mergeSha,
81650
81792
  unverified: merged.data.unverified?.recorded ?? null
81651
81793
  });
81652
- entry.merged = { pr, mergeSha: merged.data.mergeSha, at: new Date().toISOString() };
81794
+ entry.merged = {
81795
+ pr,
81796
+ mergeSha: merged.data.mergeSha,
81797
+ at: new Date().toISOString()
81798
+ };
81653
81799
  const written = writeStack(ctx.cwd, stack);
81654
81800
  if (!written.ok)
81655
81801
  return failWith(written);
@@ -87411,7 +87557,11 @@ __export(exports_stack, {
87411
87557
  run: () => run20
87412
87558
  });
87413
87559
  async function plan(argv, io) {
87414
- const flags = parseFlags(argv, { name: "value", trunk: "value", track: "value" });
87560
+ const flags = parseFlags(argv, {
87561
+ name: "value",
87562
+ trunk: "value",
87563
+ track: "value"
87564
+ });
87415
87565
  if (typeof flags === "string")
87416
87566
  return usage4(io, flags, PLAN_USAGE);
87417
87567
  const name = flags.values.name ?? null;
@@ -87472,7 +87622,12 @@ async function status3(argv, io) {
87472
87622
  const connected = connect(io, selected.data.branches[0]?.branch ?? null);
87473
87623
  if (!connected.ok)
87474
87624
  return forgeFail(io, connected);
87475
- const result = stackStatus({ cwd: io.cwd, resolved: connected.data, actor: actorFromEnv(io.env), sleep: forgeDeps.sleep }, selected.data);
87625
+ const result = stackStatus({
87626
+ cwd: io.cwd,
87627
+ resolved: connected.data,
87628
+ actor: actorFromEnv(io.env),
87629
+ sleep: forgeDeps.sleep
87630
+ }, selected.data);
87476
87631
  if (!result.ok)
87477
87632
  return stackFailed(io, result);
87478
87633
  return emit(io, ok2(result.data), (data) => [
@@ -87536,11 +87691,16 @@ async function land(argv, io) {
87536
87691
  timeout: "value",
87537
87692
  interval: "value",
87538
87693
  unverified: "boolean",
87694
+ "base-red-ok": "boolean",
87539
87695
  reason: "value"
87540
87696
  });
87541
87697
  if (typeof flags === "string")
87542
87698
  return usage4(io, flags, LAND_USAGE);
87543
- const unverified = unverifiedFlag(flags);
87699
+ const baseRedOk = flags.booleans.has("base-red-ok");
87700
+ const baseRedReason = flags.values.reason?.trim();
87701
+ if (baseRedOk && !baseRedReason)
87702
+ return usage4(io, "--base-red-ok needs --reason <why merging onto a red base is fine>", LAND_USAGE);
87703
+ const unverified = baseRedOk && !flags.booleans.has("unverified") ? null : unverifiedFlag(flags);
87544
87704
  if (typeof unverified === "string")
87545
87705
  return usage4(io, unverified, LAND_USAGE);
87546
87706
  if (flags.positionals.length)
@@ -87573,7 +87733,15 @@ async function land(argv, io) {
87573
87733
  resolved: connected.data,
87574
87734
  actor: actorFromEnv(io.env),
87575
87735
  sleep: forgeDeps.sleep
87576
- }, fresh.data ?? selected.data, { dryRun: flags.booleans.has("dry-run"), max, method, timeoutMs, intervalMs, unverified });
87736
+ }, fresh.data ?? selected.data, {
87737
+ dryRun: flags.booleans.has("dry-run"),
87738
+ max,
87739
+ method,
87740
+ timeoutMs,
87741
+ intervalMs,
87742
+ unverified,
87743
+ baseRedOk: baseRedOk && baseRedReason ? { reason: baseRedReason } : null
87744
+ });
87577
87745
  });
87578
87746
  if (!result.ok)
87579
87747
  return stackFailed(io, result);
@@ -87602,7 +87770,10 @@ async function run20(argv, io) {
87602
87770
  return land(rest, io);
87603
87771
  return usage4(io, sub && !sub.startsWith("-") ? `unknown stack subcommand "${sub}"` : "missing stack subcommand", USAGE12);
87604
87772
  }
87605
- var PLAN_USAGE = "workit stack plan [--name <n>] [--trunk <b> | --track <t>] [<bottom> … <top>] [--json]", STATUS_USAGE2 = "workit stack status [--name <n>] [--json]", SYNC_USAGE = "workit stack sync [--name <n>] [--local] [--dry-run] [--force <branch>]… [--json]", LAND_USAGE = "workit stack land [--name <n>] [--dry-run] [--max <n>] [--method squash|merge|rebase] [--unverified --reason <why>] [--timeout 20m] [--interval 30s] [--json]", USAGE12 = "workit stack plan|status|sync|land ... (workit help stack)", short5 = (sha) => sha ? sha.slice(0, 12) : "?", stackFailed = (io, result) => emit(io, fail2(result.code, result.error, { unblock: result.unblock, data: result.data ?? {} })), label3 = (forge, pr) => pr === null ? "no PR" : `${forge === "gitlab" ? "MR !" : "PR #"}${pr}`, renderSync = (data) => [
87773
+ var PLAN_USAGE = "workit stack plan [--name <n>] [--trunk <b> | --track <t>] [<bottom> … <top>] [--json]", STATUS_USAGE2 = "workit stack status [--name <n>] [--json]", SYNC_USAGE = "workit stack sync [--name <n>] [--local] [--dry-run] [--force <branch>]… [--json]", LAND_USAGE = "workit stack land [--name <n>] [--dry-run] [--max <n>] [--method squash|merge|rebase] [--unverified --reason <why>] [--base-red-ok --reason <why>] [--timeout 20m] [--interval 30s] [--json]", USAGE12 = "workit stack plan|status|sync|land ... (workit help stack)", short5 = (sha) => sha ? sha.slice(0, 12) : "?", stackFailed = (io, result) => emit(io, fail2(result.code, result.error, {
87774
+ unblock: result.unblock,
87775
+ data: result.data ?? {}
87776
+ })), label3 = (forge, pr) => pr === null ? "no PR" : `${forge === "gitlab" ? "MR !" : "PR #"}${pr}`, renderSync = (data) => [
87606
87777
  `${data.dryRun ? "would sync" : "synced"} stack ${data.name}${data.merged.length ? `; merged: ${data.merged.map((item) => item.branch).join(", ")}` : ""}`,
87607
87778
  ...data.steps.map((step) => [
87608
87779
  ` ${step.branch} on ${step.parent}:`,
@@ -106014,19 +106185,22 @@ function bounded(brief, cwd) {
106014
106185
  file = path73.join(dir, `${(brief.branch ?? "detached").replaceAll(/[^\w.-]+/gu, "-")}.txt`);
106015
106186
  fs37.writeFileSync(file, `${[...body, ...tail].join(`
106016
106187
  `)}
106017
- `, { mode: 384 });
106188
+ `, {
106189
+ mode: 384
106190
+ });
106018
106191
  } catch {
106019
106192
  file = null;
106020
106193
  }
106021
106194
  const pointer = `… cut to ${MAX_BRIEF_BYTES} bytes; full brief: ${file ?? "not written (workit handoff --json has it all)"}`;
106195
+ const cappedTail = tail.map(capLine);
106022
106196
  const kept = [];
106023
106197
  for (const line of body) {
106024
106198
  const cut = line.length > 400 ? `${line.slice(0, 400)}…` : line;
106025
- if (bytes([...kept, cut, pointer, ...tail]) > MAX_BRIEF_BYTES)
106199
+ if (bytes([...kept, cut, pointer, ...cappedTail]) > MAX_BRIEF_BYTES)
106026
106200
  break;
106027
106201
  kept.push(cut);
106028
106202
  }
106029
- return [...kept, pointer, ...tail];
106203
+ return [...kept, pointer, ...cappedTail];
106030
106204
  }
106031
106205
  async function resumeBrief(argv, io) {
106032
106206
  let values;
@@ -106048,7 +106222,9 @@ async function resumeBrief(argv, io) {
106048
106222
  }
106049
106223
  const last = values.last === undefined ? 10 : Number(values.last);
106050
106224
  if (!Number.isInteger(last) || last < 1)
106051
- return emit(io, fail2("invalid_input", "--last must be a positive integer", { unblock: USAGE19 }));
106225
+ return emit(io, fail2("invalid_input", "--last must be a positive integer", {
106226
+ unblock: USAGE19
106227
+ }));
106052
106228
  const built = buildHandoff(io.cwd, {
106053
106229
  last,
106054
106230
  note: values.note ?? null,
@@ -106074,7 +106250,7 @@ async function run27(argv, io) {
106074
106250
  }
106075
106251
  var USAGE19 = "workit handoff [--note <text>] [--next <text>] [--record] [--last <n>] [--json]", MAX_BRIEF_BYTES = 4096, short7 = (sha) => sha ? sha.slice(0, 12) : "no commit", bytes = (lines) => Buffer.byteLength(`${lines.join(`
106076
106252
  `)}
106077
- `);
106253
+ `), TAIL_LINE_BYTES = 480, capLine = (line) => Buffer.byteLength(line) <= TAIL_LINE_BYTES ? line : `${Buffer.from(line).subarray(0, TAIL_LINE_BYTES).toString().replace(/\uFFFD$/u, "")}… (cut)`;
106078
106254
  var init_handoff = __esm(() => {
106079
106255
  init_ledger();
106080
106256
  init_output();
@@ -106114,13 +106290,19 @@ var FAMILY_ACTIONS = {
106114
106290
  },
106115
106291
  evidence: { record: "Record evidence against a task's requirements" },
106116
106292
  finding: { record: "Record a finding", resolve: "Resolve a finding" },
106117
- decision: { record: "Record a task decision", revoke: "Revoke a task decision" },
106293
+ decision: {
106294
+ record: "Record a task decision",
106295
+ revoke: "Revoke a task decision"
106296
+ },
106118
106297
  worker: {
106119
106298
  assign: "Assign a worker to a task",
106120
106299
  report: "Report a worker's result",
106121
106300
  cancel: "Cancel a worker assignment"
106122
106301
  },
106123
- state: { export: "Export a task's state (v1)", import: "Import an exported task state" }
106302
+ state: {
106303
+ export: "Export a task's state (v1)",
106304
+ import: "Import an exported task state"
106305
+ }
106124
106306
  };
106125
106307
  var POLICY_JUDGE = "--judge risk=trivial|normal|high behavior=yes|no product-choice=yes|no plan=yes|no [--ref <path>]… [--why <reason>]";
106126
106308
  var TASK_IMPLICIT = [
@@ -106554,7 +106736,7 @@ var VERBS = [
106554
106736
  },
106555
106737
  {
106556
106738
  name: "land",
106557
- usage: "workit stack land [--name <n>] [--dry-run] [--max <n>] [--method squash|merge|rebase] [--unverified --reason <why>] [--timeout 20m] [--interval 30s]",
106739
+ usage: "workit stack land [--name <n>] [--dry-run] [--max <n>] [--method squash|merge|rebase] [--unverified --reason <why>] [--base-red-ok --reason <why>] [--timeout 20m] [--interval 30s]",
106558
106740
  summary: "Merge the stack root first, restacking the rest as each lands"
106559
106741
  }
106560
106742
  ],