lazycodex-ai 5.1.4 → 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 (54) hide show
  1. package/dist/cli/index.js +464 -186
  2. package/dist/cli-node/index.js +464 -186
  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/hooks/hooks.json +1 -1
  24. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
  25. package/packages/omo-codex/plugin/components/ulw-execute-continuation/hooks/hooks.json +1 -1
  26. package/packages/omo-codex/plugin/components/ulw-execute-continuation/package.json +1 -1
  27. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +5 -5
  28. package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
  29. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
  30. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
  31. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
  32. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
  33. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
  34. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
  35. package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
  36. package/packages/omo-codex/plugin/hooks/post-tool-use-recording-spawn-admission.json +1 -1
  37. package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
  38. package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
  39. package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
  40. package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
  41. package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
  42. package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
  43. package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
  44. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-execute-continuation.json +1 -1
  45. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
  46. package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
  47. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
  48. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
  49. package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
  50. package/packages/omo-codex/plugin/package-lock.json +12 -12
  51. package/packages/omo-codex/plugin/package.json +1 -1
  52. package/packages/omo-codex/plugin/skills/browser/runtime/omowright/manifest.json +1 -1
  53. package/packages/omo-codex/scripts/install-dist/install-local.mjs +311 -135
  54. package/packages/shared-skills/skills/browser/runtime/omowright/manifest.json +1 -1
