oh-my-opencode 5.0.0-beta.51 → 5.0.0-beta.53

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 (105) hide show
  1. package/README.ja.md +11 -18
  2. package/README.ko.md +10 -17
  3. package/README.md +11 -18
  4. package/README.ru.md +11 -18
  5. package/README.zh-cn.md +11 -18
  6. package/dist/cli/doctor/checks/index.d.ts +2 -0
  7. package/dist/cli/doctor/checks/latest-version.d.ts +11 -0
  8. package/dist/cli/doctor/framework/constants.d.ts +5 -0
  9. package/dist/cli/doctor/framework/types.d.ts +2 -0
  10. package/dist/cli/index.js +181 -63
  11. package/dist/cli-node/index.js +181 -63
  12. package/dist/features/background-agent/manager.d.ts +7 -0
  13. package/dist/features/background-agent/types.d.ts +4 -0
  14. package/dist/features/claude-tasks/storage.d.ts +7 -2
  15. package/dist/features/hook-message-injector/index.d.ts +1 -0
  16. package/dist/features/hook-message-injector/sdk-message-lookup.d.ts +1 -0
  17. package/dist/hooks/keyword-detector/hook.d.ts +2 -0
  18. package/dist/hooks/keyword-detector/ultrawork/index.d.ts +2 -0
  19. package/dist/hooks/unstable-agent-babysitter/task-message-analyzer.d.ts +1 -0
  20. package/dist/index.js +1539 -1292
  21. package/dist/plugin/chat-message/types.d.ts +3 -1
  22. package/dist/plugin/stop-continuation.d.ts +3 -0
  23. package/dist/plugin/system-transform.d.ts +5 -1
  24. package/dist/skills/frontend/ATTRIBUTION.md +10 -0
  25. package/dist/skills/frontend/SKILL.md +3 -0
  26. package/dist/skills/frontend/references/design/README.md +10 -2
  27. package/dist/skills/frontend/references/design/_INDEX.md +1 -0
  28. package/dist/skills/frontend/references/design/ambience-skill.md +145 -0
  29. package/dist/skills/frontend/references/design/interaction-skill.md +2 -0
  30. package/dist/skills/refactor/SKILL.md +3 -3
  31. package/dist/skills/review-work/SKILL.md +1 -1
  32. package/dist/skills/ulw-execute/SKILL.md +5 -5
  33. package/dist/tui.js +89 -13
  34. package/package.json +14 -14
  35. package/packages/lsp-daemon/dist/cli.js +1 -2
  36. package/packages/lsp-daemon/dist/ownership.js +2 -2
  37. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
  38. package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
  39. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  40. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
  41. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  42. package/packages/omo-codex/plugin/components/git-bash/dist/cli.js +1 -1
  43. package/packages/omo-codex/plugin/components/git-bash/dist/codex-hook.js +2 -1
  44. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
  45. package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
  46. package/packages/omo-codex/plugin/components/git-bash/src/codex-hook.ts +2 -1
  47. package/packages/omo-codex/plugin/components/git-bash/test/codex-hook.test.ts +6 -7
  48. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
  49. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
  50. package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +2 -2
  51. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
  52. package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
  53. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
  54. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  55. package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
  56. package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
  57. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
  58. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  59. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
  60. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
  61. package/packages/omo-codex/plugin/components/ulw-execute-continuation/hooks/hooks.json +1 -1
  62. package/packages/omo-codex/plugin/components/ulw-execute-continuation/package.json +1 -1
  63. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +5 -5
  64. package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
  65. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
  66. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
  67. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
  68. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
  69. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
  70. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
  71. package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
  72. package/packages/omo-codex/plugin/hooks/post-tool-use-recording-spawn-admission.json +1 -1
  73. package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
  74. package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
  75. package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
  76. package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
  77. package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
  78. package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
  79. package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
  80. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-execute-continuation.json +1 -1
  81. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
  82. package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
  83. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
  84. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
  85. package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
  86. package/packages/omo-codex/plugin/package-lock.json +12 -12
  87. package/packages/omo-codex/plugin/package.json +1 -1
  88. package/packages/omo-codex/plugin/skills/frontend/ATTRIBUTION.md +10 -0
  89. package/packages/omo-codex/plugin/skills/frontend/SKILL.md +3 -0
  90. package/packages/omo-codex/plugin/skills/frontend/references/design/README.md +10 -2
  91. package/packages/omo-codex/plugin/skills/frontend/references/design/_INDEX.md +1 -0
  92. package/packages/omo-codex/plugin/skills/frontend/references/design/ambience-skill.md +145 -0
  93. package/packages/omo-codex/plugin/skills/frontend/references/design/interaction-skill.md +2 -0
  94. package/packages/omo-codex/plugin/skills/refactor/SKILL.md +3 -3
  95. package/packages/omo-codex/plugin/skills/ulw-execute/SKILL.md +5 -5
  96. package/packages/omo-codex/scripts/install-dist/install-local.mjs +2 -2
  97. package/packages/shared-skills/skills/frontend/ATTRIBUTION.md +10 -0
  98. package/packages/shared-skills/skills/frontend/SKILL.md +3 -0
  99. package/packages/shared-skills/skills/frontend/references/design/README.md +10 -2
  100. package/packages/shared-skills/skills/frontend/references/design/_INDEX.md +1 -0
  101. package/packages/shared-skills/skills/frontend/references/design/ambience-skill.md +145 -0
  102. package/packages/shared-skills/skills/frontend/references/design/interaction-skill.md +2 -0
  103. package/packages/shared-skills/skills/refactor/SKILL.md +3 -3
  104. package/packages/shared-skills/skills/review-work/SKILL.md +1 -1
  105. package/packages/shared-skills/skills/ulw-execute/SKILL.md +5 -5
