@brainervirus/workit-cli 8.28.0 → 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 +218 -36
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -8412,11 +8412,15 @@ var withReleaseTracks = (workspaceRoot, policy) => {
|
|
|
8412
8412
|
correction,
|
|
8413
8413
|
error: `commit_style: commit subject ${JSON.stringify(attempted)} violates ${source} ${policy.preset} policy; ${correction}`
|
|
8414
8414
|
};
|
|
8415
|
+
}, rethrowRuntimeBug = (error) => {
|
|
8416
|
+
if (error instanceof TypeError || error instanceof ReferenceError)
|
|
8417
|
+
throw error;
|
|
8415
8418
|
}, validateBranchNameFor = (workspaceRoot, name) => {
|
|
8416
8419
|
try {
|
|
8417
8420
|
const resolved = branchPolicySnapshotFor(workspaceRoot);
|
|
8418
8421
|
return validateBranchNamePolicy(name, resolved.namePolicy, resolved.source);
|
|
8419
8422
|
} catch (error) {
|
|
8423
|
+
rethrowRuntimeBug(error);
|
|
8420
8424
|
const correction = "repair or select a valid workspace policy before creating a branch";
|
|
8421
8425
|
return {
|
|
8422
8426
|
ok: false,
|
|
@@ -8434,6 +8438,7 @@ var withReleaseTracks = (workspaceRoot, policy) => {
|
|
|
8434
8438
|
const resolved = commitPolicySnapshotFor(workspaceRoot);
|
|
8435
8439
|
return validateCommitMessagePolicy(message, resolved.policy, resolved.source);
|
|
8436
8440
|
} catch (error) {
|
|
8441
|
+
rethrowRuntimeBug(error);
|
|
8437
8442
|
const correction = "repair or select a valid workspace policy before committing";
|
|
8438
8443
|
return {
|
|
8439
8444
|
ok: false,
|
|
@@ -9240,7 +9245,7 @@ var package_default;
|
|
|
9240
9245
|
var init_package = __esm(() => {
|
|
9241
9246
|
package_default = {
|
|
9242
9247
|
name: "@brainervirus/workit-cli",
|
|
9243
|
-
version: "8.
|
|
9248
|
+
version: "8.29.0",
|
|
9244
9249
|
private: false,
|
|
9245
9250
|
description: "Workit CLI — setup wizard, doctor, and task control for agentic coding workflows",
|
|
9246
9251
|
keywords: [
|
|
@@ -9278,13 +9283,13 @@ var init_package = __esm(() => {
|
|
|
9278
9283
|
},
|
|
9279
9284
|
dependencies: {
|
|
9280
9285
|
"@babel/parser": "7.29.9",
|
|
9281
|
-
"@brainervirus/workit-cursor": "^8.
|
|
9286
|
+
"@brainervirus/workit-cursor": "^8.29.0",
|
|
9282
9287
|
"@inkjs/ui": "2.0.0",
|
|
9283
9288
|
ink: "7.1.1",
|
|
9284
9289
|
react: "19.2.8"
|
|
9285
9290
|
},
|
|
9286
9291
|
devDependencies: {
|
|
9287
|
-
"@brainervirus/workit-core": "^8.
|
|
9292
|
+
"@brainervirus/workit-core": "^8.29.0"
|
|
9288
9293
|
},
|
|
9289
9294
|
engines: {
|
|
9290
9295
|
node: ">=24"
|
|
@@ -9398,9 +9403,22 @@ function detectedChecks(root) {
|
|
|
9398
9403
|
add(plain("test", ["make", "test"]));
|
|
9399
9404
|
return checks;
|
|
9400
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
|
+
}
|
|
9401
9419
|
function loadCheckConfig(cwd) {
|
|
9402
9420
|
const root = checkRoot(cwd);
|
|
9403
|
-
const file =
|
|
9421
|
+
const file = configFileFor(root);
|
|
9404
9422
|
const legacy = path9.basename(file) === LEGACY_CHECKS_FILE;
|
|
9405
9423
|
const label = legacy ? LEGACY_CHECKS_FILE : CHECKS_FILE;
|
|
9406
9424
|
const note = legacy ? {
|
|
@@ -16358,7 +16376,7 @@ var str2 = (d, values) => ({
|
|
|
16358
16376
|
description: typeof description === "string" ? description : "",
|
|
16359
16377
|
paths: ["."],
|
|
16360
16378
|
exclusions: []
|
|
16361
|
-
}), LISTS, ENVELOPE;
|
|
16379
|
+
}), LISTS, ENVELOPE, NOT_FLAT;
|
|
16362
16380
|
var init_operation_input = __esm(() => {
|
|
16363
16381
|
init_task_contract();
|
|
16364
16382
|
scopeFields = {
|
|
@@ -16480,6 +16498,7 @@ var init_operation_input = __esm(() => {
|
|
|
16480
16498
|
"expectedWorkspaceRevision",
|
|
16481
16499
|
"judgment"
|
|
16482
16500
|
]);
|
|
16501
|
+
NOT_FLAT = new Set(["schemaVersion", "action", "workspaceId"]);
|
|
16483
16502
|
});
|
|
16484
16503
|
|
|
16485
16504
|
// packages/workit-core/src/core/policy/judgment.ts
|
|
@@ -76830,6 +76849,8 @@ var init_resources = __esm(() => {
|
|
|
76830
76849
|
// packages/workit-cli/src/verbs/check.ts
|
|
76831
76850
|
var exports_check = {};
|
|
76832
76851
|
__export(exports_check, {
|
|
76852
|
+
OUTPUT_LINES: () => OUTPUT_LINES,
|
|
76853
|
+
boundedOutput: () => boundedOutput,
|
|
76833
76854
|
hostToolWaitCapMs: () => hostToolWaitCapMs,
|
|
76834
76855
|
run: () => run11,
|
|
76835
76856
|
workspaceResources: () => workspaceResources
|
|
@@ -76843,6 +76864,7 @@ function parse6(argv) {
|
|
|
76843
76864
|
name: null,
|
|
76844
76865
|
shell: false,
|
|
76845
76866
|
heavy: false,
|
|
76867
|
+
full: false,
|
|
76846
76868
|
noLease: false,
|
|
76847
76869
|
reason: null,
|
|
76848
76870
|
waitMs: null,
|
|
@@ -76861,8 +76883,11 @@ function parse6(argv) {
|
|
|
76861
76883
|
};
|
|
76862
76884
|
if (flag === "--json")
|
|
76863
76885
|
continue;
|
|
76864
|
-
if (flag === "--shell") {
|
|
76865
|
-
|
|
76886
|
+
if (flag === "--shell" || flag === "--full") {
|
|
76887
|
+
if (flag === "--shell")
|
|
76888
|
+
options.shell = true;
|
|
76889
|
+
else
|
|
76890
|
+
options.full = true;
|
|
76866
76891
|
continue;
|
|
76867
76892
|
}
|
|
76868
76893
|
if (flag === "--heavy" || flag === "--no-lease") {
|
|
@@ -77010,6 +77035,17 @@ function boundedArgv(argv) {
|
|
|
77010
77035
|
const truncated = cut.length !== argv.length || cut.some((item, index) => item !== argv[index]);
|
|
77011
77036
|
return { argv: cut, truncated };
|
|
77012
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
|
+
}
|
|
77013
77049
|
function hostToolWaitCapMs(env) {
|
|
77014
77050
|
if (!env.CLAUDECODE && !env.OPENCODE && !env.OPENCODE_SESSION_ID)
|
|
77015
77051
|
return null;
|
|
@@ -77139,6 +77175,10 @@ async function run11(argv, io) {
|
|
|
77139
77175
|
}
|
|
77140
77176
|
const relCwd = posix(path49.relative(top, runCwd));
|
|
77141
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
|
+
`);
|
|
77142
77182
|
const actor = actorFromEnv(io.env);
|
|
77143
77183
|
const branchKey = codeKey(io.cwd, { base: options.base });
|
|
77144
77184
|
const detached = branchKey.tree === null ? worktreeTree(io.cwd) : null;
|
|
@@ -77181,7 +77221,7 @@ async function run11(argv, io) {
|
|
|
77181
77221
|
...sinks,
|
|
77182
77222
|
...wrapper ? { wrapper } : {},
|
|
77183
77223
|
...lease ? { onSpawn: (pid) => updateLease(lease, { pgid: pid }) } : {}
|
|
77184
|
-
}), 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: () => {} });
|
|
77185
77225
|
result = scoped.result;
|
|
77186
77226
|
if (heavy && scoped.fallback) {
|
|
77187
77227
|
io.stderr(`workit: the memory/CPU scope could not start (${scoped.fallback}); ran without it
|
|
@@ -77195,6 +77235,7 @@ async function run11(argv, io) {
|
|
|
77195
77235
|
const modifiedWorktree = key.tree !== null && treeAfter !== key.tree;
|
|
77196
77236
|
const store = storeRoot(io.cwd);
|
|
77197
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;
|
|
77198
77239
|
const tail = tailLines(result.log, TAIL_LINES);
|
|
77199
77240
|
const passed = result.exitCode === 0 && !result.timedOut;
|
|
77200
77241
|
const bounded = boundedArgv(command);
|
|
@@ -77267,6 +77308,7 @@ async function run11(argv, io) {
|
|
|
77267
77308
|
patchId: key.patchId,
|
|
77268
77309
|
logDigest: observation.logDigest,
|
|
77269
77310
|
logRef: observation.logRef,
|
|
77311
|
+
logPath,
|
|
77270
77312
|
logTail: tail,
|
|
77271
77313
|
outputBytes: result.outputBytes,
|
|
77272
77314
|
logTruncated: result.truncated,
|
|
@@ -77283,18 +77325,21 @@ async function run11(argv, io) {
|
|
|
77283
77325
|
const code = !passed ? "failed" : recordError ? recordError.code : "ok";
|
|
77284
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;
|
|
77285
77327
|
const label = name ?? command.join(" ");
|
|
77286
|
-
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"}`;
|
|
77287
77329
|
if (io.json)
|
|
77288
77330
|
io.stdout(`${JSON.stringify({ ok: code === "ok", code, data, ...error ? { error } : {}, ...task.stillUnsatisfied[0] ? { unblock: task.stillUnsatisfied[0].unblock } : {} })}
|
|
77289
77331
|
`);
|
|
77290
77332
|
else {
|
|
77333
|
+
if (!options.full)
|
|
77334
|
+
io.stdout(boundedOutput(result.log, OUTPUT_LINES));
|
|
77291
77335
|
io.stderr(`${summary}
|
|
77292
77336
|
`);
|
|
77293
77337
|
if (recordError && passed)
|
|
77294
77338
|
io.stderr(`workit: ${recordError.message}
|
|
77295
77339
|
`);
|
|
77296
|
-
|
|
77297
|
-
|
|
77340
|
+
if (!shadowed)
|
|
77341
|
+
for (const gap of task.stillUnsatisfied)
|
|
77342
|
+
io.stderr(` still unsatisfied: ${gap.ruleId}: ${gap.reason}
|
|
77298
77343
|
`);
|
|
77299
77344
|
}
|
|
77300
77345
|
if (!passed)
|
|
@@ -77303,7 +77348,7 @@ async function run11(argv, io) {
|
|
|
77303
77348
|
return recordError.code === "busy" ? 4 : recordError.code === "invalid_input" ? 2 : 5;
|
|
77304
77349
|
return 0;
|
|
77305
77350
|
}
|
|
77306
|
-
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;
|
|
77307
77352
|
var init_check = __esm(() => {
|
|
77308
77353
|
init_check_config();
|
|
77309
77354
|
init_checks3();
|
|
@@ -78572,18 +78617,18 @@ var COMMIT_TIMEOUT_MS, PUSH_TIMEOUT_MS = 120000, git5 = (cwd, args, options = {}
|
|
|
78572
78617
|
const lines = redactText(`${run.stderr}
|
|
78573
78618
|
${run.stdout ?? ""}`).split(/\r?\n/u).map((value) => value.trim()).filter((value) => value && !value.startsWith("hint:"));
|
|
78574
78619
|
return lines.slice(-max).join(" / ").slice(0, 400) || "git failed";
|
|
78575
|
-
},
|
|
78620
|
+
}, OUTPUT_LINES2 = 200, OUTPUT_LINE_CHARS = 1000, gitOutput = (run) => {
|
|
78576
78621
|
const lines = redactText(`${run.stderr}
|
|
78577
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);
|
|
78578
78623
|
if (!lines.length)
|
|
78579
78624
|
return "git failed";
|
|
78580
|
-
if (lines.length <=
|
|
78625
|
+
if (lines.length <= OUTPUT_LINES2)
|
|
78581
78626
|
return lines.join(`
|
|
78582
78627
|
`);
|
|
78583
|
-
const half =
|
|
78628
|
+
const half = OUTPUT_LINES2 / 2;
|
|
78584
78629
|
return [
|
|
78585
78630
|
...lines.slice(0, half),
|
|
78586
|
-
`… ${lines.length -
|
|
78631
|
+
`… ${lines.length - OUTPUT_LINES2} lines omitted …`,
|
|
78587
78632
|
...lines.slice(-half)
|
|
78588
78633
|
].join(`
|
|
78589
78634
|
`);
|
|
@@ -84330,16 +84375,66 @@ async function rerun(argv, io) {
|
|
|
84330
84375
|
"next: workit ci wait"
|
|
84331
84376
|
]);
|
|
84332
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
|
+
}
|
|
84333
84425
|
async function run15(argv, io) {
|
|
84334
84426
|
const [sub, ...rest] = argv;
|
|
84335
84427
|
if (sub === "wait")
|
|
84336
84428
|
return wait2(rest, io);
|
|
84337
84429
|
if (sub === "rerun")
|
|
84338
84430
|
return rerun(rest, io);
|
|
84431
|
+
if (sub === "logs")
|
|
84432
|
+
return logs(rest, io);
|
|
84339
84433
|
return usage3(io, sub && !sub.startsWith("-") ? `unknown ci subcommand "${sub}"` : "missing ci subcommand", `${WAIT_USAGE}
|
|
84340
|
-
${RERUN_USAGE}
|
|
84434
|
+
${RERUN_USAGE}
|
|
84435
|
+
${LOGS_USAGE}`);
|
|
84341
84436
|
}
|
|
84342
|
-
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`;
|
|
84343
84438
|
var init_ci = __esm(() => {
|
|
84344
84439
|
init_report();
|
|
84345
84440
|
init_ledger();
|
|
@@ -86173,6 +86268,27 @@ function excludeScratch(cwd) {
|
|
|
86173
86268
|
${EXCLUDE_LINE}
|
|
86174
86269
|
`);
|
|
86175
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
|
+
}
|
|
86176
86292
|
function ensureScratch(worktree) {
|
|
86177
86293
|
const scratch = path62.join(worktree, SCRATCH_DIR);
|
|
86178
86294
|
fs33.mkdirSync(scratch, { recursive: true });
|
|
@@ -86202,7 +86318,7 @@ function createSliceWorktree(cwd, plan, input) {
|
|
|
86202
86318
|
if (!createdRow(cwd, plan, slice, target))
|
|
86203
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`);
|
|
86204
86320
|
excludeScratch(cwd);
|
|
86205
|
-
const deps =
|
|
86321
|
+
const deps = worktreeDependencies(mainCheckout(cwd), target);
|
|
86206
86322
|
return {
|
|
86207
86323
|
ok: true,
|
|
86208
86324
|
data: {
|
|
@@ -86212,6 +86328,7 @@ function createSliceWorktree(cwd, plan, input) {
|
|
|
86212
86328
|
mode: resolveRef(cwd, localRef) ? "resume" : "new",
|
|
86213
86329
|
created: false,
|
|
86214
86330
|
dependencies: deps.linked,
|
|
86331
|
+
install: deps.install,
|
|
86215
86332
|
notes: [
|
|
86216
86333
|
deps.linked ? "the worktree already exists; only its missing dependencies were linked" : "the worktree already exists; nothing was changed",
|
|
86217
86334
|
...deps.notes
|
|
@@ -86265,7 +86382,7 @@ function createSliceWorktree(cwd, plan, input) {
|
|
|
86265
86382
|
}
|
|
86266
86383
|
excludeScratch(cwd);
|
|
86267
86384
|
const scratch = ensureScratch(target);
|
|
86268
|
-
const deps =
|
|
86385
|
+
const deps = worktreeDependencies(mainCheckout(cwd), target);
|
|
86269
86386
|
notes.push(...deps.notes);
|
|
86270
86387
|
const head = gitRun4(target, ["rev-parse", "HEAD"]).stdout.trim();
|
|
86271
86388
|
const baseSha = mode === "new" ? head : null;
|
|
@@ -86288,7 +86405,16 @@ function createSliceWorktree(cwd, plan, input) {
|
|
|
86288
86405
|
});
|
|
86289
86406
|
return {
|
|
86290
86407
|
ok: true,
|
|
86291
|
-
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
|
+
}
|
|
86292
86418
|
};
|
|
86293
86419
|
}
|
|
86294
86420
|
function releaseSliceWorktree(cwd, plan, input) {
|
|
@@ -86427,7 +86553,13 @@ var SLOW, SCRATCH_DIR = ".workit-scratch", EXCLUDE_LINE, DIRTY_ROW_BYTES = 2000,
|
|
|
86427
86553
|
}, inside3 = (child, parent) => {
|
|
86428
86554
|
const relative = path62.relative(canonical2(parent), canonical2(child));
|
|
86429
86555
|
return relative === "" || !relative.startsWith("..") && !path62.isAbsolute(relative);
|
|
86430
|
-
}, 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(`
|
|
86431
86563
|
`)[0] || "unknown error"}`);
|
|
86432
86564
|
var init_fanout_worktree = __esm(() => {
|
|
86433
86565
|
init_ops();
|
|
@@ -86441,6 +86573,13 @@ var init_fanout_worktree = __esm(() => {
|
|
|
86441
86573
|
worktreeDeps = {
|
|
86442
86574
|
stat: (file) => fs33.statSync(file, { bigint: true })
|
|
86443
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
|
+
];
|
|
86444
86583
|
});
|
|
86445
86584
|
|
|
86446
86585
|
// packages/workit-core/src/fanout-brief.ts
|
|
@@ -104781,10 +104920,13 @@ var init_changelog2 = __esm(() => {
|
|
|
104781
104920
|
// packages/workit-cli/src/verbs/handoff.ts
|
|
104782
104921
|
var exports_handoff = {};
|
|
104783
104922
|
__export(exports_handoff, {
|
|
104923
|
+
MAX_BRIEF_BYTES: () => MAX_BRIEF_BYTES,
|
|
104784
104924
|
run: () => run26
|
|
104785
104925
|
});
|
|
104926
|
+
import fs35 from "node:fs";
|
|
104927
|
+
import path70 from "node:path";
|
|
104786
104928
|
import { parseArgs as parseArgs2 } from "node:util";
|
|
104787
|
-
function
|
|
104929
|
+
function render3(brief) {
|
|
104788
104930
|
const lines = [
|
|
104789
104931
|
`branch: ${brief.branch ?? "(detached)"} @ ${short7(brief.head)}${brief.subject ? ` ${brief.subject}` : ""}`
|
|
104790
104932
|
];
|
|
@@ -104804,14 +104946,42 @@ function human2(brief) {
|
|
|
104804
104946
|
lines.push(`last handoff (${brief.lastHandoff.at}): ${brief.lastHandoff.next}${brief.lastHandoff.note ? ` (note: ${brief.lastHandoff.note})` : ""}`);
|
|
104805
104947
|
if (brief.recent.length)
|
|
104806
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 = [];
|
|
104807
104950
|
if (brief.note)
|
|
104808
|
-
|
|
104809
|
-
|
|
104951
|
+
tail.push(`note: ${brief.note}`);
|
|
104952
|
+
tail.push(`next: ${brief.next}`);
|
|
104810
104953
|
if (brief.next !== brief.nextCommand)
|
|
104811
|
-
|
|
104954
|
+
tail.push(`next command: ${brief.nextCommand}`);
|
|
104812
104955
|
if (brief.recorded)
|
|
104813
|
-
|
|
104814
|
-
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];
|
|
104815
104985
|
}
|
|
104816
104986
|
async function resumeBrief(argv, io) {
|
|
104817
104987
|
let values;
|
|
@@ -104849,7 +105019,7 @@ async function resumeBrief(argv, io) {
|
|
|
104849
105019
|
return emit(io, fail2(row.code, row.error, { data: { ...data, recorded } }));
|
|
104850
105020
|
recorded = row.value.id;
|
|
104851
105021
|
}
|
|
104852
|
-
return emit(io, ok2({ ...data, recorded }),
|
|
105022
|
+
return emit(io, ok2({ ...data, recorded }), (brief) => bounded(brief, io.cwd));
|
|
104853
105023
|
}
|
|
104854
105024
|
async function run26(argv, io) {
|
|
104855
105025
|
if (!argv.some((arg) => arg === "--task" || arg.startsWith("--task=")))
|
|
@@ -104857,7 +105027,9 @@ async function run26(argv, io) {
|
|
|
104857
105027
|
await Promise.resolve().then(() => init_task());
|
|
104858
105028
|
return runTaskCommand(["handoff", ...argv]);
|
|
104859
105029
|
}
|
|
104860
|
-
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
|
+
`);
|
|
104861
105033
|
var init_handoff = __esm(() => {
|
|
104862
105034
|
init_ledger();
|
|
104863
105035
|
init_output();
|
|
@@ -104866,7 +105038,7 @@ var init_handoff = __esm(() => {
|
|
|
104866
105038
|
// packages/workit-cli/src/main.ts
|
|
104867
105039
|
init_host_session();
|
|
104868
105040
|
init_package();
|
|
104869
|
-
import
|
|
105041
|
+
import path71 from "node:path";
|
|
104870
105042
|
|
|
104871
105043
|
// packages/workit-cli/src/verbs/registry.ts
|
|
104872
105044
|
var TASK_FAMILY_NAMES = [
|
|
@@ -104971,7 +105143,8 @@ var LEASE_NOTES = [
|
|
|
104971
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.",
|
|
104972
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.",
|
|
104973
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.",
|
|
104974
|
-
'--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."
|
|
104975
105148
|
];
|
|
104976
105149
|
var VERIFY_OPTIONS = "[--expect pushed|pr|merged|released] [--pr <n> | --branch <b>] [--sha <sha>] [--tag <t>] [--package <name[@version]>]";
|
|
104977
105150
|
var LEDGER_ACTOR = "[--branch <b> | --pr <n>] [--supersedes <id>] [--session <id> [--token <t>] | --as <role>]";
|
|
@@ -105054,7 +105227,7 @@ var VERBS = [
|
|
|
105054
105227
|
{
|
|
105055
105228
|
name: "check",
|
|
105056
105229
|
group: "delivery",
|
|
105057
|
-
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…>',
|
|
105058
105231
|
flagHints: {
|
|
105059
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)"
|
|
105060
105233
|
},
|
|
@@ -105174,7 +105347,7 @@ var VERBS = [
|
|
|
105174
105347
|
withSubcommands({
|
|
105175
105348
|
name: "ci",
|
|
105176
105349
|
group: "delivery",
|
|
105177
|
-
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",
|
|
105178
105351
|
subcommands: [
|
|
105179
105352
|
{
|
|
105180
105353
|
name: "wait",
|
|
@@ -105185,9 +105358,18 @@ var VERBS = [
|
|
|
105185
105358
|
name: "rerun",
|
|
105186
105359
|
usage: "workit ci rerun [--pr <n> | --branch <b>] [--check <name>… | --failed] --reason flake|infra [--force]",
|
|
105187
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"
|
|
105188
105366
|
}
|
|
105189
105367
|
],
|
|
105190
|
-
examples: [
|
|
105368
|
+
examples: [
|
|
105369
|
+
"workit ci wait --timeout 30m",
|
|
105370
|
+
"workit ci logs --failed",
|
|
105371
|
+
"workit ci rerun --failed --reason flake"
|
|
105372
|
+
],
|
|
105191
105373
|
load: () => Promise.resolve().then(() => (init_ci(), exports_ci))
|
|
105192
105374
|
}),
|
|
105193
105375
|
withSubcommands({
|
|
@@ -105728,7 +105910,7 @@ var defaultIo = (json) => ({
|
|
|
105728
105910
|
});
|
|
105729
105911
|
async function main(argv, overrides = {}, options = {}) {
|
|
105730
105912
|
const parsed = parseGlobals(argv);
|
|
105731
|
-
const cwd =
|
|
105913
|
+
const cwd = path71.resolve(overrides.cwd ?? process.cwd(), parsed.cwd ?? ".");
|
|
105732
105914
|
const io = { ...defaultIo(parsed.json), ...overrides, json: parsed.json, cwd };
|
|
105733
105915
|
if (parsed.error)
|
|
105734
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"
|