holycodex 0.8.1 → 0.8.2-dev.29763019035.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.
@@ -9,5 +9,3 @@ The caveman communication concept is adapted from [juliusbrussee/caveman](https:
9
9
  HolyCodex agent routing and orchestration instructions adapt bounded-role, task-ownership, non-overlapping-write, session-reuse, and verification-planning concepts from [alvinunreal/oh-my-opencode-slim](https://github.com/alvinunreal/oh-my-opencode-slim) at commit `7bc7b56856ee693812d87d68615757d4d1c2e218`, principally `src/agents/{orchestrator,explorer,librarian,fixer}.ts`, `src/skills/verification-planning/SKILL.md`, and `docs/background-orchestration.md`. OpenCode runtime APIs, hooks, council, ACP, companion, and background-session mechanics were not copied. Upstream material is MIT licensed; its license is preserved in `packages/plugin/plugin/LICENSE-OH-MY-OPENCODE-SLIM-MIT.txt`.
10
10
 
11
11
  The bundled LSP runtime at `packages/plugin/plugin/runtime/lsp.js` is derived from `code-yeongyu/oh-my-openagent`'s `lsp-tools-mcp`. Copyright (c) 2026 Yeongyu Kim; used under the MIT License preserved at `packages/plugin/plugin/runtime/LICENSE-LSP-MIT.txt`.
12
-
13
- The `codexslimedit` package and HolyCodex integration adapt compact-read and line-range edit behavior from [ASidorenkoCode/openslimedit](https://github.com/ASidorenkoCode/openslimedit) at commit `d5014929d6f66729b887df74a65ed6d22c3b522b`. Copyright (c) 2026 Artur; used under the MIT License preserved in both published packages. OpenCode hook APIs and token-saving claims were not copied.
package/dist/cli.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import process$1 from "node:process";
2
- import { execFileSync, spawn, spawnSync } from "node:child_process";
3
2
  import { access, copyFile, cp, lstat, mkdir, readFile, readdir, readlink, rename, rm, stat, writeFile } from "node:fs/promises";
4
3
  import { homedir, tmpdir } from "node:os";
5
4
  import { dirname, join } from "node:path";
5
+ import { execFileSync, spawn, spawnSync } from "node:child_process";
6
6
  import { existsSync } from "node:fs";
7
7
  import { Buffer } from "node:buffer";
8
8
  import { pluginRoot } from "@holycodex/plugin";
@@ -3924,170 +3924,8 @@ function superRefine(fn, params) {
3924
3924
  return /* @__PURE__ */ _superRefine(fn, params);
3925
3925
  }
3926
3926
  //#endregion
3927
- //#region packages/mcp-stdio-core/src/process.ts
3928
- var TRUNCATED_MARKER = "\n... diagnostic output truncated ...\n";
3929
- var defaultManagedProcessRuntime = {
3930
- terminationGraceMs: 2e3,
3931
- kill: killProcessTree
3932
- };
3933
- /** Runs managed process. */
3934
- async function runManagedProcess(input, runtime = defaultManagedProcessRuntime) {
3935
- return await new Promise((resolve) => {
3936
- const child = spawn(input.command, [...input.args], {
3937
- ...input.cwd === void 0 ? {} : { cwd: input.cwd },
3938
- ...input.env === void 0 ? {} : { env: input.env },
3939
- stdio: [
3940
- "pipe",
3941
- "pipe",
3942
- "pipe"
3943
- ],
3944
- windowsHide: true,
3945
- detached: input.platform !== "win32"
3946
- });
3947
- let stdout = {
3948
- head: "",
3949
- tail: "",
3950
- truncated: false
3951
- };
3952
- let stderr = {
3953
- head: "",
3954
- tail: "",
3955
- truncated: false
3956
- };
3957
- let timedOut = false;
3958
- let matched = false;
3959
- let settled = false;
3960
- let forceKillTimeout;
3961
- const finish = (exitCode, error) => {
3962
- if (settled) return;
3963
- settled = true;
3964
- clearTimeout(timeout);
3965
- if (forceKillTimeout !== void 0) clearTimeout(forceKillTimeout);
3966
- resolve({
3967
- exitCode,
3968
- stdout: outputText(stdout),
3969
- stderr: outputText(stderr),
3970
- timedOut,
3971
- matched,
3972
- outputTruncated: stdout.truncated || stderr.truncated,
3973
- ...error === void 0 ? {} : { error }
3974
- });
3975
- };
3976
- const terminate = () => {
3977
- if (forceKillTimeout !== void 0) return;
3978
- runtime.kill(child, input.platform, "SIGTERM");
3979
- forceKillTimeout = setTimeout(() => {
3980
- runtime.kill(child, input.platform, "SIGKILL");
3981
- }, runtime.terminationGraceMs);
3982
- forceKillTimeout.unref();
3983
- };
3984
- const inspectMatch = () => {
3985
- if (matched || input.matchOutput === void 0) return;
3986
- if (input.matchOutput(`${outputText(stdout)}\n${outputText(stderr)}`)) {
3987
- matched = true;
3988
- terminate();
3989
- }
3990
- };
3991
- child.stdout.on("data", (chunk) => {
3992
- stdout = appendOutput(stdout, chunk.toString(), input.maxOutputChars);
3993
- inspectMatch();
3994
- });
3995
- child.stderr.on("data", (chunk) => {
3996
- stderr = appendOutput(stderr, chunk.toString(), input.maxOutputChars);
3997
- inspectMatch();
3998
- });
3999
- child.once("error", (error) => finish(null, error.message));
4000
- child.once("close", (code) => finish(code));
4001
- const timeout = setTimeout(() => {
4002
- timedOut = true;
4003
- terminate();
4004
- }, input.timeoutMs);
4005
- timeout.unref();
4006
- if (input.stdin === void 0) child.stdin.end();
4007
- else child.stdin.end(input.stdin);
4008
- });
4009
- }
4010
- /** Terminates process tree. */
4011
- function killProcessTree(child, platform, signal = "SIGTERM", runTaskkill = (command, args) => spawnSync(command, [...args], {
4012
- stdio: "ignore",
4013
- windowsHide: true
4014
- })) {
4015
- if (platform === "win32" && child.pid !== void 0) {
4016
- const result = runTaskkill("taskkill", [
4017
- "/pid",
4018
- String(child.pid),
4019
- "/f",
4020
- "/t"
4021
- ]);
4022
- if (result.error === void 0 && result.status === 0) return;
4023
- }
4024
- if (platform !== "win32" && child.pid !== void 0) try {
4025
- process.kill(-child.pid, signal);
4026
- return;
4027
- } catch {}
4028
- try {
4029
- child.kill(signal);
4030
- } catch {}
4031
- }
4032
- function appendOutput(state, chunk, limit) {
4033
- const safeLimit = Math.max(1, limit);
4034
- const headLimit = Math.ceil(safeLimit / 2);
4035
- const tailLimit = Math.floor(safeLimit / 2);
4036
- if (!state.truncated && state.head.length + chunk.length <= safeLimit) return {
4037
- ...state,
4038
- head: state.head + chunk
4039
- };
4040
- const combined = state.truncated ? chunk : state.head + chunk;
4041
- return {
4042
- head: state.truncated ? state.head : combined.slice(0, headLimit),
4043
- tail: `${state.tail}${combined.slice(state.truncated ? 0 : headLimit)}`.slice(-tailLimit),
4044
- truncated: true
4045
- };
4046
- }
4047
- function outputText(state) {
4048
- return state.truncated ? `${state.head}${TRUNCATED_MARKER}${state.tail}` : state.head;
4049
- }
4050
- //#endregion
4051
- //#region packages/cli/src/package-runner.ts
4052
- var PACKAGE_INSTALL_TIMEOUT_MS = 12e4;
4053
- var PACKAGE_INSTALL_OUTPUT_LIMIT = 4e3;
4054
- /** Detects whether Bun or npm invoked HolyCodex. */
4055
- function detectPackageRunner(env = process.env) {
4056
- const executable = (env.npm_execpath ?? "").split(/[\\/]/).at(-1)?.toLowerCase().replace(/\.exe$/, "");
4057
- const userAgent = env.npm_config_user_agent?.trim().split(/[\s/]/, 1)[0]?.toLowerCase();
4058
- return executable === "bun" || userAgent === "bun" ? "bun" : "npm";
4059
- }
4060
- /** Builds the runner-specific codexslimedit invocation. */
4061
- function codexSlimEditInvocation(input) {
4062
- const args = [input.packageVersion.includes("-dev.") ? "codexslimedit@dev" : "codexslimedit@latest", ...input.includeVersion ? ["--version"] : []];
4063
- return input.packageRunner === "bun" ? {
4064
- command: "bunx",
4065
- args
4066
- } : {
4067
- command: input.platform === "win32" ? "npx.cmd" : "npx",
4068
- args: ["--yes", ...args]
4069
- };
4070
- }
4071
- /** Pre-resolves codexslimedit through the invoking package runner. */
4072
- async function installCodexSlimEdit(input, env = process.env) {
4073
- if (env.NODE_ENV === "test" && env.HOLYCODEX_TEST_SKIP_PACKAGE_RESOLUTION === "1") return;
4074
- const invocation = codexSlimEditInvocation({
4075
- ...input,
4076
- includeVersion: true
4077
- });
4078
- const result = await runManagedProcess({
4079
- ...invocation,
4080
- platform: input.platform,
4081
- timeoutMs: PACKAGE_INSTALL_TIMEOUT_MS,
4082
- maxOutputChars: PACKAGE_INSTALL_OUTPUT_LIMIT
4083
- });
4084
- if (result.exitCode === 0 && !result.timedOut) return;
4085
- const detail = result.error ?? (result.stderr.trim() || result.stdout.trim() || "unknown package error");
4086
- throw new Error(`Could not install codexslimedit with ${invocation.command}: ${detail}. Check package registry and network access, then retry HolyCodex installation.`);
4087
- }
4088
- //#endregion
4089
3927
  //#region packages/cli/src/catalog.ts
4090
- var VERSION = "0.8.1";
3928
+ var VERSION = "0.8.2-dev.29763019035.1";
4091
3929
  var SKILLS = [
4092
3930
  "ast-grep",
4093
3931
  "caveman",
@@ -4161,7 +3999,12 @@ var RoutingPresetSchema = strictObject({
4161
3999
  worker: ModelRouteSchema
4162
4000
  }),
4163
4001
  usage: strictObject({
4164
- maxThreads: union([literal(1), literal(2)]),
4002
+ maxSubagents: union([
4003
+ literal(0),
4004
+ literal(1),
4005
+ literal(2),
4006
+ literal(3)
4007
+ ]),
4165
4008
  maxDepth: literal(1)
4166
4009
  })
4167
4010
  });
@@ -4195,7 +4038,7 @@ var MODEL_ROUTING_PLANS = ModelRoutingPlansSchema.parse({
4195
4038
  }
4196
4039
  },
4197
4040
  usage: {
4198
- maxThreads: 1,
4041
+ maxSubagents: 0,
4199
4042
  maxDepth: 1
4200
4043
  }
4201
4044
  },
@@ -4219,14 +4062,14 @@ var MODEL_ROUTING_PLANS = ModelRoutingPlansSchema.parse({
4219
4062
  }
4220
4063
  },
4221
4064
  usage: {
4222
- maxThreads: 2,
4065
+ maxSubagents: 1,
4223
4066
  maxDepth: 1
4224
4067
  }
4225
4068
  },
