@brainervirus/workit-cli 8.28.1 → 8.29.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.
- package/dist/index.js +211 -35
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -9245,7 +9245,7 @@ var package_default;
|
|
|
9245
9245
|
var init_package = __esm(() => {
|
|
9246
9246
|
package_default = {
|
|
9247
9247
|
name: "@brainervirus/workit-cli",
|
|
9248
|
-
version: "8.
|
|
9248
|
+
version: "8.29.0",
|
|
9249
9249
|
private: false,
|
|
9250
9250
|
description: "Workit CLI — setup wizard, doctor, and task control for agentic coding workflows",
|
|
9251
9251
|
keywords: [
|
|
@@ -9283,13 +9283,13 @@ var init_package = __esm(() => {
|
|
|
9283
9283
|
},
|
|
9284
9284
|
dependencies: {
|
|
9285
9285
|
"@babel/parser": "7.29.9",
|
|
9286
|
-
"@brainervirus/workit-cursor": "^8.
|
|
9286
|
+
"@brainervirus/workit-cursor": "^8.29.0",
|
|
9287
9287
|
"@inkjs/ui": "2.0.0",
|
|
9288
9288
|
ink: "7.1.1",
|
|
9289
9289
|
react: "19.2.8"
|
|
9290
9290
|
},
|
|
9291
9291
|
devDependencies: {
|
|
9292
|
-
"@brainervirus/workit-core": "^8.
|
|
9292
|
+
"@brainervirus/workit-core": "^8.29.0"
|
|
9293
9293
|
},
|
|
9294
9294
|
engines: {
|
|
9295
9295
|
node: ">=24"
|
|
@@ -9403,9 +9403,22 @@ function detectedChecks(root) {
|
|
|
9403
9403
|
add(plain("test", ["make", "test"]));
|
|
9404
9404
|
return checks;
|
|
9405
9405
|
}
|
|
9406
|
+
function configFileFor(root) {
|
|
9407
|
+
const own = checksConfigFile(root);
|
|
9408
|
+
if (fs5.existsSync(own))
|
|
9409
|
+
return own;
|
|
9410
|
+
const common = git3(root, ["rev-parse", "--path-format=absolute", "--git-common-dir"]);
|
|
9411
|
+
if (!common || path9.basename(common) !== ".git")
|
|
9412
|
+
return own;
|
|
9413
|
+
const main = path9.dirname(common);
|
|
9414
|
+
if (path9.resolve(main) === path9.resolve(root))
|
|
9415
|
+
return own;
|
|
9416
|
+
const shared = checksConfigFile(main);
|
|
9417
|
+
return fs5.existsSync(shared) ? shared : own;
|
|
9418
|
+
}
|
|
9406
9419
|
function loadCheckConfig(cwd) {
|
|
9407
9420
|
const root = checkRoot(cwd);
|
|
9408
|
-
const file =
|
|
9421
|
+
const file = configFileFor(root);
|
|
9409
9422
|
const legacy = path9.basename(file) === LEGACY_CHECKS_FILE;
|
|
9410
9423
|
const label = legacy ? LEGACY_CHECKS_FILE : CHECKS_FILE;
|
|
9411
9424
|
const note = legacy ? {
|
|
@@ -76836,6 +76849,8 @@ var init_resources = __esm(() => {
|
|
|
76836
76849
|
// packages/workit-cli/src/verbs/check.ts
|
|
76837
76850
|
var exports_check = {};
|
|
76838
76851
|
__export(exports_check, {
|
|
76852
|
+
OUTPUT_LINES: () => OUTPUT_LINES,
|
|
76853
|
+
boundedOutput: () => boundedOutput,
|
|
76839
76854
|
hostToolWaitCapMs: () => hostToolWaitCapMs,
|
|
76840
76855
|
run: () => run11,
|
|
76841
76856
|
workspaceResources: () => workspaceResources
|
|
@@ -76849,6 +76864,7 @@ function parse6(argv) {
|
|
|
76849
76864
|
name: null,
|
|
76850
76865
|
shell: false,
|
|
76851
76866
|
heavy: false,
|
|
76867
|
+
full: false,
|
|
76852
76868
|
noLease: false,
|
|
76853
76869
|
reason: null,
|
|
76854
76870
|
waitMs: null,
|
|
@@ -76867,8 +76883,11 @@ function parse6(argv) {
|
|
|
76867
76883
|
};
|
|
76868
76884
|
if (flag === "--json")
|
|
76869
76885
|
continue;
|
|
76870
|
-
if (flag === "--shell") {
|
|
76871
|
-
|
|
76886
|
+
if (flag === "--shell" || flag === "--full") {
|
|
76887
|
+
if (flag === "--shell")
|
|
76888
|
+
options.shell = true;
|
|
76889
|
+
else
|
|
76890
|
+
options.full = true;
|
|
76872
76891
|
continue;
|
|
76873
76892
|
}
|
|
76874
76893
|
if (flag === "--heavy" || flag === "--no-lease") {
|
|
@@ -77016,6 +77035,17 @@ function boundedArgv(argv) {
|
|
|
77016
77035
|
const truncated = cut.length !== argv.length || cut.some((item, index) => item !== argv[index]);
|
|
77017
77036
|
return { argv: cut, truncated };
|
|
77018
77037
|
}
|
|
77038
|
+
function boundedOutput(log, lines) {
|
|
77039
|
+
const all = tailLines(log, Number.MAX_SAFE_INTEGER);
|
|
77040
|
+
if (all.length === 0)
|
|
77041
|
+
return "";
|
|
77042
|
+
const shown = all.slice(-lines);
|
|
77043
|
+
const omitted = all.length - shown.length;
|
|
77044
|
+
return `${omitted ? `… ${omitted} earlier line${omitted === 1 ? "" : "s"} omitted (the full log is named below; --full streams it)
|
|
77045
|
+
` : ""}${shown.join(`
|
|
77046
|
+
`)}
|
|
77047
|
+
`;
|
|
77048
|
+
}
|
|
77019
77049
|
function hostToolWaitCapMs(env) {
|
|
77020
77050
|
if (!env.CLAUDECODE && !env.OPENCODE && !env.OPENCODE_SESSION_ID)
|
|
77021
77051
|
return null;
|
|
@@ -77145,6 +77175,10 @@ async function run11(argv, io) {
|
|
|
77145
77175
|
}
|
|
77146
77176
|
const relCwd = posix(path49.relative(top, runCwd));
|
|
77147
77177
|
const configured = !options.shell && matchesNamedCheck(config, name, command, relCwd);
|
|
77178
|
+
const shadowed = !configured && name !== null ? config.checks.find((item) => item.name === name) : undefined;
|
|
77179
|
+
if (shadowed)
|
|
77180
|
+
io.stderr(`note: "${name}" is configured as \`${shadowed.argv.join(" ")}\`; this ad-hoc run does not satisfy a configured gate (run workit check ${name})
|
|
77181
|
+
`);
|
|
77148
77182
|
const actor = actorFromEnv(io.env);
|
|
77149
77183
|
const branchKey = codeKey(io.cwd, { base: options.base });
|
|
77150
77184
|
const detached = branchKey.tree === null ? worktreeTree(io.cwd) : null;
|
|
@@ -77187,7 +77221,7 @@ async function run11(argv, io) {
|
|
|
77187
77221
|
...sinks,
|
|
77188
77222
|
...wrapper ? { wrapper } : {},
|
|
77189
77223
|
...lease ? { onSpawn: (pid) => updateLease(lease, { pgid: pid }) } : {}
|
|
77190
|
-
}), heavy?.wrapper ?? null, { onStdout: io.json ? io.stderr : io.stdout, onStderr: io.stderr });
|
|
77224
|
+
}), heavy?.wrapper ?? null, options.full ? { onStdout: io.json ? io.stderr : io.stdout, onStderr: io.stderr } : { onStdout: () => {}, onStderr: () => {} });
|
|
77191
77225
|
result = scoped.result;
|
|
77192
77226
|
if (heavy && scoped.fallback) {
|
|
77193
77227
|
io.stderr(`workit: the memory/CPU scope could not start (${scoped.fallback}); ran without it
|
|
@@ -77201,6 +77235,7 @@ async function run11(argv, io) {
|
|
|
77201
77235
|
const modifiedWorktree = key.tree !== null && treeAfter !== key.tree;
|
|
77202
77236
|
const store = storeRoot(io.cwd);
|
|
77203
77237
|
const blob = store.ok ? storeLog(store.value.root, result.log) : null;
|
|
77238
|
+
const logPath = store.ok && blob ? path49.join(store.value.root, blob.ref) : null;
|
|
77204
77239
|
const tail = tailLines(result.log, TAIL_LINES);
|
|
77205
77240
|
const passed = result.exitCode === 0 && !result.timedOut;
|
|
77206
77241
|
const bounded = boundedArgv(command);
|
|
@@ -77273,6 +77308,7 @@ async function run11(argv, io) {
|
|
|
77273
77308
|
patchId: key.patchId,
|
|
77274
77309
|
logDigest: observation.logDigest,
|
|
77275
77310
|
logRef: observation.logRef,
|
|
77311
|
+
logPath,
|
|
77276
77312
|
logTail: tail,
|
|
77277
77313
|
outputBytes: result.outputBytes,
|
|
77278
77314
|
logTruncated: result.truncated,
|
|
@@ -77289,18 +77325,21 @@ async function run11(argv, io) {
|
|
|
77289
77325
|
const code = !passed ? "failed" : recordError ? recordError.code : "ok";
|
|
77290
77326
|
const error = !passed ? result.timedOut ? `timed out after ${options.timeoutMs} ms` : result.spawnError ? `cannot start ${command[0]}: ${result.spawnError}` : `exited ${result.exitCode}` : recordError?.message;
|
|
77291
77327
|
const label = name ?? command.join(" ");
|
|
77292
|
-
const summary = `workit check ${label}: ${passed ? "passed" : error ?? "failed"} in ${result.durationMs} ms (${configured ? "configured" : "ad-hoc"}${name && !configured && config.checks.some((item) => item.name === name) ? `; not the configured command for "${name}"` : ""}); ${task.evidenceId ? `evidence ${task.evidenceId} on task ${task.task?.id}` : task.note ?? (task.error ? `task: ${task.error.message}` : "ledger only")}
|
|
77328
|
+
const summary = `workit check ${label}: ${passed ? "passed, exit 0" : error ?? "failed"} in ${result.durationMs} ms (${configured ? "configured" : "ad-hoc"}${name && !configured && config.checks.some((item) => item.name === name) ? `; not the configured command for "${name}"` : ""}); ${task.evidenceId ? `evidence ${task.evidenceId} on task ${task.task?.id}` : task.note ?? (task.error ? `task: ${task.error.message}` : "ledger only")}; log: ${logPath ?? "not stored"}`;
|
|
77293
77329
|
if (io.json)
|
|
77294
77330
|
io.stdout(`${JSON.stringify({ ok: code === "ok", code, data, ...error ? { error } : {}, ...task.stillUnsatisfied[0] ? { unblock: task.stillUnsatisfied[0].unblock } : {} })}
|
|
77295
77331
|
`);
|
|
77296
77332
|
else {
|
|
77333
|
+
if (!options.full)
|
|
77334
|
+
io.stdout(boundedOutput(result.log, OUTPUT_LINES));
|
|
77297
77335
|
io.stderr(`${summary}
|
|
77298
77336
|
`);
|
|
77299
77337
|
if (recordError && passed)
|
|
77300
77338
|
io.stderr(`workit: ${recordError.message}
|
|
77301
77339
|
`);
|
|
77302
|
-
|
|
77303
|
-
|
|
77340
|
+
if (!shadowed)
|
|
77341
|
+
for (const gap of task.stillUnsatisfied)
|
|
77342
|
+
io.stderr(` still unsatisfied: ${gap.ruleId}: ${gap.reason}
|
|
77304
77343
|
`);
|
|
77305
77344
|
}
|
|
77306
77345
|
if (!passed)
|
|
@@ -77309,7 +77348,7 @@ async function run11(argv, io) {
|
|
|
77309
77348
|
return recordError.code === "busy" ? 4 : recordError.code === "invalid_input" ? 2 : 5;
|
|
77310
77349
|
return 0;
|
|
77311
77350
|
}
|
|
77312
|
-
var USAGE4 = 'workit check <name> [--no-lease --reason "<why>"] | workit check [--name <n>] [--shell] [--heavy] [--wait <s>] [--timeout <s>] [--task <id>] [--json] -- <cmd…>', MAX_UNVERIFIED_RUN_MS, RECORD_TAIL_LINES = 20, RECORD_TAIL_CHARS = 200, posix = (value) => value.split(path49.sep).join("/") || ".", ENGINE_CODES2, FINGERPRINT_VARS, HOST_TOOL_WAIT_CAP_MS = 1e5;
|
|
77351
|
+
var USAGE4 = 'workit check <name> [--full] [--no-lease --reason "<why>"] | workit check [--name <n>] [--shell] [--heavy] [--full] [--wait <s>] [--timeout <s>] [--task <id>] [--json] -- <cmd…>', OUTPUT_LINES = 60, MAX_UNVERIFIED_RUN_MS, RECORD_TAIL_LINES = 20, RECORD_TAIL_CHARS = 200, posix = (value) => value.split(path49.sep).join("/") || ".", ENGINE_CODES2, FINGERPRINT_VARS, HOST_TOOL_WAIT_CAP_MS = 1e5;
|
|
77313
77352
|
var init_check = __esm(() => {
|
|
77314
77353
|
init_check_config();
|
|
77315
77354
|
init_checks3();
|
|
@@ -78578,18 +78617,18 @@ var COMMIT_TIMEOUT_MS, PUSH_TIMEOUT_MS = 120000, git5 = (cwd, args, options = {}
|
|
|
78578
78617
|
const lines = redactText(`${run.stderr}
|
|
78579
78618
|
${run.stdout ?? ""}`).split(/\r?\n/u).map((value) => value.trim()).filter((value) => value && !value.startsWith("hint:"));
|
|
78580
78619
|
return lines.slice(-max).join(" / ").slice(0, 400) || "git failed";
|
|
78581
|
-
},
|
|
78620
|
+
}, OUTPUT_LINES2 = 200, OUTPUT_LINE_CHARS = 1000, gitOutput = (run) => {
|
|
78582
78621
|
const lines = redactText(`${run.stderr}
|
|
78583
78622
|
${run.stdout ?? ""}`).split(/\r?\n/u).map((value) => value.trimEnd()).filter((value) => value.trim() && !value.trimStart().startsWith("hint:")).map((value) => value.length > OUTPUT_LINE_CHARS ? `${value.slice(0, OUTPUT_LINE_CHARS)}…` : value);
|
|
78584
78623
|
if (!lines.length)
|
|
78585
78624
|
return "git failed";
|
|
78586
|
-
if (lines.length <=
|
|
78625
|
+
if (lines.length <= OUTPUT_LINES2)
|
|
78587
78626
|
return lines.join(`
|
|
78588
78627
|
`);
|
|
78589
|
-
const half =
|
|
78628
|
+
const half = OUTPUT_LINES2 / 2;
|
|
78590
78629
|
return [
|
|
78591
78630
|
...lines.slice(0, half),
|
|
78592
|
-
`… ${lines.length -
|
|
78631
|
+
`… ${lines.length - OUTPUT_LINES2} lines omitted …`,
|
|
78593
78632
|
...lines.slice(-half)
|
|
78594
78633
|
].join(`
|
|
78595
78634
|
`);
|
|
@@ -84336,16 +84375,66 @@ async function rerun(argv, io) {
|
|
|
84336
84375
|
"next: workit ci wait"
|
|
84337
84376
|
]);
|
|
84338
84377
|
}
|
|
84378
|
+
async function logs(argv, io) {
|
|
84379
|
+
const flags = parseFlags(argv, { pr: "value", branch: "value", failed: "boolean" });
|
|
84380
|
+
if (typeof flags === "string")
|
|
84381
|
+
return usage3(io, flags, LOGS_USAGE);
|
|
84382
|
+
if (flags.positionals.length)
|
|
84383
|
+
return usage3(io, `unexpected argument ${flags.positionals[0]}`, LOGS_USAGE);
|
|
84384
|
+
if (!flags.booleans.has("failed"))
|
|
84385
|
+
return usage3(io, "pass --failed: only the failing steps' tails are printed", LOGS_USAGE);
|
|
84386
|
+
const pr = positiveInt(flags.values.pr, "--pr");
|
|
84387
|
+
if (typeof pr === "string")
|
|
84388
|
+
return usage3(io, pr, LOGS_USAGE);
|
|
84389
|
+
if (pr && flags.values.branch)
|
|
84390
|
+
return usage3(io, "pass --pr or --branch, not both", LOGS_USAGE);
|
|
84391
|
+
const connected = connect(io, flags.values.branch);
|
|
84392
|
+
if (!connected.ok)
|
|
84393
|
+
return forgeFail(io, connected);
|
|
84394
|
+
const resolved = connected.data;
|
|
84395
|
+
const number = selectPr(io.cwd, resolved, { pr, branch: flags.values.branch ?? null });
|
|
84396
|
+
if (!number.ok)
|
|
84397
|
+
return forgeFail(io, number);
|
|
84398
|
+
const status = resolved.forge.prStatus(number.data);
|
|
84399
|
+
if (!status.ok)
|
|
84400
|
+
return forgeFail(io, status);
|
|
84401
|
+
const doc = buildStatusDoc(io.cwd, resolved, status.data, { logLines: LOG_LINES, behind: false });
|
|
84402
|
+
if (!doc.ok)
|
|
84403
|
+
return forgeFail(io, doc);
|
|
84404
|
+
const data = {
|
|
84405
|
+
pr: doc.data.number,
|
|
84406
|
+
head: status.data.head.sha,
|
|
84407
|
+
failing: doc.data.checks.failing.map((check) => ({
|
|
84408
|
+
name: check.name,
|
|
84409
|
+
url: check.url,
|
|
84410
|
+
conclusion: check.conclusion,
|
|
84411
|
+
logTail: check.logTail,
|
|
84412
|
+
...check.logError ? { logError: check.logError } : {}
|
|
84413
|
+
}))
|
|
84414
|
+
};
|
|
84415
|
+
return emit(io, ok2(data), () => data.failing.length ? [
|
|
84416
|
+
`PR #${data.pr} head ${data.head.slice(0, 7)}: ${data.failing.length} failing check${data.failing.length === 1 ? "" : "s"} (last ${LOG_LINES} log lines each)`,
|
|
84417
|
+
...data.failing.flatMap((check) => [
|
|
84418
|
+
`x ${check.name}${check.conclusion ? ` (${check.conclusion})` : ""}${check.url ? ` ${check.url}` : ""}`,
|
|
84419
|
+
...check.logTail.length ? check.logTail.map((line) => ` ${line}`) : [
|
|
84420
|
+
` (no log: ${check.logError ?? "not an Actions job, or beyond the tails fetched"})`
|
|
84421
|
+
]
|
|
84422
|
+
])
|
|
84423
|
+
] : [`PR #${data.pr} head ${data.head.slice(0, 7)}: no failing checks`]);
|
|
84424
|
+
}
|
|
84339
84425
|
async function run15(argv, io) {
|
|
84340
84426
|
const [sub, ...rest] = argv;
|
|
84341
84427
|
if (sub === "wait")
|
|
84342
84428
|
return wait2(rest, io);
|
|
84343
84429
|
if (sub === "rerun")
|
|
84344
84430
|
return rerun(rest, io);
|
|
84431
|
+
if (sub === "logs")
|
|
84432
|
+
return logs(rest, io);
|
|
84345
84433
|
return usage3(io, sub && !sub.startsWith("-") ? `unknown ci subcommand "${sub}"` : "missing ci subcommand", `${WAIT_USAGE}
|
|
84346
|
-
${RERUN_USAGE}
|
|
84434
|
+
${RERUN_USAGE}
|
|
84435
|
+
${LOGS_USAGE}`);
|
|
84347
84436
|
}
|
|
84348
|
-
var WAIT_USAGE = "workit ci wait [--pr <n> | --branch <b>] [--head <sha>] [--timeout 20m] [--interval 30s] [--json]", RERUN_USAGE = "workit ci rerun [--pr <n> | --branch <b>] [--check <name>… | --failed] --reason flake|infra [--force] [--json]", ONE_POLL_MS = 20000, MAX_POLL_ERRORS = 3, seconds = (ms) => `${Math.round(ms / 1000)}s`;
|
|
84437
|
+
var WAIT_USAGE = "workit ci wait [--pr <n> | --branch <b>] [--head <sha>] [--timeout 20m] [--interval 30s] [--json]", RERUN_USAGE = "workit ci rerun [--pr <n> | --branch <b>] [--check <name>… | --failed] --reason flake|infra [--force] [--json]", LOGS_USAGE = "workit ci logs --failed [--pr <n> | --branch <b>] [--json]", LOG_LINES = 60, ONE_POLL_MS = 20000, MAX_POLL_ERRORS = 3, seconds = (ms) => `${Math.round(ms / 1000)}s`;
|
|
84349
84438
|
var init_ci = __esm(() => {
|
|
84350
84439
|
init_report();
|
|
84351
84440
|
init_ledger();
|
|
@@ -86179,6 +86268,27 @@ function excludeScratch(cwd) {
|
|
|
86179
86268
|
${EXCLUDE_LINE}
|
|
86180
86269
|
`);
|
|
86181
86270
|
}
|
|
86271
|
+
function worktreeDependencies(main, worktree) {
|
|
86272
|
+
for (const [name, install] of LOCKFILES2) {
|
|
86273
|
+
const ours = readBytes(path62.join(main, name));
|
|
86274
|
+
const theirs = readBytes(path62.join(worktree, name));
|
|
86275
|
+
if (ours === null && theirs === null)
|
|
86276
|
+
continue;
|
|
86277
|
+
if (ours !== null && theirs !== null && ours.equals(theirs))
|
|
86278
|
+
continue;
|
|
86279
|
+
if (fs33.existsSync(path62.join(worktree, "node_modules")))
|
|
86280
|
+
break;
|
|
86281
|
+
const command = install(worktree);
|
|
86282
|
+
return {
|
|
86283
|
+
linked: null,
|
|
86284
|
+
install: command,
|
|
86285
|
+
notes: [
|
|
86286
|
+
`${name} differs from the main checkout's (${main}), so its node_modules was not linked; install dependencies first: ${command}`
|
|
86287
|
+
]
|
|
86288
|
+
};
|
|
86289
|
+
}
|
|
86290
|
+
return { ...linkWorktreeDependencies(main, worktree), install: null };
|
|
86291
|
+
}
|
|
86182
86292
|
function ensureScratch(worktree) {
|
|
86183
86293
|
const scratch = path62.join(worktree, SCRATCH_DIR);
|
|
86184
86294
|
fs33.mkdirSync(scratch, { recursive: true });
|
|
@@ -86208,7 +86318,7 @@ function createSliceWorktree(cwd, plan, input) {
|
|
|
86208
86318
|
if (!createdRow(cwd, plan, slice, target))
|
|
86209
86319
|
return fanoutFail("blocked", `${target} is a worktree that workit fanout worktree create did not make for slice ${slice.id}`, `remove it yourself (git worktree remove ${target}) once you know what it holds`);
|
|
86210
86320
|
excludeScratch(cwd);
|
|
86211
|
-
const deps =
|
|
86321
|
+
const deps = worktreeDependencies(mainCheckout(cwd), target);
|
|
86212
86322
|
return {
|
|
86213
86323
|
ok: true,
|
|
86214
86324
|
data: {
|
|
@@ -86218,6 +86328,7 @@ function createSliceWorktree(cwd, plan, input) {
|
|
|
86218
86328
|
mode: resolveRef(cwd, localRef) ? "resume" : "new",
|
|
86219
86329
|
created: false,
|
|
86220
86330
|
dependencies: deps.linked,
|
|
86331
|
+
install: deps.install,
|
|
86221
86332
|
notes: [
|
|
86222
86333
|
deps.linked ? "the worktree already exists; only its missing dependencies were linked" : "the worktree already exists; nothing was changed",
|
|
86223
86334
|
...deps.notes
|
|
@@ -86271,7 +86382,7 @@ function createSliceWorktree(cwd, plan, input) {
|
|
|
86271
86382
|
}
|
|
86272
86383
|
excludeScratch(cwd);
|
|
86273
86384
|
const scratch = ensureScratch(target);
|
|
86274
|
-
const deps =
|
|
86385
|
+
const deps = worktreeDependencies(mainCheckout(cwd), target);
|
|
86275
86386
|
notes.push(...deps.notes);
|
|
86276
86387
|
const head = gitRun4(target, ["rev-parse", "HEAD"]).stdout.trim();
|
|
86277
86388
|
const baseSha = mode === "new" ? head : null;
|
|
@@ -86294,7 +86405,16 @@ function createSliceWorktree(cwd, plan, input) {
|
|
|
86294
86405
|
});
|
|
86295
86406
|
return {
|
|
86296
86407
|
ok: true,
|
|
86297
|
-
data: {
|
|
86408
|
+
data: {
|
|
86409
|
+
...base,
|
|
86410
|
+
scratch,
|
|
86411
|
+
head,
|
|
86412
|
+
mode,
|
|
86413
|
+
created: true,
|
|
86414
|
+
dependencies: deps.linked,
|
|
86415
|
+
install: deps.install,
|
|
86416
|
+
notes
|
|
86417
|
+
}
|
|
86298
86418
|
};
|
|
86299
86419
|
}
|
|
86300
86420
|
function releaseSliceWorktree(cwd, plan, input) {
|
|
@@ -86433,7 +86553,13 @@ var SLOW, SCRATCH_DIR = ".workit-scratch", EXCLUDE_LINE, DIRTY_ROW_BYTES = 2000,
|
|
|
86433
86553
|
}, inside3 = (child, parent) => {
|
|
86434
86554
|
const relative = path62.relative(canonical2(parent), canonical2(child));
|
|
86435
86555
|
return relative === "" || !relative.startsWith("..") && !path62.isAbsolute(relative);
|
|
86436
|
-
}, slicePath = (cwd, slice) => path62.isAbsolute(slice.worktree) ? slice.worktree : path62.resolve(mainCheckout(cwd), slice.worktree), CLOCK_SLACK_MS = 2000, worktreeDeps,
|
|
86556
|
+
}, slicePath = (cwd, slice) => path62.isAbsolute(slice.worktree) ? slice.worktree : path62.resolve(mainCheckout(cwd), slice.worktree), CLOCK_SLACK_MS = 2000, worktreeDeps, LOCKFILES2, readBytes = (file) => {
|
|
86557
|
+
try {
|
|
86558
|
+
return fs33.readFileSync(file);
|
|
86559
|
+
} catch {
|
|
86560
|
+
return null;
|
|
86561
|
+
}
|
|
86562
|
+
}, worktreeFailed = (stderr) => fanoutFail("failed", `git worktree add failed: ${stderr.trim().split(`
|
|
86437
86563
|
`)[0] || "unknown error"}`);
|
|
86438
86564
|
var init_fanout_worktree = __esm(() => {
|
|
86439
86565
|
init_ops();
|
|
@@ -86447,6 +86573,13 @@ var init_fanout_worktree = __esm(() => {
|
|
|
86447
86573
|
worktreeDeps = {
|
|
86448
86574
|
stat: (file) => fs33.statSync(file, { bigint: true })
|
|
86449
86575
|
};
|
|
86576
|
+
LOCKFILES2 = [
|
|
86577
|
+
["bun.lock", (dir) => `bun install --frozen-lockfile --cwd ${dir}`],
|
|
86578
|
+
["bun.lockb", (dir) => `bun install --frozen-lockfile --cwd ${dir}`],
|
|
86579
|
+
["pnpm-lock.yaml", (dir) => `pnpm install --frozen-lockfile --dir ${dir}`],
|
|
86580
|
+
["yarn.lock", (dir) => `yarn install --frozen-lockfile --cwd ${dir}`],
|
|
86581
|
+
["package-lock.json", (dir) => `npm ci --prefix ${dir}`]
|
|
86582
|
+
];
|
|
86450
86583
|
});
|
|
86451
86584
|
|
|
86452
86585
|
// packages/workit-core/src/fanout-brief.ts
|
|
@@ -104787,10 +104920,13 @@ var init_changelog2 = __esm(() => {
|
|
|
104787
104920
|
// packages/workit-cli/src/verbs/handoff.ts
|
|
104788
104921
|
var exports_handoff = {};
|
|
104789
104922
|
__export(exports_handoff, {
|
|
104923
|
+
MAX_BRIEF_BYTES: () => MAX_BRIEF_BYTES,
|
|
104790
104924
|
run: () => run26
|
|
104791
104925
|
});
|
|
104926
|
+
import fs35 from "node:fs";
|
|
104927
|
+
import path70 from "node:path";
|
|
104792
104928
|
import { parseArgs as parseArgs2 } from "node:util";
|
|
104793
|
-
function
|
|
104929
|
+
function render3(brief) {
|
|
104794
104930
|
const lines = [
|
|
104795
104931
|
`branch: ${brief.branch ?? "(detached)"} @ ${short7(brief.head)}${brief.subject ? ` ${brief.subject}` : ""}`
|
|
104796
104932
|
];
|
|
@@ -104810,14 +104946,42 @@ function human2(brief) {
|
|
|
104810
104946
|
lines.push(`last handoff (${brief.lastHandoff.at}): ${brief.lastHandoff.next}${brief.lastHandoff.note ? ` (note: ${brief.lastHandoff.note})` : ""}`);
|
|
104811
104947
|
if (brief.recent.length)
|
|
104812
104948
|
lines.push("recent ledger:", ...brief.recent.map((row) => ` #${row.seq} ${row.type}${row.branch ? ` [${row.branch}]` : ""}${row.labels.length ? ` (${row.labels.join(", ")})` : ""} ${row.summary}`));
|
|
104949
|
+
const tail = [];
|
|
104813
104950
|
if (brief.note)
|
|
104814
|
-
|
|
104815
|
-
|
|
104951
|
+
tail.push(`note: ${brief.note}`);
|
|
104952
|
+
tail.push(`next: ${brief.next}`);
|
|
104816
104953
|
if (brief.next !== brief.nextCommand)
|
|
104817
|
-
|
|
104954
|
+
tail.push(`next command: ${brief.nextCommand}`);
|
|
104818
104955
|
if (brief.recorded)
|
|
104819
|
-
|
|
104820
|
-
return lines;
|
|
104956
|
+
tail.push(`recorded handoff ${brief.recorded}`);
|
|
104957
|
+
return { body: lines, tail };
|
|
104958
|
+
}
|
|
104959
|
+
function bounded(brief, cwd) {
|
|
104960
|
+
const { body, tail } = render3(brief);
|
|
104961
|
+
if (bytes([...body, ...tail]) <= MAX_BRIEF_BYTES)
|
|
104962
|
+
return [...body, ...tail];
|
|
104963
|
+
const store = storeRoot(cwd);
|
|
104964
|
+
let file = null;
|
|
104965
|
+
if (store.ok)
|
|
104966
|
+
try {
|
|
104967
|
+
const dir = path70.join(store.value.root, "handoff");
|
|
104968
|
+
fs35.mkdirSync(dir, { recursive: true });
|
|
104969
|
+
file = path70.join(dir, `${(brief.branch ?? "detached").replaceAll(/[^\w.-]+/gu, "-")}.txt`);
|
|
104970
|
+
fs35.writeFileSync(file, `${[...body, ...tail].join(`
|
|
104971
|
+
`)}
|
|
104972
|
+
`, { mode: 384 });
|
|
104973
|
+
} catch {
|
|
104974
|
+
file = null;
|
|
104975
|
+
}
|
|
104976
|
+
const pointer = `… cut to ${MAX_BRIEF_BYTES} bytes; full brief: ${file ?? "not written (workit handoff --json has it all)"}`;
|
|
104977
|
+
const kept = [];
|
|
104978
|
+
for (const line of body) {
|
|
104979
|
+
const cut = line.length > 400 ? `${line.slice(0, 400)}…` : line;
|
|
104980
|
+
if (bytes([...kept, cut, pointer, ...tail]) > MAX_BRIEF_BYTES)
|
|
104981
|
+
break;
|
|
104982
|
+
kept.push(cut);
|
|
104983
|
+
}
|
|
104984
|
+
return [...kept, pointer, ...tail];
|
|
104821
104985
|
}
|
|
104822
104986
|
async function resumeBrief(argv, io) {
|
|
104823
104987
|
let values;
|
|
@@ -104855,7 +105019,7 @@ async function resumeBrief(argv, io) {
|
|
|
104855
105019
|
return emit(io, fail2(row.code, row.error, { data: { ...data, recorded } }));
|
|
104856
105020
|
recorded = row.value.id;
|
|
104857
105021
|
}
|
|
104858
|
-
return emit(io, ok2({ ...data, recorded }),
|
|
105022
|
+
return emit(io, ok2({ ...data, recorded }), (brief) => bounded(brief, io.cwd));
|
|
104859
105023
|
}
|
|
104860
105024
|
async function run26(argv, io) {
|
|
104861
105025
|
if (!argv.some((arg) => arg === "--task" || arg.startsWith("--task=")))
|
|
@@ -104863,7 +105027,9 @@ async function run26(argv, io) {
|
|
|
104863
105027
|
await Promise.resolve().then(() => init_task());
|
|
104864
105028
|
return runTaskCommand(["handoff", ...argv]);
|
|
104865
105029
|
}
|
|
104866
|
-
var USAGE18 = "workit handoff [--note <text>] [--next <text>] [--record] [--last <n>] [--json]", short7 = (sha) => sha ? sha.slice(0, 12) : "no commit"
|
|
105030
|
+
var USAGE18 = "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(`
|
|
105031
|
+
`)}
|
|
105032
|
+
`);
|
|
104867
105033
|
var init_handoff = __esm(() => {
|
|
104868
105034
|
init_ledger();
|
|
104869
105035
|
init_output();
|
|
@@ -104872,7 +105038,7 @@ var init_handoff = __esm(() => {
|
|
|
104872
105038
|
// packages/workit-cli/src/main.ts
|
|
104873
105039
|
init_host_session();
|
|
104874
105040
|
init_package();
|
|
104875
|
-
import
|
|
105041
|
+
import path71 from "node:path";
|
|
104876
105042
|
|
|
104877
105043
|
// packages/workit-cli/src/verbs/registry.ts
|
|
104878
105044
|
var TASK_FAMILY_NAMES = [
|
|
@@ -104977,7 +105143,8 @@ var LEASE_NOTES = [
|
|
|
104977
105143
|
"The heavy-check lease: heavy work (tests, builds, lint, typecheck, installs, image builds) shares one machine-wide lease, so parallel agents and worktrees never exhaust this machine's memory and CPU. `slots` (default 1) heavy checks run at once; on Linux each also runs in a systemd scope with MemoryMax and CPUQuota.",
|
|
104978
105144
|
"Waiting: a heavy check that finds every slot held prints one `waiting for the heavy-check lease` line naming the holder (check, pid, session, age, directory), polls once a second, and exits 4 (busy) after `--wait <s>`, else `resources.wait` seconds (default 600, capped at 100 inside a Claude Code or OpenCode shell). `workit lock status` shows the holders; `workit lock wait` waits for a free slot.",
|
|
104979
105145
|
"--heavy: an ad-hoc `workit check -- <cmd>` takes the lease only with --heavy; the named checks test, build and typecheck always do. The shell hook runs a raw heavy command (`npx jest`, `npm run test:ci`, `cargo test`, `docker build`) as `workit check --heavy -- <cmd>` on Claude Code, OpenCode and Pi, and denies it with that exact command on Codex and Cursor.",
|
|
104980
|
-
'--no-lease skips the lease and needs --reason "<why>". Never hand-roll a flock: the lease already queues every agent on the machine.'
|
|
105146
|
+
'--no-lease skips the lease and needs --reason "<why>". Never hand-roll a flock: the lease already queues every agent on the machine.',
|
|
105147
|
+
"Output: a check prints the last 60 lines of its output and one summary line with `log: <path>` to the full log; --full streams all of it."
|
|
104981
105148
|
];
|
|
104982
105149
|
var VERIFY_OPTIONS = "[--expect pushed|pr|merged|released] [--pr <n> | --branch <b>] [--sha <sha>] [--tag <t>] [--package <name[@version]>]";
|
|
104983
105150
|
var LEDGER_ACTOR = "[--branch <b> | --pr <n>] [--supersedes <id>] [--session <id> [--token <t>] | --as <role>]";
|
|
@@ -105060,7 +105227,7 @@ var VERBS = [
|
|
|
105060
105227
|
{
|
|
105061
105228
|
name: "check",
|
|
105062
105229
|
group: "delivery",
|
|
105063
|
-
usage: 'workit check <name> [--task <id>] [--base <ref>] [--no-lease --reason "<why>"] | workit check [--name <n>] [--shell] [--timeout <s>] [--task <id>] [--base <ref>] [--heavy [--wait <s>]] [--no-lease --reason "<why>"] -- <cmd…>',
|
|
105230
|
+
usage: 'workit check <name> [--full] [--task <id>] [--base <ref>] [--no-lease --reason "<why>"] | workit check [--name <n>] [--shell] [--full] [--timeout <s>] [--task <id>] [--base <ref>] [--heavy [--wait <s>]] [--no-lease --reason "<why>"] -- <cmd…>',
|
|
105064
105231
|
flagHints: {
|
|
105065
105232
|
list: "workit check <name> runs a configured check; a name that is not configured prints the valid ones (workit check test|lint|typecheck|check)"
|
|
105066
105233
|
},
|
|
@@ -105180,7 +105347,7 @@ var VERBS = [
|
|
|
105180
105347
|
withSubcommands({
|
|
105181
105348
|
name: "ci",
|
|
105182
105349
|
group: "delivery",
|
|
105183
|
-
summary: "Wait for CI on the PR head (exit 0/1/3/4), or rerun failed jobs once per head",
|
|
105350
|
+
summary: "Wait for CI on the PR head (exit 0/1/3/4), read the failing jobs' log tails, or rerun failed jobs once per head",
|
|
105184
105351
|
subcommands: [
|
|
105185
105352
|
{
|
|
105186
105353
|
name: "wait",
|
|
@@ -105191,9 +105358,18 @@ var VERBS = [
|
|
|
105191
105358
|
name: "rerun",
|
|
105192
105359
|
usage: "workit ci rerun [--pr <n> | --branch <b>] [--check <name>… | --failed] --reason flake|infra [--force]",
|
|
105193
105360
|
summary: "Rerun failed jobs once per head, with a recorded reason"
|
|
105361
|
+
},
|
|
105362
|
+
{
|
|
105363
|
+
name: "logs",
|
|
105364
|
+
usage: "workit ci logs --failed [--pr <n> | --branch <b>]",
|
|
105365
|
+
summary: "The failing checks of the PR head, each with its job log's last 60 lines"
|
|
105194
105366
|
}
|
|
105195
105367
|
],
|
|
105196
|
-
examples: [
|
|
105368
|
+
examples: [
|
|
105369
|
+
"workit ci wait --timeout 30m",
|
|
105370
|
+
"workit ci logs --failed",
|
|
105371
|
+
"workit ci rerun --failed --reason flake"
|
|
105372
|
+
],
|
|
105197
105373
|
load: () => Promise.resolve().then(() => (init_ci(), exports_ci))
|
|
105198
105374
|
}),
|
|
105199
105375
|
withSubcommands({
|
|
@@ -105734,7 +105910,7 @@ var defaultIo = (json) => ({
|
|
|
105734
105910
|
});
|
|
105735
105911
|
async function main(argv, overrides = {}, options = {}) {
|
|
105736
105912
|
const parsed = parseGlobals(argv);
|
|
105737
|
-
const cwd =
|
|
105913
|
+
const cwd = path71.resolve(overrides.cwd ?? process.cwd(), parsed.cwd ?? ".");
|
|
105738
105914
|
const io = { ...defaultIo(parsed.json), ...overrides, json: parsed.json, cwd };
|
|
105739
105915
|
if (parsed.error)
|
|
105740
105916
|
return emit(io, fail2("invalid_input", parsed.error));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@brainervirus/workit-cli",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.29.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Workit CLI — setup wizard, doctor, and task control for agentic coding workflows",
|
|
6
6
|
"keywords": [
|
|
@@ -38,13 +38,13 @@
|
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@babel/parser": "7.29.9",
|
|
41
|
-
"@brainervirus/workit-cursor": "^8.
|
|
41
|
+
"@brainervirus/workit-cursor": "^8.29.0",
|
|
42
42
|
"@inkjs/ui": "2.0.0",
|
|
43
43
|
"ink": "7.1.1",
|
|
44
44
|
"react": "19.2.8"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
|
-
"@brainervirus/workit-core": "^8.
|
|
47
|
+
"@brainervirus/workit-core": "^8.29.0"
|
|
48
48
|
},
|
|
49
49
|
"engines": {
|
|
50
50
|
"node": ">=24"
|