lazycodex-ai 5.1.3 → 5.1.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 (63) hide show
  1. package/dist/cli/index.js +599 -191
  2. package/dist/cli-node/index.js +599 -191
  3. package/package.json +1 -1
  4. package/packages/lsp-daemon/dist/cli.js +2 -1
  5. package/packages/lsp-daemon/dist/client.js +2 -1
  6. package/packages/lsp-daemon/dist/index.js +2 -1
  7. package/packages/lsp-tools-mcp/dist/cli.js +2 -1
  8. package/packages/lsp-tools-mcp/dist/mcp.js +2 -1
  9. package/packages/lsp-tools-mcp/dist/tools.js +2 -1
  10. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
  11. package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +309 -133
  12. package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
  13. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  14. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
  15. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  16. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
  17. package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
  18. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
  19. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
  20. package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +4 -4
  21. package/packages/omo-codex/plugin/components/lsp/dist/cli.js +141 -107
  22. package/packages/omo-codex/plugin/components/lsp/dist/lsp-session-state.js +2 -2
  23. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
  24. package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
  25. package/packages/omo-codex/plugin/components/lsp/src/lsp-session-state.ts +2 -2
  26. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
  27. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  28. package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
  29. package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
  30. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
  31. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  32. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
  33. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
  34. package/packages/omo-codex/plugin/components/ulw-execute-continuation/hooks/hooks.json +1 -1
  35. package/packages/omo-codex/plugin/components/ulw-execute-continuation/package.json +1 -1
  36. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +5 -5
  37. package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
  38. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
  39. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
  40. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
  41. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
  42. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
  43. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
  44. package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
  45. package/packages/omo-codex/plugin/hooks/post-tool-use-recording-spawn-admission.json +1 -1
  46. package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
  47. package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
  48. package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
  49. package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
  50. package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
  51. package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
  52. package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
  53. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-execute-continuation.json +1 -1
  54. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
  55. package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
  56. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
  57. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
  58. package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
  59. package/packages/omo-codex/plugin/package-lock.json +12 -12
  60. package/packages/omo-codex/plugin/package.json +1 -1
  61. package/packages/omo-codex/plugin/skills/browser/runtime/omowright/manifest.json +1 -1
  62. package/packages/omo-codex/scripts/install-dist/install-local.mjs +311 -135
  63. package/packages/shared-skills/skills/browser/runtime/omowright/manifest.json +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lazycodex-ai",
3
- "version": "5.1.3",
3
+ "version": "5.1.5",
4
4
  "description": "The Best AI Agent Harness - Batteries-Included OpenCode Plugin with Multi-Model Orchestration, Parallel Background Agents, and Crafted LSP/AST Tools",
5
5
  "main": "./dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -5350,7 +5350,8 @@ function missingDependencyAvailability(error) {
5350
5350
  extensions: [...error.lookup.server.extensions],
5351
5351
  installHint: error.lookup.installHint,
5352
5352
  installDecisionTool: context.capabilities.installDecisionTool,
5353
- installDecisionsPath: context.installDecisionsPath
5353
+ installDecisionsPath: context.installDecisionsPath,
5354
+ decision: loadInstallDecision(error.lookup.server.id)?.decision ?? null
5354
5355
  };