4226
4069
  plus: {
4227
4070
  root: {
4228
4071
  model: "gpt-5.6-sol",
4229
- reasoningEffort: "medium"
4072
+ reasoningEffort: "low"
4230
4073
  },
4231
4074
  agents: {
4232
4075
  explorer: {
@@ -4243,7 +4086,7 @@ var MODEL_ROUTING_PLANS = ModelRoutingPlansSchema.parse({
4243
4086
  }
4244
4087
  },
4245
4088
  usage: {
4246
- maxThreads: 2,
4089
+ maxSubagents: 2,
4247
4090
  maxDepth: 1
4248
4091
  }
4249
4092
  },
@@ -4267,7 +4110,7 @@ var MODEL_ROUTING_PLANS = ModelRoutingPlansSchema.parse({
4267
4110
  }
4268
4111
  },
4269
4112
  usage: {
4270
- maxThreads: 2,
4113
+ maxSubagents: 2,
4271
4114
  maxDepth: 1
4272
4115
  }
4273
4116
  },
@@ -4291,7 +4134,7 @@ var MODEL_ROUTING_PLANS = ModelRoutingPlansSchema.parse({
4291
4134
  }
4292
4135
  },
4293
4136
  usage: {
4294
- maxThreads: 2,
4137
+ maxSubagents: 2,
4295
4138
  maxDepth: 1
4296
4139
  }
4297
4140
  },