@@ -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.0.0-beta.51",
68
+ version: "5.0.0-beta.53",
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",
@@ -249,7 +249,7 @@ var init_package = __esm(() => {
249
249
  zod: "^4.4.3"
250
250
  },
251
251
  devDependencies: {
252
- "@code-yeongyu/senpi": "2026.9.9-2",
252
+ "@code-yeongyu/senpi": "2026.9.10-2",
253
253
  "@oh-my-opencode/agents-md-core": "workspace:*",
254
254
  "@oh-my-opencode/ast-grep-mcp": "workspace:*",
255
255
  "@oh-my-opencode/boulder-state": "workspace:*",
@@ -290,18 +290,18 @@ var init_package = __esm(() => {
290
290
  typescript: "^7.0.2"
291
291
  },
292
292
  optionalDependencies: {
293
- "oh-my-opencode-darwin-arm64": "5.0.0-beta.51",
294
- "oh-my-opencode-darwin-x64": "5.0.0-beta.51",
295
- "oh-my-opencode-darwin-x64-baseline": "5.0.0-beta.51",
296
- "oh-my-opencode-linux-arm64": "5.0.0-beta.51",
297
- "oh-my-opencode-linux-arm64-musl": "5.0.0-beta.51",
298
- "oh-my-opencode-linux-x64": "5.0.0-beta.51",
299
- "oh-my-opencode-linux-x64-baseline": "5.0.0-beta.51",
300
- "oh-my-opencode-linux-x64-musl": "5.0.0-beta.51",
301
- "oh-my-opencode-linux-x64-musl-baseline": "5.0.0-beta.51",
302
- "oh-my-opencode-windows-arm64": "5.0.0-beta.51",
303
- "oh-my-opencode-windows-x64": "5.0.0-beta.51",
304
- "oh-my-opencode-windows-x64-baseline": "5.0.0-beta.51"
293
+ "oh-my-opencode-darwin-arm64": "5.0.0-beta.53",
294
+ "oh-my-opencode-darwin-x64": "5.0.0-beta.53",
295
+ "oh-my-opencode-darwin-x64-baseline": "5.0.0-beta.53",
296
+ "oh-my-opencode-linux-arm64": "5.0.0-beta.53",
297
+ "oh-my-opencode-linux-arm64-musl": "5.0.0-beta.53",
298
+ "oh-my-opencode-linux-x64": "5.0.0-beta.53",
299
+ "oh-my-opencode-linux-x64-baseline": "5.0.0-beta.53",
300
+ "oh-my-opencode-linux-x64-musl": "5.0.0-beta.53",
301
+ "oh-my-opencode-linux-x64-musl-baseline": "5.0.0-beta.53",
302
+ "oh-my-opencode-windows-arm64": "5.0.0-beta.53",
303
+ "oh-my-opencode-windows-x64": "5.0.0-beta.53",
304
+ "oh-my-opencode-windows-x64-baseline": "5.0.0-beta.53"
305
305
  },
306
306
  overrides: {
307
307
  "@earendil-works/pi-agent-core": "0.84.2",
@@ -64425,6 +64425,7 @@ var init_injector = __esm(() => {
64425
64425
  var init_hook_message_injector = __esm(() => {
64426
64426
  init_injector();
64427
64427
  init_constants2();
64428
+ init_id_generation();
64428
64429
  });
64429
64430
 
64430
64431
  // packages/omo-opencode/src/shared/opencode-message-dir.ts
@@ -72917,6 +72918,25 @@ var init_model_catalog = __esm(() => {
72917
72918
  OmoModelCatalogLayerSchema = record(string2(), OmoModelCatalogEntryLayerSchema);
72918
72919
  });
72919
72920
 
72921
+ // packages/omo-config-core/src/schema/model-profile.ts
72922
+ function isRecord8(value) {
72923
+ return typeof value === "object" && value !== null && !Array.isArray(value);
72924
+ }
72925
+ var OmoModelProfileInputSchema, OmoModelProfileSchema, OmoModelProfilesSchema, OmoModelProfileLayerInputSchema, OmoModelProfileLayerSchema, OmoModelProfilesLayerSchema;
72926
+ var init_model_profile = __esm(() => {
72927
+ init_zod();
72928
+ init_fallback_models();
72929
+ OmoModelProfileInputSchema = object({
72930
+ display_name: string2().optional(),
72931
+ models: array(union([string2(), OmoFallbackModelObjectSchema])).optional()
72932
+ }).strict();
72933
+ OmoModelProfileSchema = preprocess((value) => isRecord8(value) ? normalizeLegacyModelFields(value) : value, OmoModelProfileInputSchema);
72934
+ OmoModelProfilesSchema = record(string2(), OmoModelProfileSchema);
72935
+ OmoModelProfileLayerInputSchema = OmoModelProfileInputSchema.partial();
72936
+ OmoModelProfileLayerSchema = preprocess((value) => isRecord8(value) ? normalizeLegacyModelFields(value) : value, OmoModelProfileLayerInputSchema);
72937
+ OmoModelProfilesLayerSchema = record(string2(), OmoModelProfileLayerSchema);
72938
+ });
72939
+
72920
72940
  // packages/omo-config-core/src/schema/task.ts
72921
72941
  import { availableParallelism } from "node:os";
72922
72942
  function resolveOmoTaskSettings(input, resolveParallelism = availableParallelism) {
@@ -73109,6 +73129,7 @@ var init_config = __esm(() => {
73109
73129
  init_git_master();
73110
73130
  init_memory();
73111
73131
  init_model_catalog();
73132
+ init_model_profile();
73112
73133
  init_task();
73113
73134
  init_team();
73114
73135
  init_telemetry();
@@ -73122,6 +73143,8 @@ var init_config = __esm(() => {
73122
73143
  task: OmoTaskSettingsLayerSchema.optional(),
73123
73144
  teams: OmoTeamsConfigLayerSchema.optional(),
73124
73145
  models: OmoModelCatalogLayerSchema.optional(),
73146
+ model_profiles: OmoModelProfilesLayerSchema.optional(),
73147
+ model_profile: string2().optional(),
73125
73148
  memory: OmoMemorySettingsLayerSchema.optional(),
73126
73149
  telemetry: OmoTelemetrySettingsLayerSchema.optional()
73127
73150
  }).strict();
@@ -73133,6 +73156,8 @@ var init_config = __esm(() => {
73133
73156
  task: OmoTaskSettingsLayerSchema.optional(),
73134
73157
  teams: OmoTeamsConfigLayerSchema.optional(),
73135
73158
  models: OmoModelCatalogLayerSchema.optional(),
73159
+ model_profiles: OmoModelProfilesLayerSchema.optional(),
73160
+ model_profile: string2().optional(),
73136
73161
  memory: OmoMemorySettingsLayerSchema.optional(),
73137
73162
  telemetry: OmoTelemetrySettingsLayerSchema.optional(),
73138
73163
  "[opencode]": OmoOpenCodeHarnessConfigSchema.optional(),
@@ -73148,6 +73173,8 @@ var init_config = __esm(() => {
73148
73173
  task: OmoTaskSettingsSchema.optional(),
73149
73174
  teams: OmoTeamsConfigSchema.optional(),
73150
73175
  models: OmoModelCatalogSchema.optional(),
73176
+ model_profiles: OmoModelProfilesSchema.optional(),
73177
+ model_profile: string2().optional(),
73151
73178
  memory: OmoMemorySettingsSchema.optional(),
73152
73179
  telemetry: OmoTelemetrySettingsSchema.optional(),
73153
73180
  "[opencode]": OmoOpenCodeHarnessConfigSchema.optional(),
@@ -73166,6 +73193,8 @@ var init_config = __esm(() => {
73166
73193
  task: OmoTaskSettingsLayerSchema.optional(),
73167
73194
  teams: OmoTeamsConfigLayerSchema.optional(),
73168
73195
  models: OmoModelCatalogLayerSchema.optional(),
73196
+ model_profiles: OmoModelProfilesLayerSchema.optional(),
73197
+ model_profile: string2().optional(),
73169
73198
  memory: OmoMemorySettingsLayerSchema.optional(),
73170
73199
  telemetry: OmoTelemetrySettingsLayerSchema.optional(),
73171
73200
  "[opencode]": OmoOpenCodeHarnessConfigSchema.optional(),
@@ -73188,6 +73217,7 @@ var init_schema = __esm(() => {
73188
73217
  init_harness();
73189
73218
  init_memory();
73190
73219
  init_model_catalog();
73220
+ init_model_profile();
73191
73221
  init_model_ref();
73192
73222
  init_task();
73193
73223
  init_team();
@@ -73438,29 +73468,27 @@ function validationDiagnostic(path, issues) {
73438
73468
  function unrecognizedKeyIssues(issues) {
73439
73469
  return issues.flatMap((issue) => issue.code === "unrecognized_keys" ? [{ keys: issue.keys, path: issue.path.map((segment) => String(segment)) }] : []);
73440
73470
  }
73441
- function hasUnsafeUnrecognizedKey(parsed, issues) {
73442
- if (issues.some((issue) => issue.keys.some((key) => isUnsafeObjectKey2(key))))
73443
- return true;
73444
- return hasTamperedPrototype(parsed);
73471
+ function hasUnsafeUnrecognizedKey(issues) {
73472
+ return issues.some((issue) => issue.keys.some((key) => isUnsafeObjectKey2(key)));
73445
73473
  }
73446
73474
  function hasTamperedPrototype(value) {
73447
73475
  if (Array.isArray(value))
73448
73476
  return value.some((entry) => hasTamperedPrototype(entry));
73449
- if (!isRecord8(value))
73477
+ if (!isRecord9(value))
73450
73478
  return false;
73451
73479
  const prototype = Object.getPrototypeOf(value);
73452
73480
  if (prototype !== Object.prototype && prototype !== null)
73453
73481
  return true;
73454
73482
  return Object.values(value).some((entry) => hasTamperedPrototype(entry));
73455
73483
  }
73456
- function isRecord8(value) {
73484
+ function isRecord9(value) {
73457
73485
  return typeof value === "object" && value !== null && !Array.isArray(value);
73458
73486
  }
73459
73487
  function containerAt(record, path) {
73460
73488
  let container = record;
73461
73489
  for (const segment of path) {
73462
73490
  const next = container[segment];
73463
- if (!isRecord8(next))
73491
+ if (!isRecord9(next))
73464
73492
  return null;
73465
73493
  container = next;
73466
73494
  }
@@ -73514,11 +73542,17 @@ function readConfigSource(path, scope, fileSystem) {
73514
73542
  source: { exists: true, loaded: false, path, scope }
73515
73543
  };
73516
73544
  }
73545
+ if (hasTamperedPrototype(parsed.data)) {
73546
+ return {
73547
+ diagnostic: { kind: "validation", message: `Invalid omo config at ${path}: "__proto__" member is not allowed`, path },
73548
+ source: { exists: true, loaded: false, path, scope }
73549
+ };
73550
+ }
73517
73551
  const parsedRecord = toRecord2(parsed.data);
73518
73552
  const validation = OmoConfigLayerSchema.safeParse(parsed.data);
73519
73553
  if (!validation.success) {
73520
73554
  const unrecognized = unrecognizedKeyIssues(validation.error.issues);
73521
- if (unrecognized.length > 0 && hasUnsafeUnrecognizedKey(parsed.data, unrecognized)) {
73555
+ if (hasUnsafeUnrecognizedKey(unrecognized)) {
73522
73556
  return {
73523
73557
  diagnostic: validationDiagnostic(path, validation.error.issues),
73524
73558
  source: { exists: true, loaded: false, path, scope }
@@ -73716,6 +73750,38 @@ function resolveCategoryDefinition(definition, catalog, cycleNames) {
73716
73750
  ...definition.fallback_models === undefined ? {} : { fallback_models: resolveFallbackModels(definition.fallback_models, catalog, cycleNames) }
73717
73751
  };
73718
73752
  }
73753
+ function resolveModelProfile(definition, catalog, cycleNames) {
73754
+ return {
73755
+ ...definition,
73756
+ ...definition.models === undefined ? {} : { models: definition.models.map((entry) => resolveModelEntry(entry, catalog, cycleNames)) }
73757
+ };
73758
+ }
73759
+ function profileShadowDiagnostics(view) {
73760
+ if (view.model_profiles === undefined || view.models === undefined)
73761
+ return [];
73762
+ return Object.keys(view.model_profiles).flatMap((name) => view.models?.[name] === undefined ? [] : [{
73763
+ kind: "validation",
73764
+ message: `Model profile "${name}" shadows a model catalog entry of the same name`,
73765
+ path: `model_profiles.${name}`
73766
+ }]);
73767
+ }
73768
+ function profileSpliceDiagnostics(section, definitions, profileNames) {
73769
+ if (definitions === undefined || profileNames.size === 0)
73770
+ return [];
73771
+ return Object.entries(definitions).flatMap(([name, definition]) => (definition.models ?? []).flatMap((entry, index) => typeof entry !== "string" || !profileNames.has(entry) ? [] : [{
73772
+ kind: "validation",
73773
+ message: `"${entry}" is a model profile; splicing a profile into a category chain is not supported yet`,
73774
+ path: `${section}.${name}.models.${index}`
73775
+ }]));
73776
+ }
73777
+ function modelProfileDiagnostics(view) {
73778
+ const profileNames = new Set(Object.keys(view.model_profiles ?? {}));
73779
+ return [
73780
+ ...profileShadowDiagnostics(view),
73781
+ ...profileSpliceDiagnostics("categories", view.categories, profileNames),
73782
+ ...profileSpliceDiagnostics("agents", view.agents, profileNames)
73783
+ ];
73784
+ }
73719
73785
  function cycleDiagnostics(catalog) {
73720
73786
  if (catalog === undefined)
73721
73787
  return [];
@@ -73726,9 +73792,10 @@ function cycleDiagnostics(catalog) {
73726
73792
  }));
73727
73793
  }
73728
73794
  function resolveModelReferences(view) {
73729
- const diagnostics = cycleDiagnostics(view.models);
73795
+ const cycles = cycleDiagnostics(view.models);
73796
+ const diagnostics = [...cycles, ...modelProfileDiagnostics(view)];
73730
73797
  const cycleNames = new Set;
73731
- for (const diagnostic of diagnostics) {
73798
+ for (const diagnostic of cycles) {
73732
73799
  const name = diagnostic.path.split(".")[1];
73733
73800
  if (name !== undefined)
73734
73801
  cycleNames.add(name);
@@ -73741,12 +73808,17 @@ function resolveModelReferences(view) {
73741
73808
  name,
73742
73809
  resolveCategoryDefinition(definition, view.models, cycleNames)
73743
73810
  ]));
73811
+ const modelProfiles = view.model_profiles === undefined ? undefined : Object.fromEntries(Object.entries(view.model_profiles).map(([name, definition]) => [
73812
+ name,
73813
+ resolveModelProfile(definition, view.models, cycleNames)
73814
+ ]));
73744
73815
  return {
73745
73816
  diagnostics,
73746
73817
  view: {
73747
73818
  ...view,
73748
73819
  ...agents === undefined ? {} : { agents },
73749
- ...categories === undefined ? {} : { categories }
73820
+ ...categories === undefined ? {} : { categories },
73821
+ ...modelProfiles === undefined ? {} : { model_profiles: modelProfiles }
73750
73822
  }
73751
73823
  };
73752
73824
  }
@@ -77081,7 +77153,7 @@ function shouldRetainLine(line, cutoffMs) {
77081
77153
  function parseDiagnosticLine(line) {
77082
77154
  try {
77083
77155
  const parsed = JSON.parse(line);
77084
- if (!isRecord10(parsed)) {
77156
+ if (!isRecord11(parsed)) {
77085
77157
  return null;
77086
77158
  }
77087
77159
  return parsed;
@@ -77092,7 +77164,7 @@ function parseDiagnosticLine(line) {
77092
77164
  throw error;
77093
77165
  }
77094
77166
  }
77095
- function isRecord10(value) {
77167
+ function isRecord11(value) {
77096
77168
  return value !== null && typeof value === "object" && !Array.isArray(value);
77097
77169
  }
77098
77170
  function trimToMaxBytes(lines) {
@@ -82466,7 +82538,7 @@ function coerceBool(value) {
82466
82538
  function coerceString(value) {
82467
82539
  return typeof value == "string" ? value : undefined;
82468
82540
  }
82469
- function isRecord11(value) {
82541
+ function isRecord12(value) {
82470
82542
  return typeof value == "object" && value !== null && !Array.isArray(value);
82471
82543
  }
82472
82544
  function toRfc3339(timestamp) {
@@ -82488,7 +82560,7 @@ function relocateInto(properties, key, value) {
82488
82560
  properties[key] = value;
82489
82561
  }
82490
82562
  function buildV1Event(message) {
82491
- const sourceProperties = isRecord11(message.properties) ? message.properties : {};
82563
+ const sourceProperties = isRecord12(message.properties) ? message.properties : {};
82492
82564
  const properties = {
82493
82565
  ...sourceProperties
82494
82566
  };
@@ -84518,7 +84590,7 @@ var package_default2;
84518
84590
  var init_package2 = __esm(() => {
84519
84591
  package_default2 = {
84520
84592
  name: "@oh-my-opencode/omo-codex",
84521
- version: "5.0.0-beta.51",
84593
+ version: "5.0.0-beta.53",
84522
84594
  type: "module",
84523
84595
  private: true,
84524
84596
  description: "Codex harness adapter for oh-my-openagent. Vendored Codex plugin namespace (omo) + TypeScript installer + telemetry.",
@@ -87939,6 +88011,19 @@ var EXIT_CODES = {
87939
88011
  var MIN_OPENCODE_VERSION = "1.4.0";
87940
88012
  var PACKAGE_NAME = PUBLISHED_PACKAGE_NAME;
87941
88013
  var OPENCODE_BINARIES2 = ["opencode", "opencode-desktop"];
88014
+ var EDITION_LABELS = {
88015
+ opencode: "OpenCode",
88016
+ codex: "Codex"
88017
+ };
88018
+ var EDITION_PACKAGE_NAMES = {
88019
+ opencode: PUBLISHED_PACKAGE_NAME,
88020
+ codex: "lazycodex-ai"
88021
+ };
88022
+ var UPDATE_COMMANDS = {
88023
+ opencode: `bunx ${PUBLISHED_PACKAGE_NAME} install`,
88024
+ codex: "npx lazycodex-ai install --no-tui --codex-autonomous"
88025
+ };
88026
+ var LATEST_UNAVAILABLE_TEXT = "could not check";
87942
88027
 
87943
88028
  // packages/omo-opencode/src/cli/minimum-opencode-version.ts
87944
88029
  init_opencode_version();
@@ -90554,10 +90639,10 @@ function readCatalogMultiAgentVersion(model, cachePath) {
90554
90639
  } catch {
90555
90640
  return null;
90556
90641
  }
90557
- if (!isRecord9(cache) || !Array.isArray(cache.models))
90642
+ if (!isRecord10(cache) || !Array.isArray(cache.models))
90558
90643
  return null;
90559
90644
  for (const entry of cache.models) {
90560
- if (!isRecord9(entry))
90645
+ if (!isRecord10(entry))
90561
90646
  continue;
90562
90647
  if (entry.slug !== model && entry.id !== model)
90563
90648
  continue;
@@ -90582,7 +90667,7 @@ function readRootModelCatalogPath(config) {
90582
90667
  const single = config.match(/^\s*model_catalog_json\s*=\s*'([^']+)'/m);
90583
90668
  return single?.[1] ?? null;
90584
90669
  }
90585
- function isRecord9(value) {
90670
+ function isRecord10(value) {
90586
90671
  return typeof value === "object" && value !== null && !Array.isArray(value);
90587
90672
  }
90588
90673
  function removeFeatureFlagSetting(config, featureName) {
@@ -93315,7 +93400,7 @@ async function readSettings(settingsPath) {
93315
93400
  throw error;
93316
93401
  }
93317
93402
  const parsed = JSON.parse(raw);
93318
- if (!isRecord12(parsed))
93403
+ if (!isRecord13(parsed))
93319
93404
  throw new Error(`${settingsPath} must contain a JSON object`);
93320
93405
  return parsed;
93321
93406
  }
@@ -93376,7 +93461,7 @@ async function nextBackupPath(settingsPath) {
93376
93461
  function timestampForBackup() {
93377
93462
  return new Date().toISOString().replace(/[-:.]/g, "");
93378
93463
  }
93379
- function isRecord12(value) {
93464
+ function isRecord13(value) {
93380
93465
  return typeof value === "object" && value !== null && !Array.isArray(value);
93381
93466
  }
93382
93467
  async function readPackageName(packagePath) {
@@ -93396,7 +93481,7 @@ async function readPackageName(packagePath) {
93396
93481
  return;
93397
93482
  throw error;
93398
93483
  }
93399
- return isRecord12(parsed) && typeof parsed.name === "string" ? parsed.name : undefined;
93484
+ return isRecord13(parsed) && typeof parsed.name === "string" ? parsed.name : undefined;
93400
93485
  }
93401
93486
  async function fileExists(path) {
93402
93487
  try {
@@ -93514,7 +93599,7 @@ async function verifyAstGrepRuntimeIntegrity(pluginPath, platform) {
93514
93599
  }
93515
93600
  }
93516
93601
  function isAstGrepRuntimeManifest(value) {
93517
- if (!isRecord12(value))
93602
+ if (!isRecord13(value))
93518
93603
  return false;
93519
93604
  return typeof value.sha256 === "string" && /^[a-f0-9]{64}$/.test(value.sha256) && typeof value.mode === "number" && Number.isInteger(value.mode) && typeof value.stagedAtUtc === "string" && !Number.isNaN(Date.parse(value.stagedAtUtc));
93520
93605
  }
@@ -100738,7 +100823,9 @@ async function checkConfig() {
100738
100823
  }
100739
100824
 
100740
100825
  // packages/omo-opencode/src/cli/doctor/checks/deprecated-reasoning-keys.ts
100826
+ init_src4();
100741
100827
  init_main();
100828
+ init_config_migration();
100742
100829
  import { existsSync as existsSync52, readFileSync as readFileSync33 } from "node:fs";
100743
100830
  import { join as join78 } from "node:path";
100744
100831
  var CANONICAL_REPLACEMENT = new Map([
@@ -100746,18 +100833,19 @@ var CANONICAL_REPLACEMENT = new Map([
100746
100833
  ["reasoningEffort", "reasoning"],
100747
100834
  ["thinking", 'reasoning: "off" or provider_options.thinking'],
100748
100835
  ["textVerbosity", "provider_options.textVerbosity"],
100749
- ["fallback_models", "models"]
100836
+ ["fallback_models", "models: [<primary>, ...fallbacks] (the first entry becomes the primary model)"]
100750
100837
  ]);
100838
+ var MIGRATE_SUFFIX = ", or run: oh-my-openagent config migrate";
100751
100839
  var TUNING_CONTAINERS = new Set(["agents", "categories", "models"]);
100752
100840
  var PASSTHROUGH_CONTAINERS = new Set(["provider_options", "providerOptions"]);
100753
- function isRecord13(value) {
100841
+ function isRecord14(value) {
100754
100842
  return value !== null && typeof value === "object" && !Array.isArray(value);
100755
100843
  }
100756
100844
  function isHarnessBlock(key) {
100757
100845
  return key.startsWith("[") && key.endsWith("]");
100758
100846
  }
100759
- function collectIssues(configPath, value, prefix) {
100760
- if (!isRecord13(value))
100847
+ function collectIssues(configPath, value, prefix, fixSuffix) {
100848
+ if (!isRecord14(value))
100761
100849
  return [];
100762
100850
  const issues = [];
100763
100851
  for (const [key, child] of Object.entries(value)) {
@@ -100767,30 +100855,35 @@ function collectIssues(configPath, value, prefix) {
100767
100855
  issues.push({
100768
100856
  title: "Deprecated config key",
100769
100857
  description: `${configPath}: ${path}`,
100770
- fix: `Replace ${key} with ${replacement}, or run: oh-my-openagent config migrate`,
100858
+ fix: `Replace ${key} with ${replacement}${fixSuffix}`,
100771
100859
  severity: "warning",
100772
100860
  affects: [path]
100773
100861
  });
100774
100862
  continue;
100775
100863
  }
100776
- if (!isRecord13(child))
100864
+ if (!isRecord14(child))
100777
100865
  continue;
100778
100866
  if (PASSTHROUGH_CONTAINERS.has(key))
100779
100867
  continue;
100780
100868
  if (prefix.length === 0 && key === "profiles") {
100781
100869
  for (const profile of Object.values(child)) {
100782
- issues.push(...collectIssues(configPath, profile, ""));
100870
+ issues.push(...collectIssues(configPath, profile, "", fixSuffix));
100783
100871
  }
100784
100872
  continue;
100785
100873
  }
100786
100874
  if (key === "[opencode]")
100787
100875
  continue;
100788
100876
  if (TUNING_CONTAINERS.has(key) || isHarnessBlock(key) || prefix.length > 0) {
100789
- issues.push(...collectIssues(configPath, child, path));
100877
+ issues.push(...collectIssues(configPath, child, path, fixSuffix));
100790
100878
  }
100791
100879
  }
100792
100880
  return issues;
100793
100881
  }
100882
+ function migrateFixSuffix(parsed) {
100883
+ if (isRecord14(parsed) && hasMigrationMarker(parsed, REASONING_UNIFICATION_MIGRATION_ID))
100884
+ return "";
100885
+ return MIGRATE_SUFFIX;
100886
+ }
100794
100887
  function userConfigPaths() {
100795
100888
  const home = process.env.HOME ?? process.env.USERPROFILE;
100796
100889
  if (home === undefined || home.length === 0)
@@ -100805,7 +100898,7 @@ async function checkDeprecatedReasoningKeys() {
100805
100898
  continue;
100806
100899
  scanned.push(configPath);
100807
100900
  const parsed = parse2(readFileSync33(configPath, "utf-8"));
100808
- issues.push(...collectIssues(configPath, parsed, ""));
100901
+ issues.push(...collectIssues(configPath, parsed, "", migrateFixSuffix(parsed)));
100809
100902
  }
100810
100903
  return {
100811
100904
  name: CHECK_NAMES[CHECK_IDS.CONFIG],
@@ -101931,6 +102024,24 @@ async function pathExists2(path) {
101931
102024
  }
101932
102025
  }
101933
102026
 
102027
+ // packages/omo-opencode/src/cli/doctor/checks/latest-version.ts
102028
+ init_auto_update_checker();
102029
+ function gatherEditionDistTags(target, fetchDistTags = fetchNpmDistTags) {
102030
+ return fetchDistTags(EDITION_PACKAGE_NAMES[target]);
102031
+ }
102032
+ function resolveInstalledVersion(input) {
102033
+ if (input.target === "codex" && input.codex) {
102034
+ return input.codex.packageVersion ?? input.codex.installerVersion;
102035
+ }
102036
+ return input.systemInfo.pluginVersion;
102037
+ }
102038
+ function resolveLatestVersion(input) {
102039
+ if (!input.distTags)
102040
+ return null;
102041
+ const channel = extractChannel(resolveInstalledVersion(input));
102042
+ return input.distTags[channel] ?? input.distTags.latest ?? null;
102043
+ }
102044
+
101934
102045
  // packages/omo-opencode/src/cli/doctor/checks/codex-components.ts
101935
102046
  init_src();
101936
102047
  import { readdir as readdir15, readFile as readFile28, stat as stat7 } from "node:fs/promises";
@@ -102007,12 +102118,12 @@ async function auditBundleTargets(pluginRoot) {
102007
102118
  let referencedCount = 0;
102008
102119
  for (const manifestPath of await findManifestPaths(pluginRoot, ".mcp.json")) {
102009
102120
  const manifest = await readJson2(manifestPath);
102010
- if (manifest === null || !isRecord14(manifest["mcpServers"]))
102121
+ if (manifest === null || !isRecord15(manifest["mcpServers"]))
102011
102122
  continue;
102012
102123
  const manifestRoot = dirname33(manifestPath);
102013
102124
  const isRootManifest = resolve24(manifestRoot) === resolve24(pluginRoot);
102014
102125
  for (const server of Object.values(manifest["mcpServers"])) {
102015
- if (!isRecord14(server) || !Array.isArray(server["args"]))
102126
+ if (!isRecord15(server) || !Array.isArray(server["args"]))
102016
102127
  continue;
102017
102128
  for (const arg of server["args"]) {
102018
102129
  if (typeof arg !== "string" || !isPluginRuntimePathArg(arg))
@@ -102098,7 +102209,7 @@ function collectHookCommands(value, commands) {
102098
102209
  collectHookCommands(item, commands);
102099
102210
  return;
102100
102211
  }
102101
- if (!isRecord14(value))
102212
+ if (!isRecord15(value))
102102
102213
  return;
102103
102214
  if (value["type"] === "command") {
102104
102215
  if (typeof value["command"] === "string")
@@ -102153,7 +102264,7 @@ function parseDegradedEntries(value) {
102153
102264
  return [];
102154
102265
  const entries = [];
102155
102266
  for (const item of value) {
102156
- if (!isRecord14(item))
102267
+ if (!isRecord15(item))
102157
102268
  continue;
102158
102269
  if (typeof item["component"] !== "string" || typeof item["reason"] !== "string")
102159
102270
  continue;
@@ -102187,7 +102298,7 @@ function degradedDetailLines(entries) {
102187
102298
  async function readJson2(path) {
102188
102299
  try {
102189
102300
  const parsed = JSON.parse(await readFile28(path, "utf8"));
102190
- return isRecord14(parsed) ? parsed : null;
102301
+ return isRecord15(parsed) ? parsed : null;
102191
102302
  } catch (error) {
102192
102303
  if (error instanceof Error)
102193
102304
  return null;
@@ -102208,7 +102319,7 @@ function normalizeRelative(root, target) {
102208
102319
  function normalizePathSeparators(path) {
102209
102320
  return path.split("\\").join("/");
102210
102321
  }
102211
- function isRecord14(value) {
102322
+ function isRecord15(value) {
102212
102323
  return typeof value === "object" && value !== null && !Array.isArray(value);
102213
102324
  }
102214
102325
 
@@ -102341,7 +102452,6 @@ function getCodexCheckDefinitions() {
102341
102452
  }
102342
102453
 
102343
102454
  // packages/omo-opencode/src/cli/doctor/framework/format-default.ts
102344
- init_shared();
102345
102455
  var import_picocolors19 = __toESM(require_picocolors(), 1);
102346
102456
 
102347
102457
  // packages/omo-opencode/src/cli/doctor/framework/format-shared.ts
@@ -102383,23 +102493,27 @@ function formatIssue(issue, index) {
102383
102493
  }
102384
102494
 
102385
102495
  // packages/omo-opencode/src/cli/doctor/framework/format-default.ts
102496
+ function formatOkSummary(result, headline, installedVersion) {
102497
+ const target = result.target ?? "opencode";
102498
+ const latest = result.latestVersion ?? LATEST_UNAVAILABLE_TEXT;
102499
+ return [
102500
+ ` ${import_picocolors19.default.green(SYMBOLS2.check)} ${import_picocolors19.default.green(`${headline} · Edition: ${EDITION_LABELS[target]} · Installed: ${installedVersion} · Latest: ${latest}`)}`,
102501
+ ` Update: ${UPDATE_COMMANDS[target]}`
102502
+ ];
102503
+ }
102386
102504
  function formatDefault(result) {
102387
102505
  const lines = [];
102388
102506
  lines.push(formatHeader());
102389
102507
  const allIssues = result.results.flatMap((r) => r.issues);
102390
102508
  if (allIssues.length === 0) {
102391
102509
  if (result.target === "codex" && result.codex) {
102392
- const codex = result.codex.codexPath ?? result.codex.codexAppId ?? "unknown";
102393
- const pluginVer = result.codex.pluginVersion ?? "unknown";
102394
- const packageName = result.codex.packageName ?? "lazycodex-ai";
102395
102510
  const packageVer = result.codex.packageVersion ?? result.codex.installerVersion;
102396
- lines.push(` ${import_picocolors19.default.green(SYMBOLS2.check)} ${import_picocolors19.default.green(`LazyCodex OK (codex ${codex} · omo ${pluginVer} · ${packageName} ${packageVer})`)}`);
102511
+ lines.push(...formatOkSummary(result, "LazyCodex OK", packageVer));
102397
102512
  return lines.join(`
102398
102513
  `);
102399
102514
  }
102400
- const opencodeVer = result.systemInfo.opencodeVersion ?? "unknown";
102401
102515
  const pluginVer = result.systemInfo.pluginVersion ?? "unknown";
102402
- lines.push(` ${import_picocolors19.default.green(SYMBOLS2.check)} ${import_picocolors19.default.green(`System OK (opencode ${opencodeVer} · oh-my-opencode ${pluginVer})`.replace("oh-my-opencode", PLUGIN_NAME))}`);
102516
+ lines.push(...formatOkSummary(result, "System OK", pluginVer));
102403
102517
  } else {
102404
102518
  const issueCount = allIssues.filter((i) => i.severity === "error").length;
102405
102519
  const warnCount = allIssues.filter((i) => i.severity === "warning").length;
@@ -102646,7 +102760,8 @@ function buildTimeoutResult(start, options) {
102646
102760
  systemInfo: { opencodeVersion: null, opencodePath: null, pluginVersion: null, loadedVersion: null, bunVersion: null, configPath: null, configValid: false, isLocalDev: false },
102647
102761
  tools: { lspServers: [], astGrepCli: false, commentChecker: false, ghCli: { installed: false, authenticated: false, username: null }, mcpBuiltin: [], mcpUser: [] },
102648
102762
  summary: { total: 1, passed: 0, failed: 1, warnings: 0, skipped: 0, duration: Math.round(performance.now() - start) },
102649
- exitCode: EXIT_CODES.FAILURE
102763
+ exitCode: EXIT_CODES.FAILURE,
102764
+ latestVersion: null
102650
102765
  };
102651
102766
  if (options.json) {
102652
102767
  console.log(formatJsonOutput2(timeoutResult));
@@ -102666,7 +102781,8 @@ async function runDoctor(options) {
102666
102781
  Promise.all(allChecks.map(runCheck)),
102667
102782
  gatherSystemInfo(),
102668
102783
  gatherToolsSummary(),
102669
- target === "codex" ? gatherCodexSummary() : Promise.resolve(undefined)
102784
+ target === "codex" ? gatherCodexSummary() : Promise.resolve(undefined),
102785
+ gatherEditionDistTags(target)
102670
102786
  ]);
102671
102787
  let timer;
102672
102788
  const timeoutPromise = new Promise((_, reject) => {
@@ -102676,8 +102792,9 @@ async function runDoctor(options) {
102676
102792
  let systemInfo;
102677
102793
  let tools;
102678
102794
  let codex;
102795
+ let distTags;
102679
102796
  try {
102680
- [results, systemInfo, tools, codex] = await Promise.race([checksPromise, timeoutPromise]);
102797
+ [results, systemInfo, tools, codex, distTags] = await Promise.race([checksPromise, timeoutPromise]);
102681
102798
  } catch (error) {
102682
102799
  clearTimeout(timer);
102683
102800
  if (error instanceof DoctorTimeoutError) {
@@ -102696,7 +102813,8 @@ async function runDoctor(options) {
102696
102813
  summary,
102697
102814
  exitCode,
102698
102815
  target,
102699
- codex
102816
+ codex,
102817
+ latestVersion: resolveLatestVersion({ target, systemInfo, codex, distTags })
102700
102818
  };
102701
102819
  if (options.json) {
102702
102820
  console.log(formatJsonOutput2(doctorResult));
@@ -61,6 +61,7 @@ export declare class BackgroundManager {
61
61
  private queuesByKey;
62
62
  private processingKeys;
63
63
  private completionTimers;
64
+ private readonly syncAttachedSessions;
64
65
  private completedTaskArchive;
65
66
  private completedTaskSummaries;
66
67
  private idleDeferralTimers;
@@ -140,6 +141,12 @@ export declare class BackgroundManager {
140
141
  private updateBackgroundTaskMarker;
141
142
  getAllDescendantTasks(sessionID: string): BackgroundTask[];
142
143
  findBySession(sessionID: string): BackgroundTask | undefined;
144
+ /**
145
+ * Marks a session as being polled by a run_in_background=false continuation so the
146
+ * completion cleanup timer neither drops the task nor deletes the session underneath it.
147
+ * The returned detach restarts the cleanup grace window once the waiter leaves.
148
+ */
149
+ attachSyncContinuation(sessionID: string): () => void;
143
150
  private resolveTaskAttemptBySession;
144
151
  private getConcurrencyKeyFromInput;
145
152
  private getRawConcurrencyKeyFromInput;
@@ -70,6 +70,8 @@ export interface BackgroundTask {
70
70
  isUnstableAgent?: boolean;
71
71
  /** Category used for this task (e.g., 'quick', 'visual-engineering') */
72
72
  category?: string;
73
+ /** Directory the child session is created and prompted in; defaults to the parent session directory */
74
+ cwd?: string;
73
75
  onSessionCreated?: (sessionId: string) => void | Promise<void>;
74
76
  /** Pending retry notification details for the next spawned retry session */
75
77
  retryNotification?: {
@@ -118,6 +120,8 @@ export interface LaunchInput {
118
120
  skillContent?: string;
119
121
  category?: string;
120
122
  sessionPermission?: SessionPermissionRule[];
123
+ /** Directory the child session is created and prompted in; defaults to the parent session directory */
124
+ cwd?: string;
121
125
  onSessionCreated?: (sessionId: string) => void | Promise<void>;
122
126
  /** User tool overrides (ask/allow/deny) from category or agent config. Merged into launchTools before hardcoded restrictions. */
123
127
  userPermission?: Record<string, "ask" | "allow" | "deny">;
@@ -6,9 +6,14 @@ export declare function resolveTaskListId(config?: Partial<OhMyOpenCodeConfig>):
6
6
  export declare function ensureDir(dirPath: string): void;
7
7
  export declare function readJsonSafe<T>(filePath: string, schema: z.ZodType<T>): T | null;
8
8
  export declare function writeJsonAtomic(filePath: string, data: unknown): void;
9
+ export interface AcquireLockOptions {
10
+ waitTimeoutMs?: number;
11
+ retryDelayMs?: number;
12
+ }
13
+ export declare function resolveLockWaitTimeoutMs(): number;
9
14
  export declare function generateTaskId(): string;
10
15
  export declare function listTaskFiles(config?: Partial<OhMyOpenCodeConfig>): string[];
11
- export declare function acquireLock(dirPath: string): {
16
+ export declare function acquireLock(dirPath: string, options?: AcquireLockOptions): Promise<{
12
17
  acquired: boolean;
13
18
  release: () => void;
14
- };
19
+ }>;
@@ -2,3 +2,4 @@ export { injectHookMessage, findNearestMessageWithFields, findFirstMessageWithAg
2
2
  export type { StoredMessage } from "./injector";
3
3
  export type { MessageMeta, OriginalMessageContext, TextPart, ToolPermission } from "./types";
4
4
  export { MESSAGE_STORAGE } from "./constants";
5
+ export { generatePartId } from "./id-generation";