@@ -65,7 +65,7 @@ var package_default;
65
65
  var init_package = __esm(() => {
66
66
  package_default = {
67
67
  name: "oh-my-opencode",
68
- version: "5.1.4",
68
+ version: "5.1.5",
69
69
  description: "The Best AI Agent Harness - Batteries-Included OpenCode Plugin with Multi-Model Orchestration, Parallel Background Agents, and Crafted LSP/AST Tools",
70
70
  main: "./dist/index.js",
71
71
  types: "dist/index.d.ts",
@@ -300,18 +300,18 @@ var init_package = __esm(() => {
300
300
  typescript: "^7.0.2"
301
301
  },
302
302
  optionalDependencies: {
303
- "oh-my-opencode-darwin-arm64": "5.1.4",
304
- "oh-my-opencode-darwin-x64": "5.1.4",
305
- "oh-my-opencode-darwin-x64-baseline": "5.1.4",
306
- "oh-my-opencode-linux-arm64": "5.1.4",
307
- "oh-my-opencode-linux-arm64-musl": "5.1.4",
308
- "oh-my-opencode-linux-x64": "5.1.4",
309
- "oh-my-opencode-linux-x64-baseline": "5.1.4",
310
- "oh-my-opencode-linux-x64-musl": "5.1.4",
311
- "oh-my-opencode-linux-x64-musl-baseline": "5.1.4",
312
- "oh-my-opencode-windows-arm64": "5.1.4",
313
- "oh-my-opencode-windows-x64": "5.1.4",
314
- "oh-my-opencode-windows-x64-baseline": "5.1.4"
303
+ "oh-my-opencode-darwin-arm64": "5.1.5",
304
+ "oh-my-opencode-darwin-x64": "5.1.5",
305
+ "oh-my-opencode-darwin-x64-baseline": "5.1.5",
306
+ "oh-my-opencode-linux-arm64": "5.1.5",
307
+ "oh-my-opencode-linux-arm64-musl": "5.1.5",
308
+ "oh-my-opencode-linux-x64": "5.1.5",
309
+ "oh-my-opencode-linux-x64-baseline": "5.1.5",
310
+ "oh-my-opencode-linux-x64-musl": "5.1.5",
311
+ "oh-my-opencode-linux-x64-musl-baseline": "5.1.5",
312
+ "oh-my-opencode-windows-arm64": "5.1.5",
313
+ "oh-my-opencode-windows-x64": "5.1.5",
314
+ "oh-my-opencode-windows-x64-baseline": "5.1.5"
315
315
  },
316
316
  overrides: {
317
317
  hono: "^4.13.8",
@@ -74458,7 +74458,6 @@ function normalizeLegacyModelFields(entry) {
74458
74458
  delete normalized["reasoningEffort"];
74459
74459
  delete normalized["thinking"];
74460
74460
  delete normalized["textVerbosity"];
74461
- delete normalized["maxTokens"];
74462
74461
  delete normalized["providerOptions"];
74463
74462
  if (typeof entry["model"] === "string")
74464
74463
  normalized["model"] = canonicalModelString(entry["model"]);
@@ -74476,10 +74475,15 @@ function normalizeLegacyModelFields(entry) {
74476
74475
  providerOptions["textVerbosity"] = entry["textVerbosity"];
74477
74476
  if (Object.keys(providerOptions).length > 0)
74478
74477
  normalized["provider_options"] = providerOptions;
74479
- if (entry["max_tokens"] !== undefined)
74478
+ if (entry["max_tokens"] !== undefined) {
74480
74479
  normalized["max_tokens"] = entry["max_tokens"];
74481
- else if (entry["maxTokens"] !== undefined)
74480
+ if (entry["maxTokens"] === undefined || typeof entry["maxTokens"] === "number") {
74481
+ delete normalized["maxTokens"];
74482
+ }
74483
+ } else if (typeof entry["maxTokens"] === "number") {
74482
74484
  normalized["max_tokens"] = entry["maxTokens"];
74485
+ delete normalized["maxTokens"];
74486
+ }
74483
74487
  return normalized;
74484
74488
  }
74485
74489
  function normalizeLegacyModelEntry(entry) {
@@ -74522,12 +74526,25 @@ var init_fallback_models = __esm(() => {
74522
74526
  function isRecord5(value) {
74523
74527
  return typeof value === "object" && value !== null && !Array.isArray(value);
74524
74528
  }
74525
- var OmoAgentModelEntrySchema, OmoAgentDefInputSchema, OmoAgentDefSchema, OmoAgentsConfigSchema;
74529
+ var OmoAgentModelEntrySchema, PermissionValueSchema, BashPermissionSchema, OmoAgentPermissionSchema, OmoAgentDefInputSchema, OmoAgentDefSchema, OmoAgentsConfigSchema;
74526
74530
  var init_agent = __esm(() => {
74527
74531
  init_zod();
74528
74532
  init_fallback_models();
74529
74533
  init_model_ref();
74530
74534
  OmoAgentModelEntrySchema = union([string2(), OmoFallbackModelObjectSchema]);
74535
+ PermissionValueSchema = _enum(["ask", "allow", "deny"]);
74536
+ BashPermissionSchema = union([
74537
+ PermissionValueSchema,
74538
+ record(string2(), PermissionValueSchema)
74539
+ ]);
74540
+ OmoAgentPermissionSchema = object({
74541
+ edit: PermissionValueSchema.optional(),
74542
+ bash: BashPermissionSchema.optional(),
74543
+ webfetch: PermissionValueSchema.optional(),
74544
+ task: PermissionValueSchema.optional(),
74545
+ doom_loop: PermissionValueSchema.optional(),
74546
+ external_directory: PermissionValueSchema.optional()
74547
+ }).catchall(PermissionValueSchema.optional());
74531
74548
  OmoAgentDefInputSchema = object({
74532
74549
  description: string2().optional(),
74533
74550
  prompt: string2().optional(),
@@ -74544,7 +74561,9 @@ var init_agent = __esm(() => {
74544
74561
  disallowed_tools: array(string2()).optional(),
74545
74562
  max_turns: number2().int().nonnegative().optional(),
74546
74563
  temperature: number2().min(0).max(2).optional(),
74547
- disable: boolean2().optional()
74564
+ disable: boolean2().optional(),
74565
+ permission: OmoAgentPermissionSchema.optional(),
74566
+ prompt_append: string2().optional()
74548
74567
  }).strict();
74549
74568
  OmoAgentDefSchema = preprocess((value) => isRecord5(value) ? normalizeLegacyModelFields(value) : value, OmoAgentDefInputSchema);
74550
74569
  OmoAgentsConfigSchema = record(string2(), OmoAgentDefSchema);
@@ -75330,6 +75349,64 @@ var init_schema = __esm(() => {
75330
75349
  init_computer();
75331
75350
  });
75332
75351
 
75352
+ // packages/omo-config-core/src/loader/types.ts
75353
+ import { existsSync as existsSync13, lstatSync as lstatSync2, readFileSync as readFileSync5, realpathSync as realpathSync5 } from "node:fs";
75354
+ var MERGED_OMO_CONFIG_PATH = "(merged omo config)", DEFAULT_READ_FILE_SYSTEM;
75355
+ var init_types3 = __esm(() => {
75356
+ DEFAULT_READ_FILE_SYSTEM = {
75357
+ existsSync: existsSync13,
75358
+ lstatSync: lstatSync2,
75359
+ readFileSync: readFileSync5,
75360
+ realpathSync: realpathSync5
75361
+ };
75362
+ });
75363
+
75364
+ // packages/omo-config-core/src/loader/diagnostic-lines.ts
75365
+ function displayOmoConfigPath(path, homeDir) {
75366
+ if (path === MERGED_OMO_CONFIG_PATH)
75367
+ return "merged config";
75368
+ if (homeDir === undefined || homeDir.length === 0)
75369
+ return path;
75370
+ const slashed = (value) => value.replaceAll("\\", "/");
75371
+ const home = slashed(homeDir).replace(/\/+$/, "");
75372
+ const file = slashed(path);
75373
+ const fold = (value) => /^[A-Za-z]:\//.test(home) ? value.toLowerCase() : value;
75374
+ if (fold(file) === fold(home))
75375
+ return "~";
75376
+ return fold(file).startsWith(`${fold(home)}/`) ? `~${file.slice(home.length)}` : path;
75377
+ }
75378
+ function notLoadedReason(diagnostic) {
75379
+ switch (diagnostic.kind) {
75380
+ case "parse":
75381
+ return "JSONC parse error";
75382
+ case "read":
75383
+ return "unreadable";
75384
+ default:
75385
+ return diagnostic.issuePaths === undefined || diagnostic.issuePaths.length === 0 ? "invalid config" : `invalid: ${diagnostic.issuePaths.join(", ")}`;
75386
+ }
75387
+ }
75388
+ function omoConfigDiagnosticLines(diagnostics, options = {}) {
75389
+ return diagnostics.flatMap((diagnostic) => {
75390
+ const file = displayOmoConfigPath(diagnostic.path, options.homeDir);
75391
+ switch (diagnostic.kind) {
75392
+ case "invalid-value":
75393
+ return (diagnostic.issuePaths ?? []).map((key) => `config: ${file}: ${key} ignored (invalid value)`);
75394
+ case "unknown-keys":
75395
+ return (diagnostic.issuePaths ?? []).map((key) => `config: ${file}: ${key} ignored (unknown key)`);
75396
+ case "parse":
75397
+ case "read":
75398
+ case "validation":
75399
+ return diagnostic.path === MERGED_OMO_CONFIG_PATH ? [`config: ${file}: reset to defaults (${notLoadedReason(diagnostic)})`] : [`config: ${file}: not loaded (${notLoadedReason(diagnostic)})`];
75400
+ case "deprecated-keys":
75401
+ case "profile":
75402
+ return [];
75403
+ }
75404
+ });
75405
+ }
75406
+ var init_diagnostic_lines = __esm(() => {
75407
+ init_types3();
75408
+ });
75409
+
75333
75410
  // packages/omo-config-core/src/loader/disabled-skills.ts
75334
75411
  var init_disabled_skills = () => {};
75335
75412
 
@@ -75369,24 +75446,265 @@ var init_merge = __esm(() => {
75369
75446
  DANGEROUS_KEYS2 = new Set(["__proto__", "constructor", "prototype"]);
75370
75447
  });
75371
75448
 
75449
+ // packages/omo-config-core/src/loader/prune-invalid-leaves.ts
75450
+ function isContainer(value) {
75451
+ return typeof value === "object" && value !== null;
75452
+ }
75453
+ function childOf(container, segment) {
75454
+ return Array.isArray(container) ? container[Number(segment)] : container[String(segment)];
75455
+ }
75456
+ function hasChild(container, segment) {
75457
+ if (Array.isArray(container)) {
75458
+ const index = Number(segment);
75459
+ return Number.isInteger(index) && index >= 0 && index < container.length;
75460
+ }
75461
+ return Object.hasOwn(container, String(segment));
75462
+ }
75463
+ function segmentsOf(path) {
75464
+ return path.map((segment) => typeof segment === "number" ? segment : String(segment));
75465
+ }
75466
+ function targetPaths(root, issue) {
75467
+ const base = segmentsOf(issue.path);
75468
+ if (issue.code === "unrecognized_keys")
75469
+ return issue.keys.map((key) => [...base, key]);
75470
+ let node = root;
75471
+ let depth = 0;
75472
+ for (const segment of base) {
75473
+ if (!isContainer(node) || !hasChild(node, segment))
75474
+ break;
75475
+ node = childOf(node, segment);
75476
+ depth += 1;
75477
+ }
75478
+ return [base.slice(0, depth)];
75479
+ }
75480
+ function isAncestor(ancestor, path) {
75481
+ return ancestor.length < path.length && ancestor.every((segment, index) => segment === path[index]);
75482
+ }
75483
+ function compareDescending(left, right) {
75484
+ const length = Math.min(left.length, right.length);
75485
+ for (let index = 0;index < length; index += 1) {
75486
+ const a = left[index];
75487
+ const b = right[index];
75488
+ if (a === b)
75489
+ continue;
75490
+ if (typeof a === "number" && typeof b === "number")
75491
+ return b - a;
75492
+ return String(b).localeCompare(String(a));
75493
+ }
75494
+ return right.length - left.length;
75495
+ }
75496
+ function removeChild(container, segment) {
75497
+ if (Array.isArray(container))
75498
+ container.splice(Number(segment), 1);
75499
+ else
75500
+ delete container[String(segment)];
75501
+ }
75502
+ function isEmpty(container) {
75503
+ return Array.isArray(container) ? container.length === 0 : Object.keys(container).length === 0;
75504
+ }
75505
+ function removePathAndEmptiedAncestors(root, path) {
75506
+ const chain = [root];
75507
+ for (const segment of path.slice(0, -1)) {
75508
+ const current = chain[chain.length - 1];
75509
+ if (current === undefined)
75510
+ return;
75511
+ const next = childOf(current, segment);
75512
+ if (!isContainer(next))
75513
+ return;
75514
+ chain.push(next);
75515
+ }
75516
+ for (let depth = path.length - 1;depth >= 0; depth -= 1) {
75517
+ const container = chain[depth];
75518
+ const segment = path[depth];
75519
+ if (container === undefined || segment === undefined)
75520
+ return;
75521
+ removeChild(container, segment);
75522
+ if (depth === 0 || !isEmpty(container))
75523
+ return;
75524
+ }
75525
+ }
75526
+ function prunePass(root, issues) {
75527
+ const byKey = new Map;
75528
+ for (const issue of issues) {
75529
+ for (const path of targetPaths(root, issue)) {
75530
+ if (path.length === 0)
75531
+ return null;
75532
+ const key = path.map((segment) => String(segment)).join(".");
75533
+ if (!byKey.has(key))
75534
+ byKey.set(key, { key, message: issue.message, path });
75535
+ }
75536
+ }
75537
+ const targets = [...byKey.values()];
75538
+ const outermost = targets.filter((target) => !targets.some((other) => isAncestor(other.path, target.path))).sort((left, right) => compareDescending(left.path, right.path));
75539
+ const next = structuredClone(root);
75540
+ for (const target of outermost)
75541
+ removePathAndEmptiedAncestors(next, target.path);
75542
+ return { dropped: outermost, next };
75543
+ }
75544
+ function pruneInvalidConfigPaths(config, issues, validate, maxPasses = MAX_PRUNE_PASSES) {
75545
+ const dropped = [];
75546
+ let current = config;
75547
+ let pending = issues;
75548
+ for (let pass = 0;pass < maxPasses; pass += 1) {
75549
+ const step = prunePass(current, pending);
75550
+ if (step === null || step.dropped.length === 0)
75551
+ return { ok: false, dropped };
75552
+ dropped.push(...step.dropped);
75553
+ current = step.next;
75554
+ if (Object.keys(current).length === 0)
75555
+ return { ok: false, dropped };
75556
+ const validation = validate(current);
75557
+ if (validation.success)
75558
+ return { ok: true, config: current, dropped };
75559
+ pending = validation.issues;
75560
+ }
75561
+ return { ok: false, dropped };
75562
+ }
75563
+ var MAX_PRUNE_PASSES = 32;
75564
+
75565
+ // packages/omo-config-core/src/loader/layer-validation.ts
75566
+ function validationDiagnostic(path, issues) {
75567
+ const issuePaths = issues.map((issue) => issue.path.map((segment) => String(segment)).join("."));
75568
+ return {
75569
+ kind: "validation",
75570
+ message: `Invalid omo config at ${path}: ${issuePaths.join(", ")}`,
75571
+ path,
75572
+ issuePaths
75573
+ };
75574
+ }
75575
+ function invalidValueDiagnostics(path, dropped) {
75576
+ return dropped.map((entry) => ({
75577
+ kind: "invalid-value",
75578
+ message: `Ignored invalid value in ${path}: ${entry.key}: ${entry.message}`,
75579
+ path,
75580
+ issuePaths: [entry.key]
75581
+ }));
75582
+ }
75583
+ function unrecognizedKeyIssues(issues) {
75584
+ return issues.flatMap((issue) => issue.code === "unrecognized_keys" ? [{ keys: issue.keys, path: issue.path.map((segment) => String(segment)) }] : []);
75585
+ }
75586
+ function isRecord11(value) {
75587
+ return typeof value === "object" && value !== null && !Array.isArray(value);
75588
+ }
75589
+ function sanitizeUnsafeKeys(value, path = []) {
75590
+ if (Array.isArray(value)) {
75591
+ const issues = [];
75592
+ const sanitized = value.map((entry, index) => {
75593
+ const nested = sanitizeUnsafeKeys(entry, [...path, String(index)]);
75594
+ issues.push(...nested.issues);
75595
+ return nested.value;
75596
+ });
75597
+ return { issues, value: sanitized };
75598
+ }
75599
+ if (!isRecord11(value))
75600
+ return { issues: [], value };
75601
+ const issues = [];
75602
+ if (Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null) {
75603
+ issues.push({ keys: ["__proto__"], path });
75604
+ }
75605
+ const sanitized = {};
75606
+ for (const [key, entry] of Object.entries(value)) {
75607
+ if (isUnsafeObjectKey2(key)) {
75608
+ issues.push({ keys: [key], path });
75609
+ continue;
75610
+ }
75611
+ const nested = sanitizeUnsafeKeys(entry, [...path, key]);
75612
+ issues.push(...nested.issues);
75613
+ sanitized[key] = nested.value;
75614
+ }
75615
+ return { issues, value: sanitized };
75616
+ }
75617
+ function containerAt(record, path) {
75618
+ let node = record;
75619
+ for (const segment of path) {
75620
+ if (Array.isArray(node)) {
75621
+ const index = Number(segment);
75622
+ if (!Number.isInteger(index) || index < 0 || index >= node.length)
75623
+ return null;
75624
+ node = node[index];
75625
+ } else if (isRecord11(node) && Object.hasOwn(node, segment)) {
75626
+ node = node[segment];
75627
+ } else {
75628
+ return null;
75629
+ }
75630
+ }
75631
+ return isRecord11(node) ? node : null;
75632
+ }
75633
+ function stripUnrecognizedKeys(record, issues) {
75634
+ const stripped = structuredClone(record);
75635
+ const issuePaths = [];
75636
+ for (const issue of issues) {
75637
+ const container = containerAt(stripped, issue.path);
75638
+ if (container === null)
75639
+ continue;
75640
+ for (const key of issue.keys) {
75641
+ delete container[key];
75642
+ issuePaths.push([...issue.path, key].join("."));
75643
+ }
75644
+ }
75645
+ return { issuePaths, stripped };
75646
+ }
75647
+ function toRecord(value) {
75648
+ if (value === null || typeof value !== "object" || Array.isArray(value))
75649
+ return null;
75650
+ const record = {};
75651
+ for (const [key, entry] of Object.entries(value)) {
75652
+ record[key] = entry;
75653
+ }
75654
+ return record;
75655
+ }
75656
+ function validateConfigLayer(path, data) {
75657
+ const sanitized = sanitizeUnsafeKeys(data);
75658
+ const record = toRecord(sanitized.value);
75659
+ const unsafeIssuePaths = sanitized.issues.flatMap((issue) => issue.keys.map((key) => [...issue.path, key].join(".")));
75660
+ const unsafeDiagnostics = unsafeIssuePaths.length === 0 ? [] : [{ kind: "unknown-keys", message: `Ignored unknown keys in ${path}: ${unsafeIssuePaths.join(", ")}`, path, issuePaths: unsafeIssuePaths }];
75661
+ const validation = OmoConfigLayerSchema.safeParse(sanitized.value);
75662
+ if (validation.success) {
75663
+ if (record !== null)
75664
+ return { loaded: true, diagnostics: unsafeDiagnostics, value: record };
75665
+ return {
75666
+ loaded: false,
75667
+ diagnostics: [{ kind: "validation", message: `Invalid omo config at ${path}: root must be an object`, path }]
75668
+ };
75669
+ }
75670
+ const rejected = { loaded: false, diagnostics: [validationDiagnostic(path, validation.error.issues)] };
75671
+ const unknownIssues = unrecognizedKeyIssues(validation.error.issues);
75672
+ if (record === null)
75673
+ return rejected;
75674
+ let candidate = record;
75675
+ let issues = validation.error.issues;
75676
+ const diagnostics = [...unsafeDiagnostics];
75677
+ if (unknownIssues.length > 0) {
75678
+ const { issuePaths, stripped } = stripUnrecognizedKeys(record, unknownIssues);
75679
+ if (issuePaths.length > 0) {
75680
+ diagnostics.push({ kind: "unknown-keys", message: `Ignored unknown keys in ${path}: ${issuePaths.join(", ")}`, path, issuePaths });
75681
+ }
75682
+ const strippedValidation = validateLayerRecord(stripped);
75683
+ if (strippedValidation.success)
75684
+ return { loaded: true, diagnostics, value: stripped };
75685
+ candidate = stripped;
75686
+ issues = strippedValidation.issues;
75687
+ }
75688
+ const pruned = pruneInvalidConfigPaths(candidate, issues, validateLayerRecord);
75689
+ if (!pruned.ok)
75690
+ return rejected;
75691
+ return { loaded: true, diagnostics: [...diagnostics, ...invalidValueDiagnostics(path, pruned.dropped)], value: pruned.config };
75692
+ }
75693
+ var validateLayerRecord = (record) => {
75694
+ const parsed = OmoConfigLayerSchema.safeParse(record);
75695
+ return parsed.success ? { success: true } : { success: false, issues: parsed.error.issues };
75696
+ };
75697
+ var init_layer_validation = __esm(() => {
75698
+ init_schema();
75699
+ init_merge();
75700
+ });
75701
+
75372
75702
  // packages/omo-config-core/src/internal/posix-path.ts
75373
75703
  function toPosixPath(path) {
75374
75704
  return path.split("\\").join("/");
75375
75705
  }
75376
75706
  var init_posix_path = () => {};
75377
75707
 
75378
- // packages/omo-config-core/src/loader/types.ts
75379
- import { existsSync as existsSync13, lstatSync as lstatSync2, readFileSync as readFileSync5, realpathSync as realpathSync5 } from "node:fs";
75380
- var DEFAULT_READ_FILE_SYSTEM;
75381
- var init_types3 = __esm(() => {
75382
- DEFAULT_READ_FILE_SYSTEM = {
75383
- existsSync: existsSync13,
75384
- lstatSync: lstatSync2,
75385
- readFileSync: readFileSync5,
75386
- realpathSync: realpathSync5
75387
- };
75388
- });
75389
-
75390
75708
  // packages/omo-config-core/src/loader/paths.ts
75391
75709
  import { userInfo } from "node:os";
75392
75710
  import { dirname as dirname4, join as join15, posix as posix2, resolve as resolve3 } from "node:path";
@@ -75490,7 +75808,7 @@ function resolveOmoProfileName(options = {}) {
75490
75808
  const env = options.env ?? process.env;
75491
75809
  return profileName(options.profile) ?? profileName(env["OMO_PROFILE"]) ?? profileName(env["OCX_PROFILE"]) ?? profileNameFromOpenCodeConfigDir(env["OPENCODE_CONFIG_DIR"]);
75492
75810
  }
75493
- function toRecord(value) {
75811
+ function toRecord2(value) {
75494
75812
  if (value === null || typeof value !== "object" || Array.isArray(value))
75495
75813
  return;
75496
75814
  return Object.fromEntries(Object.entries(value));
@@ -75511,13 +75829,13 @@ function harnessLayer(config, harness) {
75511
75829
  const legacyKeys = Object.entries(OMO_CONFIG_LEGACY_HARNESS_ALIASES).filter(([, target]) => target === canonical).map(([legacy]) => harnessBlockKey(legacy));
75512
75830
  let layer = {};
75513
75831
  for (const key of [...legacyKeys, harnessBlockKey(canonical)]) {
75514
- layer = mergeOmoConfigRecords(layer, toRecord(config[key]) ?? {});
75832
+ layer = mergeOmoConfigRecords(layer, toRecord2(config[key]) ?? {});
75515
75833
  }
75516
75834
  return layer;
75517
75835
  }
75518
75836
  function resolveOmoConfigView(options) {
75519
- const profiles = toRecord(options.config["profiles"]);
75520
- const profile = options.profile === undefined ? undefined : toRecord(profiles?.[options.profile]);
75837
+ const profiles = toRecord2(options.config["profiles"]);
75838
+ const profile = options.profile === undefined ? undefined : toRecord2(profiles?.[options.profile]);
75521
75839
  const diagnostics = profile === undefined && options.profile !== undefined ? [{
75522
75840
  kind: "profile",
75523
75841
  message: `Activated omo profile "${options.profile}" does not exist; using the base configuration`,
@@ -75572,70 +75890,9 @@ function stripResolutionControlKeys(config) {
75572
75890
  } = config;
75573
75891
  return resolved;
75574
75892
  }
75575
- function validationDiagnostic(path, issues) {
75576
- const issuePaths = issues.map((issue) => issue.path.map((segment) => String(segment)).join("."));
75577
- return {
75578
- kind: "validation",
75579
- message: `Invalid omo config at ${path}: ${issuePaths.join(", ")}`,
75580
- path,
75581
- issuePaths
75582
- };
75583
- }
75584
- function unrecognizedKeyIssues(issues) {
75585
- return issues.flatMap((issue) => issue.code === "unrecognized_keys" ? [{ keys: issue.keys, path: issue.path.map((segment) => String(segment)) }] : []);
75586
- }
75587
- function hasUnsafeUnrecognizedKey(issues) {
75588
- return issues.some((issue) => issue.keys.some((key) => isUnsafeObjectKey2(key)));
75589
- }
75590
- function hasTamperedPrototype(value) {
75591
- if (Array.isArray(value))
75592
- return value.some((entry) => hasTamperedPrototype(entry));
75593
- if (!isRecord11(value))
75594
- return false;
75595
- const prototype = Object.getPrototypeOf(value);
75596
- if (prototype !== Object.prototype && prototype !== null)
75597
- return true;
75598
- return Object.values(value).some((entry) => hasTamperedPrototype(entry));
75599
- }
75600
- function isRecord11(value) {
75601
- return typeof value === "object" && value !== null && !Array.isArray(value);
75602
- }
75603
- function containerAt(record, path) {
75604
- let container = record;
75605
- for (const segment of path) {
75606
- const next = container[segment];
75607
- if (!isRecord11(next))
75608
- return null;
75609
- container = next;
75610
- }
75611
- return container;
75612
- }
75613
- function stripUnrecognizedKeys(record, issues) {
75614
- const stripped = structuredClone(record);
75615
- const issuePaths = [];
75616
- for (const issue of issues) {
75617
- const container = containerAt(stripped, issue.path);
75618
- if (container === null)
75619
- continue;
75620
- for (const key of issue.keys) {
75621
- delete container[key];
75622
- issuePaths.push([...issue.path, key].join("."));
75623
- }
75624
- }
75625
- return { issuePaths, stripped };
75626
- }
75627
- function toRecord2(value) {
75628
- if (value === null || typeof value !== "object" || Array.isArray(value))
75629
- return null;
75630
- const record = {};
75631
- for (const [key, entry] of Object.entries(value)) {
75632
- record[key] = entry;
75633
- }
75634
- return record;
75635
- }
75636
75893
  function readConfigSource(path, scope, fileSystem) {
75637
75894
  if (!fileSystem.existsSync(path)) {
75638
- return { source: { exists: false, loaded: false, path, scope } };
75895
+ return { diagnostics: [], source: { exists: false, loaded: false, path, scope } };
75639
75896
  }
75640
75897
  let content;
75641
75898
  try {
@@ -75643,68 +75900,23 @@ function readConfigSource(path, scope, fileSystem) {
75643
75900
  } catch (error) {
75644
75901
  const message = error instanceof Error ? error.message : String(error);
75645
75902
  return {
75646
- diagnostic: { kind: "read", message: `Failed to read ${path}: ${message}`, path },
75903
+ diagnostics: [{ kind: "read", message: `Failed to read ${path}: ${message}`, path }],
75647
75904
  source: { exists: true, loaded: false, path, scope }
75648
75905
  };
75649
75906
  }
75650
75907
  const parsed = parseJsoncSafe2(content);
75651
75908
  if (parsed.errors.length > 0) {
75652
75909
  return {
75653
- diagnostic: {
75910
+ diagnostics: [{
75654
75911
  kind: "parse",
75655
75912
  message: `JSONC parse error in ${path}: ${parsed.errors.map((error) => error.message).join(", ")}`,
75656
75913
  path
75657
- },
75658
- source: { exists: true, loaded: false, path, scope }
75659
- };
75660
- }
75661
- if (hasTamperedPrototype(parsed.data)) {
75662
- return {
75663
- diagnostic: { kind: "validation", message: `Invalid omo config at ${path}: "__proto__" member is not allowed`, path },
75664
- source: { exists: true, loaded: false, path, scope }
75665
- };
75666
- }
75667
- const parsedRecord = toRecord2(parsed.data);
75668
- const validation = OmoConfigLayerSchema.safeParse(parsed.data);
75669
- if (!validation.success) {
75670
- const unrecognized = unrecognizedKeyIssues(validation.error.issues);
75671
- if (hasUnsafeUnrecognizedKey(unrecognized)) {
75672
- return {
75673
- diagnostic: validationDiagnostic(path, validation.error.issues),
75674
- source: { exists: true, loaded: false, path, scope }
75675
- };
75676
- }
75677
- const rejected = {
75678
- diagnostic: validationDiagnostic(path, validation.error.issues),
75914
+ }],
75679
75915
  source: { exists: true, loaded: false, path, scope }
75680
75916
  };
75681
- const unknownIssues = unrecognizedKeyIssues(validation.error.issues);
75682
- if (parsedRecord === null || unknownIssues.length === 0)
75683
- return rejected;
75684
- const { issuePaths, stripped } = stripUnrecognizedKeys(parsedRecord, unknownIssues);
75685
- if (!OmoConfigLayerSchema.safeParse(stripped).success)
75686
- return rejected;
75687
- return {
75688
- diagnostic: {
75689
- kind: "unknown-keys",
75690
- message: `Ignored unknown keys in ${path}: ${issuePaths.join(", ")}`,
75691
- path,
75692
- issuePaths
75693
- },
75694
- source: { exists: true, loaded: true, path, scope },
75695
- value: stripped
75696
- };
75697
75917
  }
75698
- if (parsedRecord === null) {
75699
- return {
75700
- diagnostic: { kind: "validation", message: `Invalid omo config at ${path}: root must be an object`, path },
75701
- source: { exists: true, loaded: false, path, scope }
75702
- };
75703
- }
75704
- return {
75705
- source: { exists: true, loaded: true, path, scope },
75706
- value: parsedRecord
75707
- };
75918
+ const layer = validateConfigLayer(path, parsed.data);
75919
+ 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 } };
75708
75920
  }
75709
75921
  function legacyCategoryDiagnostic(path, renames) {
75710
75922
  const detail = renames.map((rename) => rename.dropped ? `${rename.path} ignored because ${rename.canonical} is also configured` : `${rename.path} renamed to ${rename.canonical}`).join(", ");
@@ -75739,8 +75951,7 @@ function loadOmoConfig(options = {}) {
75739
75951
  })) {
75740
75952
  const loaded = readConfigSource(candidate.path, candidate.scope, fileSystem);
75741
75953
  sources.push(loaded.source);
75742
- if (loaded.diagnostic !== undefined)
75743
- diagnostics.push(loaded.diagnostic);
75954
+ diagnostics.push(...loaded.diagnostics);
75744
75955
  if (loaded.value !== undefined) {
75745
75956
  const canonicalized = canonicalizeLegacyCategoryNames(loaded.value);
75746
75957
  if (canonicalized.renames.length > 0) {
@@ -75763,7 +75974,8 @@ function loadOmoConfig(options = {}) {
75763
75974
  ...options.harness === undefined ? {} : { harness: options.harness },
75764
75975
  ...requestedProfile === undefined ? {} : { profile: requestedProfile }
75765
75976
  });
75766
- const finalConfig = OmoConfigSchema.safeParse(mergeOmoConfigRecords(DEFAULT_RAW_CONFIG, resolved.config));
75977
+ const finalInput = mergeOmoConfigRecords(DEFAULT_RAW_CONFIG, resolved.config);
75978
+ const finalConfig = OmoConfigSchema.safeParse(finalInput);
75767
75979
  if (finalConfig.success) {
75768
75980
  return {
75769
75981
  config: stripResolutionControlKeys(finalConfig.data),
@@ -75773,9 +75985,22 @@ function loadOmoConfig(options = {}) {
75773
75985
  sources
75774
75986
  };
75775
75987
  }
75988
+ const pruned = pruneInvalidConfigPaths(finalInput, finalConfig.error.issues, (record) => {
75989
+ const parsed = OmoConfigSchema.safeParse(record);
75990
+ return parsed.success ? { success: true } : { success: false, issues: parsed.error.issues };
75991
+ });
75992
+ if (pruned.ok) {
75993
+ return {
75994
+ config: stripResolutionControlKeys(OmoConfigSchema.parse(pruned.config)),
75995
+ diagnostics: [...diagnostics, ...resolved.diagnostics, ...invalidValueDiagnostics(MERGED_OMO_CONFIG_PATH, pruned.dropped)],
75996
+ layers,
75997
+ ...resolved.profile === undefined ? {} : { profile: resolved.profile },
75998
+ sources
75999
+ };
76000
+ }
75776
76001
  return {
75777
76002
  config: stripResolutionControlKeys(OmoConfigSchema.parse(DEFAULT_RAW_CONFIG)),
75778
- diagnostics: [...diagnostics, ...resolved.diagnostics, validationDiagnostic("(merged omo config)", finalConfig.error.issues)],
76003
+ diagnostics: [...diagnostics, ...resolved.diagnostics, validationDiagnostic(MERGED_OMO_CONFIG_PATH, finalConfig.error.issues)],
75779
76004
  layers,
75780
76005
  ...resolved.profile === undefined ? {} : { profile: resolved.profile },
75781
76006
  sources
@@ -75785,6 +76010,7 @@ var DEFAULT_RAW_CONFIG;
75785
76010
  var init_loader2 = __esm(() => {
75786
76011
  init_main();
75787
76012
  init_schema();
76013
+ init_layer_validation();
75788
76014
  init_merge();
75789
76015
  init_paths();
75790
76016
  init_resolution();
@@ -75799,6 +76025,7 @@ var init_loader2 = __esm(() => {
75799
76025
 
75800
76026
  // packages/omo-config-core/src/loader/index.ts
75801
76027
  var init_loader3 = __esm(() => {
76028
+ init_diagnostic_lines();
75802
76029
  init_disabled_skills();
75803
76030
  init_loader2();
75804
76031
  init_merge();
@@ -89229,7 +89456,7 @@ var package_default2;
89229
89456
  var init_package2 = __esm(() => {
89230
89457
  package_default2 = {
89231
89458
  name: "@oh-my-opencode/omo-codex",
89232
- version: "5.1.4",
89459
+ version: "5.1.5",
89233
89460
  type: "module",
89234
89461
  private: true,
89235
89462
  description: "Codex harness adapter for oh-my-openagent. Vendored Codex plugin namespace (omo) + TypeScript installer + telemetry.",
@@ -102230,6 +102457,7 @@ async function processEvents(ctx, stream, state) {
102230
102457
  }
102231
102458
  }
102232
102459
  // packages/omo-opencode/src/config/validate.ts
102460
+ init_src4();
102233
102461
  import { relative as relative7 } from "node:path";
102234
102462
 
102235
102463
  // packages/omo-opencode/src/shared/disabled-providers.ts
@@ -102350,11 +102578,11 @@ function baseView(config) {
102350
102578
  }
102351
102579
  return result;
102352
102580
  }
102353
- function appendViews(views, layers, select) {
102581
+ function appendViews(views, layers, select, keyPrefix) {
102354
102582
  for (const layer of layers) {
102355
102583
  const config = select(layer.config);
102356
102584
  if (Object.keys(config).length > 0)
102357
- views.push({ config, path: layer.source.path });
102585
+ views.push({ config, keyPrefix, path: layer.source.path });
102358
102586
  }
102359
102587
  }
102360
102588
  function recordFields(value, fields) {
@@ -102383,10 +102611,21 @@ function modelInput(view) {
102383
102611
  };
102384
102612
  }
102385
102613
  function modelView(view) {
102386
- const parsed = OmoConfigSchema.safeParse(modelInput(view));
102387
- if (!parsed.success)
102614
+ const input = modelInput(view);
102615
+ const parsed = OmoConfigSchema.safeParse(input);
102616
+ const modelConfig = parsed.success ? parsed.data : (() => {
102617
+ const pruned = pruneInvalidConfigPaths(input, parsed.error.issues, (record) => {
102618
+ const validation = OmoConfigSchema.safeParse(record);
102619
+ return validation.success ? { success: true } : { success: false, issues: validation.error.issues };
102620
+ });
102621
+ if (!pruned.ok)
102622
+ return;
102623
+ const validation = OmoConfigSchema.safeParse(pruned.config);
102624
+ return validation.success ? validation.data : undefined;
102625
+ })();
102626
+ if (modelConfig === undefined)
102388
102627
  return { config: {}, diagnostics: [] };
102389
- const resolved = resolveModelReferences(parsed.data);
102628
+ const resolved = resolveModelReferences(modelConfig);
102390
102629
  return {
102391
102630
  config: {
102392
102631
  ...resolved.view.agents === undefined ? {} : { agents: resolved.view.agents },
@@ -102405,14 +102644,15 @@ function loadOmoOpenCodeConfigChain(directory, environment = process.env) {
102405
102644
  });
102406
102645
  const views = [];
102407
102646
  const selectedProfile = loaded.profile;
102408
- appendViews(views, loaded.layers, baseView);
102409
- appendViews(views, loaded.layers, block2);
102410
- appendViews(views, loaded.layers, (config) => baseView(profile(config, selectedProfile)));
102411
- appendViews(views, loaded.layers, (config) => block2(profile(config, selectedProfile)));
102647
+ const profilePrefix = selectedProfile === undefined ? "" : `profiles.${selectedProfile}.`;
102648
+ appendViews(views, loaded.layers, baseView, "");
102649
+ appendViews(views, loaded.layers, block2, "[opencode].");
102650
+ appendViews(views, loaded.layers, (config) => baseView(profile(config, selectedProfile)), profilePrefix);
102651
+ appendViews(views, loaded.layers, (config) => block2(profile(config, selectedProfile)), `${profilePrefix}[opencode].`);
102412
102652
  const resolvedModels = modelView(resolved.config);
102413
102653
  if (Object.keys(resolvedModels.config).length > 0) {
102414
102654
  const source = loaded.layers[0]?.source.path ?? directory;
102415
- views.push({ config: resolvedModels.config, path: source });
102655
+ views.push({ config: resolvedModels.config, keyPrefix: "", path: source });
102416
102656
  }
102417
102657
  let protectedUserView = {};
102418
102658
  for (const layer of loaded.layers) {
@@ -102499,7 +102739,7 @@ function unknownPaths(schema, value, path) {
102499
102739
  if (def.type === "object" && isPlainRecord5(value) && def.shape !== undefined) {
102500
102740
  const catchall = def.catchall !== undefined && definition(def.catchall).type !== "never" ? def.catchall : undefined;
102501
102741
  return Object.entries(value).flatMap(([key, entry]) => {
102502
- const propertySchema = def.shape?.[key];
102742
+ const propertySchema = def.shape !== undefined && Object.hasOwn(def.shape, key) ? def.shape[key] : undefined;
102503
102743
  if (propertySchema !== undefined)
102504
102744
  return unknownPaths(propertySchema, entry, [...path, key]);
102505
102745
  if (catchall !== undefined)
@@ -102537,6 +102777,9 @@ function findUnknownKeyPaths(schema, value) {
102537
102777
  return unknownPaths(schema, value, []);
102538
102778
  }
102539
102779
 
102780
+ // packages/omo-opencode/src/config/prune-plugin-view.ts
102781
+ init_src4();
102782
+
102540
102783
  // packages/omo-opencode/src/config/schema/agent-names.ts
102541
102784
  init_zod();
102542
102785
  var BuiltinAgentNameSchema = _enum([
@@ -102614,19 +102857,19 @@ var FallbackModelsSchema = union([
102614
102857
 
102615
102858
  // packages/omo-opencode/src/config/schema/internal/permission.ts
102616
102859
  init_zod();
102617
- var PermissionValueSchema = _enum(["ask", "allow", "deny"]);
102618
- var BashPermissionSchema = union([
102619
- PermissionValueSchema,
102620
- record(string2(), PermissionValueSchema)
102860
+ var PermissionValueSchema2 = _enum(["ask", "allow", "deny"]);
102861
+ var BashPermissionSchema2 = union([
102862
+ PermissionValueSchema2,
102863
+ record(string2(), PermissionValueSchema2)
102621
102864
  ]);
102622
102865
  var AgentPermissionSchema = object({
102623
- edit: PermissionValueSchema.optional(),
102624
- bash: BashPermissionSchema.optional(),
102625
- webfetch: PermissionValueSchema.optional(),
102626
- task: PermissionValueSchema.optional(),
102627
- doom_loop: PermissionValueSchema.optional(),
102628
- external_directory: PermissionValueSchema.optional()
102629
- }).catchall(PermissionValueSchema.optional());
102866
+ edit: PermissionValueSchema2.optional(),
102867
+ bash: BashPermissionSchema2.optional(),
102868
+ webfetch: PermissionValueSchema2.optional(),
102869
+ task: PermissionValueSchema2.optional(),
102870
+ doom_loop: PermissionValueSchema2.optional(),
102871
+ external_directory: PermissionValueSchema2.optional()
102872
+ }).catchall(PermissionValueSchema2.optional());
102630
102873
 
102631
102874
  // packages/omo-opencode/src/config/schema/agent-overrides.ts
102632
102875
  var AgentOverrideConfigSchema = object({
@@ -103191,6 +103434,26 @@ var OhMyOpenCodeConfigSchema = object({
103191
103434
  default_mode: DefaultModeConfigSchema.optional(),
103192
103435
  _migrations: array(string2()).optional()
103193
103436
  });
103437
+ // packages/omo-opencode/src/config/prune-plugin-view.ts
103438
+ var validatePluginRecord = (record) => {
103439
+ const parsed = OhMyOpenCodeConfigSchema.safeParse(record);
103440
+ return parsed.success ? { success: true } : { success: false, issues: parsed.error.issues };
103441
+ };
103442
+ function prunePluginView(input) {
103443
+ const validation = OhMyOpenCodeConfigSchema.safeParse(input.config);
103444
+ if (validation.success)
103445
+ return { config: input.config, issues: [], warnings: [] };
103446
+ const pruned = pruneInvalidConfigPaths(input.config, validation.error.issues, validatePluginRecord);
103447
+ if (!pruned.ok)
103448
+ return { config: input.config, issues: validation.error.issues, warnings: [] };
103449
+ const file = displayOmoConfigPath(input.path, input.homeDir);
103450
+ return {
103451
+ config: pruned.config,
103452
+ issues: [],
103453
+ warnings: pruned.dropped.map((entry) => `config: ${file}: ${input.keyPrefix}${entry.key} ignored (invalid value)`)
103454
+ };
103455
+ }
103456
+
103194
103457
  // packages/omo-opencode/src/config/validate.ts
103195
103458
  function shortPath(configPath) {
103196
103459
  const candidate = relative7(process.cwd(), configPath);
@@ -103200,9 +103463,8 @@ function formatIssuePath(path) {
103200
103463
  const formatted = path.map((segment) => String(segment)).join(".");
103201
103464
  return formatted.length > 0 ? formatted : "<root>";
103202
103465
  }
103203
- function schemaMessages(configPath, rawConfig) {
103204
- const result = OhMyOpenCodeConfigSchema.safeParse(rawConfig);
103205
- const validationMessages = result.success ? [] : result.error.issues.map((issue) => `${shortPath(configPath)}: ${formatIssuePath(issue.path)}: ${issue.message}`);
103466
+ function schemaMessages(configPath, rawConfig, issues) {
103467
+ const validationMessages = issues.map((issue) => `${shortPath(configPath)}: ${formatIssuePath(issue.path)}: ${issue.message}`);
103206
103468
  const unknownKeyMessages = findUnknownKeyPaths(OhMyOpenCodeConfigSchema, rawConfig).map((path) => `${shortPath(configPath)}: Unknown config key: ${formatIssuePath(path)}`);
103207
103469
  return [...validationMessages, ...unknownKeyMessages];
103208
103470
  }
@@ -103218,11 +103480,13 @@ function parseConfig(rawConfig) {
103218
103480
  }
103219
103481
  return config;
103220
103482
  }
103221
- function parseConfigView(path, rawConfig) {
103483
+ function parseConfigView(view, homeDir) {
103484
+ const pruned = prunePluginView({ config: view.config, homeDir, keyPrefix: view.keyPrefix, path: view.path });
103222
103485
  return {
103223
- config: parseConfig(rawConfig),
103224
- messages: schemaMessages(path, rawConfig),
103225
- path
103486
+ config: parseConfig(pruned.config),
103487
+ messages: schemaMessages(view.path, view.config, pruned.issues),
103488
+ path: view.path,
103489
+ warnings: pruned.warnings
103226
103490
  };
103227
103491
  }
103228
103492
  function mergeViews(views) {
@@ -103314,18 +103578,25 @@ function migrateRalphLoopConfig(config) {
103314
103578
  }
103315
103579
  function validatePluginConfig(directory, environment = process.env) {
103316
103580
  const chain = loadOmoOpenCodeConfigChain(directory, environment);
103317
- const views = chain.views.map((view) => parseConfigView(view.path, view.config));
103318
- const chainMessages = chain.diagnostics.filter((diagnostic) => diagnostic.kind !== "deprecated-keys").map((diagnostic) => `${shortPath(diagnostic.path)}: ${diagnostic.message}`);
103581
+ const homeDir = environment.HOME ?? environment.USERPROFILE;
103582
+ const views = chain.views.map((view) => parseConfigView(view, homeDir));
103583
+ const failing = chain.diagnostics.filter((diagnostic) => diagnostic.kind !== "deprecated-keys" && diagnostic.kind !== "invalid-value");
103584
+ const chainMessages = failing.map((diagnostic) => `${shortPath(diagnostic.path)}: ${diagnostic.message}`);
103319
103585
  const messages = [...chainMessages, ...views.flatMap((view) => view.messages)];
103586
+ const warnings = [
103587
+ ...omoConfigDiagnosticLines(chain.diagnostics.flatMap((diagnostic) => diagnostic.kind === "invalid-value" ? [diagnostic] : []), { homeDir }),
103588
+ ...views.flatMap((view) => view.warnings)
103589
+ ];
103320
103590
  const firstFailingView = views.find((view) => view.messages.length > 0);
103321
103591
  const firstView = views[0];
103322
- const userConfig = parseConfig(chain.protectedUserView);
103592
+ const userConfig = parseConfig(prunePluginView({ config: chain.protectedUserView, homeDir, keyPrefix: "", path: "" }).config);
103323
103593
  const config = applyDisabledProviders(materializeAgentModelChains(protectUserFields(mergeViews(views), userConfig)));
103324
103594
  warnLegacyUlwExecuteKey(chain.views);
103325
103595
  return {
103326
103596
  valid: messages.length === 0,
103327
103597
  messages,
103328
- path: chainMessages.length > 0 ? chain.diagnostics[0]?.path ?? null : firstFailingView?.path ?? firstView?.path ?? null,
103598
+ warnings,
103599
+ path: failing[0]?.path ?? firstFailingView?.path ?? firstView?.path ?? null,
103329
103600
  config: migrateRalphLoopConfig(migrateLegacyUlwExecuteKey(config))
103330
103601
  };
103331
103602
  }
@@ -106449,14 +106720,15 @@ function toOmoConfig(config) {
106449
106720
  function validateConfig() {
106450
106721
  const validation = validatePluginConfig(process.cwd());
106451
106722
  if (!validation.path) {
106452
- return { exists: false, path: null, valid: true, config: null, errors: [] };
106723
+ return { exists: false, path: null, valid: true, config: null, errors: [], warnings: validation.warnings };
106453
106724
  }
106454
106725
  return {
106455
106726
  exists: true,
106456
106727
  path: validation.path,
106457
106728
  valid: validation.valid,
106458
106729
  config: toOmoConfig(validation.config),
106459
- errors: [...validation.messages]
106730
+ errors: [...validation.messages],
106731
+ warnings: validation.warnings
106460
106732
  };
106461
106733
  }
106462
106734
  function collectModelResolutionIssues(config) {
@@ -106509,6 +106781,12 @@ async function checkConfig() {
106509
106781
  }));
106510
106782
  if (legacyWarning !== undefined)
106511
106783
  issues.push(legacyWarning);
106784
+ issues.push(...validation.warnings.map((warning) => ({
106785
+ title: warning,
106786
+ description: "The rest of that file still applies; fix or remove this value to use it.",
106787
+ severity: "warning",
106788
+ affects: ["configuration"]
106789
+ })));
106512
106790
  if (!validation.exists) {
106513
106791
  return {
106514
106792
  name: CHECK_NAMES[CHECK_IDS.CONFIG],