@@ -4315,7 +4158,7 @@ var MODEL_ROUTING_PLANS = ModelRoutingPlansSchema.parse({
4315
4158
  }
4316
4159
  },
4317
4160
  usage: {
4318
- maxThreads: 2,
4161
+ maxSubagents: 2,
4319
4162
  maxDepth: 1
4320
4163
  }
4321
4164
  }
@@ -4455,19 +4298,13 @@ var GENERATED_RUNTIMES = [
4455
4298
  "git-bash.js",
4456
4299
  "git-bash-resolver.js",
4457
4300
  "LICENSE-LSP-MIT.txt",
4458
- "LICENSE-OPENSLIMEDIT-MIT.txt",
4459
4301
  "lsp.js",
4460
4302
  "mcp-stdio-core.js",
4461
4303
  "rules.js"
4462
4304
  ];
4463
4305
  var WINDOWS_SHELL_POLICY = "On native Windows, before the first shell action, inspect callable and deferred tools until `mcp__git_bash__run` is resolved. Use it for every shell command, including Git, Bash, POSIX, package, build, test, and script commands. If unavailable, stop and report the blocker. Never fall back to PowerShell or cmd.";
4464
4306
  /** Provides effective mcp servers. */
4465
- function effectiveMcpServers(platform, packageRunner = "bun") {
4466
- const codexSlimEdit = codexSlimEditInvocation({
4467
- packageRunner,
4468
- platform,
4469
- packageVersion: VERSION
4470
- });
4307
+ function effectiveMcpServers(platform) {
4471
4308
  return {
4472
4309
  ...platform === "win32" ? { git_bash: {
4473
4310
  command: "node",
@@ -4480,10 +4317,6 @@ function effectiveMcpServers(platform, packageRunner = "bun") {
4480
4317
  args: ["runtime/lsp.js", "mcp"],
4481
4318
  cwd: "."
4482
4319
  },
4483
- codexslimedit: {
4484
- ...codexSlimEdit,
4485
- enabled_tools: ["read_file", "apply_patch"]
4486
- },
4487
4320
  context7: {
4488
4321
  command: "bunx",
4489
4322
  args: ["@upstash/context7-mcp"]
@@ -4576,6 +4409,130 @@ function missing(checkedPaths) {
4576
4409
  };
4577
4410
  }
4578
4411
  //#endregion
4412
+ //#region packages/mcp-stdio-core/src/process.ts
4413
+ var TRUNCATED_MARKER = "\n... diagnostic output truncated ...\n";
4414
+ var defaultManagedProcessRuntime = {
4415
+ terminationGraceMs: 2e3,
4416
+ kill: killProcessTree
4417
+ };
4418
+ /** Runs managed process. */
4419
+ async function runManagedProcess(input, runtime = defaultManagedProcessRuntime) {
4420
+ return await new Promise((resolve) => {
4421
+ const child = spawn(input.command, [...input.args], {
4422
+ ...input.cwd === void 0 ? {} : { cwd: input.cwd },
4423
+ ...input.env === void 0 ? {} : { env: input.env },
4424
+ stdio: [
4425
+ "pipe",
4426
+ "pipe",
4427
+ "pipe"
4428
+ ],
4429
+ windowsHide: true,
4430
+ detached: input.platform !== "win32"
4431
+ });
4432
+ let stdout = {
4433
+ head: "",
4434
+ tail: "",
4435
+ truncated: false
4436
+ };
4437
+ let stderr = {
4438
+ head: "",
4439
+ tail: "",
4440
+ truncated: false
4441
+ };
4442
+ let timedOut = false;
4443
+ let matched = false;
4444
+ let settled = false;
4445
+ let forceKillTimeout;
4446
+ const finish = (exitCode, error) => {
4447
+ if (settled) return;
4448
+ settled = true;
4449
+ clearTimeout(timeout);
4450
+ if (forceKillTimeout !== void 0) clearTimeout(forceKillTimeout);
4451
+ resolve({
4452
+ exitCode,
4453
+ stdout: outputText(stdout),
4454
+ stderr: outputText(stderr),
4455
+ timedOut,
4456
+ matched,
4457
+ outputTruncated: stdout.truncated || stderr.truncated,
4458
+ ...error === void 0 ? {} : { error }
4459
+ });
4460
+ };
4461
+ const terminate = () => {
4462
+ if (forceKillTimeout !== void 0) return;
4463
+ runtime.kill(child, input.platform, "SIGTERM");
4464
+ forceKillTimeout = setTimeout(() => {
4465
+ runtime.kill(child, input.platform, "SIGKILL");
4466
+ }, runtime.terminationGraceMs);
4467
+ forceKillTimeout.unref();
4468
+ };
4469
+ const inspectMatch = () => {
4470
+ if (matched || input.matchOutput === void 0) return;
4471
+ if (input.matchOutput(`${outputText(stdout)}\n${outputText(stderr)}`)) {
4472
+ matched = true;
4473
+ terminate();
4474
+ }
4475
+ };
4476
+ child.stdout.on("data", (chunk) => {
4477
+ stdout = appendOutput(stdout, chunk.toString(), input.maxOutputChars);
4478
+ inspectMatch();
4479
+ });
4480
+ child.stderr.on("data", (chunk) => {
4481
+ stderr = appendOutput(stderr, chunk.toString(), input.maxOutputChars);
4482
+ inspectMatch();
4483
+ });
4484
+ child.once("error", (error) => finish(null, error.message));
4485
+ child.once("close", (code) => finish(code));
4486
+ const timeout = setTimeout(() => {
4487
+ timedOut = true;
4488
+ terminate();
4489
+ }, input.timeoutMs);
4490
+ timeout.unref();
4491
+ if (input.stdin === void 0) child.stdin.end();
4492
+ else child.stdin.end(input.stdin);
4493
+ });
4494
+ }
4495
+ /** Terminates process tree. */
4496
+ function killProcessTree(child, platform, signal = "SIGTERM", runTaskkill = (command, args) => spawnSync(command, [...args], {
4497
+ stdio: "ignore",
4498
+ windowsHide: true
4499
+ })) {
4500
+ if (platform === "win32" && child.pid !== void 0) {
4501
+ const result = runTaskkill("taskkill", [
4502
+ "/pid",
4503
+ String(child.pid),
4504
+ "/f",
4505
+ "/t"
4506
+ ]);
4507
+ if (result.error === void 0 && result.status === 0) return;
4508
+ }
4509
+ if (platform !== "win32" && child.pid !== void 0) try {
4510
+ process.kill(-child.pid, signal);
4511
+ return;
4512
+ } catch {}
4513
+ try {
4514
+ child.kill(signal);
4515
+ } catch {}
4516
+ }
4517
+ function appendOutput(state, chunk, limit) {
4518
+ const safeLimit = Math.max(1, limit);
4519
+ const headLimit = Math.ceil(safeLimit / 2);
4520
+ const tailLimit = Math.floor(safeLimit / 2);
4521
+ if (!state.truncated && state.head.length + chunk.length <= safeLimit) return {
4522
+ ...state,
4523
+ head: state.head + chunk
4524
+ };
4525
+ const combined = state.truncated ? chunk : state.head + chunk;
4526
+ return {
4527
+ head: state.truncated ? state.head : combined.slice(0, headLimit),
4528
+ tail: `${state.tail}${combined.slice(state.truncated ? 0 : headLimit)}`.slice(-tailLimit),
4529
+ truncated: true
4530
+ };
4531
+ }
4532
+ function outputText(state) {
4533
+ return state.truncated ? `${state.head}${TRUNCATED_MARKER}${state.tail}` : state.head;
4534
+ }
4535
+ //#endregion
4579
4536
  //#region packages/cli/src/toml.ts
4580
4537
  var TOML_TABLE = /^[ \t]*(?:\[[^\]\r\n]+\]|\[\[[^\]\r\n]+\]\])[ \t]*(?:#.*)?$/m;
4581
4538
  /** Reads a root TOML string value. */
@@ -4666,6 +4623,7 @@ var END = "# <<< holycodex managed <<<";
4666
4623
  var ORIGINAL_ROOT = "# holycodex original root: ";
4667
4624
  var ORIGINAL_TABLE_KEY = "# holycodex original table key: ";
4668
4625
  var PLAN_PREFIX = "# holycodex plan: ";
4626
+ var MAX_SUBAGENTS_PREFIX = "# holycodex max-subagents: ";
4669
4627
  var OLD_NAMESPACES = [
4670
4628
  "marketplaces.sisyphuslabs",
4671
4629
  "plugins.\"omo@sisyphuslabs\"",
@@ -4743,6 +4701,16 @@ function readManagedPlan(input) {
4743
4701
  const value = new RegExp(`^${PLAN_PREFIX}(.+)$`, "m").exec(input)?.[1]?.trim();
4744
4702
  return PLAN_NAMES.find((plan) => plan === value);
4745
4703
  }
4704
+ /** Reads an explicit managed direct-subagent override. */
4705
+ function readManagedMaxSubagents(input) {
4706
+ const raw = new RegExp(`^${MAX_SUBAGENTS_PREFIX}(.*)$`, "m").exec(input)?.[1]?.trim();
4707
+ if (raw === void 0) return { configured: false };
4708
+ if (!/^[0-3]$/.test(raw)) return { configured: true };
4709
+ return {
4710
+ configured: true,
4711
+ value: Number(raw)
4712
+ };
4713
+ }
4746
4714
  /** Identifies explicit Root route overrides preserved from active managed configuration. */
4747
4715
  function readPreservedRootOverrides(input) {
4748
4716
  const managedRoot = new RegExp(`^${START}\\r?\\n([\\s\\S]*?)^${END}\\r?$`, "m").exec(input)?.[1];
@@ -4797,7 +4765,7 @@ function mergedStatusLine(original) {
4797
4765
  return `[${items.map((item) => JSON.stringify(item)).join(", ")}]`;
4798
4766
  }
4799
4767
  /** Installs config. */
4800
- function installConfig(input, mode, _platform, plan = DEFAULT_PLAN) {
4768
+ function installConfig(input, mode, _platform, plan = DEFAULT_PLAN, maxSubagents) {
4801
4769
  const base = preserveManagedRootPreferences(input, removeLegacyOmo(removeManaged(input)));
4802
4770
  const firstTable = base.search(/^\s*\[/m);
4803
4771
  const root = firstTable < 0 ? base : base.slice(0, firstTable);
@@ -4814,17 +4782,20 @@ function installConfig(input, mode, _platform, plan = DEFAULT_PLAN) {
4814
4782
  const hasEffort = /^\s*model_reasoning_effort\s*=/m.test(preservedRoot);
4815
4783
  const hasVerbosity = /^\s*model_verbosity\s*=/m.test(preservedRoot);
4816
4784
  const rootRoute = MODEL_ROUTING_PLANS[plan].root;
4785
+ const effectiveMaxSubagents = maxSubagents ?? MODEL_ROUTING_PLANS[plan].usage.maxSubagents;
4817
4786
  const model = hasModel ? "" : `model = "${rootRoute.model}"\n`;
4818
4787
  const effort = hasEffort ? "" : `model_reasoning_effort = "${rootRoute.reasoningEffort}"\n`;
4819
4788
  const verbosity = hasVerbosity ? "" : "model_verbosity = \"low\"\n";
4820
4789
  const approval = mode === "default" ? "on-request" : "never";
4821
4790
  const sandbox = mode === "dangerous" ? "danger-full-access" : "workspace-write";
4822
- let configured = `${`${START}\n${PLAN_PREFIX}${plan}\n${originalRoot ? `${ORIGINAL_ROOT}${Buffer.from(originalRoot).toString("base64")}\n` : ""}${model}${effort}${verbosity}${preservedRoot ? `${preservedRoot}\n` : ""}approval_policy = "${approval}"\nsandbox_mode = "${sandbox}"\nstatus_line = ${mergedStatusLine(controlled[3])}\n${END}`}${tables ? `\n\n${tables}` : ""}`;
4791
+ const original = originalRoot ? `${ORIGINAL_ROOT}${Buffer.from(originalRoot).toString("base64")}\n` : "";
4792
+ const preserved = preservedRoot ? `${preservedRoot}\n` : "";
4793
+ let configured = `${`${START}\n${PLAN_PREFIX}${plan}\n${maxSubagents === void 0 ? "" : `${MAX_SUBAGENTS_PREFIX}${maxSubagents}\n`}${original}${model}${effort}${verbosity}${preserved}approval_policy = "${approval}"\nsandbox_mode = "${sandbox}"\nstatus_line = ${mergedStatusLine(controlled[3])}\n${END}`}${tables ? `\n\n${tables}` : ""}`;
4823
4794
  configured = injectTableKey(configured, "features", "default_mode_request_user_input", "true");
4824
4795
  configured = injectTableKey(configured, "features", "multi_agent", "true");
4825
4796
  configured = injectTableKey(configured, "features", "multi_agent_v2", "true");
4826
4797
  const usage = MODEL_ROUTING_PLANS[plan].usage;
4827
- configured = injectTableKey(configured, "agents", "max_threads", String(usage.maxThreads));
4798
+ configured = injectTableKey(configured, "agents", "max_threads", String(effectiveMaxSubagents + 1));
4828
4799
  configured = injectTableKey(configured, "agents", "max_depth", String(usage.maxDepth));
4829
4800
  if (mode !== "dangerous") configured = injectTableKey(configured, "sandbox_workspace_write", "network_access", "true");
4830
4801
  for (const agent of AGENTS) configured = injectTableKey(configured, `agents.${agent}`, "config_file", `"holycodex/agents/${agent}.toml"`);
@@ -4879,10 +4850,7 @@ async function startContext7(platform) {
4879
4850
  }
4880
4851
  var defaultRuntime$1 = {
4881
4852
  platform: process.platform,
4882
- command: (name, args) => process.env.NODE_ENV === "test" && process.env.HOLYCODEX_TEST_SKIP_PACKAGE_RESOLUTION === "1" && args.some((argument) => argument.startsWith("codexslimedit@")) ? Promise.resolve({
4883
- ok: true,
4884
- output: "package resolution skipped in tests"
4885
- }) : runCommand(name, args, process.platform),
4853
+ command: (name, args) => runCommand(name, args, process.platform),
4886
4854
  context7: () => startContext7(process.platform),
4887
4855
  gitBash: resolveGitBashForCurrentProcess
4888
4856
  };
@@ -4937,6 +4905,13 @@ async function doctor(home = process.env.CODEX_HOME ?? join(homedir(), ".codex")
4937
4905
  const pluginRoot = join(home, "plugins", "cache", "holycodex", "holycodex", VERSION);
4938
4906
  const agentRoot = join(home, "holycodex", "agents");
4939
4907
  const configPath = join(home, "config.toml");
4908
+ let config = "";
4909
+ let configAvailable = true;
4910
+ try {
4911
+ config = await readFile(configPath, "utf8");
4912
+ } catch {
4913
+ configAvailable = false;
4914
+ }
4940
4915
  const missing = await missingFiles(pluginRoot, [
4941
4916
  ".codex-plugin/plugin.json",
4942
4917
  ".mcp.json",
@@ -4961,12 +4936,6 @@ async function doctor(home = process.env.CODEX_HOME ?? join(homedir(), ".codex")
4961
4936
  const expected = expectedMcps[name];
4962
4937
  checks.push(configured === void 0 || expected === 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.`));
4963
4938
  }
4964
- const codexSlimEdit = servers?.codexslimedit;
4965
- const codexSlimEditConfig = ["bun", "npm"].map((runner) => effectiveMcpServers(runtime.platform, runner).codexslimedit).find((expected) => {
4966
- return expected !== void 0 && codexSlimEdit !== void 0 && mcpConfigMatches(codexSlimEdit, expected);
4967
- });
4968
- const codexSlimEditStarted = codexSlimEditConfig === void 0 ? void 0 : await runtime.command(codexSlimEditConfig.command, [...codexSlimEditConfig.args, "--version"]);
4969
- checks.push(codexSlimEdit === void 0 ? check("mcp-codexslimedit", "error", "missing-codexslimedit", "codexslimedit is not configured.", "Reinstall HolyCodex.") : codexSlimEditStarted?.ok === true ? check("mcp-codexslimedit", "ok", "codexslimedit-ready", "codexslimedit is configured through npm or Bun.") : codexSlimEditConfig === void 0 ? check("mcp-codexslimedit", "error", "invalid-codexslimedit-config", "codexslimedit configuration is stale or uses an unsupported runner.", "Reinstall HolyCodex.") : check("mcp-codexslimedit", "error", "codexslimedit-unavailable", `codexslimedit could not start: ${codexSlimEditStarted?.output || "unknown runner error"}`, "Check the configured package runner and network access, then reinstall HolyCodex."));
4970
4939
  const gitBashConfig = servers?.git_bash;
4971
4940
  if (runtime.platform === "win32" && gitBashConfig !== void 0) {
4972
4941
  const expected = effectiveMcpServers("win32").git_bash;
@@ -4997,19 +4966,16 @@ async function doctor(home = process.env.CODEX_HOME ?? join(homedir(), ".codex")
4997
4966
  const gitBash = runtime.gitBash();
4998
4967
  checks.push(gitBash.found ? check("git-bash", "ok", "git-bash-ready", `Git Bash: ${gitBash.path ?? "configured"}.`) : check("git-bash", "error", "missing-git-bash", "Git Bash is required on Windows but unavailable.", gitBash.installHint));
4999
4968
  } else checks.push(check("git-bash", "ok", "git-bash-not-applicable", "Git Bash is not applicable on this platform."));
5000
- let config = "";
5001
- try {
5002
- config = await readFile(configPath, "utf8");
5003
- } catch {
5004
- checks.push(check("codex-config", "error", "missing-codex-config", `Missing ${configPath}.`, "Run holycodex install."));
5005
- }
4969
+ if (!configAvailable) checks.push(check("codex-config", "error", "missing-codex-config", `Missing ${configPath}.`, "Run holycodex install."));
5006
4970
  const mode = autonomy(config);
5007
4971
  const plan = readManagedPlan(config);
5008
4972
  checks.push(plan === void 0 ? check("routing-plan", "error", "routing-plan-missing", "No managed model routing plan is recorded.", "Rerun holycodex install.") : check("routing-plan", "ok", "routing-plan-ready", `Model routing plan ${plan} is active.`));
5009
4973
  const preset = plan === void 0 ? void 0 : MODEL_ROUTING_PLANS[plan];
4974
+ const managedMaxSubagents = readManagedMaxSubagents(config);
4975
+ const expectedMaxSubagents = managedMaxSubagents.configured ? managedMaxSubagents.value : preset?.usage.maxSubagents;
5010
4976
  const rootOverrides = readPreservedRootOverrides(config);
5011
4977
  checks.push(preset !== void 0 && rootTomlString(config, "model") === preset.root.model && rootTomlString(config, "model_reasoning_effort") === preset.root.reasoningEffort ? check("root-model", "ok", "root-model-ready", "Root model matches the selected routing plan.") : rootOverrides.model || rootOverrides.reasoningEffort ? check("root-model", "ok", "root-model-override", "Root model uses an intentionally preserved explicit override.") : check("root-model", "error", "root-model-stale", "Root model configuration does not match the selected routing plan.", "Reinstall HolyCodex."));
5012
- checks.push(preset === void 0 || tableInteger(config, "agents", "max_threads") !== preset.usage.maxThreads || tableInteger(config, "agents", "max_depth") !== preset.usage.maxDepth ? check("agent-usage", "error", "agent-usage-stale", "Agent concurrency configuration does not match the selected routing plan.", "Reinstall HolyCodex.") : check("agent-usage", "ok", "agent-usage-ready", "Agent concurrency matches the selected routing plan."));
4978
+ checks.push(preset === void 0 || expectedMaxSubagents === void 0 || tableInteger(config, "agents", "max_threads") !== expectedMaxSubagents + 1 || tableInteger(config, "agents", "max_depth") !== preset.usage.maxDepth ? check("agent-usage", "error", "agent-usage-stale", "Agent concurrency configuration does not match the selected routing plan or explicit override.", "Reinstall HolyCodex.") : check("agent-usage", "ok", "agent-usage-ready", `Agent concurrency allows ${expectedMaxSubagents} direct subagent${expectedMaxSubagents === 1 ? "" : "s"}.`));
5013
4979
  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."));
5014
4980
  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."));
5015
4981
  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."));
@@ -5078,13 +5044,7 @@ async function readText(path) {
5078
5044
  //#region packages/cli/src/install.ts
5079
5045
  var defaultRuntime = {
5080
5046
  platform: process.platform,
5081
- gitBash: resolveGitBashForCurrentProcess,
5082
- packageRunner: detectPackageRunner(),
5083
- installCodexSlimEdit: async (packageRunner) => installCodexSlimEdit({
5084
- packageRunner,
5085
- packageVersion: VERSION,
5086
- platform: process.platform
5087
- })
5047
+ gitBash: resolveGitBashForCurrentProcess
5088
5048
  };
5089
5049
  function paths(home = process.env.CODEX_HOME ?? join(homedir(), ".codex")) {
5090
5050
  const marketplaceCache = join(home, "plugins", "cache", "holycodex");
@@ -5114,7 +5074,6 @@ function assertGitBashReady(platform, resolution) {
5114
5074
  /** Provides install. */
5115
5075
  async function install(options, runtime = defaultRuntime) {
5116
5076
  assertGitBashReady(runtime.platform, runtime.gitBash());
5117
- await runtime.installCodexSlimEdit(runtime.packageRunner);
5118
5077
  const plan = options.plan ?? "plus";
5119
5078
  const target = paths();
5120
5079
  const root = backupRoot();
@@ -5126,7 +5085,8 @@ async function install(options, runtime = defaultRuntime) {
5126
5085
  ].filter((path) => path !== void 0);
5127
5086
  const existingConfig = await readText(target.config);
5128
5087
  const previousPlan = readManagedPlan(existingConfig);
5129
- const config = installConfig(existingConfig, options.autonomy, runtime.platform, plan);
5088
+ const maxSubagents = options.maxSubagents ?? MODEL_ROUTING_PLANS[plan].usage.maxSubagents;
5089
+ const config = installConfig(existingConfig, options.autonomy, runtime.platform, plan, options.maxSubagents);
5130
5090
  await atomicWrite(target.config, config);
5131
5091
  await rm(target.marketplaceCache, {
5132
5092
  recursive: true,
@@ -5134,7 +5094,7 @@ async function install(options, runtime = defaultRuntime) {
5134
5094
  });
5135
5095
  await mkdir(dirname(target.cache), { recursive: true });
5136
5096
  await cp(pluginRoot, target.cache, { recursive: true });
5137
- await writePlatformPlugin(target.cache, runtime.platform, plan, runtime.packageRunner);
5097
+ await writePlatformPlugin(target.cache, runtime.platform, plan);
5138
5098
  const existingAgentPreferences = await readAgentPreferences(target.agents, previousPlan);
5139
5099
  await rm(target.agents, {
5140
5100
  recursive: true,
@@ -5158,7 +5118,8 @@ async function install(options, runtime = defaultRuntime) {
5158
5118
  ...removedLegacy
5159
5119
  ],
5160
5120
  backups,
5161
- plan
5121
+ plan,
5122
+ maxSubagents
5162
5123
  };
5163
5124
  }
5164
5125
  async function readAgentPreferences(root, previousPlan) {
@@ -5189,8 +5150,8 @@ async function preserveAgentPreferences(root, preferences) {
5189
5150
  function replaceTomlString(input, key, value) {
5190
5151
  return input.replace(new RegExp(`^${key}\\s*=.*$`, "m"), `${key} = ${JSON.stringify(value)}`);
5191
5152
  }
5192
- async function writePlatformPlugin(root, platform, plan, packageRunner) {
5193
- await atomicWrite(join(root, ".mcp.json"), `${JSON.stringify({ mcpServers: effectiveMcpServers(platform, packageRunner) }, null, 2)}\n`);
5153
+ async function writePlatformPlugin(root, platform, plan) {
5154
+ await atomicWrite(join(root, ".mcp.json"), `${JSON.stringify({ mcpServers: effectiveMcpServers(platform) }, null, 2)}\n`);
5194
5155
  await writeInstalledAgents(join(root, "agents"), platform, plan);
5195
5156
  }
5196
5157
  async function writeInstalledAgents(root, platform, plan) {
@@ -5270,13 +5231,13 @@ function renderHelp(version, color) {
5270
5231
  const title = paint(color, `${BOLD}${CYAN}`, `HOLYCODEX ${version}`);
5271
5232
  const section = (text) => paint(color, BOLD, text);
5272
5233
  const muted = (text) => paint(color, DIM, text);
5273
- 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 -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 --json Print machine-readable output\n`;
5234
+ 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 <0-3> Override concurrent direct subagents for install\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 --json Print machine-readable output\n`;
5274
5235
  }
5275
5236
  /** Renders install-specific model plan and option help. */
5276
5237
  function renderInstallHelp(version, color) {
5277
5238
  const title = paint(color, `${BOLD}${CYAN}`, `HOLYCODEX ${version}`);
5278
5239
  const section = (text) => paint(color, BOLD, text);
5279
- 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 --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.\n\n${section("Examples:")}\n bunx holycodex install\n bunx holycodex install --plan go\n bunx holycodex install --plan plus-low\n bunx holycodex install --plan plus-high\n bunx holycodex install --plan pro-5x\n bunx holycodex install --plan pro-20x\n`;
5240
+ 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 <0-3> Override concurrent direct subagents\n --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.\n\n${section("Examples:")}\n bunx holycodex install\n bunx holycodex install --plan go\n bunx holycodex install --plan plus-low\n bunx holycodex install --plan plus-high\n bunx holycodex install --plan pro-5x\n bunx holycodex install --plan pro-20x\n`;
5280
5241
  }
5281
5242
  /** Renders error. */
5282
5243
  function renderError(message, color) {
@@ -5304,7 +5265,7 @@ async function main() {
5304
5265
  const args = process$1.argv.slice(2);
5305
5266
  const stdoutColor = supportsColor(process$1.stdout.isTTY, process$1.env.NO_COLOR);
5306
5267
  const stderrColor = supportsColor(process$1.stderr.isTTY, process$1.env.NO_COLOR);
5307
- const command = args.find((arg, index) => !arg.startsWith("-") && args[index - 1] !== "--plan");
5268
+ const command = args.find((arg, index) => !arg.startsWith("-") && args[index - 1] !== "--plan" && args[index - 1] !== "--max-subagents");
5308
5269
  if (args.includes("--help") || args.includes("-h") || args.length === 0) {
5309
5270
  process$1.stdout.write(command === "install" ? renderInstallHelp(VERSION, stdoutColor) : renderHelp(VERSION, stdoutColor));
5310
5271
  return;
@@ -5320,6 +5281,12 @@ async function main() {
5320
5281
  const parsedPlan = PlanNameSchema.safeParse(planValue);
5321
5282
  if (!parsedPlan.success) throw new Error(`Unknown plan: ${planValue}. Valid plans: ${PLAN_NAMES.join(", ")}.`);
5322
5283
  const plan = parsedPlan.data;
5284
+ if (args.flatMap((arg, index) => arg === "--max-subagents" ? [index] : []).length > 1) throw new Error("--max-subagents may be specified only once.");
5285
+ const maxSubagentsIndex = args.indexOf("--max-subagents");
5286
+ const maxSubagentsValue = maxSubagentsIndex < 0 ? void 0 : args[maxSubagentsIndex + 1];
5287
+ if (maxSubagentsIndex >= 0 && (maxSubagentsValue === void 0 || maxSubagentsValue.startsWith("-") || maxSubagentsValue === command)) throw new Error("Missing --max-subagents value. Valid range: 0-3.");
5288
+ if (maxSubagentsValue !== void 0 && !/^[0-3]$/.test(maxSubagentsValue)) throw new Error(`Invalid --max-subagents value: ${maxSubagentsValue}. Valid range: 0-3.`);
5289
+ const maxSubagents = maxSubagentsValue === void 0 ? void 0 : Number(maxSubagentsValue);
5323
5290
  const autonomyFlags = args.filter((arg) => [
5324
5291
  "--codex-autonomous",
5325
5292
  "--no-codex-autonomous",
@@ -5333,7 +5300,8 @@ async function main() {
5333
5300
  const options = {
5334
5301
  autonomy: args.includes("--dangerous-codex-autonomous") ? "dangerous" : args.includes("--codex-autonomous") ? "autonomous" : "default",
5335
5302
  json: args.includes("--json"),
5336
- plan
5303
+ plan,
5304
+ ...maxSubagents === void 0 ? {} : { maxSubagents }
5337
5305
  };
5338
5306
  if (command === "doctor") {
5339
5307
  const result = await doctor();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "holycodex",
3
- "version": "0.8.1",
3
+ "version": "0.8.2-dev.29763019035.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.8.1",
42
+ "@holycodex/plugin": "0.8.2-dev.29763019035.1",
43
43
  "zod": "^4.4.3"
44
44
  },
45
45
  "engines": {