@brainervirus/workit-cli 0.8.6 → 0.8.8
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 +179 -24
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -43026,16 +43026,22 @@ function mergeCursorMcp(mcp, serverName, server) {
|
|
|
43026
43026
|
base2.mcpServers = servers;
|
|
43027
43027
|
return { config: base2, changed };
|
|
43028
43028
|
}
|
|
43029
|
-
var CURSOR_RUNTIME_PACKAGE = "@brainervirus/workit-cursor@
|
|
43029
|
+
var CURSOR_RUNTIME_PACKAGE = "@brainervirus/workit-cursor@latest";
|
|
43030
43030
|
function cursorMcpServerEntry(_packageDir) {
|
|
43031
43031
|
return {
|
|
43032
43032
|
command: "npx",
|
|
43033
|
-
args: [
|
|
43033
|
+
args: [
|
|
43034
|
+
"-y",
|
|
43035
|
+
"--prefer-online",
|
|
43036
|
+
`--package=${CURSOR_RUNTIME_PACKAGE}`,
|
|
43037
|
+
"workit-cursor-mcp",
|
|
43038
|
+
"${workspaceFolder}"
|
|
43039
|
+
]
|
|
43034
43040
|
};
|
|
43035
43041
|
}
|
|
43036
43042
|
function cursorHooksEntry(_packageDir) {
|
|
43037
43043
|
return {
|
|
43038
|
-
command: `npx -y --package=${CURSOR_RUNTIME_PACKAGE} workit-cursor-session-start`,
|
|
43044
|
+
command: `npx -y --prefer-online --package=${CURSOR_RUNTIME_PACKAGE} workit-cursor-session-start`,
|
|
43039
43045
|
args: []
|
|
43040
43046
|
};
|
|
43041
43047
|
}
|
|
@@ -43405,12 +43411,9 @@ var registeredCursorLauncher = (res) => {
|
|
|
43405
43411
|
return "invalid";
|
|
43406
43412
|
}
|
|
43407
43413
|
const executable = path9.basename(command).toLowerCase();
|
|
43414
|
+
const canonical = cursorMcpServerEntry("").args;
|
|
43408
43415
|
if (executable === "npx" || executable === "npx.exe" || executable === "npx.cmd") {
|
|
43409
|
-
if (args
|
|
43410
|
-
return "invalid";
|
|
43411
|
-
if (args[1] !== `--package=${CURSOR_RUNTIME_PACKAGE}`)
|
|
43412
|
-
return "invalid";
|
|
43413
|
-
if (args[2] !== "workit-cursor-mcp")
|
|
43416
|
+
if (args.length !== canonical.length || args.some((a, i) => a !== canonical[i]))
|
|
43414
43417
|
return "invalid";
|
|
43415
43418
|
return { kind: "npx" };
|
|
43416
43419
|
}
|
|
@@ -43487,7 +43490,11 @@ var checkLauncher = (res) => {
|
|
|
43487
43490
|
detail: "no dev checkout found (WORKFLOW_TOOLKIT_DEV) — skipping non-Cursor launcher checks"
|
|
43488
43491
|
};
|
|
43489
43492
|
}
|
|
43490
|
-
return {
|
|
43493
|
+
return {
|
|
43494
|
+
id: "launcher",
|
|
43495
|
+
status: "pass",
|
|
43496
|
+
detail: `${res.host} launcher/hook entries present`
|
|
43497
|
+
};
|
|
43491
43498
|
};
|
|
43492
43499
|
var checkUtility = (res) => {
|
|
43493
43500
|
const git = commandOnPath("git", res.env);
|
|
@@ -43507,7 +43514,11 @@ var checkUtility = (res) => {
|
|
|
43507
43514
|
fix: "Install util-linux (flock)"
|
|
43508
43515
|
};
|
|
43509
43516
|
}
|
|
43510
|
-
return {
|
|
43517
|
+
return {
|
|
43518
|
+
id: "utility",
|
|
43519
|
+
status: "pass",
|
|
43520
|
+
detail: "git (and flock where required) on PATH"
|
|
43521
|
+
};
|
|
43511
43522
|
};
|
|
43512
43523
|
var staleEntry = (entry) => {
|
|
43513
43524
|
if (!entry)
|
|
@@ -43529,7 +43540,11 @@ var checkStalePin = (res) => {
|
|
|
43529
43540
|
};
|
|
43530
43541
|
}
|
|
43531
43542
|
if (!existsSync7(res.opencodeConfig)) {
|
|
43532
|
-
return {
|
|
43543
|
+
return {
|
|
43544
|
+
id: "stale_pin",
|
|
43545
|
+
status: "pass",
|
|
43546
|
+
detail: "no opencode config — not registered"
|
|
43547
|
+
};
|
|
43533
43548
|
}
|
|
43534
43549
|
const cfg = readJson(res.opencodeConfig);
|
|
43535
43550
|
const entries = pluginEntries(cfg);
|
|
@@ -43560,6 +43575,118 @@ var checkStalePin = (res) => {
|
|
|
43560
43575
|
}
|
|
43561
43576
|
return { id: "stale_pin", status: "pass", detail: "opencode pin resolves" };
|
|
43562
43577
|
};
|
|
43578
|
+
var pluginMcpSelectors = (res) => {
|
|
43579
|
+
const p = path9.join(res.cursorPluginDir, "mcp.json");
|
|
43580
|
+
if (!existsSync7(p))
|
|
43581
|
+
return null;
|
|
43582
|
+
const cfg = readJson(p);
|
|
43583
|
+
const server = cfg?.mcpServers?.workit;
|
|
43584
|
+
if (!server || typeof server !== "object" || Array.isArray(server))
|
|
43585
|
+
return null;
|
|
43586
|
+
const args = server.args;
|
|
43587
|
+
if (!Array.isArray(args))
|
|
43588
|
+
return null;
|
|
43589
|
+
return args.map(String).filter((a) => a.startsWith("--package="));
|
|
43590
|
+
};
|
|
43591
|
+
var registryLatestVersion = (res) => {
|
|
43592
|
+
const seam = res.env.WORKIT_DOCTOR_STALE_REGISTRY_VERSION;
|
|
43593
|
+
if (typeof seam === "string" && seam) {
|
|
43594
|
+
return /^\d+(?:\.\d+){1,2}$/.test(seam) ? seam : null;
|
|
43595
|
+
}
|
|
43596
|
+
const cmd = res.env.WORKIT_DOCTOR_STALE_REGISTRY_CMD ?? (commandOnPath("npm", res.env) ? "npm" : null);
|
|
43597
|
+
if (!cmd)
|
|
43598
|
+
return null;
|
|
43599
|
+
try {
|
|
43600
|
+
const r = spawnSync2(cmd, ["view", CURSOR_RUNTIME_PACKAGE, "version"], {
|
|
43601
|
+
encoding: "utf8",
|
|
43602
|
+
timeout: 20000,
|
|
43603
|
+
env: res.env
|
|
43604
|
+
});
|
|
43605
|
+
const v = (r.stdout ?? "").trim().split(/\s+/)[0];
|
|
43606
|
+
return r.status === 0 && /^\d+(?:\.\d+){1,2}$/.test(v) ? v : null;
|
|
43607
|
+
} catch {
|
|
43608
|
+
return null;
|
|
43609
|
+
}
|
|
43610
|
+
};
|
|
43611
|
+
var installedPluginVersion = (res) => {
|
|
43612
|
+
const pkg = readJson(path9.join(res.cursorPluginDir, "package.json"));
|
|
43613
|
+
return typeof pkg?.version === "string" && pkg.version ? pkg.version : null;
|
|
43614
|
+
};
|
|
43615
|
+
var checkStaleInstall = (res) => {
|
|
43616
|
+
if (res.host !== "cursor" && res.host !== "cli") {
|
|
43617
|
+
return {
|
|
43618
|
+
id: "stale_install",
|
|
43619
|
+
status: "pass",
|
|
43620
|
+
detail: "cursor plugin not inspected on the opencode host"
|
|
43621
|
+
};
|
|
43622
|
+
}
|
|
43623
|
+
const canonicalMcp = cursorMcpServerEntry("").args.find((a) => a.startsWith("--package="));
|
|
43624
|
+
const mcpSelectors = pluginMcpSelectors(res);
|
|
43625
|
+
const legacyPin = (mcpSelectors ?? []).find((s) => s !== canonicalMcp && s.includes("@brainervirus/workit-cursor@"));
|
|
43626
|
+
if (legacyPin) {
|
|
43627
|
+
return {
|
|
43628
|
+
id: "stale_install",
|
|
43629
|
+
status: "fail",
|
|
43630
|
+
detail: `stale_install: plugin mcp.json pins a legacy selector ${legacyPin} (canonical: ${canonicalMcp})`,
|
|
43631
|
+
fix: "Re-run install-cursor-plugin.sh — it rewrites the workit MCP entry to the canonical @latest selector"
|
|
43632
|
+
};
|
|
43633
|
+
}
|
|
43634
|
+
const hooksFile = path9.join(res.cursorPluginDir, "hooks", "hooks-cursor.json");
|
|
43635
|
+
const hookCmd = readJson(hooksFile)?.hooks?.sessionStart?.[0]?.command ?? null;
|
|
43636
|
+
const canonicalHook = canonicalCursorHook;
|
|
43637
|
+
const staleHook = hookCmd !== null && hookCmd !== canonicalHook && !hookCmd.startsWith("node ") && hookCmd.includes("@brainervirus/workit-cursor@");
|
|
43638
|
+
if (staleHook) {
|
|
43639
|
+
return {
|
|
43640
|
+
id: "stale_install",
|
|
43641
|
+
status: "fail",
|
|
43642
|
+
detail: `stale_install: sessionStart hook runs a legacy selector (canonical: ${canonicalHook})`,
|
|
43643
|
+
fix: "Re-run install-cursor-plugin.sh — it rewrites the sessionStart hook to the canonical @latest selector"
|
|
43644
|
+
};
|
|
43645
|
+
}
|
|
43646
|
+
const installed = installedPluginVersion(res);
|
|
43647
|
+
const source = res.dev ? readJson(path9.join(res.dev, "packages/workit-cursor/package.json"))?.version ?? null : readJson(path9.join(packageRoot(), "package.json"))?.version ?? null;
|
|
43648
|
+
const localDist = mcpSelectors === null && hookCmd !== null && hookCmd.startsWith("node ");
|
|
43649
|
+
if (localDist && installed !== null && source !== null && !semverAtLeast(installed, source)) {
|
|
43650
|
+
return {
|
|
43651
|
+
id: "stale_install",
|
|
43652
|
+
status: "fail",
|
|
43653
|
+
detail: `stale_install: installed workit-cursor ${installed} is behind the current runtime ${source}`,
|
|
43654
|
+
fix: "Re-run install-cursor-plugin.sh — it refreshes the plugin directory and rewrites the workit MCP/hook entries"
|
|
43655
|
+
};
|
|
43656
|
+
}
|
|
43657
|
+
if (installed !== null && localDist) {
|
|
43658
|
+
const expected = registryLatestVersion(res);
|
|
43659
|
+
if (expected === null) {
|
|
43660
|
+
return {
|
|
43661
|
+
id: "registry_unreachable",
|
|
43662
|
+
status: "warn",
|
|
43663
|
+
registryProbed: true,
|
|
43664
|
+
detail: "registry_unreachable: cannot compare installed workit-cursor against the published runtime",
|
|
43665
|
+
fix: "Retry when the npm registry is reachable, or re-run install-cursor-plugin.sh to refresh the install"
|
|
43666
|
+
};
|
|
43667
|
+
}
|
|
43668
|
+
if (!semverAtLeast(installed, expected)) {
|
|
43669
|
+
return {
|
|
43670
|
+
id: "stale_install",
|
|
43671
|
+
status: "fail",
|
|
43672
|
+
registryProbed: true,
|
|
43673
|
+
detail: `stale_install: local-dist workit-cursor ${installed} is behind the published runtime ${expected}`,
|
|
43674
|
+
fix: "Re-run install-cursor-plugin.sh — it refreshes the plugin directory with the current build"
|
|
43675
|
+
};
|
|
43676
|
+
}
|
|
43677
|
+
return {
|
|
43678
|
+
id: "stale_install",
|
|
43679
|
+
status: "pass",
|
|
43680
|
+
registryProbed: true,
|
|
43681
|
+
detail: `installed local-dist workit-cursor ${installed} matches the published runtime ${expected}`
|
|
43682
|
+
};
|
|
43683
|
+
}
|
|
43684
|
+
return {
|
|
43685
|
+
id: "stale_install",
|
|
43686
|
+
status: "pass",
|
|
43687
|
+
detail: installed === null ? "installed workit-cursor selectors are canonical" : `installed workit-cursor ${installed} is metadata on the canonical @latest install (fresh at launch)`
|
|
43688
|
+
};
|
|
43689
|
+
};
|
|
43563
43690
|
var checkDuplicateRegistration = (res) => {
|
|
43564
43691
|
const problems = [];
|
|
43565
43692
|
const opencodeHost = res.host !== "cursor";
|
|
@@ -43595,7 +43722,11 @@ var checkDuplicateRegistration = (res) => {
|
|
|
43595
43722
|
}
|
|
43596
43723
|
}
|
|
43597
43724
|
if (problems.length === 0) {
|
|
43598
|
-
return {
|
|
43725
|
+
return {
|
|
43726
|
+
id: "duplicate_registration",
|
|
43727
|
+
status: "pass",
|
|
43728
|
+
detail: "no duplicate registrations"
|
|
43729
|
+
};
|
|
43599
43730
|
}
|
|
43600
43731
|
return {
|
|
43601
43732
|
id: "duplicate_registration",
|
|
@@ -43621,7 +43752,11 @@ var checkMalformedConfig = (res) => {
|
|
|
43621
43752
|
files.push(res.cursorMcp);
|
|
43622
43753
|
const bad = files.filter((p) => !parsesAsConfigObject(p));
|
|
43623
43754
|
if (bad.length === 0)
|
|
43624
|
-
return {
|
|
43755
|
+
return {
|
|
43756
|
+
id: "malformed_config",
|
|
43757
|
+
status: "pass",
|
|
43758
|
+
detail: "config files parse"
|
|
43759
|
+
};
|
|
43625
43760
|
return {
|
|
43626
43761
|
id: "malformed_config",
|
|
43627
43762
|
status: "fail",
|
|
@@ -43632,10 +43767,18 @@ var checkMalformedConfig = (res) => {
|
|
|
43632
43767
|
var checkWorkspaceMismatch = (res) => {
|
|
43633
43768
|
const file = path9.join(res.configDir, "workspaces.json");
|
|
43634
43769
|
if (!existsSync7(file))
|
|
43635
|
-
return {
|
|
43770
|
+
return {
|
|
43771
|
+
id: "workspace_mismatch",
|
|
43772
|
+
status: "pass",
|
|
43773
|
+
detail: "no workspaces configured"
|
|
43774
|
+
};
|
|
43636
43775
|
const ws = readJson(file);
|
|
43637
43776
|
if (!Array.isArray(ws?.workspaces)) {
|
|
43638
|
-
return {
|
|
43777
|
+
return {
|
|
43778
|
+
id: "workspace_mismatch",
|
|
43779
|
+
status: "pass",
|
|
43780
|
+
detail: "no workspaces configured"
|
|
43781
|
+
};
|
|
43639
43782
|
}
|
|
43640
43783
|
const match = resolveWorkspaceFrom(res.cwd, res.configDir);
|
|
43641
43784
|
if (match)
|
|
@@ -43677,7 +43820,11 @@ var checkCredentialMetadata = (res) => {
|
|
|
43677
43820
|
}
|
|
43678
43821
|
}
|
|
43679
43822
|
if (tokenPaths.length === 0) {
|
|
43680
|
-
return {
|
|
43823
|
+
return {
|
|
43824
|
+
id: "credential_metadata",
|
|
43825
|
+
status: "pass",
|
|
43826
|
+
detail: "no credentials configured"
|
|
43827
|
+
};
|
|
43681
43828
|
}
|
|
43682
43829
|
const problems = [];
|
|
43683
43830
|
for (const raw of tokenPaths) {
|
|
@@ -43715,7 +43862,11 @@ var checkLogWritable = (res) => {
|
|
|
43715
43862
|
mkdirSync2(logsDir, { recursive: true, mode: 448 });
|
|
43716
43863
|
writeFileSync4(probe, `{"probe":true}
|
|
43717
43864
|
`, { mode: 384 });
|
|
43718
|
-
return {
|
|
43865
|
+
return {
|
|
43866
|
+
id: "log_writable",
|
|
43867
|
+
status: "pass",
|
|
43868
|
+
detail: "log directory writable"
|
|
43869
|
+
};
|
|
43719
43870
|
} catch (err) {
|
|
43720
43871
|
return {
|
|
43721
43872
|
id: "log_writable",
|
|
@@ -43736,6 +43887,7 @@ var RUN_CHECKS = [
|
|
|
43736
43887
|
checkLauncher,
|
|
43737
43888
|
checkUtility,
|
|
43738
43889
|
checkStalePin,
|
|
43890
|
+
checkStaleInstall,
|
|
43739
43891
|
checkDuplicateRegistration,
|
|
43740
43892
|
checkMalformedConfig,
|
|
43741
43893
|
checkWorkspaceMismatch,
|
|
@@ -43748,21 +43900,27 @@ var INSTALLER_REQUIRED = new Set([
|
|
|
43748
43900
|
"launcher",
|
|
43749
43901
|
"utility",
|
|
43750
43902
|
"stale_pin",
|
|
43903
|
+
"stale_install",
|
|
43751
43904
|
"duplicate_registration",
|
|
43752
43905
|
"malformed_config"
|
|
43753
43906
|
]);
|
|
43754
43907
|
var runDoctor = (options = {}) => {
|
|
43755
43908
|
const res = resolve(options);
|
|
43756
43909
|
const raw = RUN_CHECKS.map((fn) => fn(res));
|
|
43757
|
-
const checks = res.installer ? raw.map((c) => c.status === "fail" && !INSTALLER_REQUIRED.has(c.id) ? {
|
|
43910
|
+
const checks = res.installer ? raw.map((c) => c.status === "fail" && !INSTALLER_REQUIRED.has(c.id) ? {
|
|
43911
|
+
...c,
|
|
43912
|
+
status: "warn",
|
|
43913
|
+
detail: `${c.detail} (not enforced by installer)`
|
|
43914
|
+
} : c) : raw;
|
|
43758
43915
|
const failed = checks.filter((c) => c.status === "fail").length;
|
|
43759
43916
|
const warned = checks.filter((c) => c.status === "warn").length;
|
|
43760
43917
|
const passed = checks.filter((c) => c.status === "pass").length;
|
|
43761
43918
|
const exitCode = failed > 0 ? 1 : 0;
|
|
43919
|
+
const offline = !raw.some((c) => ("registryProbed" in c) && c.registryProbed);
|
|
43762
43920
|
const report = {
|
|
43763
43921
|
ok: failed === 0,
|
|
43764
43922
|
exitCode,
|
|
43765
|
-
offline
|
|
43923
|
+
offline,
|
|
43766
43924
|
host: res.host,
|
|
43767
43925
|
checked_at: new Date().toISOString(),
|
|
43768
43926
|
summary: { passed, warned, failed, total: checks.length },
|
|
@@ -43772,7 +43930,7 @@ var runDoctor = (options = {}) => {
|
|
|
43772
43930
|
getDiagnosticLogger()?.info(EVENT.doctor, {
|
|
43773
43931
|
host: res.host,
|
|
43774
43932
|
exit_code: exitCode,
|
|
43775
|
-
offline
|
|
43933
|
+
offline,
|
|
43776
43934
|
failed: checks.filter((c) => c.status === "fail").map((c) => c.id),
|
|
43777
43935
|
total: checks.length
|
|
43778
43936
|
});
|
|
@@ -47504,9 +47662,6 @@ var resetForSpecDrift = (state) => ({
|
|
|
47504
47662
|
var resetForPlanDrift = (state) => ({
|
|
47505
47663
|
...state,
|
|
47506
47664
|
plan: { ...state.plan, status: "draft", evidence: null, approved_digest: null },
|
|
47507
|
-
menu: { presented: false, chosen: "", evidence: null },
|
|
47508
|
-
execution: { status: "pending", mode: null, evidence: null },
|
|
47509
|
-
handoff_destination: false,
|
|
47510
47665
|
updated_at: Date.now()
|
|
47511
47666
|
});
|
|
47512
47667
|
var driftCodeFor = (root, relPath, storedDigest) => {
|
|
@@ -48582,7 +48737,7 @@ function runDoctorCommand(args) {
|
|
|
48582
48737
|
if (args.includes("--json")) {
|
|
48583
48738
|
console.log(JSON.stringify(report, null, 2));
|
|
48584
48739
|
} else {
|
|
48585
|
-
console.log(`workit doctor — ${report.ok ? "healthy" : "problems found"} (offline)`);
|
|
48740
|
+
console.log(`workit doctor — ${report.ok ? "healthy" : "problems found"} (${report.offline ? "offline" : "online"})`);
|
|
48586
48741
|
for (const check2 of report.checks) {
|
|
48587
48742
|
const mark = check2.status === "fail" ? "FAIL" : check2.status === "warn" ? "WARN" : "ok ";
|
|
48588
48743
|
console.log(`${mark} ${check2.id} — ${check2.detail}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@brainervirus/workit-cli",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.8",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Workit interactive setup wizard (Ink TUI)",
|
|
6
6
|
"keywords": [
|
|
@@ -34,9 +34,9 @@
|
|
|
34
34
|
"typecheck": "tsc --noEmit"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@brainervirus/workit-core": "^0.8.
|
|
38
|
-
"@brainervirus/workit-cursor": "^0.8.
|
|
39
|
-
"@brainervirus/workit-opencode": "^0.8.
|
|
37
|
+
"@brainervirus/workit-core": "^0.8.8",
|
|
38
|
+
"@brainervirus/workit-cursor": "^0.8.8",
|
|
39
|
+
"@brainervirus/workit-opencode": "^0.8.8",
|
|
40
40
|
"@inkjs/ui": "2.0.0",
|
|
41
41
|
"ink": "7.1.1",
|
|
42
42
|
"react": "19.2.8"
|