lazycodex-ai 5.1.4 → 5.1.6

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 (61) hide show
  1. package/dist/cli/index.js +465 -187
  2. package/dist/cli-node/index.js +465 -187
  3. package/package.json +1 -1
  4. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
  5. package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +309 -133
  6. package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
  7. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  8. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
  9. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  10. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
  11. package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
  12. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
  13. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
  14. package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +2 -2
  15. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
  16. package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
  17. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
  18. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  19. package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
  20. package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
  21. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
  22. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  23. package/packages/omo-codex/plugin/components/ultrawork/dist/cli.js +25 -18
  24. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
  25. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
  26. package/packages/omo-codex/plugin/components/ultrawork/src/directive-content.ts +1 -1
  27. package/packages/omo-codex/plugin/components/ulw-execute-continuation/hooks/hooks.json +1 -1
  28. package/packages/omo-codex/plugin/components/ulw-execute-continuation/package.json +1 -1
  29. package/packages/omo-codex/plugin/components/ulw-loop/directive.md +25 -18
  30. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +5 -5
  31. package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
  32. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
  33. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
  34. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
  35. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
  36. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
  37. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
  38. package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
  39. package/packages/omo-codex/plugin/hooks/post-tool-use-recording-spawn-admission.json +1 -1
  40. package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
  41. package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
  42. package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
  43. package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
  44. package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
  45. package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
  46. package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
  47. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-execute-continuation.json +1 -1
  48. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
  49. package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
  50. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
  51. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
  52. package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
  53. package/packages/omo-codex/plugin/package-lock.json +12 -12
  54. package/packages/omo-codex/plugin/package.json +1 -1
  55. package/packages/omo-codex/plugin/skills/browser/runtime/omowright/manifest.json +1 -1
  56. package/packages/omo-codex/plugin/skills/ultrawork/SKILL.md +25 -18
  57. package/packages/omo-codex/plugin/skills/ulw-execute/SKILL.md +1 -1
  58. package/packages/omo-codex/scripts/install-dist/install-local.mjs +311 -135
  59. package/packages/prompts-core/prompts/ultrawork/codex.md +25 -18
  60. package/packages/shared-skills/skills/browser/runtime/omowright/manifest.json +1 -1
  61. package/packages/shared-skills/skills/ulw-execute/SKILL.md +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lazycodex-ai",
3
- "version": "5.1.4",
3
+ "version": "5.1.6",
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",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "omo",
3
- "version": "5.1.4",
3
+ "version": "5.1.6",
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.4) Checking Bootstrap Provisioning"
11
+ "statusMessage": "(OmO 5.1.6) 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.4",
3
+ "version": "5.1.6",
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.4) Checking Comments"
11
+ "statusMessage": "(OmO 5.1.6) 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.4",
3
+ "version": "5.1.6",
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",
@@ -8,7 +8,7 @@
8
8
  "type": "command",
9
9
  "command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook pre-tool-use",
10
10
  "timeout": 5,
11
- "statusMessage": "(OmO 5.1.4) Recommending Git Bash MCP"
11
+ "statusMessage": "(OmO 5.1.6) Recommending Git Bash MCP"
12
12
  }
13
13
  ]
14
14
  }
@@ -20,7 +20,7 @@
20
20
  "type": "command",
21
21
  "command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook post-compact",
22
22
  "timeout": 5,
23
- "statusMessage": "(OmO 5.1.4) Resetting Git Bash MCP Reminder"
23
+ "statusMessage": "(OmO 5.1.6) Resetting Git Bash MCP Reminder"
24
24
  }
25
25
  ]
26
26
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sisyphuslabs/codex-git-bash-hook",
3
- "version": "5.1.4",
3
+ "version": "5.1.6",
4
4
  "description": "Codex hook component that reminds Windows sessions to prefer the OMO git_bash MCP.",
5
5
  "type": "module",
6
6
  "private": true,
@@ -8,7 +8,7 @@
8
8
  "type": "command",
9
9
  "command": "node \"${PLUGIN_ROOT}/components/lazycodex-executor-verify/dist/cli.js\" hook subagent-stop",
10
10
  "timeout": 10,
11
- "statusMessage": "(OmO 5.1.4) Verifying LazyCodex Executor Evidence"
11
+ "statusMessage": "(OmO 5.1.6) Verifying LazyCodex Executor Evidence"
12
12
  }
13
13
  ]
14
14
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@code-yeongyu/codex-lazycodex-executor-verify",
3
- "version": "5.1.4",
3
+ "version": "5.1.6",
4
4
  "description": "Codex SubagentStop evidence verifier for LazyCodex executor completions.",
5
5
  "type": "module",
6
6
  "packageManager": "npm@11.12.1",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "version": "5.1.4",
4
- "inputDigest": "sha256:4b9c0202761e8abe92155e627fa7548e4252aadd31dd92f1412d6bf1e357ed23",
3
+ "version": "5.1.6",
4
+ "inputDigest": "sha256:5fed95326ac014f60c76d07d954ae544627555bd0fd71e5d7175ca389b1898fb",
5
5
  "outputs": [
6
6
  {
7
7
  "path": "cli.d.ts",