holycodex 0.10.2 → 0.10.3

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 +4 -0
  2. package/dist/cli.js +253 -25
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -9,4 +9,8 @@ bunx holycodex@dev doctor
9
9
 
10
10
  Use `holycodex --help` for commands, autonomy options, and service tiers. `--fast` selects the fast tier; `--no-fast` or omitting both tier flags selects the default. Stable releases use `bunx holycodex`; development releases use npm's `dev` dist-tag.
11
11
 
12
+ Default and `--no-codex-autonomous` installs use Codex Approve for me semantics: `approval_policy = "on-request"`, `approvals_reviewer = "auto_review"`, and `sandbox_mode = "workspace-write"`. Autonomous modes omit the reviewer and retain their documented sandbox behavior. The optional `holycodex-config` permission profile remains available without forcing `default_permissions`, so users may select Full access or another profile.
13
+
14
+ Install also attempts to add or enable the official `codex-security@openai-curated` plugin through structured Codex CLI commands. External availability failures are non-fatal and reported in human and JSON results. Cleanup leaves this independent official plugin installed. Build Web Apps remains separately managed by Codex.
15
+
12
16
  Repository, documentation, license, and security notices: https://github.com/davidbasilefilho/holycodex
package/dist/cli.js CHANGED
@@ -614,6 +614,7 @@ var string$1 = (params) => {
614
614
  };
615
615
  var integer = /^-?\d+$/;
616
616
  var number$1 = /^-?\d+(?:\.\d+)?$/;
617
+ var boolean$1 = /^(?:true|false)$/i;
617
618
  var lowercase = /^[^A-Z]*$/;
618
619
  var uppercase = /^[^a-z]*$/;
619
620
  //#endregion
@@ -1408,6 +1409,24 @@ var $ZodNumberFormat = /*@__PURE__*/ $constructor("$ZodNumberFormat", (inst, def
1408
1409
  $ZodCheckNumberFormat.init(inst, def);
1409
1410
  $ZodNumber.init(inst, def);
1410
1411
  });
1412
+ var $ZodBoolean = /*@__PURE__*/ $constructor("$ZodBoolean", (inst, def) => {
1413
+ $ZodType.init(inst, def);
1414
+ inst._zod.pattern = boolean$1;
1415
+ inst._zod.parse = (payload, _ctx) => {
1416
+ if (def.coerce) try {
1417
+ payload.value = Boolean(payload.value);
1418
+ } catch (_) {}
1419
+ const input = payload.value;
1420
+ if (typeof input === "boolean") return payload;
1421
+ payload.issues.push({
1422
+ expected: "boolean",
1423
+ code: "invalid_type",
1424
+ input,
1425
+ inst
1426
+ });
1427
+ return payload;
1428
+ };
1429
+ });
1411
1430
  var $ZodUnknown = /*@__PURE__*/ $constructor("$ZodUnknown", (inst, def) => {
1412
1431
  $ZodType.init(inst, def);
1413
1432
  inst._zod.parse = (payload) => payload;
@@ -2623,6 +2642,13 @@ function _int(Class, params) {
2623
2642
  });
2624
2643
  }
2625
2644
  // @__NO_SIDE_EFFECTS__
2645
+ function _boolean(Class, params) {
2646
+ return new Class({
2647
+ type: "boolean",
2648
+ ...normalizeParams(params)
2649
+ });
2650
+ }
2651
+ // @__NO_SIDE_EFFECTS__
2626
2652
  function _unknown(Class) {
2627
2653
  return new Class({ type: "unknown" });
2628
2654
  }
@@ -3168,6 +3194,9 @@ var numberProcessor = (schema, ctx, _json, _params) => {
3168
3194
  else if (typeof maximum === "number") json.maximum = maximum;
3169
3195
  if (typeof multipleOf === "number") json.multipleOf = multipleOf;
3170
3196
  };
3197
+ var booleanProcessor = (_schema, _ctx, json, _params) => {
3198
+ json.type = "boolean";
3199
+ };
3171
3200
  var neverProcessor = (_schema, _ctx, json, _params) => {
3172
3201
  json.not = {};
3173
3202
  };
