holycodex 0.13.4 → 0.13.5

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.
Files changed (3) hide show
  1. package/README.md +12 -8
  2. package/dist/cli.js +172 -33
  3. package/package.json +7 -4
package/README.md CHANGED
@@ -1,18 +1,22 @@
1
1
  # holycodex
2
2
 
3
- HolyCodex installer and doctor CLI. Plugin prompts, skills, agents, hooks, and runtime assets ship through the exact-version `@holycodex/plugin` dependency.
3
+ `holycodex` is the public installer, doctor, and cleanup CLI for HolyCodex. It installs the exact matching `@holycodex/plugin` payload and makes durable Codex workflows, retained Luna specialists, plan-aware routing, Context7, LSP, and native-Windows Git Bash available to Codex. Product and ownership details live in the repository [README](../../README.md) and [architecture](../../docs/ARCHITECTURE.md).
4
+
5
+ Stable installation:
4
6
 
5
7
  ```sh
6
- bunx holycodex@dev install
7
- bunx holycodex@dev doctor
8
+ bunx holycodex install
9
+ bunx holycodex doctor
8
10
  ```
9
11
 
10
- Use `holycodex --help` for commands, autonomy options, routing plans, and service tiers. `--fast` selects Fast for generated agents, `--fast-all` selects Fast for Root and generated agents, and `--no-fast` or omitting Fast flags selects Standard. Fast uses `2×` API-equivalent usage and changes only the serving tier, not model quality or routing. See the repository's [routing policy](../../docs/ROUTING.md). Stable releases use `bunx holycodex`; development releases use npm's `dev` dist-tag.
12
+ Development installation uses the development dist-tag:
11
13
 
12
- On a fresh installation, omitting autonomy flags seeds Codex Approve for me semantics: `approval_policy = "on-request"`, `approvals_reviewer = "auto_review"`, and `sandbox_mode = "workspace-write"`. On an existing installation, omitting autonomy flags preserves the complete current permission selection. `--no-codex-autonomous`, `--codex-autonomous`, and `--dangerous-codex-autonomous` explicitly replace that selection with their documented modes. HolyCodex never generates `default_permissions` or selects a named permission profile.
14
+ ```sh
15
+ bunx holycodex@dev install
16
+ ```
13
17
 
14
- Install keeps an explicit managed Computer Use choice across upgrades. Use `--computer-use` to install and verify the official `computer-use@openai-bundled` plugin and enable Root-only guidance, or `--no-computer-use` to keep both disabled. Interactive installs ask when no choice is persisted; non-interactive installs require one of these flags. The official `codex-security@openai-curated` plugin remains a separate install attempt. If no global Codex CLI is available, HolyCodex can use the active Bun executable or a supported npm/pnpm package runner. External availability failures are reported with actionable human and JSON results. Cleanup leaves independent official plugins installed. Build Web Apps remains separately managed by Codex.
18
+ Use `holycodex --help` for commands and options. `--plan` selects the catalog plan, `--fast`, `--fast-all`, and `--no-fast` select the service tier, and `--computer-use` or `--no-computer-use` controls the optional official plugin. Standard is the default tier. See [routing policy](../../docs/ROUTING.md) for plan values, quotas, and route ownership.
15
19
 
16
- Human-readable installs show each step as it completes. Use `-v` or `--verbose` for launcher, backup, plan, and plugin-state details; `--json` remains progress-free and machine-readable.
20
+ `doctor` and `cleanup` accept `--json`; install also supports JSON output and concise human progress. Cleanup removes only HolyCodex-managed assets and preserves unrelated Codex configuration and plugins. The CLI does not install MCP servers.
17
21
 
