holycodex 0.7.0-dev.29549405174.1 → 0.7.0-dev.29579145024.1
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/cli.js +101 -48
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -7,7 +7,7 @@ import { existsSync } from "node:fs";
|
|
|
7
7
|
import { pluginRoot } from "@holycodex/plugin";
|
|
8
8
|
import { Buffer } from "node:buffer";
|
|
9
9
|
//#region packages/cli/src/catalog.ts
|
|
10
|
-
var VERSION = "0.7.0-dev.
|
|
10
|
+
var VERSION = "0.7.0-dev.29579145024.1";
|
|
11
11
|
var SKILLS = [
|
|
12
12
|
"ast-grep",
|
|
13
13
|
"caveman",
|
|
@@ -97,7 +97,7 @@ function effectiveMcpServers(platform) {
|
|
|
97
97
|
};
|
|
98
98
|
}
|
|
99
99
|
function requiredPackageRuntimes(platform) {
|
|
100
|
-
return platform === "win32" ? GENERATED_RUNTIMES : GENERATED_RUNTIMES.filter((file) => file !== "git-bash.js"
|
|
100
|
+
return platform === "win32" ? GENERATED_RUNTIMES : GENERATED_RUNTIMES.filter((file) => file !== "git-bash.js");
|
|
101
101
|
}
|
|
102
102
|
//#endregion
|
|
103
103
|
//#region packages/git-bash-mcp/src/git-bash-resolver.ts
|
|
@@ -301,6 +301,72 @@ function outputText(state) {
|
|
|
301
301
|
return state.truncated ? `${state.head}${TRUNCATED_MARKER}${state.tail}` : state.head;
|
|
302
302
|
}
|
|
303
303
|
//#endregion
|
|
304
|
+
//#region packages/cli/src/toml.ts
|
|
305
|
+
var TOML_TABLE = /^[ \t]*(?:\[[^\]\r\n]+\]|\[\[[^\]\r\n]+\]\])[ \t]*(?:#.*)?$/m;
|
|
306
|
+
function rootTomlString(input, key) {
|
|
307
|
+
const table = TOML_TABLE.exec(input);
|
|
308
|
+
const root = table === null ? input : input.slice(0, table.index);
|
|
309
|
+
const match = new RegExp(String.raw`^[ \t]*${escapeRegExp(key)}[ \t]*=[ \t]*(?:"((?:\\.|[^"\\\r\n])*)"|'([^'\r\n]*)')[ \t]*(?:#.*)?$`, "m").exec(root);
|
|
310
|
+
if (match === null) return void 0;
|
|
311
|
+
if (match[2] !== void 0) return match[2];
|
|
312
|
+
try {
|
|
313
|
+
const parsed = JSON.parse(`"${match[1] ?? ""}"`);
|
|
314
|
+
return typeof parsed === "string" ? parsed : void 0;
|
|
315
|
+
} catch {
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
function rootTomlStringArray(input, key) {
|
|
320
|
+
const table = TOML_TABLE.exec(input);
|
|
321
|
+
const root = table === null ? input : input.slice(0, table.index);
|
|
322
|
+
const assignment = new RegExp(String.raw`^[ \t]*${escapeRegExp(key)}[ \t]*=`, "m").exec(root);
|
|
323
|
+
if (assignment === null) return void 0;
|
|
324
|
+
const start = root.indexOf("[", assignment.index + assignment[0].length);
|
|
325
|
+
if (start < 0) return void 0;
|
|
326
|
+
const items = [];
|
|
327
|
+
let quote;
|
|
328
|
+
let raw = "";
|
|
329
|
+
let escaped = false;
|
|
330
|
+
let comment = false;
|
|
331
|
+
for (let index = start + 1; index < root.length; index += 1) {
|
|
332
|
+
const character = root[index];
|
|
333
|
+
if (comment) {
|
|
334
|
+
if (character === "\n") comment = false;
|
|
335
|
+
continue;
|
|
336
|
+
}
|
|
337
|
+
if (quote === "\"") {
|
|
338
|
+
if (escaped) {
|
|
339
|
+
raw += character;
|
|
340
|
+
escaped = false;
|
|
341
|
+
} else if (character === "\\") {
|
|
342
|
+
raw += character;
|
|
343
|
+
escaped = true;
|
|
344
|
+
} else if (character === "\"") {
|
|
345
|
+
const parsed = JSON.parse(`"${raw}"`);
|
|
346
|
+
if (typeof parsed !== "string") return void 0;
|
|
347
|
+
items.push(parsed);
|
|
348
|
+
quote = void 0;
|
|
349
|
+
raw = "";
|
|
350
|
+
} else raw += character;
|
|
351
|
+
continue;
|
|
352
|
+
}
|
|
353
|
+
if (quote === "'") {
|
|
354
|
+
if (character === "'") {
|
|
355
|
+
items.push(raw);
|
|
356
|
+
quote = void 0;
|
|
357
|
+
raw = "";
|
|
358
|
+
} else raw += character;
|
|
359
|
+
continue;
|
|
360
|
+
}
|
|
361
|
+
if (character === "#") comment = true;
|
|
362
|
+
else if (character === "\"" || character === "'") quote = character;
|
|
363
|
+
else if (character === "]") return items;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
function escapeRegExp(value) {
|
|
367
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
368
|
+
}
|
|
369
|
+
//#endregion
|
|
304
370
|
//#region packages/cli/src/doctor.ts
|
|
305
371
|
async function runCommand(name, args, platform) {
|
|
306
372
|
const result = await runManagedProcess({
|
|
@@ -339,7 +405,8 @@ async function startContext7(platform) {
|
|
|
339
405
|
});
|
|
340
406
|
const diagnostic = `${result.stdout}\n${result.stderr}`.trim() || result.error || "";
|
|
341
407
|
return {
|
|
342
|
-
ok: result.matched,
|
|
408
|
+
ok: result.matched && !result.timedOut,
|
|
409
|
+
timedOut: result.timedOut,
|
|
343
410
|
packageFailure: /(?:404|failed to resolve|package.*not found|error: GET)/i.test(diagnostic),
|
|
344
411
|
detail: diagnostic
|
|
345
412
|
};
|
|
@@ -359,6 +426,14 @@ function check(id, status, code, detail, fix) {
|
|
|
359
426
|
...fix === void 0 ? {} : { fix }
|
|
360
427
|
};
|
|
361
428
|
}
|
|
429
|
+
function mcpConfigMatches(actual, expected) {
|
|
430
|
+
const expectedEntries = Object.entries(expected);
|
|
431
|
+
if (Object.keys(actual).length !== expectedEntries.length) return false;
|
|
432
|
+
return expectedEntries.every(([key, expectedValue]) => {
|
|
433
|
+
const actualValue = actual[key];
|
|
434
|
+
return Array.isArray(expectedValue) ? Array.isArray(actualValue) && actualValue.length === expectedValue.length && actualValue.every((value, index) => value === expectedValue[index]) : actualValue === expectedValue;
|
|
435
|
+
});
|
|
436
|
+
}
|
|
362
437
|
async function missingFiles(root, paths) {
|
|
363
438
|
const missing = [];
|
|
364
439
|
for (const path of paths) try {
|
|
@@ -368,17 +443,14 @@ async function missingFiles(root, paths) {
|
|
|
368
443
|
}
|
|
369
444
|
return missing;
|
|
370
445
|
}
|
|
371
|
-
function rootString(config, key) {
|
|
372
|
-
return new RegExp(`^\\s*${key}\\s*=\\s*"([^"]+)"`, "m").exec(config)?.[1];
|
|
373
|
-
}
|
|
374
446
|
function tableBoolean(config, table, key) {
|
|
375
447
|
const body = new RegExp(`^\\s*\\[${table.replaceAll(".", "\\.")}]\\s*$([\\s\\S]*?)(?=^\\s*\\[|(?![\\s\\S]))`, "m").exec(config)?.[1];
|
|
376
448
|
const value = body === void 0 ? void 0 : new RegExp(`^\\s*${key}\\s*=\\s*(true|false)`, "m").exec(body)?.[1];
|
|
377
449
|
return value === void 0 ? void 0 : value === "true";
|
|
378
450
|
}
|
|
379
451
|
function autonomy(config) {
|
|
380
|
-
const approval =
|
|
381
|
-
const sandbox =
|
|
452
|
+
const approval = rootTomlString(config, "approval_policy");
|
|
453
|
+
const sandbox = rootTomlString(config, "sandbox_mode");
|
|
382
454
|
const network = tableBoolean(config, "sandbox_workspace_write", "network_access");
|
|
383
455
|
if (approval === "on-request" && sandbox === "workspace-write" && network === true) return "safe-workspace";
|
|
384
456
|
if (approval === "never" && sandbox === "workspace-write" && network === true) return "autonomous-workspace";
|
|
@@ -408,11 +480,16 @@ async function doctor(home = process.env.CODEX_HOME ?? join(homedir(), ".codex")
|
|
|
408
480
|
}
|
|
409
481
|
const servers = mcp?.mcpServers;
|
|
410
482
|
const requiredMcps = runtime.platform === "win32" ? ["git_bash", "lsp"] : ["lsp"];
|
|
411
|
-
|
|
483
|
+
const expectedMcps = effectiveMcpServers(runtime.platform);
|
|
484
|
+
for (const name of requiredMcps) {
|
|
485
|
+
const configured = servers?.[name];
|
|
486
|
+
const expected = expectedMcps[name];
|
|
487
|
+
checks.push(configured === void 0 ? check(`mcp-${name}`, "error", "missing-required-mcp", `${name} is not configured.`, "Reinstall HolyCodex.") : !mcpConfigMatches(configured, expected) ? check(`mcp-${name}`, "error", "invalid-required-mcp-config", `${name} configuration is stale or contains unsupported settings.`, "Reinstall HolyCodex.") : check(`mcp-${name}`, "ok", "required-mcp-ready", `${name} is configured locally.`));
|
|
488
|
+
}
|
|
412
489
|
const gitBashConfig = servers?.git_bash;
|
|
413
490
|
if (runtime.platform === "win32" && gitBashConfig !== void 0) {
|
|
414
491
|
const expected = effectiveMcpServers("win32").git_bash;
|
|
415
|
-
checks.push(
|
|
492
|
+
checks.push(mcpConfigMatches(gitBashConfig, expected) ? check("mcp-git_bash-config", "ok", "git-bash-mcp-config-ready", "Git Bash MCP exposes only run through the supported allowlist.") : check("mcp-git_bash-config", "error", "invalid-git-bash-mcp-config", "Git Bash MCP command or enabled_tools configuration is stale.", "Reinstall HolyCodex."));
|
|
416
493
|
} else if (runtime.platform !== "win32" && gitBashConfig !== void 0) checks.push(check("mcp-git_bash-config", "error", "unexpected-git-bash-mcp", "Git Bash MCP must not be installed on non-Windows platforms.", "Reinstall HolyCodex for this platform."));
|
|
417
494
|
const context7 = servers?.context7;
|
|
418
495
|
const obsoleteAuth = context7 !== void 0 && [
|
|
@@ -432,7 +509,7 @@ async function doctor(home = process.env.CODEX_HOME ?? join(homedir(), ".codex")
|
|
|
432
509
|
checks.push(bunx.ok ? check("bunx", "ok", "bunx-ready", `bunx ${bunx.output || "available"}.`) : check("bunx", "error", "missing-bunx", "bunx is unavailable.", "Repair the Bun installation."));
|
|
433
510
|
if (bun.ok && bunx.ok && checks.some((item) => item.code === "local-context7-config")) {
|
|
434
511
|
const started = await runtime.context7();
|
|
435
|
-
checks.push(started.ok ? check("context7-startup", "ok", "context7-healthy", "Context7 completed a bounded MCP handshake.") : started.packageFailure ? check("context7-startup", "error", "context7-package-resolution-failed", started.detail || "Context7 package resolution failed.", "Check network/package availability.") : check("context7-startup", "error", "context7-startup-failed", started.detail || "Context7 did not complete an MCP handshake within 15 seconds.", runtime.platform === "win32" ? "Run bunx @upstash/context7-mcp in Git Bash." : "Run bunx @upstash/context7-mcp in the native shell."));
|
|
512
|
+
checks.push(started.ok && !started.timedOut ? check("context7-startup", "ok", "context7-healthy", "Context7 completed a bounded MCP handshake.") : started.packageFailure ? check("context7-startup", "error", "context7-package-resolution-failed", started.detail || "Context7 package resolution failed.", "Check network/package availability.") : check("context7-startup", "error", "context7-startup-failed", started.detail || "Context7 did not complete an MCP handshake within 15 seconds.", runtime.platform === "win32" ? "Run bunx @upstash/context7-mcp in Git Bash." : "Run bunx @upstash/context7-mcp in the native shell."));
|
|
436
513
|
}
|
|
437
514
|
if (runtime.platform === "win32") {
|
|
438
515
|
const gitBash = runtime.gitBash();
|
|
@@ -447,14 +524,14 @@ async function doctor(home = process.env.CODEX_HOME ?? join(homedir(), ".codex")
|
|
|
447
524
|
const mode = autonomy(config);
|
|
448
525
|
checks.push(mode === "unknown" ? check("autonomy", "error", "invalid-autonomy-config", "Approval, sandbox, and network settings do not match a supported mode.", "Rerun install with the intended autonomy flag.") : mode === "dangerous" ? check("autonomy", "warning", "dangerous-autonomy", "Explicit dangerous autonomy is active; workspace containment is removed.") : check("autonomy", "ok", `${mode}-ready`, mode === "safe-workspace" ? "Safe workspace autonomy is active." : "Approval-free workspace autonomy is active."));
|
|
449
526
|
checks.push(tableBoolean(config, "features", "default_mode_request_user_input") === true ? check("user-input", "ok", "user-input-ready", "default_mode_request_user_input is enabled.") : check("user-input", "error", "user-input-disabled", "default_mode_request_user_input is not enabled.", "Rerun holycodex install."));
|
|
450
|
-
checks.push(
|
|
527
|
+
checks.push(rootTomlStringArray(config, "status_line")?.includes("context-remaining") === true ? check("context-visibility", "warning", "context-visible-support-unverified", "status_line includes context-remaining. Current official Codex config documents this item, but publishes no minimum compatible Codex version.") : check("context-visibility", "error", "context-hidden", "status_line does not include context-remaining.", "Rerun holycodex install."));
|
|
451
528
|
const codex = await runtime.command("codex", ["--version"]);
|
|
452
529
|
checks.push(codex.ok ? check("codex", "ok", "codex-version", codex.output || "Codex is available.") : check("codex", "warning", "codex-version-unavailable", "Codex version could not be read; status-line compatibility cannot be independently confirmed."));
|
|
453
530
|
const agentModelFailures = [];
|
|
454
531
|
for (const agent of AGENTS) try {
|
|
455
532
|
const text = await readFile(join(agentRoot, `${agent}.toml`), "utf8");
|
|
456
533
|
const expected = AGENT_MODELS[agent];
|
|
457
|
-
if (
|
|
534
|
+
if (rootTomlString(text, "model") !== expected.model || rootTomlString(text, "model_reasoning_effort") !== expected.reasoningEffort) agentModelFailures.push(agent);
|
|
458
535
|
} catch {
|
|
459
536
|
agentModelFailures.push(agent);
|
|
460
537
|
}
|
|
@@ -564,37 +641,10 @@ function preserveManagedRootPreferences(input, base) {
|
|
|
564
641
|
}
|
|
565
642
|
function mergedStatusLine(original) {
|
|
566
643
|
if (original === void 0) return "[\"model-with-reasoning\", \"context-remaining\", \"current-dir\"]";
|
|
567
|
-
const items =
|
|
568
|
-
if (match[1] === void 0) return match[2] ?? "";
|
|
569
|
-
const parsed = JSON.parse(`"${match[1]}"`);
|
|
570
|
-
if (typeof parsed !== "string") throw new Error("Invalid status-line string");
|
|
571
|
-
return parsed;
|
|
572
|
-
});
|
|
644
|
+
const items = rootTomlStringArray(original, "status_line") ?? [];
|
|
573
645
|
if (!items.includes("context-remaining")) items.push("context-remaining");
|
|
574
646
|
return `[${items.map((item) => JSON.stringify(item)).join(", ")}]`;
|
|
575
647
|
}
|
|
576
|
-
function tomlArrayValue(input) {
|
|
577
|
-
const start = input.indexOf("[");
|
|
578
|
-
if (start < 0) return input;
|
|
579
|
-
let quote;
|
|
580
|
-
let escaped = false;
|
|
581
|
-
for (let index = start + 1; index < input.length; index += 1) {
|
|
582
|
-
const character = input[index];
|
|
583
|
-
if (quote === "\"") {
|
|
584
|
-
if (escaped) escaped = false;
|
|
585
|
-
else if (character === "\\") escaped = true;
|
|
586
|
-
else if (character === "\"") quote = void 0;
|
|
587
|
-
continue;
|
|
588
|
-
}
|
|
589
|
-
if (quote === "'") {
|
|
590
|
-
if (character === "'") quote = void 0;
|
|
591
|
-
continue;
|
|
592
|
-
}
|
|
593
|
-
if (character === "\"" || character === "'") quote = character;
|
|
594
|
-
else if (character === "]") return input.slice(start, index + 1);
|
|
595
|
-
}
|
|
596
|
-
return input.slice(start);
|
|
597
|
-
}
|
|
598
648
|
function installConfig(input, mode, _platform) {
|
|
599
649
|
const base = preserveManagedRootPreferences(input, removeLegacyOmo(removeManaged(input)));
|
|
600
650
|
const firstTable = base.search(/^\s*\[/m);
|
|
@@ -744,8 +794,8 @@ async function readAgentPreferences(root) {
|
|
|
744
794
|
const preferences = {};
|
|
745
795
|
await Promise.all(AGENTS.map(async (agent) => {
|
|
746
796
|
const source = await readText(join(root, `${agent}.toml`));
|
|
747
|
-
const model =
|
|
748
|
-
const reasoningEffort =
|
|
797
|
+
const model = rootTomlString(source, "model");
|
|
798
|
+
const reasoningEffort = rootTomlString(source, "model_reasoning_effort");
|
|
749
799
|
if (model === void 0 && reasoningEffort === void 0) return;
|
|
750
800
|
if (!MANAGED_AGENT_MODEL_HISTORY[agent].some((item) => item.model === model && item.reasoningEffort === reasoningEffort)) preferences[agent] = {
|
|
751
801
|
...model === void 0 ? {} : { model },
|
|
@@ -765,9 +815,6 @@ async function preserveAgentPreferences(root, preferences) {
|
|
|
765
815
|
await atomicWrite(path, source);
|
|
766
816
|
}));
|
|
767
817
|
}
|
|
768
|
-
function tomlString(input, key) {
|
|
769
|
-
return new RegExp(`^${key}\\s*=\\s*"([^"]+)"`, "m").exec(input)?.[1];
|
|
770
|
-
}
|
|
771
818
|
function replaceTomlString(input, key, value) {
|
|
772
819
|
return input.replace(new RegExp(`^${key}\\s*=.*$`, "m"), `${key} = ${JSON.stringify(value)}`);
|
|
773
820
|
}
|
|
@@ -779,7 +826,7 @@ async function writePlatformAgents(root, platform) {
|
|
|
779
826
|
if (platform === "win32") return;
|
|
780
827
|
await Promise.all(AGENTS.map(async (agent) => {
|
|
781
828
|
const path = join(root, `${agent}.toml`);
|
|
782
|
-
await atomicWrite(path, (await readText(path)).replace(`${WINDOWS_SHELL_POLICY}\n\n`, ""));
|
|
829
|
+
await atomicWrite(path, (await readText(path)).replace(`${WINDOWS_SHELL_POLICY}\r\n\r\n`, "").replace(`${WINDOWS_SHELL_POLICY}\n\n`, ""));
|
|
783
830
|
}));
|
|
784
831
|
}
|
|
785
832
|
async function cleanup(_options) {
|
|
@@ -899,5 +946,11 @@ async function main() {
|
|
|
899
946
|
}
|
|
900
947
|
process$1.stdout.write(options.json ? `${JSON.stringify(result)}\n` : renderRunResult(result, stdoutColor));
|
|
901
948
|
}
|
|
902
|
-
|
|
949
|
+
try {
|
|
950
|
+
await main();
|
|
951
|
+
} catch (error) {
|
|
952
|
+
const stderrColor = supportsColor(process$1.stderr.isTTY, process$1.env.NO_COLOR);
|
|
953
|
+
process$1.stderr.write(renderError(error instanceof Error ? error.message : String(error), stderrColor));
|
|
954
|
+
process$1.exitCode = 1;
|
|
955
|
+
}
|
|
903
956
|
//#endregion
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "holycodex",
|
|
3
|
-
"version": "0.7.0-dev.
|
|
3
|
+
"version": "0.7.0-dev.29579145024.1",
|
|
4
4
|
"description": "Lean Codex-only agent toolkit installer and doctor",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agents",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"prepack": "vp run --workspace-root build"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@holycodex/plugin": "0.7.0-dev.
|
|
42
|
+
"@holycodex/plugin": "0.7.0-dev.29579145024.1"
|
|
43
43
|
},
|
|
44
44
|
"engines": {
|
|
45
45
|
"node": ">=20"
|