@@ -3851,6 +3880,14 @@ var ZodNumberFormat = /*@__PURE__*/ $constructor("ZodNumberFormat", (inst, def)
3851
3880
  function int(params) {
3852
3881
  return /* @__PURE__ */ _int(ZodNumberFormat, params);
3853
3882
  }
3883
+ var ZodBoolean = /*@__PURE__*/ $constructor("ZodBoolean", (inst, def) => {
3884
+ $ZodBoolean.init(inst, def);
3885
+ ZodType.init(inst, def);
3886
+ inst._zod.processJSONSchema = (ctx, json, params) => booleanProcessor(inst, ctx, json, params);
3887
+ });
3888
+ function boolean(params) {
3889
+ return /* @__PURE__ */ _boolean(ZodBoolean, params);
3890
+ }
3854
3891
  var ZodUnknown = /*@__PURE__*/ $constructor("ZodUnknown", (inst, def) => {
3855
3892
  $ZodUnknown.init(inst, def);
3856
3893
  ZodType.init(inst, def);
@@ -4252,7 +4289,7 @@ function superRefine(fn, params) {
4252
4289
  }
4253
4290
  //#endregion
4254
4291
  //#region packages/cli/src/catalog.ts
4255
- var VERSION = "0.10.2";
4292
+ var VERSION = "0.10.3";
4256
4293
  var SKILLS = [
4257
4294
  "ast-grep",
4258
4295
  "caveman",
@@ -4804,17 +4841,46 @@ var defaultManagedProcessRuntime = {
4804
4841
  /** Runs managed process. */
4805
4842
  async function runManagedProcess(input, runtime = defaultManagedProcessRuntime) {
4806
4843
  return await new Promise((resolve) => {
4807
- const child = spawn(input.command, [...input.args], {
4808
- ...input.cwd === void 0 ? {} : { cwd: input.cwd },
4809
- ...input.env === void 0 ? {} : { env: input.env },
4810
- stdio: [
4811
- "pipe",
4812
- "pipe",
4813
- "pipe"
4814
- ],
4815
- windowsHide: true,
4816
- detached: input.platform !== "win32"
4817
- });
4844
+ let child;
4845
+ try {
4846
+ child = (runtime.spawnChild ?? spawn)(input.command, [...input.args], {
4847
+ ...input.cwd === void 0 ? {} : { cwd: input.cwd },
4848
+ ...input.env === void 0 ? {} : { env: input.env },
4849
+ stdio: [
4850
+ "pipe",
4851
+ "pipe",
4852
+ "pipe"
4853
+ ],
4854
+ windowsHide: true,
4855
+ detached: input.platform !== "win32"
4856
+ });
4857
+ } catch (error) {
4858
+ resolve({
4859
+ exitCode: null,
4860
+ stdout: "",
4861
+ stderr: "",
4862
+ timedOut: false,
4863
+ matched: false,
4864
+ outputTruncated: false,
4865
+ error: error instanceof Error ? error.message : String(error)
4866
+ });
4867
+ return;
4868
+ }
4869
+ const childStdin = child.stdin;
4870
+ const childStdout = child.stdout;
4871
+ const childStderr = child.stderr;
4872
+ if (childStdin === null || childStdout === null || childStderr === null) {
4873
+ resolve({
4874
+ exitCode: null,
4875
+ stdout: "",
4876
+ stderr: "",
4877
+ timedOut: false,
4878
+ matched: false,
4879
+ outputTruncated: false,
4880
+ error: "Managed process did not expose piped standard streams."
4881
+ });
4882
+ return;
4883
+ }
4818
4884
  let stdout = {
4819
4885
  head: "",
4820
4886
  tail: "",
@@ -4859,11 +4925,11 @@ async function runManagedProcess(input, runtime = defaultManagedProcessRuntime)
4859
4925
  terminate();
4860
4926
  }
4861
4927
  };
4862
- child.stdout.on("data", (chunk) => {
4928
+ childStdout.on("data", (chunk) => {
4863
4929
  stdout = appendOutput(stdout, chunk.toString(), input.maxOutputChars);
4864
4930
  inspectMatch();
4865
4931
  });
4866
- child.stderr.on("data", (chunk) => {
4932
+ childStderr.on("data", (chunk) => {
4867
4933
  stderr = appendOutput(stderr, chunk.toString(), input.maxOutputChars);
4868
4934
  inspectMatch();
4869
4935
  });
@@ -4874,8 +4940,8 @@ async function runManagedProcess(input, runtime = defaultManagedProcessRuntime)
4874
4940
  terminate();
4875
4941
  }, input.timeoutMs);
4876
4942
  timeout.unref();
4877
- if (input.stdin === void 0) child.stdin.end();
4878
- else child.stdin.end(input.stdin);
4943
+ if (input.stdin === void 0) childStdin.end();
4944
+ else childStdin.end(input.stdin);
4879
4945
  });
4880
4946
  }
4881
4947
  /** Terminates process tree. */
@@ -5167,8 +5233,8 @@ function installConfig(input, mode, _platform, plan = DEFAULT_PLAN, maxSubagents
5167
5233
  const tables = firstTable < 0 ? "" : base.slice(firstTable);
5168
5234
  const controlled = [
5169
5235
  "approval_policy",
5236
+ "approvals_reviewer",
5170
5237
  "sandbox_mode",
5171
- "default_permissions",
5172
5238
  "max_concurrent_threads_per_session",
5173
5239
  "status_line",
5174
5240
  "model_verbosity",
@@ -5176,8 +5242,8 @@ function installConfig(input, mode, _platform, plan = DEFAULT_PLAN, maxSubagents
5176
5242
  ].map((key) => rootValue(root, key));
5177
5243
  const preservedRoot = [
5178
5244
  "approval_policy",
5245
+ "approvals_reviewer",
5179
5246
  "sandbox_mode",
5180
- "default_permissions",
5181
5247
  "max_concurrent_threads_per_session",
5182
5248
  "status_line",
5183
5249
  "model_verbosity",
@@ -5191,9 +5257,10 @@ function installConfig(input, mode, _platform, plan = DEFAULT_PLAN, maxSubagents
5191
5257
  const model = hasModel ? "" : `model = "${rootRoute.model}"\n`;
5192
5258
  const effort = hasEffort ? "" : `model_reasoning_effort = "${rootRoute.reasoningEffort}"\n`;
5193
5259
  const approval = mode === "default" ? "on-request" : "never";
5260
+ const approvalsReviewer = mode === "default" ? "approvals_reviewer = \"auto_review\"\n" : "";
5194
5261
  const sandbox = mode === "dangerous" ? "danger-full-access" : "workspace-write";
5195
5262
  const original = originalControlled ? `${ORIGINAL_ROOT}${Buffer.from(originalControlled).toString("base64")}\n` : "";
5196
- const rootBlock = `${START}\n${PLAN_PREFIX}${plan}\n${FAST_MODE_PREFIX}${fastMode}\n${maxSubagents === void 0 ? "" : `${MAX_SUBAGENTS_PREFIX}${maxSubagents}\n`}${original}${model}${effort}model_verbosity = "low"\nservice_tier = "${fastMode === "fast-all" ? "fast" : "default"}"\napproval_policy = "${approval}"\nsandbox_mode = "${sandbox}"\ndefault_permissions = "${MANAGED_PERMISSION_PROFILE}"\nstatus_line = ${mergedStatusLine(rootValue(root, "status_line"))}\n${END}`;
5263
+ const rootBlock = `${START}\n${PLAN_PREFIX}${plan}\n${FAST_MODE_PREFIX}${fastMode}\n${maxSubagents === void 0 ? "" : `${MAX_SUBAGENTS_PREFIX}${maxSubagents}\n`}${original}${model}${effort}model_verbosity = "low"\nservice_tier = "${fastMode === "fast-all" ? "fast" : "default"}"\napproval_policy = "${approval}"\n${approvalsReviewer}sandbox_mode = "${sandbox}"\nstatus_line = ${mergedStatusLine(rootValue(root, "status_line"))}\n${END}`;
5197
5264
  let configured = `${preservedRoot ? `${preservedRoot}\n` : ""}${rootBlock}${tables ? `\n\n${tables}` : ""}`;
5198
5265
  configured = injectTableKeys(configured, `permissions.${MANAGED_PERMISSION_PROFILE}`, [["description", "\"HolyCodex config.toml permissions.\""], ["extends", "\":workspace\""]]);
5199
5266
  configured = injectTableKeys(configured, `permissions.${MANAGED_PERMISSION_PROFILE}.network`, [["enabled", "true"]]);
@@ -5309,11 +5376,12 @@ function tableInteger(config, table, key) {
5309
5376
  }
5310
5377
  function autonomy(config) {
5311
5378
  const approval = rootTomlString(config, "approval_policy");
5379
+ const approvalsReviewer = rootTomlString(config, "approvals_reviewer");
5312
5380
  const sandbox = rootTomlString(config, "sandbox_mode");
5313
5381
  const network = tableBoolean(config, "sandbox_workspace_write", "network_access");
5314
- if (approval === "on-request" && sandbox === "workspace-write" && network === true) return "safe-workspace";
5315
- if (approval === "never" && sandbox === "workspace-write" && network === true) return "autonomous-workspace";
5316
- if (approval === "never" && sandbox === "danger-full-access") return "dangerous";
5382
+ if (approval === "on-request" && approvalsReviewer === "auto_review" && sandbox === "workspace-write" && network === true) return "safe-workspace";
5383
+ if (approval === "never" && approvalsReviewer === void 0 && sandbox === "workspace-write" && network === true) return "autonomous-workspace";
5384
+ if (approval === "never" && approvalsReviewer === void 0 && sandbox === "danger-full-access") return "dangerous";
5317
5385
  return "unknown";
5318
5386
  }
5319
5387
  /** Runs HolyCodex installation and environment health checks. */
@@ -5396,7 +5464,7 @@ async function doctor(home = process.env.CODEX_HOME ?? join(homedir(), ".codex")
5396
5464
  checks.push(["default", "fast"].includes(rootTomlString(config, "service_tier") ?? "") && (managedFastMode === void 0 || rootTomlString(config, "service_tier") === (managedFastMode === "fast-all" ? "fast" : "default")) ? check("service-tier", "ok", "service-tier-ready", "Codex service tier is explicitly managed.") : check("service-tier", "error", "service-tier-stale", "service_tier does not match the managed Fast mode.", "Reinstall HolyCodex with --fast, --fast-all, or --no-fast."));
5397
5465
  checks.push(rootTomlString(config, "model_verbosity") === "low" ? check("root-verbosity", "ok", "root-verbosity-ready", "Root model verbosity is forced to low.") : check("root-verbosity", "error", "root-verbosity-stale", "Root model verbosity must be low.", "Reinstall HolyCodex."));
5398
5466
  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"}.`));
5399
- 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."));
5467
+ checks.push(mode === "unknown" ? check("autonomy", "error", "invalid-autonomy-config", "Approval policy, approval reviewer, 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."));
5400
5468
  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."));
5401
5469
  checks.push(tableStringArray(config, "desktop", "enabled-reasoning-efforts")?.join(",") === "low,medium,high" ? check("desktop-reasoning", "ok", "desktop-reasoning-ready", "Desktop exposes low, medium, and high reasoning efforts.") : check("desktop-reasoning", "error", "desktop-reasoning-stale", "Desktop reasoning choices must be low, medium, and high.", "Reinstall HolyCodex."));
5402
5470
  checks.push(tableBoolean(config, "desktop", "show-context-window-usage") === true ? check("desktop-context-usage", "ok", "desktop-context-usage-ready", "Desktop context-window usage is visible.") : check("desktop-context-usage", "error", "desktop-context-usage-hidden", "Desktop context-window usage is not enabled.", "Reinstall HolyCodex."));
@@ -5424,6 +5492,156 @@ async function doctor(home = process.env.CODEX_HOME ?? join(homedir(), ".codex")
5424
5492
  };
5425
5493
  }
5426
5494
  //#endregion
5495
+ //#region packages/cli/src/codex-security.ts
5496
+ var CODEX_SECURITY_PLUGIN = "codex-security@openai-curated";
5497
+ var CODEX_PLUGIN_TIMEOUT_MS = 2e4;
5498
+ var MAX_CODEX_OUTPUT_CHARS = 64 * 1024;
5499
+ var PluginEntrySchema = looseObject({
5500
+ pluginId: string(),
5501
+ installed: boolean().optional(),
5502
+ enabled: boolean().optional()
5503
+ });
5504
+ var PluginListSchema = looseObject({
5505
+ installed: array(PluginEntrySchema),
5506
+ available: array(PluginEntrySchema)
5507
+ });
5508
+ var PluginAddSchema = looseObject({ pluginId: string() });
5509
+ /** Installs or enables the official Codex Security plugin without failing HolyCodex installation. */
5510
+ async function installCodexSecurity(runProcess = runManagedProcess, platform = process.platform, env = process.env) {
5511
+ const listed = await runCodexPlugin(runProcess, [
5512
+ "plugin",
5513
+ "list",
5514
+ "--available",
5515
+ "--json"
5516
+ ], platform, env);
5517
+ const listFailure = externalFailure(listed);
5518
+ if (listFailure !== void 0) return listFailure;
5519
+ const parsedList = parseJson(listed.stdout, PluginListSchema);
5520
+ if (parsedList === void 0) return skipped("invalid-response");
5521
+ const installed = parsedList.installed.find((plugin) => plugin.pluginId === CODEX_SECURITY_PLUGIN);
5522
+ if (installed?.installed === true && installed.enabled === true) return { status: "already-installed" };
5523
+ const wasDisabled = installed?.installed === true;
5524
+ const available = parsedList.available.some((plugin) => plugin.pluginId === CODEX_SECURITY_PLUGIN);
5525
+ if (!wasDisabled && !available) return skipped("plugin-unavailable");
5526
+ const added = await runCodexPlugin(runProcess, [
5527
+ "plugin",
5528
+ "add",
5529
+ CODEX_SECURITY_PLUGIN,
5530
+ "--json"
5531
+ ], platform, env);
5532
+ const addFailure = externalFailure(added);
5533
+ if (addFailure !== void 0) return addFailure;
5534
+ if (parseJson(added.stdout, PluginAddSchema)?.pluginId !== CODEX_SECURITY_PLUGIN) return skipped("invalid-response");
5535
+ return { status: wasDisabled ? "enabled" : "installed" };
5536
+ }
5537
+ async function runCodexPlugin(runProcess, args, platform, env) {
5538
+ try {
5539
+ return await runProcess({
5540
+ command: "codex",
5541
+ args,
5542
+ platform,
5543
+ timeoutMs: CODEX_PLUGIN_TIMEOUT_MS,
5544
+ maxOutputChars: MAX_CODEX_OUTPUT_CHARS,
5545
+ env
5546
+ });
5547
+ } catch (error) {
5548
+ if (!isUnavailableProcessError(error)) throw error;
5549
+ return {
5550
+ exitCode: null,
5551
+ stdout: "",
5552
+ stderr: "",
5553
+ timedOut: false,
5554
+ matched: false,
5555
+ outputTruncated: false,
5556
+ error: "Codex executable unavailable."
5557
+ };
5558
+ }
5559
+ }
5560
+ function externalFailure(result) {
5561
+ if (result.timedOut) return skipped("timeout");
5562
+ if (result.error !== void 0) return skipped("codex-unavailable");
5563
+ if (result.exitCode === 0) return void 0;
5564
+ const diagnostic = parseUnknownJson(result.stderr) ?? parseUnknownJson(result.stdout);
5565
+ if (diagnostic === void 0) return skipped("invalid-response");
5566
+ return skipped(classifyStructuredFailure(diagnostic));
5567
+ }
5568
+ function classifyStructuredFailure(value) {
5569
+ const code = structuredErrorCode(value);
5570
+ if (code === void 0) return "invalid-response";
5571
+ if ([
5572
+ "401",
5573
+ "UNAUTHENTICATED",
5574
+ "AUTHENTICATION_REQUIRED"
5575
+ ].includes(code)) return "unauthenticated";
5576
+ if ([
5577
+ "502",
5578
+ "503",
5579
+ "504",
5580
+ "MARKETPLACE_UNAVAILABLE",
5581
+ "MARKETPLACE_LOAD_FAILED",
5582
+ "CATALOG_UNAVAILABLE"
5583
+ ].includes(code)) return "marketplace-unavailable";
5584
+ if ([
5585
+ "404",
5586
+ "PLUGIN_NOT_FOUND",
5587
+ "PLUGIN_UNAVAILABLE"
5588
+ ].includes(code)) return "plugin-unavailable";
5589
+ if ([
5590
+ "403",
5591
+ "INSTALLATION_REJECTED",
5592
+ "PERMISSION_DENIED",
5593
+ "POLICY_REJECTED",
5594
+ "ACCOUNT_RESTRICTED"
5595
+ ].includes(code)) return "installation-rejected";
5596
+ return "invalid-response";
5597
+ }
5598
+ function structuredErrorCode(value) {
5599
+ if (!isRecord(value)) return void 0;
5600
+ const nested = value.error;
5601
+ if (nested !== void 0) {
5602
+ const nestedCode = structuredErrorCode(nested);
5603
+ if (nestedCode !== void 0) return nestedCode;
5604
+ }
5605
+ for (const key of [
5606
+ "code",
5607
+ "status",
5608
+ "statusCode"
5609
+ ]) {
5610
+ const candidate = value[key];
5611
+ if (typeof candidate === "string" || typeof candidate === "number") return String(candidate).trim().toUpperCase();
5612
+ }
5613
+ }
5614
+ function parseJson(input, schema) {
5615
+ const value = parseUnknownJson(input);
5616
+ if (value === void 0) return void 0;
5617
+ const parsed = schema.safeParse(value);
5618
+ return parsed.success ? parsed.data : void 0;
5619
+ }
5620
+ function parseUnknownJson(input) {
5621
+ try {
5622
+ return JSON.parse(input);
5623
+ } catch {
5624
+ return;
5625
+ }
5626
+ }
5627
+ function isRecord(value) {
5628
+ return typeof value === "object" && value !== null;
5629
+ }
5630
+ function isUnavailableProcessError(value) {
5631
+ if (!isRecord(value)) return false;
5632
+ return [
5633
+ "EACCES",
5634
+ "ENOENT",
5635
+ "EPERM"
5636
+ ].includes(String(value.code).toUpperCase());
5637
+ }
5638
+ function skipped(reason) {
5639
+ return {
5640
+ status: "skipped",
5641
+ reason
5642
+ };
5643
+ }
5644
+ //#endregion
5427
5645
  //#region packages/cli/src/files.ts
5428
5646
  /** Provides exists. */
5429
5647
  async function exists(path) {
@@ -5471,7 +5689,8 @@ async function readText(path) {
5471
5689
  //#region packages/cli/src/install.ts
5472
5690
  var defaultRuntime = {
5473
5691
  platform: process.platform,
5474
- gitBash: resolveGitBashForCurrentProcess
5692
+ gitBash: resolveGitBashForCurrentProcess,
5693
+ runProcess: runManagedProcess
5475
5694
  };
5476
5695
  function paths(home = process.env.CODEX_HOME ?? join(homedir(), ".codex")) {
5477
5696
  const marketplaceCache = join(home, "plugins", "cache", "holycodex");
@@ -5536,6 +5755,7 @@ async function install(options, runtime = defaultRuntime) {
5536
5755
  await rm(path, { recursive: true });
5537
5756
  removedLegacy.push(path);
5538
5757
  }
5758
+ const codexSecurity = await installCodexSecurity(runtime.runProcess, runtime.platform, process.env);
5539
5759
  return {
5540
5760
  action: "install",
5541
5761
  changed: [
@@ -5546,6 +5766,7 @@ async function install(options, runtime = defaultRuntime) {
5546
5766
  ],
5547
5767
  backups,
5548
5768
  plan,
5769
+ codexSecurity,
5549
5770
  ...options.maxSubagents === void 0 ? {} : { maxSubagents: options.maxSubagents }
5550
5771
  };
5551
5772
  }
@@ -5728,7 +5949,14 @@ function renderRunResult(result, color) {
5728
5949
  const action = result.action === "install" ? "Updated" : "Removed";
5729
5950
  const empty = result.action === "install" ? "changes" : "removal";
5730
5951
  const backup = result.backups.length === 0 ? "" : `\n Existing HolyCodex files were backed up before ${result.action === "install" ? "replacement" : "cleanup"}.`;
5731
- return `${title}\n ${result.changed.length === 0 ? `No HolyCodex-managed files needed ${empty}.` : `${action} HolyCodex configuration, plugin files, and agent profiles.`}${backup}\n`;
5952
+ return `${title}\n ${result.changed.length === 0 ? `No HolyCodex-managed files needed ${empty}.` : `${action} HolyCodex configuration, plugin files, and agent profiles.`}${backup}${renderCodexSecurity(result)}\n`;
5953
+ }
5954
+ function renderCodexSecurity(result) {
5955
+ if (result.codexSecurity === void 0) return "";
5956
+ if (result.codexSecurity.status === "installed") return "\n Installed official Codex Security plugin.";
5957
+ if (result.codexSecurity.status === "enabled") return "\n Enabled existing official Codex Security plugin.";
5958
+ if (result.codexSecurity.status === "already-installed") return "\n Official Codex Security plugin is already installed and enabled.";
5959
+ return `\n Skipped official Codex Security plugin: ${result.codexSecurity.reason}.`;
5732
5960
  }
5733
5961
  /** Renders notice. */
5734
5962
  function renderNotice(kind, message, color) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "holycodex",
3
- "version": "0.10.2",
3
+ "version": "0.10.3",
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.10.2",
42
+ "@holycodex/plugin": "0.10.3",
43
43
  "zod": "^4.4.3"
44
44
  },
45
45
  "engines": {