18
- Repository, documentation, license, and security notices: https://github.com/davidbasilefilho/holycodex
22
+ Repository, documentation, license, and security notices: [HolyCodex](https://github.com/davidbasilefilho/holycodex), [security advisories](https://github.com/davidbasilefilho/holycodex/security/advisories/new).
package/dist/cli.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import process$1 from "node:process";
2
- import { access, copyFile, cp, lstat, mkdir, mkdtemp, readFile, readdir, readlink, rename, rm, stat, writeFile } from "node:fs/promises";
2
+ import { access, copyFile, cp, lstat, mkdir, mkdtemp, readFile, readdir, readlink, rename, rm, stat, symlink, writeFile } from "node:fs/promises";
3
3
  import { homedir, tmpdir } from "node:os";
4
4
  import { delimiter, dirname, join, resolve } from "node:path";
5
5
  import { execFileSync, spawn, spawnSync } from "node:child_process";
@@ -4391,7 +4391,7 @@ function superRefine(fn, params) {
4391
4391
  }
4392
4392
  //#endregion
4393
4393
  //#region packages/cli/src/catalog.ts
4394
- var VERSION = "0.13.4";
4394
+ var VERSION = "0.13.5";
4395
4395
  var SKILLS = [
4396
4396
  "ast-grep",
4397
4397
  "babysit-ci",
@@ -6758,7 +6758,9 @@ function formatInstalledRuntimeGuidance(pluginRoot) {
6758
6758
  var CORE_INSTRUCTIONS = "HolyCodex: Root is user-facing. Before updates, classify intent and load required skills. Start with \"I detect [intent] intent — [action].\" Choose the accurate intent naturally; no fixed intent taxonomy applies. `plan` and `plan-review` instead own their exact heading and intent as the first visible block; no other mode prints a heading. Do not conceal orchestration. Give concise updates naming each specialist type and what it will do, such as \"Explorer maps X\", \"Librarian verifies Y\", or \"Worker implements Z\". Do not disclose Root orchestration mechanics or explain why delegation is running unless asked. Skills govern method only. Root owns interaction, intent, scope, architecture, product choices, ambiguity, integration, external state, and final judgment and verification. Root is not another implementation branch: evaluate specialist output against scope, fixed architecture, user decisions, repository conventions, and proof; reject or repair weak output and integrate only accepted work. On every plan other than Go, use a CLI workflow for substantive discovery, implementation, verification, multi-file work, risky changes, or architecture-sensitive work. Root may work directly for genuinely small bounded operations such as repository synchronization, one quick mechanical edit, or an equivalent one-off change. State when the direct-work exception applies, and never use it to bypass delegation for broader work. Never invoke regular Codex collaboration subagents. If a required workflow is unavailable or cannot perform the operation, report the blocker instead of bypassing delegation. Missing task-child visibility is not a reason to avoid workflows. Go does not support workflows, so Root works directly without specialist subagents. A task may contain multiple sequential workflows. Prefer the smallest useful fan-out, stop discovery when evidence is sufficient, and avoid duplicate investigation. The selected plan is authoritative: enforce its permitted model routes for each agent and stage, low verbosity, Fast as the only service-tier variation, concurrency, soft target calls, hard maximum calls, workflow depth, retries, loop iterations, fan-out, projected usage, and soft-size guidance. Root should remain near target calls and exceed them only when intermediate evidence justifies more work; the hard maximum is only a safety and quota ceiling. Larger plans do not automatically consume larger allowances. Keep explorer, librarian, and worker selectable only where the plan permits. Root owns workflow integration and final proof. After any code or manifest implementation, Root loads `code-review` exactly once before final response; it also loads `code-review` for a user-requested snippet, file, directory, diff, patch, or PR review. That skill owns the final audit, repair, proportional checks and reruns, reinspection, diff, and status. Classify unknowns: delegate facts, ask material decisions, and state and use safe reversible defaults. Whenever Root needs user input or would ask any question, it must use `request_user_input` when that tool is available, in every scenario and mode. Root must never stop or reply with a plain-text question when the tool is available. If the tool is unavailable, use a safe reversible default where possible or report a non-question blocker. Never repeat questions or ask discoverable facts. Root must use `request_user_input` immediately before committing, pushing, creating or moving tags, building or compiling, publishing, deploying, destructive or irreversible actions, permission changes, financial actions, sending, or any other externally visible action. Earlier general authorization does not replace this immediate approval unless the user explicitly authorized that exact action in the current turn. Root controls browser and native desktop UI itself. Explorer is repository-read-only, Librarian research-only, and Worker cannot alter dashboards, accounts, permissions, or external state. Specialists never delegate, broaden, review, or make final judgments.";
6759
6759
  var NATIVE_IO_INSTRUCTIONS = "For `plan` and `plan-review` headings, never print provisionally. Never delegate browser or computer control. For frontend creation, redesign, or visual verification, use installed Build Web Apps `frontend-app-builder` for concept, approval, implementation, and visual verification. For authorized security reviews, audits, scans, threat models, vulnerabilities, or attack paths, use matching installed Codex Security plugin skills. Use these capabilities instead of manual-click instructions, shell-as-GUI, or public research as a substitute for authenticated control. Use Codex native `apply_patch` for workspace file creation, updates, moves, and deletion. Use available native read or shell tools for file inspection and repository search. Do not re-read files only to verify a successful `apply_patch` call.";
6760
6760
  var COMPUTER_USE_INSTRUCTIONS = "For native desktop tasks, use the available Computer Use capability.";
6761
- var ROOT_LUNA_POLICY = "Root is the judgment and control plane: own interaction, scope, architecture, product and risk decisions, workflow integration, material ambiguity, external state, and the final decision. Luna specialists are bounded execution context: Explorer maps sufficient repository facts, Librarian verifies assigned current facts, and Worker implements, integrates, inspects diffs, runs checks, performs mechanical repair and retest, routine review, evidence compression, and optional synthesis. Root accepts successful structured Luna evidence without rereading or re-verifying it; material architecture, product, scope, risk, or contradictory-evidence decisions return to Root. On plus-low, prefer retained context, compact outcomes, Luna-local loops and synthesis, sufficient discovery, and genuine concurrency without changing plan quotas. Structured substantive outcomes are the branching contract, not prose parsing. Escalate Luna high to xhigh to max only when the evidence justifies it and the active plan permits the route; max insufficiency returns compact evidence to Root and never creates a Sol specialist.";
6761
+ var ROOT_LUNA_POLICY = "Root is the judgment and control plane: own interaction, scope, architecture, product and risk decisions, workflow integration, material ambiguity, external state, and the final decision. Luna specialists are bounded execution context: Explorer maps sufficient repository facts, Librarian verifies assigned current facts, and Worker implements, integrates, inspects diffs, runs checks, performs mechanical repair and retest, routine review, evidence compression, and optional synthesis. Root accepts successful structured Luna evidence without rereading or re-verifying it; material architecture, product, scope, risk, or contradictory-evidence decisions return to Root. When retained context is valid, prefer it with compact outcomes, Luna-local loops and synthesis, sufficient discovery, and genuine concurrency without changing plan quotas. Structured substantive outcomes are the branching contract, not prose parsing. Escalate Luna high to xhigh to max only when the evidence justifies it and the active plan permits the route; max insufficiency returns compact evidence to Root and never creates a Sol specialist.";
6762
+ var ROOT_DESIGN_GATE_POLICY = "Use a lightweight Root design gate only for architecture-sensitive, substantive, or meaningfully multi-file work; trivial, one-off mechanical, and genuinely small single-file work is excluded. Record the owner and seam, data and control flow, stable interfaces, state and policy location, exclusions, duplication seam, errors and recovery, tests, compatibility, and why the chosen shape is preferred when real alternatives exist. This is a compact constraint gate, not a mandatory extra call or a second plan. Repository-native evidence from source, tests, configuration, commands, diff, and status is authoritative for implementation facts. If repository evidence conflicts with the approved constraint, architecture, scope, or another material decision, escalate to Root rather than resolving it silently.";
6763
+ var WORKER_BRIEF_POLICY = "Root gives Worker a compact constraint/outcome brief containing the objective and outcome, literal scope and exclusions, owner and seam, existing mechanism to extend, data and control flow, stable interfaces, state and policy location, error and recovery obligations, compatibility, tests and exact repository-native proof, plus stop and escalation conditions. Worker follows that brief, does not rediscover architecture or make material choices, and returns the standard structured outcome. Worker may perform one warranted bounded diff-level taste/simplification pass for clarity, naming, duplication, or avoidable complexity in changed files only; it must preserve behavior, interfaces, ownership, and scope and then stop. Worker routine review and repair stay within that seam; Root retains final judgment for material architecture, product, scope, risk, and contradictory evidence.";
6762
6764
  var CODE_REVIEW_ACTIVATION_POLICY = "After loading `code-review`, its first visible line is **CODE REVIEW MODE ACTIVATED**.";
6763
6765
  /** Gets core instructions with platform and active agent-capacity context. */
6764
6766
  function coreInstructions(platform, capacity, computerUseEnabled = false, pluginRoot) {
@@ -6766,7 +6768,7 @@ function coreInstructions(platform, capacity, computerUseEnabled = false, plugin
6766
6768
  const depth = capacity?.maxDepth;
6767
6769
  const capacityInstructions = threads === void 0 || depth === void 0 ? "Before delegation, use active collaboration tool instructions as the authoritative agent-capacity limit." : `Host agent capacity: agents.max_concurrent_threads_per_session=${threads} includes Root. The host nesting limit is ${depth}; the active plan's maxCalls is the hard workflow call ceiling and targetCalls is soft planning guidance. Its lower concurrency, depth, and fan-out limits remain authoritative. Substantive, multi-file, risky, and architecture-sensitive work uses a CLI workflow; genuinely small bounded operations may remain direct. Report a blocker when a required workflow runtime is unavailable. Go does not support workflows, so Root works directly without specialist subagents.`;
6768
6770
  const platformInstructions = platform === "win32" ? ` ${WINDOWS_SHELL_POLICY}` : "";
6769
- return `${CORE_INSTRUCTIONS} ${ROOT_LUNA_POLICY} ${LITE_WRITING_POLICY} ${CONTEXT7_POLICY} ${NATIVE_IO_INSTRUCTIONS}${computerUseEnabled ? ` ${COMPUTER_USE_INSTRUCTIONS}` : ""} ${CODE_REVIEW_ACTIVATION_POLICY} ${capacityInstructions}${platformInstructions}${pluginRoot === void 0 ? "" : ` ${formatInstalledRuntimeGuidance(pluginRoot)}`}`;
6771
+ return `${CORE_INSTRUCTIONS} ${ROOT_LUNA_POLICY} ${ROOT_DESIGN_GATE_POLICY} ${WORKER_BRIEF_POLICY} ${LITE_WRITING_POLICY} ${CONTEXT7_POLICY} ${NATIVE_IO_INSTRUCTIONS}${computerUseEnabled ? ` ${COMPUTER_USE_INSTRUCTIONS}` : ""} ${CODE_REVIEW_ACTIVATION_POLICY} ${capacityInstructions}${platformInstructions}${pluginRoot === void 0 ? "" : ` ${formatInstalledRuntimeGuidance(pluginRoot)}`}`;
6770
6772
  }
6771
6773
  //#endregion
6772
6774
  //#region packages/cli/src/doctor.ts
@@ -6935,16 +6937,26 @@ async function exists(path) {
6935
6937
  }
6936
6938
  /** Provides backup. */
6937
6939
  async function backup(path, root) {
6938
- if (!await exists(path)) return void 0;
6939
- const target = join(root, path.replace(/^([A-Za-z]:)?[\\/]+/, "").replaceAll(":", ""));
6940
+ try {
6941
+ await lstat(path);
6942
+ } catch (error) {
6943
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") return void 0;
6944
+ throw error;
6945
+ }
6946
+ const target = join(root, backupPath(path));
6940
6947
  await mkdir(dirname(target), { recursive: true });
6941
6948
  await copyBackup(path, target);
6942
6949
  return target;
6943
6950
  }
6951
+ function backupPath(path) {
6952
+ const segments = path.replaceAll("\\", "/").replace(/^(?:[A-Za-z]:)?\/+/, "").split("/").filter((segment) => segment !== "" && segment !== ".");
6953
+ if (segments.some((segment) => segment === "..")) throw new Error(`Cannot create a backup for unsafe path: ${path}`);
6954
+ return join(...segments);
6955
+ }
6944
6956
  async function copyBackup(source, target) {
6945
6957
  const metadata = await lstat(source);
6946
6958
  if (metadata.isSymbolicLink()) {
6947
- await writeFile(`${target}.symlink`, await readlink(source), "utf8");
6959
+ await symlink(await readlink(source), target);
6948
6960
  return;
6949
6961
  }
6950
6962
  if (!metadata.isDirectory()) {
@@ -6954,6 +6966,60 @@ async function copyBackup(source, target) {
6954
6966
  await mkdir(target, { recursive: true });
6955
6967
  for (const entry of await readdir(source)) await copyBackup(join(source, entry), join(target, entry));
6956
6968
  }
6969
+ /** Restores a backup while preserving the original file and symlink types. */
6970
+ async function restoreBackup(path, source) {
6971
+ if (source === void 0) {
6972
+ await rm(path, {
6973
+ recursive: true,
6974
+ force: true
6975
+ });
6976
+ return;
6977
+ }
6978
+ if ((await lstat(source)).isSymbolicLink()) {
6979
+ await rm(path, {
6980
+ recursive: true,
6981
+ force: true
6982
+ });
6983
+ await mkdir(dirname(path), { recursive: true });
6984
+ await symlink(await readlink(source), path);
6985
+ return;
6986
+ }
6987
+ await rm(path, {
6988
+ recursive: true,
6989
+ force: true
6990
+ });
6991
+ await restoreBackupTree(source, path);
6992
+ }
6993
+ async function restoreBackupTree(source, target) {
6994
+ if (!(await lstat(source)).isDirectory()) {
6995
+ await mkdir(dirname(target), { recursive: true });
6996
+ await copyFile(source, target);
6997
+ return;
6998
+ }
6999
+ await mkdir(target, { recursive: true });
7000
+ for (const entry of await readdir(source)) {
7001
+ const entrySource = join(source, entry);
7002
+ const entryTarget = join(target, entry);
7003
+ if ((await lstat(entrySource)).isSymbolicLink()) {
7004
+ await rm(entryTarget, {
7005
+ recursive: true,
7006
+ force: true
7007
+ });
7008
+ await symlink(await readlink(entrySource), entryTarget);
7009
+ continue;
7010
+ }
7011
+ if (entry.endsWith(".symlink")) {
7012
+ const symlinkTarget = entryTarget.slice(0, -8);
7013
+ await rm(symlinkTarget, {
7014
+ recursive: true,
7015
+ force: true
7016
+ });
7017
+ await symlink(await readFile(entrySource, "utf8"), symlinkTarget);
7018
+ continue;
7019
+ }
7020
+ await restoreBackupTree(entrySource, entryTarget);
7021
+ }
7022
+ }
6957
7023
  /** Provides atomic write. */
6958
7024
  async function atomicWrite(path, content) {
6959
7025
  await mkdir(dirname(path), { recursive: true });
@@ -7000,23 +7066,31 @@ function assertGitBashReady(platform, resolution) {
7000
7066
  }
7001
7067
  /** Provides install. */
7002
7068
  async function install(options, runtime = defaultRuntime) {
7069
+ try {
7070
+ return await installOnce(options, runtime);
7071
+ } finally {
7072
+ await pruneBackupHistory();
7073
+ }
7074
+ }
7075
+ async function installOnce(options, runtime) {
7003
7076
  notify(options, "prerequisites", "Checking prerequisites", "running");
7004
7077
  assertGitBashReady(runtime.platform, runtime.gitBash());
7005
7078
  notify(options, "prerequisites", "Checking prerequisites", "complete");
7006
7079
  const target = paths();
7007
7080
  const existingConfig = await readText(target.config);
7008
7081
  const plan = options.plan ?? readManagedPlan(existingConfig) ?? "plus";
7009
- const computerUseChoice = resolveComputerUseChoice(options);
7082
+ const computerUseChoice = resolveComputerUseChoice(options, existingConfig);
7010
7083
  const root = backupRoot();
7011
7084
  notify(options, "backup", "Backing up existing installation", "running");
7012
7085
  const configBackup = await backup(target.config, root);
7013
7086
  const cacheBackup = await backup(target.marketplaceCache, root);
7014
7087
  const agentsBackup = await backup(target.agents, root);
7088
+ const legacyBackups = await Promise.all(target.legacy.map((path) => backup(path, root)));
7015
7089
  const backups = [
7016
7090
  configBackup,
7017
7091
  cacheBackup,
7018
7092
  agentsBackup,
7019
- ...await Promise.all(target.legacy.map((path) => backup(path, root)))
7093
+ ...legacyBackups
7020
7094
  ].filter((path) => path !== void 0);
7021
7095
  notify(options, "backup", "Backing up existing installation", "complete", `${backups.length} saved`);
7022
7096
  notify(options, "configuration", "Preparing configuration", "running");
@@ -7083,9 +7157,13 @@ async function install(options, runtime = defaultRuntime) {
7083
7157
  await removeObsoleteVersionCaches(target.cacheRoot);
7084
7158
  notify(options, "cleanup", "Removing obsolete caches", "complete");
7085
7159
  } catch (error) {
7086
- await restoreTarget(target.config, configBackup);
7087
- await restoreTarget(target.marketplaceCache, cacheBackup);
7088
- await restoreTarget(target.agents, agentsBackup);
7160
+ await restoreBackup(target.config, configBackup);
7161
+ await restoreBackup(target.marketplaceCache, cacheBackup);
7162
+ await restoreBackup(target.agents, agentsBackup);
7163
+ await Promise.all(target.legacy.map(async (path, index) => {
7164
+ const source = legacyBackups[index];
7165
+ if (source !== void 0) await restoreBackup(path, source);
7166
+ }));
7089
7167
  throw error;
7090
7168
  } finally {
7091
7169
  await rm(staging, {
@@ -7093,7 +7171,6 @@ async function install(options, runtime = defaultRuntime) {
7093
7171
  force: true
7094
7172
  });
7095
7173
  }
7096
- await pruneBackupHistory();
7097
7174
  return {
7098
7175
  action: "install",
7099
7176
  changed: [
@@ -7109,8 +7186,8 @@ async function install(options, runtime = defaultRuntime) {
7109
7186
  buildWebApps
7110
7187
  };
7111
7188
  }
7112
- function resolveComputerUseChoice(options) {
7113
- return options.computerUse ?? "disabled";
7189
+ function resolveComputerUseChoice(options, existingConfig) {
7190
+ return options.computerUse ?? readManagedComputerUse(existingConfig) ?? "disabled";
7114
7191
  }
7115
7192
  function computerUseFailure(result) {
7116
7193
  const reason = result.reason.replaceAll("-", " ");
@@ -7139,16 +7216,9 @@ async function validateStaging(cache, agents) {
7139
7216
  for (const path of required) if (!await exists(path)) missing.push(path);
7140
7217
  if (missing.length > 0) throw new Error(`Staged HolyCodex installation is incomplete: ${missing.join(", ")}`);
7141
7218
  }
7142
- async function restoreTarget(target, source) {
7143
- await rm(target, {
7144
- recursive: true,
7145
- force: true
7146
- });
7147
- if (source !== void 0) await cp(source, target, { recursive: true });
7148
- }
7149
7219
  async function removeObsoleteVersionCaches(cacheRoot) {
7150
7220
  if (!await exists(cacheRoot)) return;
7151
- for (const entry of await readdir(cacheRoot)) if (entry !== "0.13.4") await rm(join(cacheRoot, entry), {
7221
+ for (const entry of await readdir(cacheRoot)) if (entry !== "0.13.5") await rm(join(cacheRoot, entry), {
7152
7222
  recursive: true,
7153
7223
  force: true
7154
7224
  });
@@ -7157,7 +7227,7 @@ async function pruneBackupHistory() {
7157
7227
  const root = join(tmpdir(), "holycodex-backups");
7158
7228
  if (!await exists(root)) return;
7159
7229
  const entries = (await readdir(root)).sort().reverse();
7160
- await Promise.allSettled(entries.slice(BACKUP_RETENTION, 6).map((entry) => rm(join(root, entry), {
7230
+ await Promise.allSettled(entries.slice(BACKUP_RETENTION).map((entry) => rm(join(root, entry), {
7161
7231
  recursive: true,
7162
7232
  force: true
7163
7233
  })));
@@ -7256,6 +7326,13 @@ function composeAgentPolicies(input, platform) {
7256
7326
  }
7257
7327
  /** Provides cleanup. */
7258
7328
  async function cleanup(_options) {
7329
+ try {
7330
+ return await cleanupOnce();
7331
+ } finally {
7332
+ await pruneBackupHistory();
7333
+ }
7334
+ }
7335
+ async function cleanupOnce() {
7259
7336
  const target = paths();
7260
7337
  const root = backupRoot();
7261
7338
  const backups = [
@@ -7308,6 +7385,10 @@ function formatCliError(error) {
7308
7385
  if (!(error instanceof ZodError)) return error instanceof Error ? error.message : String(error);
7309
7386
  return error.issues.map((issue) => `${issue.path.length === 0 ? "input" : issue.path.join(".")}: ${issue.message}`).join("; ");
7310
7387
  }
7388
+ /** Renders a stable machine-readable CLI failure envelope. */
7389
+ function renderJsonError(message) {
7390
+ return `${JSON.stringify({ error: { message } })}\n`;
7391
+ }
7311
7392
  /** Checks whether terminal color output is supported. */
7312
7393
  function supportsColor(isTTY, noColor) {
7313
7394
  return isTTY === true && noColor === void 0;
@@ -7317,15 +7398,70 @@ function renderHelp(version, color) {
7317
7398
  const title = paint(color, `${BOLD}${CYAN}`, `HolyCodex ${version}`);
7318
7399
  const section = (text) => paint(color, BOLD, text);
7319
7400
  const muted = (text) => paint(color, DIM, text);
7320
- return `${title}\n${muted("Lean Codex toolkit installer and doctor")}\n\n${section("USAGE")}\n holycodex <command> [options]\n\n${section("COMMANDS")}\n install Install or update HolyCodex\n cleanup Remove HolyCodex-owned state\n doctor Diagnose installation and runtime\n\n${section("OPTIONS")}\n --plan <plan> Model routing plan for install: ${PLAN_HELP}\n Default: ${DEFAULT_PLAN}\n --max-subagents <count> Override concurrent direct subagents for install\n --fast Use Fast for generated subagents only\n --fast-all Use Fast for Root and generated subagents\n --no-fast Use Standard for Root and generated subagents\n -h, --help Show help\n -v, --version Show version\n --no-tui Accepted; commands remain noninteractive\n --codex-autonomous Never ask; keep workspace sandbox\n --no-codex-autonomous Safe interactive defaults\n --dangerous-codex-autonomous Never ask; disable filesystem sandbox\n install --verbose Show detailed install steps
7321
- --json Print machine-readable output\n --computer-use Enable and verify the official Computer Use plugin\n --no-computer-use Keep Computer Use disabled\n`;
7401
+ return `${title}
7402
+ ${muted("Durable Codex workflow installer, doctor, and cleanup")}
7403
+
7404
+ ${section("USAGE")}
7405
+ holycodex <command> [options]
7406
+
7407
+ ${section("COMMANDS")}
7408
+ install Install or update HolyCodex
7409
+ cleanup Remove HolyCodex-owned state
7410
+ doctor Diagnose installation and runtime
7411
+
7412
+ ${section("OPTIONS")}
7413
+ --plan <plan> Model routing plan for install: ${PLAN_HELP}
7414
+ Default: ${DEFAULT_PLAN}
7415
+ --max-subagents <count> Override concurrent direct subagents for install
7416
+ --fast Use Fast for generated subagents only
7417
+ --fast-all Use Fast for Root and generated subagents
7418
+ --no-fast Use Standard for Root and generated subagents
7419
+ -h, --help Show help
7420
+ -v, --version Show version
7421
+ --no-tui Accepted; commands remain noninteractive
7422
+ --codex-autonomous Never ask; keep workspace sandbox
7423
+ --no-codex-autonomous Safe interactive defaults
7424
+ --dangerous-codex-autonomous Never ask; disable filesystem sandbox
7425
+ install --verbose Show detailed install steps
7426
+ --json Print machine-readable output
7427
+ --computer-use Enable and verify the official Computer Use plugin
7428
+ --no-computer-use Keep Computer Use disabled
7429
+ `;
7322
7430
  }
7323
7431
  /** Renders install-specific model plan and option help. */
7324
7432
  function renderInstallHelp(version, color) {
7325
7433
  const title = paint(color, `${BOLD}${CYAN}`, `HolyCodex ${version}`);
7326
7434
  const section = (text) => `${paint(color, BOLD, text)}${text === "Options:" ? "\n --computer-use Enable and verify the official Computer Use plugin\n --no-computer-use Keep Computer Use disabled" : ""}`;
7327
- return `${title}\n\n${section("Usage:")}\n holycodex install [options]\n\n${section("Options:")}\n --plan <plan> Model routing plan: ${PLAN_HELP}\n Default: ${DEFAULT_PLAN}\n --max-subagents <count> Override concurrent direct subagents\n --fast Use Fast for generated subagents only\n --fast-all Use Fast for Root and generated subagents\n --no-fast Use Standard for Root and generated subagents\n -v, --verbose Show detailed install steps
7328
- --json Print machine-readable output\n --no-tui Accepted; install remains noninteractive\n --codex-autonomous Never ask; keep workspace sandbox\n --no-codex-autonomous Safe interactive defaults\n --dangerous-codex-autonomous Never ask; disable filesystem sandbox\n -h, --help Show help\n\nPlans provide increasing expected model usage and capability. Fast flags are mutually exclusive.\n\n${section("Examples:")}\n bunx holycodex install\n bunx holycodex install --plan go\n bunx holycodex install --plan plus-low --fast\n bunx holycodex install --plan plus-high\n bunx holycodex install --plan pro-5x --fast-all\n bunx holycodex install --plan pro-20x --no-fast\n`;
7435
+ return `${title}
7436
+
7437
+ ${section("Usage:")}
7438
+ holycodex install [options]
7439
+
7440
+ ${section("Options:")}
7441
+ --plan <plan> Model routing plan: ${PLAN_HELP}
7442
+ Default: ${DEFAULT_PLAN}
7443
+ --max-subagents <count> Override concurrent direct subagents
7444
+ --fast Use Fast for generated subagents only
7445
+ --fast-all Use Fast for Root and generated subagents
7446
+ --no-fast Use Standard for Root and generated subagents
7447
+ -v, --verbose Show detailed install steps
7448
+ --json Print machine-readable output
7449
+ --no-tui Accepted; install remains noninteractive
7450
+ --codex-autonomous Never ask; keep workspace sandbox
7451
+ --no-codex-autonomous Safe interactive defaults
7452
+ --dangerous-codex-autonomous Never ask; disable filesystem sandbox
7453
+ -h, --help Show help
7454
+
7455
+ Plans provide increasing expected model usage and capability. Fast flags are mutually exclusive.
7456
+
7457
+ ${section("Examples:")}
7458
+ bunx holycodex install
7459
+ bunx holycodex install --plan go
7460
+ bunx holycodex install --plan plus-low --fast
7461
+ bunx holycodex install --plan plus-high
7462
+ bunx holycodex install --plan pro-5x --fast-all
7463
+ bunx holycodex install --plan pro-20x --no-fast
7464
+ `;
7329
7465
  }
7330
7466
  /** Renders error. */
7331
7467
  function renderError(message, color) {
@@ -7394,8 +7530,8 @@ function renderNotice(kind, message, color) {
7394
7530
  }
7395
7531
  //#endregion
7396
7532
  //#region packages/cli/src/cli.ts
7397
- async function main() {
7398
- const parsed = parseCliArguments(process$1.argv.slice(2));
7533
+ async function main(args = process$1.argv.slice(2)) {
7534
+ const parsed = parseCliArguments(args);
7399
7535
  const stdoutColor = supportsColor(process$1.stdout.isTTY, process$1.env.NO_COLOR);
7400
7536
  const stderrColor = supportsColor(process$1.stderr.isTTY, process$1.env.NO_COLOR);
7401
7537
  if (parsed.action === "help") {
@@ -7422,15 +7558,18 @@ async function main() {
7422
7558
  if (!result.healthy) process$1.exitCode = 1;
7423
7559
  return;
7424
7560
  }
7425
- if (parsed.autonomy.requested && parsed.autonomy.mode === "dangerous") process$1.stderr.write(renderNotice("warning", "Dangerous autonomy disables approvals and filesystem sandboxing.", stderrColor));
7561
+ if (!parsed.json && parsed.autonomy.requested && parsed.autonomy.mode === "dangerous") process$1.stderr.write(renderNotice("warning", "Dangerous autonomy disables approvals and filesystem sandboxing.", stderrColor));
7426
7562
  const result = parsed.command === "install" ? await install(options) : await cleanup(options);
7427
7563
  process$1.stdout.write(parsed.json ? `${JSON.stringify(result)}\n` : renderRunResult(result, stdoutColor));
7428
7564
  }
7429
7565
  try {
7430
7566
  await main();
7431
7567
  } catch (error) {
7432
- const color = supportsColor(process$1.stderr.isTTY, process$1.env.NO_COLOR);
7433
- process$1.stderr.write(renderError(formatCliError(error), color));
7568
+ if (process$1.argv.slice(2).includes("--json")) process$1.stderr.write(renderJsonError(formatCliError(error)));
7569
+ else {
7570
+ const color = supportsColor(process$1.stderr.isTTY, process$1.env.NO_COLOR);
7571
+ process$1.stderr.write(renderError(formatCliError(error), color));
7572
+ }
7434
7573
  process$1.exitCode = 1;
7435
7574
  }
7436
7575
  //#endregion
package/package.json CHANGED
@@ -1,12 +1,15 @@
1
1
  {
2
2
  "name": "holycodex",
3
- "version": "0.13.4",
4
- "description": "Lean Codex-only agent toolkit installer and doctor",
3
+ "version": "0.13.5",
4
+ "description": "HolyCodex installer, doctor, and cleanup CLI for durable Codex workflows",
5
5
  "keywords": [
6
6
  "agents",
7
7
  "chatgpt",
8
8
  "codex",
9
- "developer-tools"
9
+ "developer-tools",
10
+ "lsp",
11
+ "orchestration",
12
+ "workflows"
10
13
  ],
11
14
  "homepage": "https://github.com/davidbasilefilho/holycodex#readme",
12
15
  "bugs": {
@@ -39,7 +42,7 @@
39
42
  "prepack": "vp run --workspace-root build"
40
43
  },
41
44
  "dependencies": {
42
- "@holycodex/plugin": "0.13.4",
45
+ "@holycodex/plugin": "0.13.5",
43
46
  "zod": "^4.4.3"
44
47
  },
45
48
  "devDependencies": {