@brainervirus/workit-cli 8.6.0 → 8.7.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 +440 -36
- 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.7.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.7.0",
|
|
107
|
+
"@brainervirus/workit-cursor": "^8.7.0",
|
|
108
|
+
"@brainervirus/workit-opencode": "^8.7.0",
|
|
109
109
|
"@inkjs/ui": "2.0.0",
|
|
110
110
|
ink: "7.1.1",
|
|
111
111
|
react: "19.2.8"
|
|
@@ -15016,7 +15016,9 @@ function clearStanding(context, input) {
|
|
|
15016
15016
|
target: input.target
|
|
15017
15017
|
}, { now: context.now });
|
|
15018
15018
|
}
|
|
15019
|
-
function dirtyElsewhere(cwd, branch) {
|
|
15019
|
+
function dirtyElsewhere(cwd, branch, head) {
|
|
15020
|
+
if (headSha(cwd) === head)
|
|
15021
|
+
return worktreeTree(cwd)?.dirty !== false;
|
|
15020
15022
|
const list = git4(cwd, ["worktree", "list", "--porcelain"]);
|
|
15021
15023
|
let worktree = null;
|
|
15022
15024
|
for (const line of (list ?? "").split(`
|
|
@@ -15051,7 +15053,7 @@ function recordVerdict(context, input) {
|
|
|
15051
15053
|
const key = codeKey(context.cwd, { branch, base: context.base });
|
|
15052
15054
|
if (!key.head)
|
|
15053
15055
|
return err("not_found", `branch "${branch}" has no commit to judge`);
|
|
15054
|
-
if (key.dirty === true || key.dirty === null && dirtyElsewhere(context.cwd, branch))
|
|
15056
|
+
if (key.dirty === true || key.dirty === null && dirtyElsewhere(context.cwd, branch, key.head))
|
|
15055
15057
|
return err("blocked", `dirty_worktree: ${branch} has uncommitted changes, so its head is not what was judged`, "commit or stash the changes, re-check, then record the verdict");
|
|
15056
15058
|
const session = context.actor.session;
|
|
15057
15059
|
const selfReason = input.self === true ? "flag" : session && input.derivedFrom !== null ? null : "no_session";
|
|
@@ -63930,11 +63932,13 @@ var init_skill_manifests = __esm(() => {
|
|
|
63930
63932
|
|
|
63931
63933
|
// packages/workit-cli/src/admin/doctor.ts
|
|
63932
63934
|
import { spawnSync as spawnSync13 } from "node:child_process";
|
|
63935
|
+
import { createHash as createHash13 } from "node:crypto";
|
|
63933
63936
|
import {
|
|
63934
63937
|
existsSync as existsSync13,
|
|
63935
63938
|
lstatSync as lstatSync4,
|
|
63936
63939
|
mkdirSync as mkdirSync5,
|
|
63937
63940
|
mkdtempSync,
|
|
63941
|
+
readdirSync as readdirSync7,
|
|
63938
63942
|
readFileSync as readFileSync13,
|
|
63939
63943
|
readlinkSync as readlinkSync2,
|
|
63940
63944
|
rmSync as rmSync2,
|
|
@@ -63975,8 +63979,11 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
63975
63979
|
cursorMcp: options.cursorMcp ?? path30.join(home, ".cursor", "mcp.json"),
|
|
63976
63980
|
cursorPluginDir: options.cursorPluginDir ?? path30.join(home, ".cursor", "plugins", "local", "workit"),
|
|
63977
63981
|
cursorHeartbeatDir: options.stateDir ?? (env.WORKFLOW_TOOLKIT_STATE || resolveStateDir()),
|
|
63982
|
+
codexHome: options.codexHome,
|
|
63983
|
+
piAgentDir: options.piAgentDir,
|
|
63978
63984
|
env,
|
|
63979
|
-
installer: options.installer ?? false
|
|
63985
|
+
installer: options.installer ?? false,
|
|
63986
|
+
cliVersion: options.cliVersion ?? null
|
|
63980
63987
|
};
|
|
63981
63988
|
}, readJson = (p) => {
|
|
63982
63989
|
try {
|
|
@@ -64197,6 +64204,368 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64197
64204
|
detail: `codex CLI ${installed} differs from the qualified ${qualified}`,
|
|
64198
64205
|
fix: `Reinstall the qualified Codex CLI ${qualified} or record fresh qualification evidence`
|
|
64199
64206
|
};
|
|
64207
|
+
}, readTomlTables = (file) => {
|
|
64208
|
+
const tables = new Map;
|
|
64209
|
+
let text;
|
|
64210
|
+
try {
|
|
64211
|
+
text = readFileSync13(file, "utf8");
|
|
64212
|
+
} catch {
|
|
64213
|
+
return tables;
|
|
64214
|
+
}
|
|
64215
|
+
const unquote = (raw) => {
|
|
64216
|
+
const s = raw.trim();
|
|
64217
|
+
if (s.startsWith('"')) {
|
|
64218
|
+
try {
|
|
64219
|
+
return JSON.parse(s);
|
|
64220
|
+
} catch {
|
|
64221
|
+
return s.slice(1, -1);
|
|
64222
|
+
}
|
|
64223
|
+
}
|
|
64224
|
+
return s.startsWith("'") ? s.slice(1, -1) : s;
|
|
64225
|
+
};
|
|
64226
|
+
const SEGMENT = /\s*("(?:[^"\\]|\\.)*"|'[^']*'|[A-Za-z0-9_-]+)\s*(?:\.|$)/y;
|
|
64227
|
+
let current = {};
|
|
64228
|
+
tables.set("", current);
|
|
64229
|
+
for (const line of text.split(/\r?\n/)) {
|
|
64230
|
+
const header = /^\s*\[([^[\]]+)\]\s*(?:#.*)?$/.exec(line);
|
|
64231
|
+
if (header) {
|
|
64232
|
+
const parts = [];
|
|
64233
|
+
SEGMENT.lastIndex = 0;
|
|
64234
|
+
let match;
|
|
64235
|
+
while (SEGMENT.lastIndex < header[1].length && (match = SEGMENT.exec(header[1])))
|
|
64236
|
+
parts.push(unquote(match[1]));
|
|
64237
|
+
const key = parts.join("\x00");
|
|
64238
|
+
current = tables.get(key) ?? {};
|
|
64239
|
+
tables.set(key, current);
|
|
64240
|
+
continue;
|
|
64241
|
+
}
|
|
64242
|
+
const pair = /^\s*("(?:[^"\\]|\\.)*"|[A-Za-z0-9_-]+)\s*=\s*(.+?)\s*$/.exec(line);
|
|
64243
|
+
if (!pair)
|
|
64244
|
+
continue;
|
|
64245
|
+
const value = pair[2].replace(/\s+#[^"']*$/, "");
|
|
64246
|
+
current[unquote(pair[1])] = value === "true" ? true : value === "false" ? false : unquote(value);
|
|
64247
|
+
}
|
|
64248
|
+
return tables;
|
|
64249
|
+
}, codexHomeOf = (res) => res.codexHome ?? (res.env.CODEX_HOME || path30.join(res.home, ".codex")), codexWorkitInstalls = (res) => {
|
|
64250
|
+
const codexHome = codexHomeOf(res);
|
|
64251
|
+
const configFile = path30.join(codexHome, "config.toml");
|
|
64252
|
+
const installs = [];
|
|
64253
|
+
for (const [key, table] of readTomlTables(configFile)) {
|
|
64254
|
+
const [kind, id, ...rest] = key.split("\x00");
|
|
64255
|
+
if (kind !== "plugins" || rest.length > 0 || !id?.startsWith("workit@") || table.enabled === false)
|
|
64256
|
+
continue;
|
|
64257
|
+
const marketplace = id.slice("workit@".length);
|
|
64258
|
+
const dir = path30.join(codexHome, "plugins", "cache", marketplace, "workit");
|
|
64259
|
+
let versions = [];
|
|
64260
|
+
try {
|
|
64261
|
+
versions = readdirSync7(dir).filter((v) => existsSync13(path30.join(dir, v, ".codex-plugin")));
|
|
64262
|
+
} catch {
|
|
64263
|
+
versions = [];
|
|
64264
|
+
}
|
|
64265
|
+
const version = versions.reduce((best, v) => best && semverAtLeast(best, v) ? best : v, null);
|
|
64266
|
+
installs.push({
|
|
64267
|
+
id,
|
|
64268
|
+
marketplace,
|
|
64269
|
+
root: version ? path30.join(dir, version) : null,
|
|
64270
|
+
version,
|
|
64271
|
+
configFile
|
|
64272
|
+
});
|
|
64273
|
+
}
|
|
64274
|
+
return installs;
|
|
64275
|
+
}, snakeEvent = (event) => event.replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase(), codexHookHash = (event, matcher, handler) => {
|
|
64276
|
+
if (handler.type !== "command" || typeof handler.command !== "string" || Object.keys(handler).some((k) => !["type", "command", "timeout", "async"].includes(k)))
|
|
64277
|
+
return null;
|
|
64278
|
+
const hook = {
|
|
64279
|
+
async: handler.async ?? false,
|
|
64280
|
+
command: handler.command,
|
|
64281
|
+
timeout: handler.timeout ?? 600,
|
|
64282
|
+
type: "command"
|
|
64283
|
+
};
|
|
64284
|
+
const body = {
|
|
64285
|
+
event_name: snakeEvent(event),
|
|
64286
|
+
hooks: [hook],
|
|
64287
|
+
...typeof matcher === "string" ? { matcher } : {}
|
|
64288
|
+
};
|
|
64289
|
+
return `sha256:${createHash13("sha256").update(JSON.stringify(body)).digest("hex")}`;
|
|
64290
|
+
}, codexHookTrust = (install, tables) => {
|
|
64291
|
+
const hooks = install.root ? readJson(path30.join(install.root, "hooks", "hooks.json"))?.hooks : null;
|
|
64292
|
+
if (!hooks || typeof hooks !== "object")
|
|
64293
|
+
return null;
|
|
64294
|
+
const result = [];
|
|
64295
|
+
for (const [event, groups] of Object.entries(hooks)) {
|
|
64296
|
+
if (!Array.isArray(groups))
|
|
64297
|
+
continue;
|
|
64298
|
+
groups.forEach((group, g) => {
|
|
64299
|
+
const handlers = Array.isArray(group?.hooks) ? group.hooks : [];
|
|
64300
|
+
handlers.forEach((handler, h) => {
|
|
64301
|
+
const key = `${install.id}:hooks/hooks.json:${snakeEvent(event)}:${g}:${h}`;
|
|
64302
|
+
const hash = codexHookHash(event, group?.matcher, handler ?? {});
|
|
64303
|
+
const state = tables.get(["hooks", "state", key].join("\x00"));
|
|
64304
|
+
const trusted = typeof state?.trusted_hash === "string" ? state.trusted_hash : null;
|
|
64305
|
+
result.push({
|
|
64306
|
+
key,
|
|
64307
|
+
hash,
|
|
64308
|
+
state: state?.enabled === false ? "disabled" : trusted === null ? "untrusted" : hash !== null && trusted !== hash ? "modified" : "trusted"
|
|
64309
|
+
});
|
|
64310
|
+
});
|
|
64311
|
+
});
|
|
64312
|
+
}
|
|
64313
|
+
return result;
|
|
64314
|
+
}, checkCodexHooks = (res) => {
|
|
64315
|
+
const installs = codexWorkitInstalls(res);
|
|
64316
|
+
if (installs.length === 0)
|
|
64317
|
+
return {
|
|
64318
|
+
id: "codex_hooks",
|
|
64319
|
+
status: "pass",
|
|
64320
|
+
detail: "no Workit Codex plugin enabled — skipping"
|
|
64321
|
+
};
|
|
64322
|
+
const tables = readTomlTables(installs[0].configFile);
|
|
64323
|
+
const problems = [];
|
|
64324
|
+
const toTrust = [];
|
|
64325
|
+
let reinstall;
|
|
64326
|
+
let total = 0;
|
|
64327
|
+
for (const install of installs) {
|
|
64328
|
+
const trust = codexHookTrust(install, tables);
|
|
64329
|
+
if (!trust) {
|
|
64330
|
+
problems.push(`${install.id}: no installed hooks/hooks.json`);
|
|
64331
|
+
reinstall ??= `codex plugin remove ${install.id} && codex plugin add ${install.id}`;
|
|
64332
|
+
continue;
|
|
64333
|
+
}
|
|
64334
|
+
total += trust.length;
|
|
64335
|
+
for (const state of ["untrusted", "modified", "disabled"]) {
|
|
64336
|
+
const hit = trust.filter((t) => t.state === state);
|
|
64337
|
+
if (hit.length > 0)
|
|
64338
|
+
problems.push(`${install.id}: ${hit.length} of ${trust.length} hooks ${state === "modified" ? "changed since trusted" : state} (${hit.map((t) => t.key.split(":")[2]).join(", ")})`);
|
|
64339
|
+
}
|
|
64340
|
+
toTrust.push(...trust.filter((t) => t.state !== "trusted"));
|
|
64341
|
+
}
|
|
64342
|
+
if (problems.length === 0)
|
|
64343
|
+
return {
|
|
64344
|
+
id: "codex_hooks",
|
|
64345
|
+
status: "pass",
|
|
64346
|
+
detail: `${total} Workit Codex plugin hooks trusted (${installs.map((i) => `${i.id} ${i.version ?? "?"}`).join(", ")})`
|
|
64347
|
+
};
|
|
64348
|
+
const disabled = toTrust.some((t) => t.state === "disabled");
|
|
64349
|
+
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)`;
|
|
64350
|
+
return {
|
|
64351
|
+
id: "codex_hooks",
|
|
64352
|
+
status: "warn",
|
|
64353
|
+
detail: `Codex skips untrusted plugin hooks — ${problems.join("; ")}`,
|
|
64354
|
+
fix
|
|
64355
|
+
};
|
|
64356
|
+
}, 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) => {
|
|
64357
|
+
const installs = codexWorkitInstalls(res);
|
|
64358
|
+
if (installs.length === 0)
|
|
64359
|
+
return {
|
|
64360
|
+
id: "codex_agents",
|
|
64361
|
+
status: "pass",
|
|
64362
|
+
detail: "no Workit Codex plugin enabled — skipping"
|
|
64363
|
+
};
|
|
64364
|
+
const agentsDir = path30.join(codexHomeOf(res), "agents");
|
|
64365
|
+
const problems = [];
|
|
64366
|
+
const fixes = [];
|
|
64367
|
+
const installed = [];
|
|
64368
|
+
for (const install of installs) {
|
|
64369
|
+
const source = install.root ? path30.join(install.root, "agents") : null;
|
|
64370
|
+
const files = source && existsSync13(source) ? readdirSync7(source).filter((f) => f.endsWith(".toml")).toSorted() : [];
|
|
64371
|
+
if (files.length === 0) {
|
|
64372
|
+
problems.push(`${install.id} ${install.version ?? "?"} bundles no agents`);
|
|
64373
|
+
fixes.push(`codex plugin remove ${install.id} && codex plugin add ${install.id}`);
|
|
64374
|
+
continue;
|
|
64375
|
+
}
|
|
64376
|
+
const install_fix = `node ${JSON.stringify(path30.join(install.root, "dist", "launch-mcp.js"))} --install-agents, then start a new Codex session`;
|
|
64377
|
+
const pluginVersion = readJson(path30.join(install.root, "package.json"))?.version;
|
|
64378
|
+
const version = typeof pluginVersion === "string" ? pluginVersion.match(SEMVER)?.[0] ?? null : null;
|
|
64379
|
+
let stale = false;
|
|
64380
|
+
for (const file of files) {
|
|
64381
|
+
const dest = path30.join(agentsDir, file);
|
|
64382
|
+
const want = stampCodexAgent(readFileSync13(path30.join(source, file), "utf8"), version);
|
|
64383
|
+
let link = false;
|
|
64384
|
+
try {
|
|
64385
|
+
link = lstatSync4(dest).isSymbolicLink();
|
|
64386
|
+
} catch {
|
|
64387
|
+
link = false;
|
|
64388
|
+
}
|
|
64389
|
+
if (link) {
|
|
64390
|
+
problems.push(`${dest} is a symlink (the plugin never writes through one)`);
|
|
64391
|
+
fixes.push(`replace the symlink ${dest} with a file or remove it, then run ${install_fix}`);
|
|
64392
|
+
continue;
|
|
64393
|
+
}
|
|
64394
|
+
let have = null;
|
|
64395
|
+
try {
|
|
64396
|
+
have = readFileSync13(dest, "utf8");
|
|
64397
|
+
} catch {
|
|
64398
|
+
have = null;
|
|
64399
|
+
}
|
|
64400
|
+
const written = have === null ? null : agentMarkerVersion(have);
|
|
64401
|
+
const newer = written !== null && version !== null && versionBehind(version, written);
|
|
64402
|
+
if (have === want || newer) {
|
|
64403
|
+
installed.push(file.replace(/\.toml$/, ""));
|
|
64404
|
+
continue;
|
|
64405
|
+
}
|
|
64406
|
+
if (have !== null && !have.startsWith(CODEX_AGENT_MARKER)) {
|
|
64407
|
+
problems.push(`${dest} is a user agent that shadows ${install.id}'s ${file}`);
|
|
64408
|
+
fixes.push(`rename or remove ${dest}, then run ${install_fix}`);
|
|
64409
|
+
continue;
|
|
64410
|
+
}
|
|
64411
|
+
problems.push(`${dest} ${have === null ? "missing" : "outdated"}`);
|
|
64412
|
+
stale = true;
|
|
64413
|
+
}
|
|
64414
|
+
if (stale)
|
|
64415
|
+
fixes.push(install_fix);
|
|
64416
|
+
}
|
|
64417
|
+
if (problems.length === 0)
|
|
64418
|
+
return {
|
|
64419
|
+
id: "codex_agents",
|
|
64420
|
+
status: "pass",
|
|
64421
|
+
detail: `Codex agents ${installed.join(", ")} installed in ${agentsDir}`
|
|
64422
|
+
};
|
|
64423
|
+
return {
|
|
64424
|
+
id: "codex_agents",
|
|
64425
|
+
status: "warn",
|
|
64426
|
+
detail: problems.join("; "),
|
|
64427
|
+
fix: [...new Set(fixes)].join("; ")
|
|
64428
|
+
};
|
|
64429
|
+
}, PI_PACKAGE = "@brainervirus/workit-pi", PI_EXTENSION = "dist/workit.js", piAgentDirOf = (res) => {
|
|
64430
|
+
if (res.piAgentDir)
|
|
64431
|
+
return res.piAgentDir;
|
|
64432
|
+
const env = res.env.PI_CODING_AGENT_DIR;
|
|
64433
|
+
if (env)
|
|
64434
|
+
return env === "~" ? res.home : env.replace(/^~(?=\/|\\)/, res.home);
|
|
64435
|
+
return path30.join(res.home, ".pi", "agent");
|
|
64436
|
+
}, npmSpecName = (spec) => {
|
|
64437
|
+
const at = spec.indexOf("@", spec.startsWith("@") ? 1 : 0);
|
|
64438
|
+
return at > 0 ? { name: spec.slice(0, at), pinned: true } : { name: spec, pinned: false };
|
|
64439
|
+
}, findPiEntry = (res, agentDir) => {
|
|
64440
|
+
const scopes = [
|
|
64441
|
+
{
|
|
64442
|
+
scope: "project",
|
|
64443
|
+
settingsFile: path30.join(res.cwd, ".pi", "settings.json"),
|
|
64444
|
+
base: path30.join(res.cwd, ".pi")
|
|
64445
|
+
},
|
|
64446
|
+
{ scope: "user", settingsFile: path30.join(agentDir, "settings.json"), base: agentDir }
|
|
64447
|
+
];
|
|
64448
|
+
for (const { scope, settingsFile, base } of scopes) {
|
|
64449
|
+
const packages = readJson(settingsFile)?.packages;
|
|
64450
|
+
if (!Array.isArray(packages))
|
|
64451
|
+
continue;
|
|
64452
|
+
for (const entry of packages) {
|
|
64453
|
+
const source = typeof entry === "string" ? entry : typeof entry?.source === "string" ? entry.source : null;
|
|
64454
|
+
if (!source)
|
|
64455
|
+
continue;
|
|
64456
|
+
const filter = typeof entry === "object" ? entry : null;
|
|
64457
|
+
if (source.startsWith("npm:")) {
|
|
64458
|
+
const spec = npmSpecName(source.slice(4).trim());
|
|
64459
|
+
if (spec.name !== PI_PACKAGE)
|
|
64460
|
+
continue;
|
|
64461
|
+
const root = path30.join(base, "npm", "node_modules", ...PI_PACKAGE.split("/"));
|
|
64462
|
+
return { scope, settingsFile, source, filter, root, npm: { pinned: spec.pinned } };
|
|
64463
|
+
}
|
|
64464
|
+
if (/^(git:|https?:|ssh:|git@)/.test(source))
|
|
64465
|
+
continue;
|
|
64466
|
+
const local = path30.resolve(base, source.replace(/^~(?=\/|\\)/, res.home));
|
|
64467
|
+
if (readJson(path30.join(local, "package.json"))?.name === PI_PACKAGE)
|
|
64468
|
+
return { scope, settingsFile, source, filter, root: local, npm: null };
|
|
64469
|
+
}
|
|
64470
|
+
}
|
|
64471
|
+
return null;
|
|
64472
|
+
}, globToRegExp3 = (pattern) => new RegExp(`^${pattern.replace(/^\.\//, "").replace(/[.+^${}()|[\]\\]/g, "\\$&").split(/\*\*\/?/).map((part) => part.replace(/\*/g, "[^/]*").replace(/\?/g, "[^/]")).join(".*")}$`), piFilterKeeps = (patterns, file) => {
|
|
64473
|
+
if (!Array.isArray(patterns))
|
|
64474
|
+
return true;
|
|
64475
|
+
const list = patterns.filter((p) => typeof p === "string");
|
|
64476
|
+
if (list.length === 0)
|
|
64477
|
+
return false;
|
|
64478
|
+
const name = path30.posix.basename(file);
|
|
64479
|
+
const matches = (p) => {
|
|
64480
|
+
const re = globToRegExp3(p);
|
|
64481
|
+
return re.test(file) || re.test(name);
|
|
64482
|
+
};
|
|
64483
|
+
const exact = (p) => p.replace(/^\.\//, "") === file;
|
|
64484
|
+
const includes = list.filter((p) => !/^[!+-]/.test(p));
|
|
64485
|
+
let kept = includes.length === 0 || includes.some(matches);
|
|
64486
|
+
if (list.some((p) => p.startsWith("!") && matches(p.slice(1))))
|
|
64487
|
+
kept = false;
|
|
64488
|
+
if (list.some((p) => p.startsWith("+") && exact(p.slice(1))))
|
|
64489
|
+
kept = true;
|
|
64490
|
+
if (list.some((p) => p.startsWith("-") && exact(p.slice(1))))
|
|
64491
|
+
kept = false;
|
|
64492
|
+
return kept;
|
|
64493
|
+
}, checkPiExtension = (res) => {
|
|
64494
|
+
const agentDir = piAgentDirOf(res);
|
|
64495
|
+
if (!existsSync13(agentDir) && !commandOnPath("pi", res.env))
|
|
64496
|
+
return { id: "pi_extension", status: "pass", detail: "Pi not installed — skipping" };
|
|
64497
|
+
const installCmd = (scope, spec = `npm:${PI_PACKAGE}`) => `pi install ${spec}${scope === "project" ? " -l" : ""}`;
|
|
64498
|
+
const entry = findPiEntry(res, agentDir);
|
|
64499
|
+
if (!entry)
|
|
64500
|
+
return {
|
|
64501
|
+
id: "pi_extension",
|
|
64502
|
+
status: "warn",
|
|
64503
|
+
detail: `Workit Pi extension missing: no ${PI_PACKAGE} entry in ${path30.join(agentDir, "settings.json")} or ${path30.join(res.cwd, ".pi", "settings.json")}`,
|
|
64504
|
+
fix: installCmd("user")
|
|
64505
|
+
};
|
|
64506
|
+
const where = `${entry.source} (${entry.scope}, ${entry.settingsFile})`;
|
|
64507
|
+
const rebuild = `cd ${JSON.stringify(entry.root)} && bun run build`;
|
|
64508
|
+
const pkg = readJson(path30.join(entry.root, "package.json"));
|
|
64509
|
+
if (!pkg)
|
|
64510
|
+
return {
|
|
64511
|
+
id: "pi_extension",
|
|
64512
|
+
status: "warn",
|
|
64513
|
+
detail: `Workit Pi extension missing: ${where} is listed but not installed at ${entry.root}`,
|
|
64514
|
+
fix: entry.npm ? installCmd(entry.scope, entry.source) : `restore ${entry.root}, then ${rebuild}`
|
|
64515
|
+
};
|
|
64516
|
+
const declared = Array.isArray(pkg.pi?.extensions) ? pkg.pi.extensions.some((e) => typeof e === "string" && e.replace(/^\.\//, "") === PI_EXTENSION) : false;
|
|
64517
|
+
if (!declared || !existsSync13(path30.join(entry.root, PI_EXTENSION)))
|
|
64518
|
+
return {
|
|
64519
|
+
id: "pi_extension",
|
|
64520
|
+
status: "warn",
|
|
64521
|
+
detail: `Workit Pi extension not loading: ${entry.root} ${declared ? `has no ${PI_EXTENSION}` : `does not declare ${PI_EXTENSION} in its pi manifest`}`,
|
|
64522
|
+
fix: entry.npm ? `pi remove ${entry.source}${entry.scope === "project" ? " -l" : ""} && ${installCmd(entry.scope, entry.source)}` : rebuild
|
|
64523
|
+
};
|
|
64524
|
+
const filter = entry.filter?.extensions;
|
|
64525
|
+
if (!piFilterKeeps(filter, PI_EXTENSION))
|
|
64526
|
+
return {
|
|
64527
|
+
id: "pi_extension",
|
|
64528
|
+
status: "warn",
|
|
64529
|
+
detail: `Workit Pi extension not loading: the ${PI_PACKAGE} entry in ${entry.settingsFile} filters out ${PI_EXTENSION} (extensions: ${JSON.stringify(filter)})`,
|
|
64530
|
+
fix: `remove the "extensions" filter from the ${PI_PACKAGE} entry in ${entry.settingsFile}, or enable the extension with \`pi config${entry.scope === "project" ? " -l" : ""}\``
|
|
64531
|
+
};
|
|
64532
|
+
const version = typeof pkg.version === "string" ? pkg.version : null;
|
|
64533
|
+
const cli = res.cliVersion;
|
|
64534
|
+
if (version && cli && versionBehind(version, cli)) {
|
|
64535
|
+
if (!entry.npm)
|
|
64536
|
+
return {
|
|
64537
|
+
id: "pi_extension",
|
|
64538
|
+
status: "pass",
|
|
64539
|
+
detail: `Workit Pi extension ${version} from local checkout ${where} loads ${PI_EXTENSION} (older than workit ${cli}; a checkout is not compared with the registry)`
|
|
64540
|
+
};
|
|
64541
|
+
const latest = registryLatestVersion(res, PI_PACKAGE);
|
|
64542
|
+
const registryProbed = latest !== null && !res.env.WORKIT_DOCTOR_STALE_REGISTRY_VERSION;
|
|
64543
|
+
if (!latest)
|
|
64544
|
+
return {
|
|
64545
|
+
id: "pi_extension",
|
|
64546
|
+
status: "pass",
|
|
64547
|
+
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})`
|
|
64548
|
+
};
|
|
64549
|
+
if (versionBehind(version, latest))
|
|
64550
|
+
return {
|
|
64551
|
+
id: "pi_extension",
|
|
64552
|
+
status: "warn",
|
|
64553
|
+
detail: `Workit Pi extension stale: ${PI_PACKAGE} ${version} from ${where} is older than workit ${cli} (published ${latest})`,
|
|
64554
|
+
fix: entry.npm.pinned ? installCmd(entry.scope, `npm:${PI_PACKAGE}@${latest}`) : `pi update npm:${PI_PACKAGE}`,
|
|
64555
|
+
registryProbed
|
|
64556
|
+
};
|
|
64557
|
+
return {
|
|
64558
|
+
id: "pi_extension",
|
|
64559
|
+
status: "pass",
|
|
64560
|
+
detail: `Workit Pi extension ${version} from ${where} is the newest published (workit ${cli})`,
|
|
64561
|
+
registryProbed
|
|
64562
|
+
};
|
|
64563
|
+
}
|
|
64564
|
+
return {
|
|
64565
|
+
id: "pi_extension",
|
|
64566
|
+
status: "pass",
|
|
64567
|
+
detail: `Workit Pi extension ${version ?? "?"} from ${where} loads ${PI_EXTENSION}`
|
|
64568
|
+
};
|
|
64200
64569
|
}, assetPathsFor = (host, dev) => {
|
|
64201
64570
|
const pkg = path30.join(dev, "packages", `workit-${host}`);
|
|
64202
64571
|
switch (host) {
|
|
@@ -65304,6 +65673,7 @@ var init_doctor = __esm(() => {
|
|
|
65304
65673
|
init_host_install();
|
|
65305
65674
|
init_skill_manifests();
|
|
65306
65675
|
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`;
|
|
65676
|
+
AGENT_MARKER_VERSION = /^# Generated by Workit (\d+\.\d+\.\d+)\b/;
|
|
65307
65677
|
canonicalCursorHook = cursorHooksEntry().command;
|
|
65308
65678
|
SILENT_HOOK_GRACE_MS = 2 * 60000;
|
|
65309
65679
|
SEMVER = /\d+\.\d+\.\d+/;
|
|
@@ -65312,6 +65682,9 @@ var init_doctor = __esm(() => {
|
|
|
65312
65682
|
checkRuntime,
|
|
65313
65683
|
checkVersions,
|
|
65314
65684
|
checkCodexPin,
|
|
65685
|
+
checkCodexHooks,
|
|
65686
|
+
checkCodexAgents,
|
|
65687
|
+
checkPiExtension,
|
|
65315
65688
|
checkOpencodeVersion,
|
|
65316
65689
|
checkClaudePlugin,
|
|
65317
65690
|
checkWorkitOnPath,
|
|
@@ -65351,7 +65724,7 @@ import {
|
|
|
65351
65724
|
mkdirSync as mkdirSync6,
|
|
65352
65725
|
mkdtempSync as mkdtempSync2,
|
|
65353
65726
|
readFileSync as readFileSync14,
|
|
65354
|
-
readdirSync as
|
|
65727
|
+
readdirSync as readdirSync8,
|
|
65355
65728
|
realpathSync as realpathSync7,
|
|
65356
65729
|
renameSync as renameSync3,
|
|
65357
65730
|
rmSync as rmSync3,
|
|
@@ -66237,7 +66610,7 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
|
|
|
66237
66610
|
}
|
|
66238
66611
|
}, samePluginContent = (src, dest, pluginDir, relative = "") => {
|
|
66239
66612
|
try {
|
|
66240
|
-
for (const entry of
|
|
66613
|
+
for (const entry of readdirSync8(src, { withFileTypes: true })) {
|
|
66241
66614
|
if (entry.name === "node_modules")
|
|
66242
66615
|
continue;
|
|
66243
66616
|
const source = path31.join(src, entry.name);
|
|
@@ -66252,7 +66625,7 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
|
|
|
66252
66625
|
return false;
|
|
66253
66626
|
}
|
|
66254
66627
|
}
|
|
66255
|
-
for (const entry of
|
|
66628
|
+
for (const entry of readdirSync8(dest, { withFileTypes: true })) {
|
|
66256
66629
|
if (existsSync14(path31.join(src, entry.name)))
|
|
66257
66630
|
continue;
|
|
66258
66631
|
const rel = path31.join(relative, entry.name);
|
|
@@ -66271,7 +66644,7 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
|
|
|
66271
66644
|
const sourceRules = path31.join(src, "rules");
|
|
66272
66645
|
const installedRules = path31.join(dest, "rules");
|
|
66273
66646
|
try {
|
|
66274
|
-
for (const entry of
|
|
66647
|
+
for (const entry of readdirSync8(installedRules, { withFileTypes: true })) {
|
|
66275
66648
|
if (!entry.isFile() || !entry.name.endsWith(".mdc"))
|
|
66276
66649
|
continue;
|
|
66277
66650
|
if (existsSync14(path31.join(sourceRules, entry.name)))
|
|
@@ -66288,7 +66661,7 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
|
|
|
66288
66661
|
if (existsSync14(legacyRules)) {
|
|
66289
66662
|
try {
|
|
66290
66663
|
mkdirSync6(path31.join(res.cursorPluginDir, "rules"), { recursive: true });
|
|
66291
|
-
for (const entry of
|
|
66664
|
+
for (const entry of readdirSync8(legacyRules, { withFileTypes: true })) {
|
|
66292
66665
|
if (!entry.isFile() || !entry.name.endsWith(".mdc"))
|
|
66293
66666
|
continue;
|
|
66294
66667
|
const target = path31.join(res.cursorPluginDir, "rules", entry.name);
|
|
@@ -70080,7 +70453,7 @@ import {
|
|
|
70080
70453
|
} from "node:fs";
|
|
70081
70454
|
import path35 from "node:path";
|
|
70082
70455
|
import os12 from "node:os";
|
|
70083
|
-
import { createHash as
|
|
70456
|
+
import { createHash as createHash14 } from "node:crypto";
|
|
70084
70457
|
function previewUpgrade(hosts = HOSTS2, deps = {}) {
|
|
70085
70458
|
const paths = upgradePaths(deps);
|
|
70086
70459
|
const { home, configDir } = paths;
|
|
@@ -70208,7 +70581,7 @@ function applyUpgrade(plan, deps = {}) {
|
|
|
70208
70581
|
mkdirSync8(backup, { recursive: true, mode: 448 });
|
|
70209
70582
|
for (const file of Object.keys(plan.configDigests))
|
|
70210
70583
|
if (existsSync17(file)) {
|
|
70211
|
-
const target = path35.join(backup,
|
|
70584
|
+
const target = path35.join(backup, createHash14("sha256").update(file).digest("hex").slice(0, 12) + "-" + path35.basename(file));
|
|
70212
70585
|
copyFileSync5(file, target);
|
|
70213
70586
|
chmodSync(target, 384);
|
|
70214
70587
|
}
|
|
@@ -70463,7 +70836,7 @@ var HOSTS2, upgradePaths = (deps) => {
|
|
|
70463
70836
|
if (!data || typeof data !== "object" || Array.isArray(data))
|
|
70464
70837
|
throw new Error(`${file} is not a configuration object`);
|
|
70465
70838
|
return data;
|
|
70466
|
-
}, digest2 = (file) => existsSync17(file) ?
|
|
70839
|
+
}, digest2 = (file) => existsSync17(file) ? createHash14("sha256").update(readFileSync17(file)).digest("hex") : "missing", runner = (deps) => deps.run ?? ((command, args) => {
|
|
70467
70840
|
const { home, env } = upgradePaths(deps);
|
|
70468
70841
|
let step;
|
|
70469
70842
|
try {
|
|
@@ -70949,7 +71322,12 @@ async function run5(argv, io) {
|
|
|
70949
71322
|
}
|
|
70950
71323
|
fixLock = clearStaleMetadataLock(root, { force });
|
|
70951
71324
|
}
|
|
70952
|
-
const report = runDoctor({
|
|
71325
|
+
const report = runDoctor({
|
|
71326
|
+
host: "cli",
|
|
71327
|
+
cwd: io.cwd,
|
|
71328
|
+
workspaceRoot: root,
|
|
71329
|
+
cliVersion: package_default.version
|
|
71330
|
+
});
|
|
70953
71331
|
let knowledge = null;
|
|
70954
71332
|
try {
|
|
70955
71333
|
knowledge = lintKnowledge(root);
|
|
@@ -70982,7 +71360,9 @@ async function run5(argv, io) {
|
|
|
70982
71360
|
io.stdout(`${mark} ${check.id} — ${check.detail}
|
|
70983
71361
|
`);
|
|
70984
71362
|
if (check.fix)
|
|
70985
|
-
io.stdout(` fix: ${check.fix
|
|
71363
|
+
io.stdout(` fix: ${check.fix.replaceAll(`
|
|
71364
|
+
`, `
|
|
71365
|
+
`)}
|
|
70986
71366
|
`);
|
|
70987
71367
|
}
|
|
70988
71368
|
io.stdout(`${knowledgeLine}
|
|
@@ -70992,6 +71372,7 @@ async function run5(argv, io) {
|
|
|
70992
71372
|
return report.exitCode;
|
|
70993
71373
|
}
|
|
70994
71374
|
var init_doctor2 = __esm(() => {
|
|
71375
|
+
init_package();
|
|
70995
71376
|
init_doctor();
|
|
70996
71377
|
init_knowledge();
|
|
70997
71378
|
init_store_lock();
|
|
@@ -71105,7 +71486,7 @@ var init_redact = __esm(() => {
|
|
|
71105
71486
|
|
|
71106
71487
|
// packages/workit-core/src/checks.ts
|
|
71107
71488
|
import { spawn, spawnSync as spawnSync16 } from "node:child_process";
|
|
71108
|
-
import { createHash as
|
|
71489
|
+
import { createHash as createHash15 } from "node:crypto";
|
|
71109
71490
|
import fs18 from "node:fs";
|
|
71110
71491
|
import os13 from "node:os";
|
|
71111
71492
|
import path37 from "node:path";
|
|
@@ -71439,7 +71820,7 @@ function pruneCheckLogs(storeRoot, options = {}) {
|
|
|
71439
71820
|
}
|
|
71440
71821
|
return report;
|
|
71441
71822
|
}
|
|
71442
|
-
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:${
|
|
71823
|
+
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;
|
|
71443
71824
|
var init_checks3 = __esm(() => {
|
|
71444
71825
|
init_redact();
|
|
71445
71826
|
MAX_LOG_BYTES = 2 * 1024 * 1024;
|
|
@@ -72429,6 +72810,23 @@ function patchEquivalent(cwd, branch, tip) {
|
|
|
72429
72810
|
`).filter(Boolean) : [];
|
|
72430
72811
|
return lines.length > 0 && lines.every((line) => line.startsWith("-"));
|
|
72431
72812
|
}
|
|
72813
|
+
function resolveExpectPrefix(prefix, tips, label) {
|
|
72814
|
+
const known = [...new Set(tips.filter((tip) => typeof tip === "string"))];
|
|
72815
|
+
if (!SHA_PREFIX.test(prefix))
|
|
72816
|
+
return {
|
|
72817
|
+
ok: false,
|
|
72818
|
+
code: "invalid_input",
|
|
72819
|
+
error: "--expect must be a commit sha (full, or an abbreviation of at least 7 hex digits)"
|
|
72820
|
+
};
|
|
72821
|
+
const matches = known.filter((tip) => tip.startsWith(prefix));
|
|
72822
|
+
if (matches.length === 1)
|
|
72823
|
+
return { ok: true, sha: matches[0] };
|
|
72824
|
+
return {
|
|
72825
|
+
ok: false,
|
|
72826
|
+
code: "invalid_input",
|
|
72827
|
+
error: matches.length > 1 ? `--expect ${prefix} is ambiguous for ${label}; choose one of: ${matches.join(", ")}` : `--expect ${prefix} matches no known tip of ${label}${known.length ? `; known: ${known.join(", ")}` : ""}; pass the full sha`
|
|
72828
|
+
};
|
|
72829
|
+
}
|
|
72432
72830
|
function executePush(cwd, plan, input) {
|
|
72433
72831
|
const before = remoteRefTip(cwd, plan.rawUrl, `refs/heads/${plan.branch}`);
|
|
72434
72832
|
if (!before.ok)
|
|
@@ -72439,10 +72837,15 @@ function executePush(cwd, plan, input) {
|
|
|
72439
72837
|
const args = ["push", "--porcelain", "--no-follow-tags", "--recurse-submodules=no"];
|
|
72440
72838
|
if (input.forceWithLease) {
|
|
72441
72839
|
const explicit = input.expect !== undefined && input.expect !== null;
|
|
72442
|
-
|
|
72443
|
-
|
|
72840
|
+
let expectSha = input.expect ?? null;
|
|
72841
|
+
if (explicit && !SHA.test(expectSha)) {
|
|
72842
|
+
const resolved = resolveExpectPrefix(expectSha, [before.sha, recordedRemoteTip(cwd, plan)], `${plan.remote}/${plan.branch}`);
|
|
72843
|
+
if (!resolved.ok)
|
|
72844
|
+
return failure3(resolved.code, resolved.error);
|
|
72845
|
+
expectSha = resolved.sha;
|
|
72846
|
+
}
|
|
72444
72847
|
const integrate = `git fetch ${plan.remote} ${plan.branch} && git rebase ${plan.remote}/${plan.branch} # or merge it; then: workit git push`;
|
|
72445
|
-
const recorded = explicit ?
|
|
72848
|
+
const recorded = explicit ? expectSha : recordedRemoteTip(cwd, plan);
|
|
72446
72849
|
if (recorded === undefined && before.sha !== null)
|
|
72447
72850
|
return failure3("blocked", `lease_unknown: workit has no recorded push of ${plan.branch}, so it cannot tell whose commits ${plan.remote}/${plan.branch} (${before.sha.slice(0, 12)}) holds`, `${integrate} # or, after reviewing that tip: workit git push --force-with-lease --expect <sha you reviewed> (--overwrite-unintegrated only to drop commits you never had)`);
|
|
72448
72851
|
const expected = recorded ?? null;
|
|
@@ -72574,7 +72977,7 @@ ${run.stdout ?? ""}`).split(/\r?\n/u).map((value) => value.trimEnd()).filter((va
|
|
|
72574
72977
|
...lines.slice(-half)
|
|
72575
72978
|
].join(`
|
|
72576
72979
|
`);
|
|
72577
|
-
}, validRefName = (cwd, name) => !name.startsWith("-") && git5(cwd, ["check-ref-format", "--branch", name]).ok, nulList = (text) => text.split("\x00").filter(Boolean), SESSION_SAFE, TRAILER_CONFIG, nothingToCommit = (what) => failure3("failed", `nothing_to_commit: ${what}`, "workit git commit --allow-empty -m '<msg>' # only to record an empty commit on purpose"), SHA;
|
|
72980
|
+
}, validRefName = (cwd, name) => !name.startsWith("-") && git5(cwd, ["check-ref-format", "--branch", name]).ok, nulList = (text) => text.split("\x00").filter(Boolean), SESSION_SAFE, TRAILER_CONFIG, nothingToCommit = (what) => failure3("failed", `nothing_to_commit: ${what}`, "workit git commit --allow-empty -m '<msg>' # only to record an empty commit on purpose"), SHA, SHA_PREFIX;
|
|
72578
72981
|
var init_ops = __esm(() => {
|
|
72579
72982
|
init_branch();
|
|
72580
72983
|
init_commit_flavors();
|
|
@@ -72588,6 +72991,7 @@ var init_ops = __esm(() => {
|
|
|
72588
72991
|
SESSION_SAFE = /^[\w.:@/+-]{1,128}$/u;
|
|
72589
72992
|
TRAILER_CONFIG = ["-c", "trailer.separators=:", "-c", "trailer.where=end"];
|
|
72590
72993
|
SHA = /^[0-9a-f]{40,64}$/u;
|
|
72994
|
+
SHA_PREFIX = /^[0-9a-f]{7,39}$/u;
|
|
72591
72995
|
});
|
|
72592
72996
|
|
|
72593
72997
|
// packages/workit-core/src/forge/reruns.ts
|
|
@@ -73401,7 +73805,7 @@ var init_pr_ops = __esm(() => {
|
|
|
73401
73805
|
|
|
73402
73806
|
// packages/workit-core/src/stack.ts
|
|
73403
73807
|
import { spawnSync as spawnSync19 } from "node:child_process";
|
|
73404
|
-
import { createHash as
|
|
73808
|
+
import { createHash as createHash16, randomBytes as randomBytes3 } from "node:crypto";
|
|
73405
73809
|
import fs20 from "node:fs";
|
|
73406
73810
|
import path41 from "node:path";
|
|
73407
73811
|
function worktreeOf(cwd, branch) {
|
|
@@ -74568,7 +74972,7 @@ var STACK_VERSION = 1, stackFail = (code, error, unblock, data) => ({
|
|
|
74568
74972
|
return dir.ok ? path41.join(dir.data, "worktrees") : null;
|
|
74569
74973
|
}, firstLine = (run) => (`${run.stderr}
|
|
74570
74974
|
${run.stdout}`.split(`
|
|
74571
|
-
`).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()}-${
|
|
74975
|
+
`).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) => {
|
|
74572
74976
|
if (name.length === 0 || name.length > 200)
|
|
74573
74977
|
return false;
|
|
74574
74978
|
for (let index = 0;index < name.length; index += 1) {
|
|
@@ -76894,8 +77298,8 @@ async function push(argv, io) {
|
|
|
76894
77298
|
const expect = flags.values.expect ?? null;
|
|
76895
77299
|
if ((expect !== null || flags.booleans.has("overwrite-unintegrated")) && !flags.booleans.has("force-with-lease"))
|
|
76896
77300
|
return usage3(io, "--expect and --overwrite-unintegrated only apply with --force-with-lease", PUSH_USAGE);
|
|
76897
|
-
if (expect !== null && !/^[0-9a-f]{
|
|
76898
|
-
return usage3(io, "--expect must be a
|
|
77301
|
+
if (expect !== null && !/^[0-9a-f]{7,64}$/u.test(expect))
|
|
77302
|
+
return usage3(io, "--expect must be a commit sha (at least 7 hex digits)", PUSH_USAGE);
|
|
76899
77303
|
const plan = pushPreflight(io.cwd);
|
|
76900
77304
|
if (!plan.ok)
|
|
76901
77305
|
return forgeFail(io, plan);
|
|
@@ -77497,7 +77901,7 @@ var init_stack2 = __esm(() => {
|
|
|
77497
77901
|
|
|
77498
77902
|
// packages/workit-core/src/fanout.ts
|
|
77499
77903
|
import { spawnSync as spawnSync23 } from "node:child_process";
|
|
77500
|
-
import { createHash as
|
|
77904
|
+
import { createHash as createHash17 } from "node:crypto";
|
|
77501
77905
|
import fs23 from "node:fs";
|
|
77502
77906
|
import path45 from "node:path";
|
|
77503
77907
|
function expandBraces(pattern, limit = 64) {
|
|
@@ -77978,7 +78382,7 @@ function sliceHash(slice) {
|
|
|
77978
78382
|
context: _context,
|
|
77979
78383
|
...definition
|
|
77980
78384
|
} = slice;
|
|
77981
|
-
return
|
|
78385
|
+
return createHash17("sha256").update(JSON.stringify(definition)).digest("hex").slice(0, 16);
|
|
77982
78386
|
}
|
|
77983
78387
|
function fanoutsDir(cwd) {
|
|
77984
78388
|
const root = storeRoot(cwd);
|
|
@@ -78683,13 +79087,13 @@ var init_fanout_worktree = __esm(() => {
|
|
|
78683
79087
|
});
|
|
78684
79088
|
|
|
78685
79089
|
// packages/workit-core/src/fanout-brief.ts
|
|
78686
|
-
import { createHash as
|
|
79090
|
+
import { createHash as createHash18 } from "node:crypto";
|
|
78687
79091
|
function workerSession(lead, slice, attempt) {
|
|
78688
79092
|
const tail = attempt === null ? "" : `+try${attempt}`;
|
|
78689
79093
|
const full = `${lead}-w-${slice}${tail}`;
|
|
78690
79094
|
if (full.length <= SESSION_MAX)
|
|
78691
79095
|
return full;
|
|
78692
|
-
const digest =
|
|
79096
|
+
const digest = createHash18("sha256").update(slice).digest("hex").slice(0, 12);
|
|
78693
79097
|
return `${lead.slice(0, SESSION_MAX - 3 - digest.length - tail.length)}-w-${digest}${tail}`;
|
|
78694
79098
|
}
|
|
78695
79099
|
function renderBrief(cwd, plan, input) {
|
|
@@ -95875,7 +96279,7 @@ var init_rules = __esm(() => {
|
|
|
95875
96279
|
|
|
95876
96280
|
// packages/workit-cli/src/test-audit/audit.ts
|
|
95877
96281
|
import { spawnSync as spawnSync25 } from "node:child_process";
|
|
95878
|
-
import { existsSync as existsSync19, readdirSync as
|
|
96282
|
+
import { existsSync as existsSync19, readdirSync as readdirSync9, readFileSync as readFileSync22, statSync as statSync7 } from "node:fs";
|
|
95879
96283
|
import path49 from "node:path";
|
|
95880
96284
|
function git7(cwd, args) {
|
|
95881
96285
|
const run = spawnSync25("git", ["-c", "core.quotepath=off", ...args], {
|
|
@@ -95886,7 +96290,7 @@ function git7(cwd, args) {
|
|
|
95886
96290
|
return { ok: run.status === 0, stdout: run.stdout ?? "" };
|
|
95887
96291
|
}
|
|
95888
96292
|
function walkTests(dir, out) {
|
|
95889
|
-
for (const entry of
|
|
96293
|
+
for (const entry of readdirSync9(dir, { withFileTypes: true })) {
|
|
95890
96294
|
if (entry.name.startsWith(".") && entry.name !== "." && entry.isDirectory())
|
|
95891
96295
|
continue;
|
|
95892
96296
|
const full = path49.join(dir, entry.name);
|
|
@@ -96022,7 +96426,7 @@ import {
|
|
|
96022
96426
|
lstatSync as lstatSync7,
|
|
96023
96427
|
mkdirSync as mkdirSync9,
|
|
96024
96428
|
mkdtempSync as mkdtempSync4,
|
|
96025
|
-
readdirSync as
|
|
96429
|
+
readdirSync as readdirSync10,
|
|
96026
96430
|
readFileSync as readFileSync23,
|
|
96027
96431
|
readlinkSync as readlinkSync3,
|
|
96028
96432
|
realpathSync as realpathSync9,
|
|
@@ -96119,7 +96523,7 @@ function removeStaleCopies(tmp = os14.tmpdir()) {
|
|
|
96119
96523
|
let removed = 0;
|
|
96120
96524
|
let names = [];
|
|
96121
96525
|
try {
|
|
96122
|
-
names =
|
|
96526
|
+
names = readdirSync10(tmp);
|
|
96123
96527
|
} catch {
|
|
96124
96528
|
return 0;
|
|
96125
96529
|
}
|
|
@@ -96148,7 +96552,7 @@ function removeStaleCopies(tmp = os14.tmpdir()) {
|
|
|
96148
96552
|
}
|
|
96149
96553
|
function linkNodeModules(origin, target, repo, copy) {
|
|
96150
96554
|
mkdirSync9(target, { recursive: true });
|
|
96151
|
-
for (const entry of
|
|
96555
|
+
for (const entry of readdirSync10(origin, { withFileTypes: true })) {
|
|
96152
96556
|
const from = path50.join(origin, entry.name);
|
|
96153
96557
|
const to = path50.join(target, entry.name);
|
|
96154
96558
|
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.7.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.7.0",
|
|
42
|
+
"@brainervirus/workit-cursor": "^8.7.0",
|
|
43
|
+
"@brainervirus/workit-opencode": "^8.7.0",
|
|
44
44
|
"@inkjs/ui": "2.0.0",
|
|
45
45
|
"ink": "7.1.1",
|
|
46
46
|
"react": "19.2.8"
|