5355
5356
  default: {
5356
5357
  const exhaustive = error.lookup;
@@ -5586,7 +5586,8 @@ function missingDependencyAvailability(error) {
5586
5586
  extensions: [...error.lookup.server.extensions],
5587
5587
  installHint: error.lookup.installHint,
5588
5588
  installDecisionTool: context.capabilities.installDecisionTool,
5589
- installDecisionsPath: context.installDecisionsPath
5589
+ installDecisionsPath: context.installDecisionsPath,
5590
+ decision: loadInstallDecision(error.lookup.server.id)?.decision ?? null
5590
5591
  };
5591
5592
  default: {
5592
5593
  const exhaustive = error.lookup;
@@ -5581,7 +5581,8 @@ function missingDependencyAvailability(error) {
5581
5581
  extensions: [...error.lookup.server.extensions],
5582
5582
  installHint: error.lookup.installHint,
5583
5583
  installDecisionTool: context.capabilities.installDecisionTool,
5584
- installDecisionsPath: context.installDecisionsPath
5584
+ installDecisionsPath: context.installDecisionsPath,
5585
+ decision: loadInstallDecision(error.lookup.server.id)?.decision ?? null
5585
5586
  };
5586
5587
  default: {
5587
5588
  const exhaustive = error.lookup;
@@ -4919,7 +4919,8 @@ function missingDependencyAvailability(error) {
4919
4919
  extensions: [...error.lookup.server.extensions],
4920
4920
  installHint: error.lookup.installHint,
4921
4921
  installDecisionTool: context.capabilities.installDecisionTool,
4922
- installDecisionsPath: context.installDecisionsPath
4922
+ installDecisionsPath: context.installDecisionsPath,
4923
+ decision: loadInstallDecision(error.lookup.server.id)?.decision ?? null
4923
4924
  };
4924
4925
  default: {
4925
4926
  const exhaustive = error.lookup;
@@ -4915,7 +4915,8 @@ function missingDependencyAvailability(error) {
4915
4915
  extensions: [...error.lookup.server.extensions],
4916
4916
  installHint: error.lookup.installHint,
4917
4917
  installDecisionTool: context.capabilities.installDecisionTool,
4918
- installDecisionsPath: context.installDecisionsPath
4918
+ installDecisionsPath: context.installDecisionsPath,
4919
+ decision: loadInstallDecision(error.lookup.server.id)?.decision ?? null
4919
4920
  };
4920
4921
  default: {
4921
4922
  const exhaustive = error.lookup;
@@ -4603,7 +4603,8 @@ function missingDependencyAvailability(error) {
4603
4603
  extensions: [...error.lookup.server.extensions],
4604
4604
  installHint: error.lookup.installHint,
4605
4605
  installDecisionTool: context.capabilities.installDecisionTool,
4606
- installDecisionsPath: context.installDecisionsPath
4606
+ installDecisionsPath: context.installDecisionsPath,
4607
+ decision: loadInstallDecision(error.lookup.server.id)?.decision ?? null
4607
4608
  };
4608
4609
  default: {
4609
4610
  const exhaustive = error.lookup;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "omo",
3
- "version": "5.1.3",
3
+ "version": "5.1.5",
4
4
  "description": "One Codex plugin namespace for Yeongyu's local Codex components.",
5
5
  "author": {
6
6
  "name": "Yeongyu Kim",
@@ -6958,7 +6958,6 @@ function normalizeLegacyModelFields(entry) {
6958
6958
  delete normalized["reasoningEffort"];
6959
6959
  delete normalized["thinking"];
6960
6960
  delete normalized["textVerbosity"];
6961
- delete normalized["maxTokens"];
6962
6961
  delete normalized["providerOptions"];
6963
6962
  if (typeof entry["model"] === "string")
6964
6963
  normalized["model"] = canonicalModelString(entry["model"]);
@@ -6976,10 +6975,15 @@ function normalizeLegacyModelFields(entry) {
6976
6975
  providerOptions["textVerbosity"] = entry["textVerbosity"];
6977
6976
  if (Object.keys(providerOptions).length > 0)
6978
6977
  normalized["provider_options"] = providerOptions;
6979
- if (entry["max_tokens"] !== undefined)
6978
+ if (entry["max_tokens"] !== undefined) {
6980
6979
  normalized["max_tokens"] = entry["max_tokens"];
6981
- else if (entry["maxTokens"] !== undefined)
6980
+ if (entry["maxTokens"] === undefined || typeof entry["maxTokens"] === "number") {
6981
+ delete normalized["maxTokens"];
6982
+ }
6983
+ } else if (typeof entry["maxTokens"] === "number") {
6982
6984
  normalized["max_tokens"] = entry["maxTokens"];
6985
+ delete normalized["maxTokens"];
6986
+ }
6983
6987
  return normalized;
6984
6988
  }
6985
6989
  var OmoLegacyFallbackModelObjectInputSchema = object({
@@ -7009,6 +7013,19 @@ function isRecord3(value) {
7009
7013
  return typeof value === "object" && value !== null && !Array.isArray(value);
7010
7014
  }
7011
7015
  var OmoAgentModelEntrySchema = union([string2(), OmoFallbackModelObjectSchema]);
7016
+ var PermissionValueSchema = _enum(["ask", "allow", "deny"]);
7017
+ var BashPermissionSchema = union([
7018
+ PermissionValueSchema,
7019
+ record(string2(), PermissionValueSchema)
7020
+ ]);
7021
+ var OmoAgentPermissionSchema = object({
7022
+ edit: PermissionValueSchema.optional(),
7023
+ bash: BashPermissionSchema.optional(),
7024
+ webfetch: PermissionValueSchema.optional(),
7025
+ task: PermissionValueSchema.optional(),
7026
+ doom_loop: PermissionValueSchema.optional(),
7027
+ external_directory: PermissionValueSchema.optional()
7028
+ }).catchall(PermissionValueSchema.optional());
7012
7029
  var OmoAgentDefInputSchema = object({
7013
7030
  description: string2().optional(),
7014
7031
  prompt: string2().optional(),
@@ -7025,7 +7042,9 @@ var OmoAgentDefInputSchema = object({
7025
7042
  disallowed_tools: array(string2()).optional(),
7026
7043
  max_turns: number2().int().nonnegative().optional(),
7027
7044
  temperature: number2().min(0).max(2).optional(),
7028
- disable: boolean2().optional()
7045
+ disable: boolean2().optional(),
7046
+ permission: OmoAgentPermissionSchema.optional(),
7047
+ prompt_append: string2().optional()
7029
7048
  }).strict();
7030
7049
  var OmoAgentDefSchema = preprocess((value) => isRecord3(value) ? normalizeLegacyModelFields(value) : value, OmoAgentDefInputSchema);
7031
7050
  var OmoAgentsConfigSchema = record(string2(), OmoAgentDefSchema);
@@ -7714,6 +7733,16 @@ function canonicalizeLegacyHarnessBlocks(document) {
7714
7733
  return { document: canonicalized, renames };
7715
7734
  }
7716
7735
 
7736
+ // ../../omo-config-core/src/loader/types.ts
7737
+ import { existsSync as existsSync2, lstatSync, readFileSync, realpathSync } from "node:fs";
7738
+ var MERGED_OMO_CONFIG_PATH = "(merged omo config)";
7739
+ var DEFAULT_READ_FILE_SYSTEM = {
7740
+ existsSync: existsSync2,
7741
+ lstatSync,
7742
+ readFileSync,
7743
+ realpathSync
7744
+ };
7745
+
7717
7746
  // ../../../node_modules/.bun/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/impl/scanner.js
7718
7747
  function createScanner(text, ignoreTrivia = false) {
7719
7748
  const len = text.length;
@@ -8588,6 +8617,255 @@ function mergeOmoConfigRecords(base, override) {
8588
8617
  return result;
8589
8618
  }
8590
8619
 
8620
+ // ../../omo-config-core/src/loader/prune-invalid-leaves.ts
8621
+ var MAX_PRUNE_PASSES = 32;
8622
+ function isContainer(value) {
8623
+ return typeof value === "object" && value !== null;
8624
+ }
8625
+ function childOf(container, segment) {
8626
+ return Array.isArray(container) ? container[Number(segment)] : container[String(segment)];
8627
+ }
8628
+ function hasChild(container, segment) {
8629
+ if (Array.isArray(container)) {
8630
+ const index = Number(segment);
8631
+ return Number.isInteger(index) && index >= 0 && index < container.length;
8632
+ }
8633
+ return Object.hasOwn(container, String(segment));
8634
+ }
8635
+ function segmentsOf(path) {
8636
+ return path.map((segment) => typeof segment === "number" ? segment : String(segment));
8637
+ }
8638
+ function targetPaths(root, issue) {
8639
+ const base = segmentsOf(issue.path);
8640
+ if (issue.code === "unrecognized_keys")
8641
+ return issue.keys.map((key) => [...base, key]);
8642
+ let node = root;
8643
+ let depth = 0;
8644
+ for (const segment of base) {
8645
+ if (!isContainer(node) || !hasChild(node, segment))
8646
+ break;
8647
+ node = childOf(node, segment);
8648
+ depth += 1;
8649
+ }
8650
+ return [base.slice(0, depth)];
8651
+ }
8652
+ function isAncestor(ancestor, path) {
8653
+ return ancestor.length < path.length && ancestor.every((segment, index) => segment === path[index]);
8654
+ }
8655
+ function compareDescending(left, right) {
8656
+ const length = Math.min(left.length, right.length);
8657
+ for (let index = 0;index < length; index += 1) {
8658
+ const a = left[index];
8659
+ const b = right[index];
8660
+ if (a === b)
8661
+ continue;
8662
+ if (typeof a === "number" && typeof b === "number")
8663
+ return b - a;
8664
+ return String(b).localeCompare(String(a));
8665
+ }
8666
+ return right.length - left.length;
8667
+ }
8668
+ function removeChild(container, segment) {
8669
+ if (Array.isArray(container))
8670
+ container.splice(Number(segment), 1);
8671
+ else
8672
+ delete container[String(segment)];
8673
+ }
8674
+ function isEmpty(container) {
8675
+ return Array.isArray(container) ? container.length === 0 : Object.keys(container).length === 0;
8676
+ }
8677
+ function removePathAndEmptiedAncestors(root, path) {
8678
+ const chain = [root];
8679
+ for (const segment of path.slice(0, -1)) {
8680
+ const current = chain[chain.length - 1];
8681
+ if (current === undefined)
8682
+ return;
8683
+ const next = childOf(current, segment);
8684
+ if (!isContainer(next))
8685
+ return;
8686
+ chain.push(next);
8687
+ }
8688
+ for (let depth = path.length - 1;depth >= 0; depth -= 1) {
8689
+ const container = chain[depth];
8690
+ const segment = path[depth];
8691
+ if (container === undefined || segment === undefined)
8692
+ return;
8693
+ removeChild(container, segment);
8694
+ if (depth === 0 || !isEmpty(container))
8695
+ return;
8696
+ }
8697
+ }
8698
+ function prunePass(root, issues) {
8699
+ const byKey = new Map;
8700
+ for (const issue of issues) {
8701
+ for (const path of targetPaths(root, issue)) {
8702
+ if (path.length === 0)
8703
+ return null;
8704
+ const key = path.map((segment) => String(segment)).join(".");
8705
+ if (!byKey.has(key))
8706
+ byKey.set(key, { key, message: issue.message, path });
8707
+ }
8708
+ }
8709
+ const targets = [...byKey.values()];
8710
+ const outermost = targets.filter((target) => !targets.some((other) => isAncestor(other.path, target.path))).sort((left, right) => compareDescending(left.path, right.path));
8711
+ const next = structuredClone(root);
8712
+ for (const target of outermost)
8713
+ removePathAndEmptiedAncestors(next, target.path);
8714
+ return { dropped: outermost, next };
8715
+ }
8716
+ function pruneInvalidConfigPaths(config, issues, validate, maxPasses = MAX_PRUNE_PASSES) {
8717
+ const dropped = [];
8718
+ let current = config;
8719
+ let pending = issues;
8720
+ for (let pass = 0;pass < maxPasses; pass += 1) {
8721
+ const step = prunePass(current, pending);
8722
+ if (step === null || step.dropped.length === 0)
8723
+ return { ok: false, dropped };
8724
+ dropped.push(...step.dropped);
8725
+ current = step.next;
8726
+ if (Object.keys(current).length === 0)
8727
+ return { ok: false, dropped };
8728
+ const validation = validate(current);
8729
+ if (validation.success)
8730
+ return { ok: true, config: current, dropped };
8731
+ pending = validation.issues;
8732
+ }
8733
+ return { ok: false, dropped };
8734
+ }
8735
+
8736
+ // ../../omo-config-core/src/loader/layer-validation.ts
8737
+ function validationDiagnostic(path, issues) {
8738
+ const issuePaths = issues.map((issue) => issue.path.map((segment) => String(segment)).join("."));
8739
+ return {
8740
+ kind: "validation",
8741
+ message: `Invalid omo config at ${path}: ${issuePaths.join(", ")}`,
8742
+ path,
8743
+ issuePaths
8744
+ };
8745
+ }
8746
+ function invalidValueDiagnostics(path, dropped) {
8747
+ return dropped.map((entry) => ({
8748
+ kind: "invalid-value",
8749
+ message: `Ignored invalid value in ${path}: ${entry.key}: ${entry.message}`,
8750
+ path,
8751
+ issuePaths: [entry.key]
8752
+ }));
8753
+ }
8754
+ function unrecognizedKeyIssues(issues) {
8755
+ return issues.flatMap((issue) => issue.code === "unrecognized_keys" ? [{ keys: issue.keys, path: issue.path.map((segment) => String(segment)) }] : []);
8756
+ }
8757
+ function isRecord9(value) {
8758
+ return typeof value === "object" && value !== null && !Array.isArray(value);
8759
+ }
8760
+ function sanitizeUnsafeKeys(value, path = []) {
8761
+ if (Array.isArray(value)) {
8762
+ const issues = [];
8763
+ const sanitized = value.map((entry, index) => {
8764
+ const nested = sanitizeUnsafeKeys(entry, [...path, String(index)]);
8765
+ issues.push(...nested.issues);
8766
+ return nested.value;
8767
+ });
8768
+ return { issues, value: sanitized };
8769
+ }
8770
+ if (!isRecord9(value))
8771
+ return { issues: [], value };
8772
+ const issues = [];
8773
+ if (Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null) {
8774
+ issues.push({ keys: ["__proto__"], path });
8775
+ }
8776
+ const sanitized = {};
8777
+ for (const [key, entry] of Object.entries(value)) {
8778
+ if (isUnsafeObjectKey(key)) {
8779
+ issues.push({ keys: [key], path });
8780
+ continue;
8781
+ }
8782
+ const nested = sanitizeUnsafeKeys(entry, [...path, key]);
8783
+ issues.push(...nested.issues);
8784
+ sanitized[key] = nested.value;
8785
+ }
8786
+ return { issues, value: sanitized };
8787
+ }
8788
+ function containerAt(record, path) {
8789
+ let node = record;
8790
+ for (const segment of path) {
8791
+ if (Array.isArray(node)) {
8792
+ const index = Number(segment);
8793
+ if (!Number.isInteger(index) || index < 0 || index >= node.length)
8794
+ return null;
8795
+ node = node[index];
8796
+ } else if (isRecord9(node) && Object.hasOwn(node, segment)) {
8797
+ node = node[segment];
8798
+ } else {
8799
+ return null;
8800
+ }
8801
+ }
8802
+ return isRecord9(node) ? node : null;
8803
+ }
8804
+ function stripUnrecognizedKeys(record, issues) {
8805
+ const stripped = structuredClone(record);
8806
+ const issuePaths = [];
8807
+ for (const issue of issues) {
8808
+ const container = containerAt(stripped, issue.path);
8809
+ if (container === null)
8810
+ continue;
8811
+ for (const key of issue.keys) {
8812
+ delete container[key];
8813
+ issuePaths.push([...issue.path, key].join("."));
8814
+ }
8815
+ }
8816
+ return { issuePaths, stripped };
8817
+ }
8818
+ function toRecord(value) {
8819
+ if (value === null || typeof value !== "object" || Array.isArray(value))
8820
+ return null;
8821
+ const record = {};
8822
+ for (const [key, entry] of Object.entries(value)) {
8823
+ record[key] = entry;
8824
+ }
8825
+ return record;
8826
+ }
8827
+ var validateLayerRecord = (record) => {
8828
+ const parsed = OmoConfigLayerSchema.safeParse(record);
8829
+ return parsed.success ? { success: true } : { success: false, issues: parsed.error.issues };
8830
+ };
8831
+ function validateConfigLayer(path, data) {
8832
+ const sanitized = sanitizeUnsafeKeys(data);
8833
+ const record = toRecord(sanitized.value);
8834
+ const unsafeIssuePaths = sanitized.issues.flatMap((issue) => issue.keys.map((key) => [...issue.path, key].join(".")));
8835
+ const unsafeDiagnostics = unsafeIssuePaths.length === 0 ? [] : [{ kind: "unknown-keys", message: `Ignored unknown keys in ${path}: ${unsafeIssuePaths.join(", ")}`, path, issuePaths: unsafeIssuePaths }];
8836
+ const validation = OmoConfigLayerSchema.safeParse(sanitized.value);
8837
+ if (validation.success) {
8838
+ if (record !== null)
8839
+ return { loaded: true, diagnostics: unsafeDiagnostics, value: record };
8840
+ return {
8841
+ loaded: false,
8842
+ diagnostics: [{ kind: "validation", message: `Invalid omo config at ${path}: root must be an object`, path }]
8843
+ };
8844
+ }
8845
+ const rejected = { loaded: false, diagnostics: [validationDiagnostic(path, validation.error.issues)] };
8846
+ const unknownIssues = unrecognizedKeyIssues(validation.error.issues);
8847
+ if (record === null)
8848
+ return rejected;
8849
+ let candidate = record;
8850
+ let issues = validation.error.issues;
8851
+ const diagnostics = [...unsafeDiagnostics];
8852
+ if (unknownIssues.length > 0) {
8853
+ const { issuePaths, stripped } = stripUnrecognizedKeys(record, unknownIssues);
8854
+ if (issuePaths.length > 0) {
8855
+ diagnostics.push({ kind: "unknown-keys", message: `Ignored unknown keys in ${path}: ${issuePaths.join(", ")}`, path, issuePaths });
8856
+ }
8857
+ const strippedValidation = validateLayerRecord(stripped);
8858
+ if (strippedValidation.success)
8859
+ return { loaded: true, diagnostics, value: stripped };
8860
+ candidate = stripped;
8861
+ issues = strippedValidation.issues;
8862
+ }
8863
+ const pruned = pruneInvalidConfigPaths(candidate, issues, validateLayerRecord);
8864
+ if (!pruned.ok)
8865
+ return rejected;
8866
+ return { loaded: true, diagnostics: [...diagnostics, ...invalidValueDiagnostics(path, pruned.dropped)], value: pruned.config };
8867
+ }
8868
+
8591
8869
  // ../../omo-config-core/src/loader/paths.ts
8592
8870
  import { userInfo } from "node:os";
8593
8871
  import { dirname as dirname5, join as join8, posix, resolve as resolve3 } from "node:path";
@@ -8597,15 +8875,6 @@ function toPosixPath(path) {
8597
8875
  return path.split("\\").join("/");
8598
8876
  }
8599
8877
 
8600
- // ../../omo-config-core/src/loader/types.ts
8601
- import { existsSync as existsSync2, lstatSync, readFileSync, realpathSync } from "node:fs";
8602
- var DEFAULT_READ_FILE_SYSTEM = {
8603
- existsSync: existsSync2,
8604
- lstatSync,
8605
- readFileSync,
8606
- realpathSync
8607
- };
8608
-
8609
8878
  // ../../omo-config-core/src/loader/paths.ts
8610
8879
  var MAX_PROJECT_CONFIG_DIRECTORY_DEPTH = 256;
8611
8880
  var ACCOUNT_HOME_DIR = userInfo().homedir;
@@ -8701,7 +8970,7 @@ function resolveOmoProfileName(options = {}) {
8701
8970
  const env = options.env ?? process.env;
8702
8971
  return profileName(options.profile) ?? profileName(env["OMO_PROFILE"]) ?? profileName(env["OCX_PROFILE"]) ?? profileNameFromOpenCodeConfigDir(env["OPENCODE_CONFIG_DIR"]);
8703
8972
  }
8704
- function toRecord(value) {
8973
+ function toRecord2(value) {
8705
8974
  if (value === null || typeof value !== "object" || Array.isArray(value))
8706
8975
  return;
8707
8976
  return Object.fromEntries(Object.entries(value));
@@ -8722,13 +8991,13 @@ function harnessLayer(config, harness) {
8722
8991
  const legacyKeys = Object.entries(OMO_CONFIG_LEGACY_HARNESS_ALIASES).filter(([, target]) => target === canonical).map(([legacy]) => harnessBlockKey(legacy));
8723
8992
  let layer = {};
8724
8993
  for (const key of [...legacyKeys, harnessBlockKey(canonical)]) {
8725
- layer = mergeOmoConfigRecords(layer, toRecord(config[key]) ?? {});
8994
+ layer = mergeOmoConfigRecords(layer, toRecord2(config[key]) ?? {});
8726
8995
  }
8727
8996
  return layer;
8728
8997
  }
8729
8998
  function resolveOmoConfigView(options) {
8730
- const profiles = toRecord(options.config["profiles"]);
8731
- const profile = options.profile === undefined ? undefined : toRecord(profiles?.[options.profile]);
8999
+ const profiles = toRecord2(options.config["profiles"]);
9000
+ const profile = options.profile === undefined ? undefined : toRecord2(profiles?.[options.profile]);
8732
9001
  const diagnostics = profile === undefined && options.profile !== undefined ? [{
8733
9002
  kind: "profile",
8734
9003
  message: `Activated omo profile "${options.profile}" does not exist; using the base configuration`,
@@ -8783,70 +9052,9 @@ function stripResolutionControlKeys(config) {
8783
9052
  } = config;
8784
9053
  return resolved;
8785
9054
  }
8786
- function validationDiagnostic(path, issues) {
8787
- const issuePaths = issues.map((issue) => issue.path.map((segment) => String(segment)).join("."));
8788
- return {
8789
- kind: "validation",
8790
- message: `Invalid omo config at ${path}: ${issuePaths.join(", ")}`,
8791
- path,
8792
- issuePaths
8793
- };
8794
- }
8795
- function unrecognizedKeyIssues(issues) {
8796
- return issues.flatMap((issue) => issue.code === "unrecognized_keys" ? [{ keys: issue.keys, path: issue.path.map((segment) => String(segment)) }] : []);
8797
- }
8798
- function hasUnsafeUnrecognizedKey(issues) {
8799
- return issues.some((issue) => issue.keys.some((key) => isUnsafeObjectKey(key)));
8800
- }
8801
- function hasTamperedPrototype(value) {
8802
- if (Array.isArray(value))
8803
- return value.some((entry) => hasTamperedPrototype(entry));
8804
- if (!isRecord9(value))
8805
- return false;
8806
- const prototype = Object.getPrototypeOf(value);
8807
- if (prototype !== Object.prototype && prototype !== null)
8808
- return true;
8809
- return Object.values(value).some((entry) => hasTamperedPrototype(entry));
8810
- }
8811
- function isRecord9(value) {
8812
- return typeof value === "object" && value !== null && !Array.isArray(value);
8813
- }
8814
- function containerAt(record, path) {
8815
- let container = record;
8816
- for (const segment of path) {
8817
- const next = container[segment];
8818
- if (!isRecord9(next))
8819
- return null;
8820
- container = next;
8821
- }
8822
- return container;
8823
- }
8824
- function stripUnrecognizedKeys(record, issues) {
8825
- const stripped = structuredClone(record);
8826
- const issuePaths = [];
8827
- for (const issue of issues) {
8828
- const container = containerAt(stripped, issue.path);
8829
- if (container === null)
8830
- continue;
8831
- for (const key of issue.keys) {
8832
- delete container[key];
8833
- issuePaths.push([...issue.path, key].join("."));
8834
- }
8835
- }
8836
- return { issuePaths, stripped };
8837
- }
8838
- function toRecord2(value) {
8839
- if (value === null || typeof value !== "object" || Array.isArray(value))
8840
- return null;
8841
- const record = {};
8842
- for (const [key, entry] of Object.entries(value)) {
8843
- record[key] = entry;
8844
- }
8845
- return record;
8846
- }
8847
9055
  function readConfigSource(path, scope, fileSystem) {
8848
9056
  if (!fileSystem.existsSync(path)) {
8849
- return { source: { exists: false, loaded: false, path, scope } };
9057
+ return { diagnostics: [], source: { exists: false, loaded: false, path, scope } };
8850
9058
  }
8851
9059
  let content;
8852
9060
  try {
@@ -8854,68 +9062,23 @@ function readConfigSource(path, scope, fileSystem) {
8854
9062
  } catch (error) {
8855
9063
  const message = error instanceof Error ? error.message : String(error);
8856
9064
  return {
8857
- diagnostic: { kind: "read", message: `Failed to read ${path}: ${message}`, path },
9065
+ diagnostics: [{ kind: "read", message: `Failed to read ${path}: ${message}`, path }],
8858
9066
  source: { exists: true, loaded: false, path, scope }
8859
9067
  };
8860
9068
  }
8861
9069
  const parsed = parseJsoncSafe(content);
8862
9070
  if (parsed.errors.length > 0) {
8863
9071
  return {
8864
- diagnostic: {
9072
+ diagnostics: [{
8865
9073
  kind: "parse",
8866
9074
  message: `JSONC parse error in ${path}: ${parsed.errors.map((error) => error.message).join(", ")}`,
8867
9075
  path
8868
- },
8869
- source: { exists: true, loaded: false, path, scope }
8870
- };
8871
- }
8872
- if (hasTamperedPrototype(parsed.data)) {
8873
- return {
8874
- diagnostic: { kind: "validation", message: `Invalid omo config at ${path}: "__proto__" member is not allowed`, path },
8875
- source: { exists: true, loaded: false, path, scope }
8876
- };
8877
- }
8878
- const parsedRecord = toRecord2(parsed.data);
8879
- const validation = OmoConfigLayerSchema.safeParse(parsed.data);
8880
- if (!validation.success) {
8881
- const unrecognized = unrecognizedKeyIssues(validation.error.issues);
8882
- if (hasUnsafeUnrecognizedKey(unrecognized)) {
8883
- return {
8884
- diagnostic: validationDiagnostic(path, validation.error.issues),
8885
- source: { exists: true, loaded: false, path, scope }
8886
- };
8887
- }
8888
- const rejected = {
8889
- diagnostic: validationDiagnostic(path, validation.error.issues),
9076
+ }],
8890
9077
  source: { exists: true, loaded: false, path, scope }
8891
9078
  };
8892
- const unknownIssues = unrecognizedKeyIssues(validation.error.issues);
8893
- if (parsedRecord === null || unknownIssues.length === 0)
8894
- return rejected;
8895
- const { issuePaths, stripped } = stripUnrecognizedKeys(parsedRecord, unknownIssues);
8896
- if (!OmoConfigLayerSchema.safeParse(stripped).success)
8897
- return rejected;
8898
- return {
8899
- diagnostic: {
8900
- kind: "unknown-keys",
8901
- message: `Ignored unknown keys in ${path}: ${issuePaths.join(", ")}`,
8902
- path,
8903
- issuePaths
8904
- },
8905
- source: { exists: true, loaded: true, path, scope },
8906
- value: stripped
8907
- };
8908
9079
  }
8909
- if (parsedRecord === null) {
8910
- return {
8911
- diagnostic: { kind: "validation", message: `Invalid omo config at ${path}: root must be an object`, path },
8912
- source: { exists: true, loaded: false, path, scope }
8913
- };
8914
- }
8915
- return {
8916
- source: { exists: true, loaded: true, path, scope },
8917
- value: parsedRecord
8918
- };
9080
+ const layer = validateConfigLayer(path, parsed.data);
9081
+ return layer.loaded ? { diagnostics: layer.diagnostics, source: { exists: true, loaded: true, path, scope }, value: layer.value } : { diagnostics: layer.diagnostics, source: { exists: true, loaded: false, path, scope } };
8919
9082
  }
8920
9083
  function legacyCategoryDiagnostic(path, renames) {
8921
9084
  const detail = renames.map((rename) => rename.dropped ? `${rename.path} ignored because ${rename.canonical} is also configured` : `${rename.path} renamed to ${rename.canonical}`).join(", ");
@@ -8950,8 +9113,7 @@ function loadOmoConfig(options = {}) {
8950
9113
  })) {
8951
9114
  const loaded = readConfigSource(candidate.path, candidate.scope, fileSystem);
8952
9115
  sources.push(loaded.source);
8953
- if (loaded.diagnostic !== undefined)
8954
- diagnostics.push(loaded.diagnostic);
9116
+ diagnostics.push(...loaded.diagnostics);
8955
9117
  if (loaded.value !== undefined) {
8956
9118
  const canonicalized = canonicalizeLegacyCategoryNames(loaded.value);
8957
9119
  if (canonicalized.renames.length > 0) {
@@ -8974,7 +9136,8 @@ function loadOmoConfig(options = {}) {
8974
9136
  ...options.harness === undefined ? {} : { harness: options.harness },
8975
9137
  ...requestedProfile === undefined ? {} : { profile: requestedProfile }
8976
9138
  });
8977
- const finalConfig = OmoConfigSchema.safeParse(mergeOmoConfigRecords(DEFAULT_RAW_CONFIG, resolved.config));
9139
+ const finalInput = mergeOmoConfigRecords(DEFAULT_RAW_CONFIG, resolved.config);
9140
+ const finalConfig = OmoConfigSchema.safeParse(finalInput);
8978
9141
  if (finalConfig.success) {
8979
9142
  return {
8980
9143
  config: stripResolutionControlKeys(finalConfig.data),
@@ -8984,9 +9147,22 @@ function loadOmoConfig(options = {}) {
8984
9147
  sources
8985
9148
  };
8986
9149
  }
9150
+ const pruned = pruneInvalidConfigPaths(finalInput, finalConfig.error.issues, (record) => {
9151
+ const parsed = OmoConfigSchema.safeParse(record);
9152
+ return parsed.success ? { success: true } : { success: false, issues: parsed.error.issues };
9153
+ });
9154
+ if (pruned.ok) {
9155
+ return {
9156
+ config: stripResolutionControlKeys(OmoConfigSchema.parse(pruned.config)),
9157
+ diagnostics: [...diagnostics, ...resolved.diagnostics, ...invalidValueDiagnostics(MERGED_OMO_CONFIG_PATH, pruned.dropped)],
9158
+ layers,
9159
+ ...resolved.profile === undefined ? {} : { profile: resolved.profile },
9160
+ sources
9161
+ };
9162
+ }
8987
9163
  return {
8988
9164
  config: stripResolutionControlKeys(OmoConfigSchema.parse(DEFAULT_RAW_CONFIG)),
8989
- diagnostics: [...diagnostics, ...resolved.diagnostics, validationDiagnostic("(merged omo config)", finalConfig.error.issues)],
9165
+ diagnostics: [...diagnostics, ...resolved.diagnostics, validationDiagnostic(MERGED_OMO_CONFIG_PATH, finalConfig.error.issues)],
8990
9166
  layers,
8991
9167
  ...resolved.profile === undefined ? {} : { profile: resolved.profile },
8992
9168
  sources
@@ -8,7 +8,7 @@
8
8
  "command": "node \"${PLUGIN_ROOT}/components/bootstrap/dist/cli.js\" hook session-start",
9
9
  "commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\bootstrap.ps1\"",
10
10
  "timeout": 30,
11
- "statusMessage": "(OmO 5.1.3) Checking Bootstrap Provisioning"
11
+ "statusMessage": "(OmO 5.1.5) Checking Bootstrap Provisioning"
12
12
  }
13
13
  ]
14
14
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sisyphuslabs/codex-bootstrap",
3
- "version": "5.1.3",
3
+ "version": "5.1.5",
4
4
  "description": "Codex SessionStart bootstrap component that provisions LazyCodex runtime dependencies from a detached worker.",
5
5
  "type": "module",
6
6
  "private": true,
@@ -8,7 +8,7 @@
8
8
  "type": "command",
9
9
  "command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook post-tool-use",
10
10
  "timeout": 30,
11
- "statusMessage": "(OmO 5.1.3) Checking Comments"
11
+ "statusMessage": "(OmO 5.1.5) Checking Comments"
12
12
  }
13
13
  ]
14
14
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@code-yeongyu/codex-comment-checker",
3
- "version": "5.1.3",
3
+ "version": "5.1.5",
4
4
  "description": "Codex plugin that runs comment-checker after edit-like PostToolUse hooks.",
5
5
  "type": "module",
6
6
  "packageManager": "npm@11.12.1",