@brainervirus/workit-cli 8.6.1 → 8.8.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 +452 -31
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -65,7 +65,7 @@ var package_default;
|
|
|
65
65
|
var init_package = __esm(() => {
|
|
66
66
|
package_default = {
|
|
67
67
|
name: "@brainervirus/workit-cli",
|
|
68
|
-
version: "8.
|
|
68
|
+
version: "8.8.0",
|
|
69
69
|
private: false,
|
|
70
70
|
description: "Workit CLI — setup wizard, doctor, and task control for agentic coding workflows",
|
|
71
71
|
keywords: [
|
|
@@ -103,9 +103,9 @@ var init_package = __esm(() => {
|
|
|
103
103
|
},
|
|
104
104
|
dependencies: {
|
|
105
105
|
"@babel/parser": "7.29.9",
|
|
106
|
-
"@brainervirus/workit-core": "^8.
|
|
107
|
-
"@brainervirus/workit-cursor": "^8.
|
|
108
|
-
"@brainervirus/workit-opencode": "^8.
|
|
106
|
+
"@brainervirus/workit-core": "^8.8.0",
|
|
107
|
+
"@brainervirus/workit-cursor": "^8.8.0",
|
|
108
|
+
"@brainervirus/workit-opencode": "^8.8.0",
|
|
109
109
|
"@inkjs/ui": "2.0.0",
|
|
110
110
|
ink: "7.1.1",
|
|
111
111
|
react: "19.2.8"
|
|
@@ -15136,6 +15136,9 @@ function summarizeRow(row) {
|
|
|
15136
15136
|
case "pr.created":
|
|
15137
15137
|
summary = `#${row.pr ?? "?"} -> ${text("base")} at ${(row.head ?? "?").slice(0, 12)}${row.created === false ? " (existing)" : ""}`;
|
|
15138
15138
|
break;
|
|
15139
|
+
case "pr.status":
|
|
15140
|
+
summary = `#${row.pr ?? "?"} ${text("state") && text("state") !== "open" ? `${text("state")} ` : ""}checks ${text("checks") || "?"} at ${(row.head ?? "?").slice(0, 12)}`;
|
|
15141
|
+
break;
|
|
15139
15142
|
case "pr.merged":
|
|
15140
15143
|
summary = `#${row.pr ?? "?"} ${text("method")} at ${(row.head ?? "?").slice(0, 12)}${text("mergeSha") ? ` -> ${text("mergeSha").slice(0, 12)}` : ""}`;
|
|
15141
15144
|
break;
|
|
@@ -63192,7 +63195,7 @@ function cursorHookDrift(installed, pluginDir) {
|
|
|
63192
63195
|
if (pluginDir)
|
|
63193
63196
|
commands.push(canonicalHookEntry(event, pluginDir).command);
|
|
63194
63197
|
const entry = Array.isArray(list) ? list[0] : undefined;
|
|
63195
|
-
if (!isRecord4(entry) || !commands.includes(entry.command) || entry.failClosed === true || event === "preToolUse" && entry.matcher !== canonical.matcher)
|
|
63198
|
+
if (!isRecord4(entry) || !commands.includes(entry.command) || entry.failClosed === true || event === "stop" && entry.loop_limit !== canonical.loop_limit || event === "preToolUse" && entry.matcher !== canonical.matcher)
|
|
63196
63199
|
drift.push(event);
|
|
63197
63200
|
}
|
|
63198
63201
|
return drift;
|
|
@@ -63215,7 +63218,11 @@ function cursorHooksEntry(pluginDir) {
|
|
|
63215
63218
|
}
|
|
63216
63219
|
var OPENCODE_NPM_PIN = "@brainervirus/workit-opencode", isRecord4 = (v) => v !== null && typeof v === "object" && !Array.isArray(v), named = (s, name) => s === name || s.startsWith(`${name}@`), CURSOR_RUNTIME_PACKAGE = "@brainervirus/workit-cursor@latest", cursorHookLauncher = (pluginDir) => pluginDir ? `node "${shellQuotedPath(path26.join(pluginDir, "hooks", "launch.mjs"))}"` : 'node "${CURSOR_PLUGIN_ROOT}/hooks/launch.mjs"', shellQuotedPath = (file) => path26.sep === "\\" ? file : file.replace(/([$`"\\])/g, "\\$1"), CURSOR_HOOK_RUN_COMMAND, CURSOR_PRETOOLUSE_MATCHER = "Write|Edit|Delete|Shell|Remove|ApplyPatch|Apply_Patch|Patch|Rename|Mkdir|Mv|Cp|Touch", CURSOR_HOOK_EVENTS, canonicalHookEntry = (event, pluginDir) => {
|
|
63217
63220
|
const command = `${cursorHookLauncher(pluginDir)} workit-cursor-hook`;
|
|
63218
|
-
|
|
63221
|
+
if (event === "preToolUse")
|
|
63222
|
+
return { command, matcher: CURSOR_PRETOOLUSE_MATCHER, failClosed: false };
|
|
63223
|
+
if (event === "stop")
|
|
63224
|
+
return { command, loop_limit: 1, failClosed: false };
|
|
63225
|
+
return { command, failClosed: false };
|
|
63219
63226
|
};
|
|
63220
63227
|
var init_registration = __esm(() => {
|
|
63221
63228
|
CURSOR_HOOK_RUN_COMMAND = `${cursorHookLauncher()} workit-cursor-hook`;
|
|
@@ -63224,6 +63231,7 @@ var init_registration = __esm(() => {
|
|
|
63224
63231
|
"beforeShellExecution",
|
|
63225
63232
|
"subagentStart",
|
|
63226
63233
|
"subagentStop",
|
|
63234
|
+
"stop",
|
|
63227
63235
|
"preCompact"
|
|
63228
63236
|
];
|
|
63229
63237
|
});
|
|
@@ -63932,11 +63940,13 @@ var init_skill_manifests = __esm(() => {
|
|
|
63932
63940
|
|
|
63933
63941
|
// packages/workit-cli/src/admin/doctor.ts
|
|
63934
63942
|
import { spawnSync as spawnSync13 } from "node:child_process";
|
|
63943
|
+
import { createHash as createHash13 } from "node:crypto";
|
|
63935
63944
|
import {
|
|
63936
63945
|
existsSync as existsSync13,
|
|
63937
63946
|
lstatSync as lstatSync4,
|
|
63938
63947
|
mkdirSync as mkdirSync5,
|
|
63939
63948
|
mkdtempSync,
|
|
63949
|
+
readdirSync as readdirSync7,
|
|
63940
63950
|
readFileSync as readFileSync13,
|
|
63941
63951
|
readlinkSync as readlinkSync2,
|
|
63942
63952
|
rmSync as rmSync2,
|
|
@@ -63977,8 +63987,11 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
63977
63987
|
cursorMcp: options.cursorMcp ?? path30.join(home, ".cursor", "mcp.json"),
|
|
63978
63988
|
cursorPluginDir: options.cursorPluginDir ?? path30.join(home, ".cursor", "plugins", "local", "workit"),
|
|
63979
63989
|
cursorHeartbeatDir: options.stateDir ?? (env.WORKFLOW_TOOLKIT_STATE || resolveStateDir()),
|
|
63990
|
+
codexHome: options.codexHome,
|
|
63991
|
+
piAgentDir: options.piAgentDir,
|
|
63980
63992
|
env,
|
|
63981
|
-
installer: options.installer ?? false
|
|
63993
|
+
installer: options.installer ?? false,
|
|
63994
|
+
cliVersion: options.cliVersion ?? null
|
|
63982
63995
|
};
|
|
63983
63996
|
}, readJson = (p) => {
|
|
63984
63997
|
try {
|
|
@@ -64199,6 +64212,368 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64199
64212
|
detail: `codex CLI ${installed} differs from the qualified ${qualified}`,
|
|
64200
64213
|
fix: `Reinstall the qualified Codex CLI ${qualified} or record fresh qualification evidence`
|
|
64201
64214
|
};
|
|
64215
|
+
}, readTomlTables = (file) => {
|
|
64216
|
+
const tables = new Map;
|
|
64217
|
+
let text;
|
|
64218
|
+
try {
|
|
64219
|
+
text = readFileSync13(file, "utf8");
|
|
64220
|
+
} catch {
|
|
64221
|
+
return tables;
|
|
64222
|
+
}
|
|
64223
|
+
const unquote = (raw) => {
|
|
64224
|
+
const s = raw.trim();
|
|
64225
|
+
if (s.startsWith('"')) {
|
|
64226
|
+
try {
|
|
64227
|
+
return JSON.parse(s);
|
|
64228
|
+
} catch {
|
|
64229
|
+
return s.slice(1, -1);
|
|
64230
|
+
}
|
|
64231
|
+
}
|
|
64232
|
+
return s.startsWith("'") ? s.slice(1, -1) : s;
|
|
64233
|
+
};
|
|
64234
|
+
const SEGMENT = /\s*("(?:[^"\\]|\\.)*"|'[^']*'|[A-Za-z0-9_-]+)\s*(?:\.|$)/y;
|
|
64235
|
+
let current = {};
|
|
64236
|
+
tables.set("", current);
|
|
64237
|
+
for (const line of text.split(/\r?\n/)) {
|
|
64238
|
+
const header = /^\s*\[([^[\]]+)\]\s*(?:#.*)?$/.exec(line);
|
|
64239
|
+
if (header) {
|
|
64240
|
+
const parts = [];
|
|
64241
|
+
SEGMENT.lastIndex = 0;
|
|
64242
|
+
let match;
|
|
64243
|
+
while (SEGMENT.lastIndex < header[1].length && (match = SEGMENT.exec(header[1])))
|
|
64244
|
+
parts.push(unquote(match[1]));
|
|
64245
|
+
const key = parts.join("\x00");
|
|
64246
|
+
current = tables.get(key) ?? {};
|
|
64247
|
+
tables.set(key, current);
|
|
64248
|
+
continue;
|
|
64249
|
+
}
|
|
64250
|
+
const pair = /^\s*("(?:[^"\\]|\\.)*"|[A-Za-z0-9_-]+)\s*=\s*(.+?)\s*$/.exec(line);
|
|
64251
|
+
if (!pair)
|
|
64252
|
+
continue;
|
|
64253
|
+
const value = pair[2].replace(/\s+#[^"']*$/, "");
|
|
64254
|
+
current[unquote(pair[1])] = value === "true" ? true : value === "false" ? false : unquote(value);
|
|
64255
|
+
}
|
|
64256
|
+
return tables;
|
|
64257
|
+
}, codexHomeOf = (res) => res.codexHome ?? (res.env.CODEX_HOME || path30.join(res.home, ".codex")), codexWorkitInstalls = (res) => {
|
|
64258
|
+
const codexHome = codexHomeOf(res);
|
|
64259
|
+
const configFile = path30.join(codexHome, "config.toml");
|
|
64260
|
+
const installs = [];
|
|
64261
|
+
for (const [key, table] of readTomlTables(configFile)) {
|
|
64262
|
+
const [kind, id, ...rest] = key.split("\x00");
|
|
64263
|
+
if (kind !== "plugins" || rest.length > 0 || !id?.startsWith("workit@") || table.enabled === false)
|
|
64264
|
+
continue;
|
|
64265
|
+
const marketplace = id.slice("workit@".length);
|
|
64266
|
+
const dir = path30.join(codexHome, "plugins", "cache", marketplace, "workit");
|
|
64267
|
+
let versions = [];
|
|
64268
|
+
try {
|
|
64269
|
+
versions = readdirSync7(dir).filter((v) => existsSync13(path30.join(dir, v, ".codex-plugin")));
|
|
64270
|
+
} catch {
|
|
64271
|
+
versions = [];
|
|
64272
|
+
}
|
|
64273
|
+
const version = versions.reduce((best, v) => best && semverAtLeast(best, v) ? best : v, null);
|
|
64274
|
+
installs.push({
|
|
64275
|
+
id,
|
|
64276
|
+
marketplace,
|
|
64277
|
+
root: version ? path30.join(dir, version) : null,
|
|
64278
|
+
version,
|
|
64279
|
+
configFile
|
|
64280
|
+
});
|
|
64281
|
+
}
|
|
64282
|
+
return installs;
|
|
64283
|
+
}, snakeEvent = (event) => event.replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase(), codexHookHash = (event, matcher, handler) => {
|
|
64284
|
+
if (handler.type !== "command" || typeof handler.command !== "string" || Object.keys(handler).some((k) => !["type", "command", "timeout", "async"].includes(k)))
|
|
64285
|
+
return null;
|
|
64286
|
+
const hook = {
|
|
64287
|
+
async: handler.async ?? false,
|
|
64288
|
+
command: handler.command,
|
|
64289
|
+
timeout: handler.timeout ?? 600,
|
|
64290
|
+
type: "command"
|
|
64291
|
+
};
|
|
64292
|
+
const body = {
|
|
64293
|
+
event_name: snakeEvent(event),
|
|
64294
|
+
hooks: [hook],
|
|
64295
|
+
...typeof matcher === "string" ? { matcher } : {}
|
|
64296
|
+
};
|
|
64297
|
+
return `sha256:${createHash13("sha256").update(JSON.stringify(body)).digest("hex")}`;
|
|
64298
|
+
}, codexHookTrust = (install, tables) => {
|
|
64299
|
+
const hooks = install.root ? readJson(path30.join(install.root, "hooks", "hooks.json"))?.hooks : null;
|
|
64300
|
+
if (!hooks || typeof hooks !== "object")
|
|
64301
|
+
return null;
|
|
64302
|
+
const result = [];
|
|
64303
|
+
for (const [event, groups] of Object.entries(hooks)) {
|
|
64304
|
+
if (!Array.isArray(groups))
|
|
64305
|
+
continue;
|
|
64306
|
+
groups.forEach((group, g) => {
|
|
64307
|
+
const handlers = Array.isArray(group?.hooks) ? group.hooks : [];
|
|
64308
|
+
handlers.forEach((handler, h) => {
|
|
64309
|
+
const key = `${install.id}:hooks/hooks.json:${snakeEvent(event)}:${g}:${h}`;
|
|
64310
|
+
const hash = codexHookHash(event, group?.matcher, handler ?? {});
|
|
64311
|
+
const state = tables.get(["hooks", "state", key].join("\x00"));
|
|
64312
|
+
const trusted = typeof state?.trusted_hash === "string" ? state.trusted_hash : null;
|
|
64313
|
+
result.push({
|
|
64314
|
+
key,
|
|
64315
|
+
hash,
|
|
64316
|
+
state: state?.enabled === false ? "disabled" : trusted === null ? "untrusted" : hash !== null && trusted !== hash ? "modified" : "trusted"
|
|
64317
|
+
});
|
|
64318
|
+
});
|
|
64319
|
+
});
|
|
64320
|
+
}
|
|
64321
|
+
return result;
|
|
64322
|
+
}, checkCodexHooks = (res) => {
|
|
64323
|
+
const installs = codexWorkitInstalls(res);
|
|
64324
|
+
if (installs.length === 0)
|
|
64325
|
+
return {
|
|
64326
|
+
id: "codex_hooks",
|
|
64327
|
+
status: "pass",
|
|
64328
|
+
detail: "no Workit Codex plugin enabled — skipping"
|
|
64329
|
+
};
|
|
64330
|
+
const tables = readTomlTables(installs[0].configFile);
|
|
64331
|
+
const problems = [];
|
|
64332
|
+
const toTrust = [];
|
|
64333
|
+
let reinstall;
|
|
64334
|
+
let total = 0;
|
|
64335
|
+
for (const install of installs) {
|
|
64336
|
+
const trust = codexHookTrust(install, tables);
|
|
64337
|
+
if (!trust) {
|
|
64338
|
+
problems.push(`${install.id}: no installed hooks/hooks.json`);
|
|
64339
|
+
reinstall ??= `codex plugin remove ${install.id} && codex plugin add ${install.id}`;
|
|
64340
|
+
continue;
|
|
64341
|
+
}
|
|
64342
|
+
total += trust.length;
|
|
64343
|
+
for (const state of ["untrusted", "modified", "disabled"]) {
|
|
64344
|
+
const hit = trust.filter((t) => t.state === state);
|
|
64345
|
+
if (hit.length > 0)
|
|
64346
|
+
problems.push(`${install.id}: ${hit.length} of ${trust.length} hooks ${state === "modified" ? "changed since trusted" : state} (${hit.map((t) => t.key.split(":")[2]).join(", ")})`);
|
|
64347
|
+
}
|
|
64348
|
+
toTrust.push(...trust.filter((t) => t.state !== "trusted"));
|
|
64349
|
+
}
|
|
64350
|
+
if (problems.length === 0)
|
|
64351
|
+
return {
|
|
64352
|
+
id: "codex_hooks",
|
|
64353
|
+
status: "pass",
|
|
64354
|
+
detail: `${total} Workit Codex plugin hooks trusted (${installs.map((i) => `${i.id} ${i.version ?? "?"}`).join(", ")})`
|
|
64355
|
+
};
|
|
64356
|
+
const disabled = toTrust.some((t) => t.state === "disabled");
|
|
64357
|
+
const fix = reinstall ?? `Start \`codex\`, run \`/hooks\` and ${disabled ? "enable and " : ""}trust the workit hooks (or pick "Trust all and continue" when Codex asks you to review hooks at startup)`;
|
|
64358
|
+
return {
|
|
64359
|
+
id: "codex_hooks",
|
|
64360
|
+
status: "warn",
|
|
64361
|
+
detail: `Codex skips untrusted plugin hooks — ${problems.join("; ")}`,
|
|
64362
|
+
fix
|
|
64363
|
+
};
|
|
64364
|
+
}, CODEX_AGENT_MARKER = "# Generated by Workit", AGENT_MARKER_VERSION, agentMarkerVersion = (text) => AGENT_MARKER_VERSION.exec(text)?.[1] ?? null, stampCodexAgent = (content, version) => version && content.startsWith(CODEX_AGENT_MARKER) && !agentMarkerVersion(content) ? `${CODEX_AGENT_MARKER} ${version}${content.slice(CODEX_AGENT_MARKER.length)}` : content, checkCodexAgents = (res) => {
|
|
64365
|
+
const installs = codexWorkitInstalls(res);
|
|
64366
|
+
if (installs.length === 0)
|
|
64367
|
+
return {
|
|
64368
|
+
id: "codex_agents",
|
|
64369
|
+
status: "pass",
|
|
64370
|
+
detail: "no Workit Codex plugin enabled — skipping"
|
|
64371
|
+
};
|
|
64372
|
+
const agentsDir = path30.join(codexHomeOf(res), "agents");
|
|
64373
|
+
const problems = [];
|
|
64374
|
+
const fixes = [];
|
|
64375
|
+
const installed = [];
|
|
64376
|
+
for (const install of installs) {
|
|
64377
|
+
const source = install.root ? path30.join(install.root, "agents") : null;
|
|
64378
|
+
const files = source && existsSync13(source) ? readdirSync7(source).filter((f) => f.endsWith(".toml")).toSorted() : [];
|
|
64379
|
+
if (files.length === 0) {
|
|
64380
|
+
problems.push(`${install.id} ${install.version ?? "?"} bundles no agents`);
|
|
64381
|
+
fixes.push(`codex plugin remove ${install.id} && codex plugin add ${install.id}`);
|
|
64382
|
+
continue;
|
|
64383
|
+
}
|
|
64384
|
+
const install_fix = `node ${JSON.stringify(path30.join(install.root, "dist", "launch-mcp.js"))} --install-agents, then start a new Codex session`;
|
|
64385
|
+
const pluginVersion = readJson(path30.join(install.root, "package.json"))?.version;
|
|
64386
|
+
const version = typeof pluginVersion === "string" ? pluginVersion.match(SEMVER)?.[0] ?? null : null;
|
|
64387
|
+
let stale = false;
|
|
64388
|
+
for (const file of files) {
|
|
64389
|
+
const dest = path30.join(agentsDir, file);
|
|
64390
|
+
const want = stampCodexAgent(readFileSync13(path30.join(source, file), "utf8"), version);
|
|
64391
|
+
let link = false;
|
|
64392
|
+
try {
|
|
64393
|
+
link = lstatSync4(dest).isSymbolicLink();
|
|
64394
|
+
} catch {
|
|
64395
|
+
link = false;
|
|
64396
|
+
}
|
|
64397
|
+
if (link) {
|
|
64398
|
+
problems.push(`${dest} is a symlink (the plugin never writes through one)`);
|
|
64399
|
+
fixes.push(`replace the symlink ${dest} with a file or remove it, then run ${install_fix}`);
|
|
64400
|
+
continue;
|
|
64401
|
+
}
|
|
64402
|
+
let have = null;
|
|
64403
|
+
try {
|
|
64404
|
+
have = readFileSync13(dest, "utf8");
|
|
64405
|
+
} catch {
|
|
64406
|
+
have = null;
|
|
64407
|
+
}
|
|
64408
|
+
const written = have === null ? null : agentMarkerVersion(have);
|
|
64409
|
+
const newer = written !== null && version !== null && versionBehind(version, written);
|
|
64410
|
+
if (have === want || newer) {
|
|
64411
|
+
installed.push(file.replace(/\.toml$/, ""));
|
|
64412
|
+
continue;
|
|
64413
|
+
}
|
|
64414
|
+
if (have !== null && !have.startsWith(CODEX_AGENT_MARKER)) {
|
|
64415
|
+
problems.push(`${dest} is a user agent that shadows ${install.id}'s ${file}`);
|
|
64416
|
+
fixes.push(`rename or remove ${dest}, then run ${install_fix}`);
|
|
64417
|
+
continue;
|
|
64418
|
+
}
|
|
64419
|
+
problems.push(`${dest} ${have === null ? "missing" : "outdated"}`);
|
|
64420
|
+
stale = true;
|
|
64421
|
+
}
|
|
64422
|
+
if (stale)
|
|
64423
|
+
fixes.push(install_fix);
|
|
64424
|
+
}
|
|
64425
|
+
if (problems.length === 0)
|
|
64426
|
+
return {
|
|
64427
|
+
id: "codex_agents",
|
|
64428
|
+
status: "pass",
|
|
64429
|
+
detail: `Codex agents ${installed.join(", ")} installed in ${agentsDir}`
|
|
64430
|
+
};
|
|
64431
|
+
return {
|
|
64432
|
+
id: "codex_agents",
|
|
64433
|
+
status: "warn",
|
|
64434
|
+
detail: problems.join("; "),
|
|
64435
|
+
fix: [...new Set(fixes)].join("; ")
|
|
64436
|
+
};
|
|
64437
|
+
}, PI_PACKAGE = "@brainervirus/workit-pi", PI_EXTENSION = "dist/workit.js", piAgentDirOf = (res) => {
|
|
64438
|
+
if (res.piAgentDir)
|
|
64439
|
+
return res.piAgentDir;
|
|
64440
|
+
const env = res.env.PI_CODING_AGENT_DIR;
|
|
64441
|
+
if (env)
|
|
64442
|
+
return env === "~" ? res.home : env.replace(/^~(?=\/|\\)/, res.home);
|
|
64443
|
+
return path30.join(res.home, ".pi", "agent");
|
|
64444
|
+
}, npmSpecName = (spec) => {
|
|
64445
|
+
const at = spec.indexOf("@", spec.startsWith("@") ? 1 : 0);
|
|
64446
|
+
return at > 0 ? { name: spec.slice(0, at), pinned: true } : { name: spec, pinned: false };
|
|
64447
|
+
}, findPiEntry = (res, agentDir) => {
|
|
64448
|
+
const scopes = [
|
|
64449
|
+
{
|
|
64450
|
+
scope: "project",
|
|
64451
|
+
settingsFile: path30.join(res.cwd, ".pi", "settings.json"),
|
|
64452
|
+
base: path30.join(res.cwd, ".pi")
|
|
64453
|
+
},
|
|
64454
|
+
{ scope: "user", settingsFile: path30.join(agentDir, "settings.json"), base: agentDir }
|
|
64455
|
+
];
|
|
64456
|
+
for (const { scope, settingsFile, base } of scopes) {
|
|
64457
|
+
const packages = readJson(settingsFile)?.packages;
|
|
64458
|
+
if (!Array.isArray(packages))
|
|
64459
|
+
continue;
|
|
64460
|
+
for (const entry of packages) {
|
|
64461
|
+
const source = typeof entry === "string" ? entry : typeof entry?.source === "string" ? entry.source : null;
|
|
64462
|
+
if (!source)
|
|
64463
|
+
continue;
|
|
64464
|
+
const filter = typeof entry === "object" ? entry : null;
|
|
64465
|
+
if (source.startsWith("npm:")) {
|
|
64466
|
+
const spec = npmSpecName(source.slice(4).trim());
|
|
64467
|
+
if (spec.name !== PI_PACKAGE)
|
|
64468
|
+
continue;
|
|
64469
|
+
const root = path30.join(base, "npm", "node_modules", ...PI_PACKAGE.split("/"));
|
|
64470
|
+
return { scope, settingsFile, source, filter, root, npm: { pinned: spec.pinned } };
|
|
64471
|
+
}
|
|
64472
|
+
if (/^(git:|https?:|ssh:|git@)/.test(source))
|
|
64473
|
+
continue;
|
|
64474
|
+
const local = path30.resolve(base, source.replace(/^~(?=\/|\\)/, res.home));
|
|
64475
|
+
if (readJson(path30.join(local, "package.json"))?.name === PI_PACKAGE)
|
|
64476
|
+
return { scope, settingsFile, source, filter, root: local, npm: null };
|
|
64477
|
+
}
|
|
64478
|
+
}
|
|
64479
|
+
return null;
|
|
64480
|
+
}, globToRegExp3 = (pattern) => new RegExp(`^${pattern.replace(/^\.\//, "").replace(/[.+^${}()|[\]\\]/g, "\\$&").split(/\*\*\/?/).map((part) => part.replace(/\*/g, "[^/]*").replace(/\?/g, "[^/]")).join(".*")}$`), piFilterKeeps = (patterns, file) => {
|
|
64481
|
+
if (!Array.isArray(patterns))
|
|
64482
|
+
return true;
|
|
64483
|
+
const list = patterns.filter((p) => typeof p === "string");
|
|
64484
|
+
if (list.length === 0)
|
|
64485
|
+
return false;
|
|
64486
|
+
const name = path30.posix.basename(file);
|
|
64487
|
+
const matches = (p) => {
|
|
64488
|
+
const re = globToRegExp3(p);
|
|
64489
|
+
return re.test(file) || re.test(name);
|
|
64490
|
+
};
|
|
64491
|
+
const exact = (p) => p.replace(/^\.\//, "") === file;
|
|
64492
|
+
const includes = list.filter((p) => !/^[!+-]/.test(p));
|
|
64493
|
+
let kept = includes.length === 0 || includes.some(matches);
|
|
64494
|
+
if (list.some((p) => p.startsWith("!") && matches(p.slice(1))))
|
|
64495
|
+
kept = false;
|
|
64496
|
+
if (list.some((p) => p.startsWith("+") && exact(p.slice(1))))
|
|
64497
|
+
kept = true;
|
|
64498
|
+
if (list.some((p) => p.startsWith("-") && exact(p.slice(1))))
|
|
64499
|
+
kept = false;
|
|
64500
|
+
return kept;
|
|
64501
|
+
}, checkPiExtension = (res) => {
|
|
64502
|
+
const agentDir = piAgentDirOf(res);
|
|
64503
|
+
if (!existsSync13(agentDir) && !commandOnPath("pi", res.env))
|
|
64504
|
+
return { id: "pi_extension", status: "pass", detail: "Pi not installed — skipping" };
|
|
64505
|
+
const installCmd = (scope, spec = `npm:${PI_PACKAGE}`) => `pi install ${spec}${scope === "project" ? " -l" : ""}`;
|
|
64506
|
+
const entry = findPiEntry(res, agentDir);
|
|
64507
|
+
if (!entry)
|
|
64508
|
+
return {
|
|
64509
|
+
id: "pi_extension",
|
|
64510
|
+
status: "warn",
|
|
64511
|
+
detail: `Workit Pi extension missing: no ${PI_PACKAGE} entry in ${path30.join(agentDir, "settings.json")} or ${path30.join(res.cwd, ".pi", "settings.json")}`,
|
|
64512
|
+
fix: installCmd("user")
|
|
64513
|
+
};
|
|
64514
|
+
const where = `${entry.source} (${entry.scope}, ${entry.settingsFile})`;
|
|
64515
|
+
const rebuild = `cd ${JSON.stringify(entry.root)} && bun run build`;
|
|
64516
|
+
const pkg = readJson(path30.join(entry.root, "package.json"));
|
|
64517
|
+
if (!pkg)
|
|
64518
|
+
return {
|
|
64519
|
+
id: "pi_extension",
|
|
64520
|
+
status: "warn",
|
|
64521
|
+
detail: `Workit Pi extension missing: ${where} is listed but not installed at ${entry.root}`,
|
|
64522
|
+
fix: entry.npm ? installCmd(entry.scope, entry.source) : `restore ${entry.root}, then ${rebuild}`
|
|
64523
|
+
};
|
|
64524
|
+
const declared = Array.isArray(pkg.pi?.extensions) ? pkg.pi.extensions.some((e) => typeof e === "string" && e.replace(/^\.\//, "") === PI_EXTENSION) : false;
|
|
64525
|
+
if (!declared || !existsSync13(path30.join(entry.root, PI_EXTENSION)))
|
|
64526
|
+
return {
|
|
64527
|
+
id: "pi_extension",
|
|
64528
|
+
status: "warn",
|
|
64529
|
+
detail: `Workit Pi extension not loading: ${entry.root} ${declared ? `has no ${PI_EXTENSION}` : `does not declare ${PI_EXTENSION} in its pi manifest`}`,
|
|
64530
|
+
fix: entry.npm ? `pi remove ${entry.source}${entry.scope === "project" ? " -l" : ""} && ${installCmd(entry.scope, entry.source)}` : rebuild
|
|
64531
|
+
};
|
|
64532
|
+
const filter = entry.filter?.extensions;
|
|
64533
|
+
if (!piFilterKeeps(filter, PI_EXTENSION))
|
|
64534
|
+
return {
|
|
64535
|
+
id: "pi_extension",
|
|
64536
|
+
status: "warn",
|
|
64537
|
+
detail: `Workit Pi extension not loading: the ${PI_PACKAGE} entry in ${entry.settingsFile} filters out ${PI_EXTENSION} (extensions: ${JSON.stringify(filter)})`,
|
|
64538
|
+
fix: `remove the "extensions" filter from the ${PI_PACKAGE} entry in ${entry.settingsFile}, or enable the extension with \`pi config${entry.scope === "project" ? " -l" : ""}\``
|
|
64539
|
+
};
|
|
64540
|
+
const version = typeof pkg.version === "string" ? pkg.version : null;
|
|
64541
|
+
const cli = res.cliVersion;
|
|
64542
|
+
if (version && cli && versionBehind(version, cli)) {
|
|
64543
|
+
if (!entry.npm)
|
|
64544
|
+
return {
|
|
64545
|
+
id: "pi_extension",
|
|
64546
|
+
status: "pass",
|
|
64547
|
+
detail: `Workit Pi extension ${version} from local checkout ${where} loads ${PI_EXTENSION} (older than workit ${cli}; a checkout is not compared with the registry)`
|
|
64548
|
+
};
|
|
64549
|
+
const latest = registryLatestVersion(res, PI_PACKAGE);
|
|
64550
|
+
const registryProbed = latest !== null && !res.env.WORKIT_DOCTOR_STALE_REGISTRY_VERSION;
|
|
64551
|
+
if (!latest)
|
|
64552
|
+
return {
|
|
64553
|
+
id: "pi_extension",
|
|
64554
|
+
status: "pass",
|
|
64555
|
+
detail: `Workit Pi extension ${version} from ${where} loads ${PI_EXTENSION}; registry unreachable, so whether a version newer than ${version} is published is unknown (workit ${cli})`
|
|
64556
|
+
};
|
|
64557
|
+
if (versionBehind(version, latest))
|
|
64558
|
+
return {
|
|
64559
|
+
id: "pi_extension",
|
|
64560
|
+
status: "warn",
|
|
64561
|
+
detail: `Workit Pi extension stale: ${PI_PACKAGE} ${version} from ${where} is older than workit ${cli} (published ${latest})`,
|
|
64562
|
+
fix: entry.npm.pinned ? installCmd(entry.scope, `npm:${PI_PACKAGE}@${latest}`) : `pi update npm:${PI_PACKAGE}`,
|
|
64563
|
+
registryProbed
|
|
64564
|
+
};
|
|
64565
|
+
return {
|
|
64566
|
+
id: "pi_extension",
|
|
64567
|
+
status: "pass",
|
|
64568
|
+
detail: `Workit Pi extension ${version} from ${where} is the newest published (workit ${cli})`,
|
|
64569
|
+
registryProbed
|
|
64570
|
+
};
|
|
64571
|
+
}
|
|
64572
|
+
return {
|
|
64573
|
+
id: "pi_extension",
|
|
64574
|
+
status: "pass",
|
|
64575
|
+
detail: `Workit Pi extension ${version ?? "?"} from ${where} loads ${PI_EXTENSION}`
|
|
64576
|
+
};
|
|
64202
64577
|
}, assetPathsFor = (host, dev) => {
|
|
64203
64578
|
const pkg = path30.join(dev, "packages", `workit-${host}`);
|
|
64204
64579
|
switch (host) {
|
|
@@ -65306,6 +65681,7 @@ var init_doctor = __esm(() => {
|
|
|
65306
65681
|
init_host_install();
|
|
65307
65682
|
init_skill_manifests();
|
|
65308
65683
|
OPENCODE_V1_FIX = `OpenCode < ${SUPPORT_MATRIX.opencode.minimum} cannot load Workit 3 (V2 plugin API only): upgrade OpenCode to ${SUPPORT_MATRIX.opencode.minimum}+, or stay on Workit 2.x by pinning "@brainervirus/workit-opencode@2" in the opencode.json "plugin" array`;
|
|
65684
|
+
AGENT_MARKER_VERSION = /^# Generated by Workit (\d+\.\d+\.\d+)\b/;
|
|
65309
65685
|
canonicalCursorHook = cursorHooksEntry().command;
|
|
65310
65686
|
SILENT_HOOK_GRACE_MS = 2 * 60000;
|
|
65311
65687
|
SEMVER = /\d+\.\d+\.\d+/;
|
|
@@ -65314,6 +65690,9 @@ var init_doctor = __esm(() => {
|
|
|
65314
65690
|
checkRuntime,
|
|
65315
65691
|
checkVersions,
|
|
65316
65692
|
checkCodexPin,
|
|
65693
|
+
checkCodexHooks,
|
|
65694
|
+
checkCodexAgents,
|
|
65695
|
+
checkPiExtension,
|
|
65317
65696
|
checkOpencodeVersion,
|
|
65318
65697
|
checkClaudePlugin,
|
|
65319
65698
|
checkWorkitOnPath,
|
|
@@ -65353,7 +65732,7 @@ import {
|
|
|
65353
65732
|
mkdirSync as mkdirSync6,
|
|
65354
65733
|
mkdtempSync as mkdtempSync2,
|
|
65355
65734
|
readFileSync as readFileSync14,
|
|
65356
|
-
readdirSync as
|
|
65735
|
+
readdirSync as readdirSync8,
|
|
65357
65736
|
realpathSync as realpathSync7,
|
|
65358
65737
|
renameSync as renameSync3,
|
|
65359
65738
|
rmSync as rmSync3,
|
|
@@ -66239,7 +66618,7 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
|
|
|
66239
66618
|
}
|
|
66240
66619
|
}, samePluginContent = (src, dest, pluginDir, relative = "") => {
|
|
66241
66620
|
try {
|
|
66242
|
-
for (const entry of
|
|
66621
|
+
for (const entry of readdirSync8(src, { withFileTypes: true })) {
|
|
66243
66622
|
if (entry.name === "node_modules")
|
|
66244
66623
|
continue;
|
|
66245
66624
|
const source = path31.join(src, entry.name);
|
|
@@ -66254,7 +66633,7 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
|
|
|
66254
66633
|
return false;
|
|
66255
66634
|
}
|
|
66256
66635
|
}
|
|
66257
|
-
for (const entry of
|
|
66636
|
+
for (const entry of readdirSync8(dest, { withFileTypes: true })) {
|
|
66258
66637
|
if (existsSync14(path31.join(src, entry.name)))
|
|
66259
66638
|
continue;
|
|
66260
66639
|
const rel = path31.join(relative, entry.name);
|
|
@@ -66273,7 +66652,7 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
|
|
|
66273
66652
|
const sourceRules = path31.join(src, "rules");
|
|
66274
66653
|
const installedRules = path31.join(dest, "rules");
|
|
66275
66654
|
try {
|
|
66276
|
-
for (const entry of
|
|
66655
|
+
for (const entry of readdirSync8(installedRules, { withFileTypes: true })) {
|
|
66277
66656
|
if (!entry.isFile() || !entry.name.endsWith(".mdc"))
|
|
66278
66657
|
continue;
|
|
66279
66658
|
if (existsSync14(path31.join(sourceRules, entry.name)))
|
|
@@ -66290,7 +66669,7 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
|
|
|
66290
66669
|
if (existsSync14(legacyRules)) {
|
|
66291
66670
|
try {
|
|
66292
66671
|
mkdirSync6(path31.join(res.cursorPluginDir, "rules"), { recursive: true });
|
|
66293
|
-
for (const entry of
|
|
66672
|
+
for (const entry of readdirSync8(legacyRules, { withFileTypes: true })) {
|
|
66294
66673
|
if (!entry.isFile() || !entry.name.endsWith(".mdc"))
|
|
66295
66674
|
continue;
|
|
66296
66675
|
const target = path31.join(res.cursorPluginDir, "rules", entry.name);
|
|
@@ -70082,7 +70461,7 @@ import {
|
|
|
70082
70461
|
} from "node:fs";
|
|
70083
70462
|
import path35 from "node:path";
|
|
70084
70463
|
import os12 from "node:os";
|
|
70085
|
-
import { createHash as
|
|
70464
|
+
import { createHash as createHash14 } from "node:crypto";
|
|
70086
70465
|
function previewUpgrade(hosts = HOSTS2, deps = {}) {
|
|
70087
70466
|
const paths = upgradePaths(deps);
|
|
70088
70467
|
const { home, configDir } = paths;
|
|
@@ -70210,7 +70589,7 @@ function applyUpgrade(plan, deps = {}) {
|
|
|
70210
70589
|
mkdirSync8(backup, { recursive: true, mode: 448 });
|
|
70211
70590
|
for (const file of Object.keys(plan.configDigests))
|
|
70212
70591
|
if (existsSync17(file)) {
|
|
70213
|
-
const target = path35.join(backup,
|
|
70592
|
+
const target = path35.join(backup, createHash14("sha256").update(file).digest("hex").slice(0, 12) + "-" + path35.basename(file));
|
|
70214
70593
|
copyFileSync5(file, target);
|
|
70215
70594
|
chmodSync(target, 384);
|
|
70216
70595
|
}
|
|
@@ -70465,7 +70844,7 @@ var HOSTS2, upgradePaths = (deps) => {
|
|
|
70465
70844
|
if (!data || typeof data !== "object" || Array.isArray(data))
|
|
70466
70845
|
throw new Error(`${file} is not a configuration object`);
|
|
70467
70846
|
return data;
|
|
70468
|
-
}, digest2 = (file) => existsSync17(file) ?
|
|
70847
|
+
}, digest2 = (file) => existsSync17(file) ? createHash14("sha256").update(readFileSync17(file)).digest("hex") : "missing", runner = (deps) => deps.run ?? ((command, args) => {
|
|
70469
70848
|
const { home, env } = upgradePaths(deps);
|
|
70470
70849
|
let step;
|
|
70471
70850
|
try {
|
|
@@ -70951,7 +71330,12 @@ async function run5(argv, io) {
|
|
|
70951
71330
|
}
|
|
70952
71331
|
fixLock = clearStaleMetadataLock(root, { force });
|
|
70953
71332
|
}
|
|
70954
|
-
const report = runDoctor({
|
|
71333
|
+
const report = runDoctor({
|
|
71334
|
+
host: "cli",
|
|
71335
|
+
cwd: io.cwd,
|
|
71336
|
+
workspaceRoot: root,
|
|
71337
|
+
cliVersion: package_default.version
|
|
71338
|
+
});
|
|
70955
71339
|
let knowledge = null;
|
|
70956
71340
|
try {
|
|
70957
71341
|
knowledge = lintKnowledge(root);
|
|
@@ -70984,7 +71368,9 @@ async function run5(argv, io) {
|
|
|
70984
71368
|
io.stdout(`${mark} ${check.id} — ${check.detail}
|
|
70985
71369
|
`);
|
|
70986
71370
|
if (check.fix)
|
|
70987
|
-
io.stdout(` fix: ${check.fix
|
|
71371
|
+
io.stdout(` fix: ${check.fix.replaceAll(`
|
|
71372
|
+
`, `
|
|
71373
|
+
`)}
|
|
70988
71374
|
`);
|
|
70989
71375
|
}
|
|
70990
71376
|
io.stdout(`${knowledgeLine}
|
|
@@ -70994,6 +71380,7 @@ async function run5(argv, io) {
|
|
|
70994
71380
|
return report.exitCode;
|
|
70995
71381
|
}
|
|
70996
71382
|
var init_doctor2 = __esm(() => {
|
|
71383
|
+
init_package();
|
|
70997
71384
|
init_doctor();
|
|
70998
71385
|
init_knowledge();
|
|
70999
71386
|
init_store_lock();
|
|
@@ -71107,7 +71494,7 @@ var init_redact = __esm(() => {
|
|
|
71107
71494
|
|
|
71108
71495
|
// packages/workit-core/src/checks.ts
|
|
71109
71496
|
import { spawn, spawnSync as spawnSync16 } from "node:child_process";
|
|
71110
|
-
import { createHash as
|
|
71497
|
+
import { createHash as createHash15 } from "node:crypto";
|
|
71111
71498
|
import fs18 from "node:fs";
|
|
71112
71499
|
import os13 from "node:os";
|
|
71113
71500
|
import path37 from "node:path";
|
|
@@ -71441,7 +71828,7 @@ function pruneCheckLogs(storeRoot, options = {}) {
|
|
|
71441
71828
|
}
|
|
71442
71829
|
return report;
|
|
71443
71830
|
}
|
|
71444
|
-
var MAX_LOG_BYTES, TAIL_LINES = 80, MAX_LINE_CHARS = 400, redactLog = (text) => redactText(text), PEM_BEGIN, PEM_END, BATCH_BYTES, MAX_PENDING, PEM_BODY, MAX_KEY_LINES = 4096, MAX_KEY_BYTES, CMD_META, DRAIN_MS = 250, FORWARDED_SIGNALS, logDigest = (log) => `sha256:${
|
|
71831
|
+
var MAX_LOG_BYTES, TAIL_LINES = 80, MAX_LINE_CHARS = 400, redactLog = (text) => redactText(text), PEM_BEGIN, PEM_END, BATCH_BYTES, MAX_PENDING, PEM_BODY, MAX_KEY_LINES = 4096, MAX_KEY_BYTES, CMD_META, DRAIN_MS = 250, FORWARDED_SIGNALS, logDigest = (log) => `sha256:${createHash15("sha256").update(log).digest("hex")}`, LOG_RETENTION;
|
|
71445
71832
|
var init_checks3 = __esm(() => {
|
|
71446
71833
|
init_redact();
|
|
71447
71834
|
MAX_LOG_BYTES = 2 * 1024 * 1024;
|
|
@@ -72916,6 +73303,33 @@ function buildStatusDoc(cwd, resolved, status, options) {
|
|
|
72916
73303
|
babysit: babysitAction(blockers[0]?.next ?? "READY", blockers[0]?.reason ?? null, status.draft || blockers.some((blocker) => blocker.next === "MARK_READY"))
|
|
72917
73304
|
});
|
|
72918
73305
|
}
|
|
73306
|
+
function recordPrStatus(cwd, doc, actor) {
|
|
73307
|
+
const checks = doc.checks.state;
|
|
73308
|
+
const state = doc.state;
|
|
73309
|
+
if (state !== "open" && state !== "merged" && state !== "closed")
|
|
73310
|
+
return;
|
|
73311
|
+
if (state === "open" && checks !== "passing" && checks !== "failing" && checks !== "pending")
|
|
73312
|
+
return;
|
|
73313
|
+
try {
|
|
73314
|
+
const ledger = readLedger(cwd);
|
|
73315
|
+
if (!ledger.ok)
|
|
73316
|
+
return;
|
|
73317
|
+
const last = ledger.value.rows.findLast((row) => row.type === "pr.status" && row.observer === "workit_cli" && row.pr === doc.number && row.repo === doc.repo);
|
|
73318
|
+
if (last && last.head === doc.head.sha && last.checks === checks && (last.state ?? "open") === state)
|
|
73319
|
+
return;
|
|
73320
|
+
appendObserved(cwd, {
|
|
73321
|
+
type: "pr.status",
|
|
73322
|
+
actor,
|
|
73323
|
+
branch: doc.head.branch,
|
|
73324
|
+
head: doc.head.sha,
|
|
73325
|
+
pr: doc.number,
|
|
73326
|
+
repo: doc.repo,
|
|
73327
|
+
forge: doc.forge,
|
|
73328
|
+
state,
|
|
73329
|
+
checks
|
|
73330
|
+
});
|
|
73331
|
+
} catch {}
|
|
73332
|
+
}
|
|
72919
73333
|
function prStatusReport(cwd, resolved, options = {}) {
|
|
72920
73334
|
const number = selectPr(cwd, resolved, options);
|
|
72921
73335
|
if (!number.ok)
|
|
@@ -72930,6 +73344,8 @@ function prStatusReport(cwd, resolved, options = {}) {
|
|
|
72930
73344
|
});
|
|
72931
73345
|
if (!doc.ok)
|
|
72932
73346
|
return doc;
|
|
73347
|
+
if (options.actor)
|
|
73348
|
+
recordPrStatus(cwd, doc.data, options.actor);
|
|
72933
73349
|
return success2({ doc: doc.data, raw: status.data });
|
|
72934
73350
|
}
|
|
72935
73351
|
function waitVerdict(doc, options) {
|
|
@@ -73055,6 +73471,7 @@ function recordAccepted(cwd, resolved, status, accepted, options) {
|
|
|
73055
73471
|
var MAX_LOG_TAILS = 5, GITLAB_MERGEABLE, GITHUB_MERGEABLE, NO_CHECKS_GRACE_MS = 90000;
|
|
73056
73472
|
var init_report = __esm(() => {
|
|
73057
73473
|
init_rev();
|
|
73474
|
+
init_ledger();
|
|
73058
73475
|
init_reruns();
|
|
73059
73476
|
GITLAB_MERGEABLE = new Set(["mergeable"]);
|
|
73060
73477
|
GITHUB_MERGEABLE = new Set(["clean", "unstable", "has_hooks"]);
|
|
@@ -73426,7 +73843,7 @@ var init_pr_ops = __esm(() => {
|
|
|
73426
73843
|
|
|
73427
73844
|
// packages/workit-core/src/stack.ts
|
|
73428
73845
|
import { spawnSync as spawnSync19 } from "node:child_process";
|
|
73429
|
-
import { createHash as
|
|
73846
|
+
import { createHash as createHash16, randomBytes as randomBytes3 } from "node:crypto";
|
|
73430
73847
|
import fs20 from "node:fs";
|
|
73431
73848
|
import path41 from "node:path";
|
|
73432
73849
|
function worktreeOf(cwd, branch) {
|
|
@@ -74593,7 +75010,7 @@ var STACK_VERSION = 1, stackFail = (code, error, unblock, data) => ({
|
|
|
74593
75010
|
return dir.ok ? path41.join(dir.data, "worktrees") : null;
|
|
74594
75011
|
}, firstLine = (run) => (`${run.stderr}
|
|
74595
75012
|
${run.stdout}`.split(`
|
|
74596
|
-
`).find((line) => line.trim()) ?? "git failed").trim().slice(0, 300), stackFileName = (name) => `${name.replace(/[^A-Za-z0-9._-]+/gu, "_").replace(/^[._]+/u, "").slice(0, 48).toLowerCase()}-${
|
|
75013
|
+
`).find((line) => line.trim()) ?? "git failed").trim().slice(0, 300), stackFileName = (name) => `${name.replace(/[^A-Za-z0-9._-]+/gu, "_").replace(/^[._]+/u, "").slice(0, 48).toLowerCase()}-${createHash16("sha256").update(name).digest("hex").slice(0, 12)}.json`, fileFor, validName = (name) => {
|
|
74597
75014
|
if (name.length === 0 || name.length > 200)
|
|
74598
75015
|
return false;
|
|
74599
75016
|
for (let index = 0;index < name.length; index += 1) {
|
|
@@ -76216,7 +76633,8 @@ async function status(argv, io) {
|
|
|
76216
76633
|
pr,
|
|
76217
76634
|
branch: flags.values.branch ?? null,
|
|
76218
76635
|
logLines: logLines ?? 60,
|
|
76219
|
-
identity: connected.data.identity
|
|
76636
|
+
identity: connected.data.identity,
|
|
76637
|
+
actor: actorFromEnv(io.env)
|
|
76220
76638
|
});
|
|
76221
76639
|
if (!report.ok)
|
|
76222
76640
|
return forgeFail(io, report);
|
|
@@ -76587,6 +77005,7 @@ async function wait(argv, io) {
|
|
|
76587
77005
|
const number = selectPr(io.cwd, resolved, { pr, branch: flags.values.branch ?? null });
|
|
76588
77006
|
if (!number.ok)
|
|
76589
77007
|
return forgeFail(io, number);
|
|
77008
|
+
const actor = actorFromEnv(io.env);
|
|
76590
77009
|
let polls = 0;
|
|
76591
77010
|
let errors = 0;
|
|
76592
77011
|
let status = null;
|
|
@@ -76601,6 +77020,7 @@ async function wait(argv, io) {
|
|
|
76601
77020
|
const doc = buildStatusDoc(io.cwd, resolved, status, { logLines: 0, behind: false });
|
|
76602
77021
|
if (!doc.ok)
|
|
76603
77022
|
return forgeFail(io, doc);
|
|
77023
|
+
recordPrStatus(io.cwd, doc.data, actor);
|
|
76604
77024
|
verdict = waitVerdict(doc.data, { head, elapsedMs });
|
|
76605
77025
|
if (verdict.state !== "waiting")
|
|
76606
77026
|
break;
|
|
@@ -76727,6 +77147,7 @@ async function run11(argv, io) {
|
|
|
76727
77147
|
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`;
|
|
76728
77148
|
var init_ci = __esm(() => {
|
|
76729
77149
|
init_report();
|
|
77150
|
+
init_ledger();
|
|
76730
77151
|
init_autonomy();
|
|
76731
77152
|
init_output();
|
|
76732
77153
|
init_forge_common();
|
|
@@ -77522,7 +77943,7 @@ var init_stack2 = __esm(() => {
|
|
|
77522
77943
|
|
|
77523
77944
|
// packages/workit-core/src/fanout.ts
|
|
77524
77945
|
import { spawnSync as spawnSync23 } from "node:child_process";
|
|
77525
|
-
import { createHash as
|
|
77946
|
+
import { createHash as createHash17 } from "node:crypto";
|
|
77526
77947
|
import fs23 from "node:fs";
|
|
77527
77948
|
import path45 from "node:path";
|
|
77528
77949
|
function expandBraces(pattern, limit = 64) {
|
|
@@ -78003,7 +78424,7 @@ function sliceHash(slice) {
|
|
|
78003
78424
|
context: _context,
|
|
78004
78425
|
...definition
|
|
78005
78426
|
} = slice;
|
|
78006
|
-
return
|
|
78427
|
+
return createHash17("sha256").update(JSON.stringify(definition)).digest("hex").slice(0, 16);
|
|
78007
78428
|
}
|
|
78008
78429
|
function fanoutsDir(cwd) {
|
|
78009
78430
|
const root = storeRoot(cwd);
|
|
@@ -78708,13 +79129,13 @@ var init_fanout_worktree = __esm(() => {
|
|
|
78708
79129
|
});
|
|
78709
79130
|
|
|
78710
79131
|
// packages/workit-core/src/fanout-brief.ts
|
|
78711
|
-
import { createHash as
|
|
79132
|
+
import { createHash as createHash18 } from "node:crypto";
|
|
78712
79133
|
function workerSession(lead, slice, attempt) {
|
|
78713
79134
|
const tail = attempt === null ? "" : `+try${attempt}`;
|
|
78714
79135
|
const full = `${lead}-w-${slice}${tail}`;
|
|
78715
79136
|
if (full.length <= SESSION_MAX)
|
|
78716
79137
|
return full;
|
|
78717
|
-
const digest =
|
|
79138
|
+
const digest = createHash18("sha256").update(slice).digest("hex").slice(0, 12);
|
|
78718
79139
|
return `${lead.slice(0, SESSION_MAX - 3 - digest.length - tail.length)}-w-${digest}${tail}`;
|
|
78719
79140
|
}
|
|
78720
79141
|
function renderBrief(cwd, plan, input) {
|
|
@@ -95900,7 +96321,7 @@ var init_rules = __esm(() => {
|
|
|
95900
96321
|
|
|
95901
96322
|
// packages/workit-cli/src/test-audit/audit.ts
|
|
95902
96323
|
import { spawnSync as spawnSync25 } from "node:child_process";
|
|
95903
|
-
import { existsSync as existsSync19, readdirSync as
|
|
96324
|
+
import { existsSync as existsSync19, readdirSync as readdirSync9, readFileSync as readFileSync22, statSync as statSync7 } from "node:fs";
|
|
95904
96325
|
import path49 from "node:path";
|
|
95905
96326
|
function git7(cwd, args) {
|
|
95906
96327
|
const run = spawnSync25("git", ["-c", "core.quotepath=off", ...args], {
|
|
@@ -95911,7 +96332,7 @@ function git7(cwd, args) {
|
|
|
95911
96332
|
return { ok: run.status === 0, stdout: run.stdout ?? "" };
|
|
95912
96333
|
}
|
|
95913
96334
|
function walkTests(dir, out) {
|
|
95914
|
-
for (const entry of
|
|
96335
|
+
for (const entry of readdirSync9(dir, { withFileTypes: true })) {
|
|
95915
96336
|
if (entry.name.startsWith(".") && entry.name !== "." && entry.isDirectory())
|
|
95916
96337
|
continue;
|
|
95917
96338
|
const full = path49.join(dir, entry.name);
|
|
@@ -96047,7 +96468,7 @@ import {
|
|
|
96047
96468
|
lstatSync as lstatSync7,
|
|
96048
96469
|
mkdirSync as mkdirSync9,
|
|
96049
96470
|
mkdtempSync as mkdtempSync4,
|
|
96050
|
-
readdirSync as
|
|
96471
|
+
readdirSync as readdirSync10,
|
|
96051
96472
|
readFileSync as readFileSync23,
|
|
96052
96473
|
readlinkSync as readlinkSync3,
|
|
96053
96474
|
realpathSync as realpathSync9,
|
|
@@ -96144,7 +96565,7 @@ function removeStaleCopies(tmp = os14.tmpdir()) {
|
|
|
96144
96565
|
let removed = 0;
|
|
96145
96566
|
let names = [];
|
|
96146
96567
|
try {
|
|
96147
|
-
names =
|
|
96568
|
+
names = readdirSync10(tmp);
|
|
96148
96569
|
} catch {
|
|
96149
96570
|
return 0;
|
|
96150
96571
|
}
|
|
@@ -96173,7 +96594,7 @@ function removeStaleCopies(tmp = os14.tmpdir()) {
|
|
|
96173
96594
|
}
|
|
96174
96595
|
function linkNodeModules(origin, target, repo, copy) {
|
|
96175
96596
|
mkdirSync9(target, { recursive: true });
|
|
96176
|
-
for (const entry of
|
|
96597
|
+
for (const entry of readdirSync10(origin, { withFileTypes: true })) {
|
|
96177
96598
|
const from = path50.join(origin, entry.name);
|
|
96178
96599
|
const to = path50.join(target, entry.name);
|
|
96179
96600
|
if (entry.name.startsWith("@") && entry.isDirectory()) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@brainervirus/workit-cli",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.8.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Workit CLI — setup wizard, doctor, and task control for agentic coding workflows",
|
|
6
6
|
"keywords": [
|
|
@@ -38,9 +38,9 @@
|
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@babel/parser": "7.29.9",
|
|
41
|
-
"@brainervirus/workit-core": "^8.
|
|
42
|
-
"@brainervirus/workit-cursor": "^8.
|
|
43
|
-
"@brainervirus/workit-opencode": "^8.
|
|
41
|
+
"@brainervirus/workit-core": "^8.8.0",
|
|
42
|
+
"@brainervirus/workit-cursor": "^8.8.0",
|
|
43
|
+
"@brainervirus/workit-opencode": "^8.8.0",
|
|
44
44
|
"@inkjs/ui": "2.0.0",
|
|
45
45
|
"ink": "7.1.1",
|
|
46
46
|
"react": "19.2.8"
|