oh-my-opencode 5.1.60 → 5.1.62

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 (121) hide show
  1. package/.agents/command/remove-deadcode.md +1 -1
  2. package/.agents/skills/remove-deadcode/SKILL.md +1 -1
  3. package/.opencode/command/remove-deadcode.md +1 -1
  4. package/dist/cli/index.js +181 -32
  5. package/dist/cli/service-auth/index.d.ts +2 -1
  6. package/dist/cli/service-auth/session.d.ts +27 -0
  7. package/dist/cli/service-auth/sync-pin-retire.d.ts +7 -0
  8. package/dist/cli-node/index.js +181 -32
  9. package/dist/config/schema/agent-names.d.ts +1 -0
  10. package/dist/index.js +2029 -1406
  11. package/dist/skills/browser/references/owned-engine/README.md +1 -1
  12. package/dist/skills/browser/runtime/omowright/manifest.json +1 -1
  13. package/dist/skills/frontend/SKILL.md +2 -2
  14. package/dist/skills/frontend/references/design/README.md +2 -2
  15. package/dist/skills/frontend/references/design/component-catalogs.md +1 -1
  16. package/dist/skills/frontend/references/design/design-system-architecture.md +1 -1
  17. package/dist/skills/frontend/references/design/react-dev-tooling-skill.md +1 -1
  18. package/dist/skills/frontend/references/designpowers/lane-a-direction.md +5 -5
  19. package/dist/skills/frontend/references/designpowers/routing.md +2 -2
  20. package/dist/skills/frontend/references/perfection/README.md +1 -1
  21. package/dist/skills/programming/references/python/libraries.md +3 -3
  22. package/dist/skills/programming/references/python/one-liners.md +1 -1
  23. package/dist/skills/programming/references/python/pyproject-strict.md +1 -1
  24. package/dist/skills/programming/references/rust/libraries.md +2 -2
  25. package/dist/skills/refactor/SKILL.md +1 -1
  26. package/dist/skills/ultimate-browsing/SKILL.md +1 -1
  27. package/dist/skills/ultimate-browsing/references/insane-search/README.md +1 -1
  28. package/dist/skills/ulw-execute/SKILL.md +1 -1
  29. package/dist/skills/ulw-research/SKILL.md +2 -2
  30. package/dist/tui.js +41 -19
  31. package/package.json +14 -14
  32. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
  33. package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +13 -0
  34. package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
  35. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  36. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
  37. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  38. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
  39. package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
  40. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
  41. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
  42. package/packages/omo-codex/plugin/components/lcx/skills/lcx-doctor/SKILL.md +1 -1
  43. package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +2 -2
  44. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
  45. package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
  46. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
  47. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  48. package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
  49. package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
  50. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
  51. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  52. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
  53. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
  54. package/packages/omo-codex/plugin/components/ulw-execute-continuation/hooks/hooks.json +1 -1
  55. package/packages/omo-codex/plugin/components/ulw-execute-continuation/package.json +1 -1
  56. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +5 -5
  57. package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
  58. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
  59. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
  60. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
  61. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
  62. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
  63. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
  64. package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
  65. package/packages/omo-codex/plugin/hooks/post-tool-use-recording-spawn-admission.json +1 -1
  66. package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
  67. package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
  68. package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
  69. package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
  70. package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
  71. package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
  72. package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
  73. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-execute-continuation.json +1 -1
  74. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
  75. package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
  76. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
  77. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
  78. package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
  79. package/packages/omo-codex/plugin/package-lock.json +12 -12
  80. package/packages/omo-codex/plugin/package.json +1 -1
  81. package/packages/omo-codex/plugin/skills/browser/references/owned-engine/README.md +1 -1
  82. package/packages/omo-codex/plugin/skills/browser/runtime/omowright/manifest.json +1 -1
  83. package/packages/omo-codex/plugin/skills/frontend/SKILL.md +2 -2
  84. package/packages/omo-codex/plugin/skills/frontend/references/design/README.md +2 -2
  85. package/packages/omo-codex/plugin/skills/frontend/references/design/component-catalogs.md +1 -1
  86. package/packages/omo-codex/plugin/skills/frontend/references/design/design-system-architecture.md +1 -1
  87. package/packages/omo-codex/plugin/skills/frontend/references/design/react-dev-tooling-skill.md +1 -1
  88. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/lane-a-direction.md +5 -5
  89. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/routing.md +2 -2
  90. package/packages/omo-codex/plugin/skills/frontend/references/perfection/README.md +1 -1
  91. package/packages/omo-codex/plugin/skills/lcx-doctor/SKILL.md +1 -1
  92. package/packages/omo-codex/plugin/skills/programming/references/python/libraries.md +3 -3
  93. package/packages/omo-codex/plugin/skills/programming/references/python/one-liners.md +1 -1
  94. package/packages/omo-codex/plugin/skills/programming/references/python/pyproject-strict.md +1 -1
  95. package/packages/omo-codex/plugin/skills/programming/references/rust/libraries.md +2 -2
  96. package/packages/omo-codex/plugin/skills/refactor/SKILL.md +1 -1
  97. package/packages/omo-codex/plugin/skills/ultimate-browsing/SKILL.md +1 -1
  98. package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/README.md +1 -1
  99. package/packages/omo-codex/plugin/skills/ulw-execute/SKILL.md +1 -1
  100. package/packages/omo-codex/plugin/skills/ulw-research/SKILL.md +2 -2
  101. package/packages/omo-codex/scripts/install-dist/install-local.mjs +15 -2
  102. package/packages/shared-skills/skills/browser/references/owned-engine/README.md +1 -1
  103. package/packages/shared-skills/skills/browser/runtime/omowright/manifest.json +1 -1
  104. package/packages/shared-skills/skills/frontend/SKILL.md +2 -2
  105. package/packages/shared-skills/skills/frontend/references/design/README.md +2 -2
  106. package/packages/shared-skills/skills/frontend/references/design/component-catalogs.md +1 -1
  107. package/packages/shared-skills/skills/frontend/references/design/design-system-architecture.md +1 -1
  108. package/packages/shared-skills/skills/frontend/references/design/react-dev-tooling-skill.md +1 -1
  109. package/packages/shared-skills/skills/frontend/references/designpowers/lane-a-direction.md +5 -5
  110. package/packages/shared-skills/skills/frontend/references/designpowers/routing.md +2 -2
  111. package/packages/shared-skills/skills/frontend/references/perfection/README.md +1 -1
  112. package/packages/shared-skills/skills/programming/references/python/libraries.md +3 -3
  113. package/packages/shared-skills/skills/programming/references/python/one-liners.md +1 -1
  114. package/packages/shared-skills/skills/programming/references/python/pyproject-strict.md +1 -1
  115. package/packages/shared-skills/skills/programming/references/rust/libraries.md +2 -2
  116. package/packages/shared-skills/skills/refactor/SKILL.md +1 -1
  117. package/packages/shared-skills/skills/ultimate-browsing/SKILL.md +1 -1
  118. package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/README.md +1 -1
  119. package/packages/shared-skills/skills/ulw-execute/SKILL.md +1 -1
  120. package/packages/shared-skills/skills/ulw-research/SKILL.md +2 -2
  121. package/.opencode/skills/hyperplan/SKILL.md +0 -450
@@ -114,7 +114,7 @@ For EACH batch, fire a deep agent:
114
114
  ```
115
115
  task(
116
116
  category="deep-low",
117
- load_skills=["typescript-programmer", "git-master"],
117
+ load_skills=["programming", "git-master"],
118
118
  run_in_background=true,
119
119
  description="Remove dead code batch N: [brief description]",
120
120
  prompt="[see template below]"
@@ -114,7 +114,7 @@ For EACH batch, fire a deep agent:
114
114
  ```
115
115
  task(
116
116
  category="deep-low",
117
- load_skills=["typescript-programmer", "git-master"],
117
+ load_skills=["programming", "git-master"],
118
118
  run_in_background=true,
119
119
  description="Remove dead code batch N: [brief description]",
120
120
  prompt="[see template below]"
@@ -114,7 +114,7 @@ For EACH batch, fire a deep agent:
114
114
  ```
115
115
  task(
116
116
  category="deep",
117
- load_skills=["typescript-programmer", "git-master"],
117
+ load_skills=["programming", "git-master"],
118
118
  run_in_background=true,
119
119
  description="Remove dead code batch N: [brief description]",
120
120
  prompt="[see template below]"
package/dist/cli/index.js CHANGED
@@ -2132,7 +2132,7 @@ var package_default;
2132
2132
  var init_package = __esm(() => {
2133
2133
  package_default = {
2134
2134
  name: "oh-my-opencode",
2135
- version: "5.1.60",
2135
+ version: "5.1.62",
2136
2136
  description: "The Best AI Agent Harness - Batteries-Included OpenCode Plugin with Multi-Model Orchestration, Parallel Background Agents, and Crafted LSP/AST Tools",
2137
2137
  main: "./dist/index.js",
2138
2138
  types: "dist/index.d.ts",
@@ -2319,7 +2319,7 @@ var init_package = __esm(() => {
2319
2319
  },
2320
2320
  devDependencies: {
2321
2321
  "@clack/prompts": "^1.8.1",
2322
- "@code-yeongyu/senpi": "2026.11.2-3",
2322
+ "@code-yeongyu/senpi": "2026.11.5-1",
2323
2323
  "@modelcontextprotocol/sdk": "^1.30.0",
2324
2324
  "@oh-my-opencode/agents-md-core": "workspace:*",
2325
2325
  "@oh-my-opencode/ast-grep-mcp": "workspace:*",
@@ -2384,18 +2384,18 @@ var init_package = __esm(() => {
2384
2384
  typescript: "^7.0.2"
2385
2385
  },
2386
2386
  optionalDependencies: {
2387
- "oh-my-opencode-darwin-arm64": "5.1.60",
2388
- "oh-my-opencode-darwin-x64": "5.1.60",
2389
- "oh-my-opencode-darwin-x64-baseline": "5.1.60",
2390
- "oh-my-opencode-linux-arm64": "5.1.60",
2391
- "oh-my-opencode-linux-arm64-musl": "5.1.60",
2392
- "oh-my-opencode-linux-x64": "5.1.60",
2393
- "oh-my-opencode-linux-x64-baseline": "5.1.60",
2394
- "oh-my-opencode-linux-x64-musl": "5.1.60",
2395
- "oh-my-opencode-linux-x64-musl-baseline": "5.1.60",
2396
- "oh-my-opencode-windows-arm64": "5.1.60",
2397
- "oh-my-opencode-windows-x64": "5.1.60",
2398
- "oh-my-opencode-windows-x64-baseline": "5.1.60"
2387
+ "oh-my-opencode-darwin-arm64": "5.1.62",
2388
+ "oh-my-opencode-darwin-x64": "5.1.62",
2389
+ "oh-my-opencode-darwin-x64-baseline": "5.1.62",
2390
+ "oh-my-opencode-linux-arm64": "5.1.62",
2391
+ "oh-my-opencode-linux-arm64-musl": "5.1.62",
2392
+ "oh-my-opencode-linux-x64": "5.1.62",
2393
+ "oh-my-opencode-linux-x64-baseline": "5.1.62",
2394
+ "oh-my-opencode-linux-x64-musl": "5.1.62",
2395
+ "oh-my-opencode-linux-x64-musl-baseline": "5.1.62",
2396
+ "oh-my-opencode-windows-arm64": "5.1.62",
2397
+ "oh-my-opencode-windows-x64": "5.1.62",
2398
+ "oh-my-opencode-windows-x64-baseline": "5.1.62"
2399
2399
  },
2400
2400
  overrides: {
2401
2401
  hono: "^4.13.8",
@@ -7490,7 +7490,7 @@ function createLogger(options) {
7490
7490
  function scheduleFlush() {
7491
7491
  if (flushTimer)
7492
7492
  return;
7493
- flushTimer = setTimeout(() => {
7493
+ flushTimer = scheduleTimeout(() => {
7494
7494
  flushTimer = null;
7495
7495
  flush();
7496
7496
  }, flushIntervalMs);
@@ -7517,7 +7517,7 @@ function createLogger(options) {
7517
7517
  function _setLoggerForTesting(overrides) {
7518
7518
  buffer = [];
7519
7519
  if (flushTimer) {
7520
- clearTimeout(flushTimer);
7520
+ cancelTimeout(flushTimer);
7521
7521
  flushTimer = null;
7522
7522
  }
7523
7523
  if (overrides.filePath !== undefined)
@@ -7533,13 +7533,13 @@ function createLogger(options) {
7533
7533
  maxLogFileBackups = maxLogFileBackupsDefault;
7534
7534
  buffer = [];
7535
7535
  if (flushTimer) {
7536
- clearTimeout(flushTimer);
7536
+ cancelTimeout(flushTimer);
7537
7537
  flushTimer = null;
7538
7538
  }
7539
7539
  }
7540
7540
  function _flushForTesting() {
7541
7541
  if (flushTimer) {
7542
- clearTimeout(flushTimer);
7542
+ cancelTimeout(flushTimer);
7543
7543
  flushTimer = null;
7544
7544
  }
7545
7545
  flush();
@@ -7552,8 +7552,10 @@ function createLogger(options) {
7552
7552
  _flushForTesting
7553
7553
  };
7554
7554
  }
7555
- var DEFAULT_MAX_LOG_FILE_SIZE_BYTES, DEFAULT_MAX_LOG_FILE_BACKUPS = 2, DEFAULT_LOG_FLUSH_INTERVAL_MS = 500, DEFAULT_LOG_BUFFER_SIZE_LIMIT = 50;
7555
+ var scheduleTimeout, cancelTimeout, DEFAULT_MAX_LOG_FILE_SIZE_BYTES, DEFAULT_MAX_LOG_FILE_BACKUPS = 2, DEFAULT_LOG_FLUSH_INTERVAL_MS = 500, DEFAULT_LOG_BUFFER_SIZE_LIMIT = 50;
7556
7556
  var init_logger = __esm(() => {
7557
+ scheduleTimeout = globalThis.setTimeout;
7558
+ cancelTimeout = globalThis.clearTimeout;
7557
7559
  DEFAULT_MAX_LOG_FILE_SIZE_BYTES = 50 * 1024 * 1024;
7558
7560
  });
7559
7561
 
@@ -77637,6 +77639,19 @@ var init_telemetry = __esm(() => {
77637
77639
  }).strict();
77638
77640
  });
77639
77641
 
77642
+ // packages/omo-config-core/src/schema/device-service.ts
77643
+ var OmoDeviceServiceSettingsShape, OmoDeviceServiceSettingsLayerSchema, OmoDeviceServiceSettingsSchema;
77644
+ var init_device_service = __esm(() => {
77645
+ init_zod();
77646
+ OmoDeviceServiceSettingsShape = {
77647
+ enabled: boolean2()
77648
+ };
77649
+ OmoDeviceServiceSettingsLayerSchema = object(OmoDeviceServiceSettingsShape).partial().strict();
77650
+ OmoDeviceServiceSettingsSchema = OmoDeviceServiceSettingsLayerSchema.extend({
77651
+ enabled: boolean2().default(true)
77652
+ }).strict();
77653
+ });
77654
+
77640
77655
  // packages/omo-config-core/src/schema/format-on-mutation.ts
77641
77656
  var mode, languages, OmoFormatOnMutationLayerSchema, OmoFormatOnMutationSchema;
77642
77657
  var init_format_on_mutation = __esm(() => {
@@ -77685,6 +77700,7 @@ var init_config = __esm(() => {
77685
77700
  init_task();
77686
77701
  init_team();
77687
77702
  init_telemetry();
77703
+ init_device_service();
77688
77704
  init_format_on_mutation();
77689
77705
  init_provenance();
77690
77706
  OmoOpenCodeHarnessConfigSchema = record(string2(), unknown());
@@ -77704,6 +77720,7 @@ var init_config = __esm(() => {
77704
77720
  model_pad: OmoModelPadSchema.optional(),
77705
77721
  memory: OmoMemorySettingsLayerSchema.optional(),
77706
77722
  telemetry: OmoTelemetrySettingsLayerSchema.optional(),
77723
+ device_service: OmoDeviceServiceSettingsLayerSchema.optional(),
77707
77724
  side_panel: OmoSidePanelSettingsLayerSchema.optional(),
77708
77725
  computer: OmoComputerSettingsLayerSchema.optional(),
77709
77726
  disabled_skills: OmoDisabledSkillsSchema.optional(),
@@ -77723,6 +77740,7 @@ var init_config = __esm(() => {
77723
77740
  model_pad: OmoModelPadSchema.optional(),
77724
77741
  memory: OmoMemorySettingsLayerSchema.optional(),
77725
77742
  telemetry: OmoTelemetrySettingsLayerSchema.optional(),
77743
+ device_service: OmoDeviceServiceSettingsLayerSchema.optional(),
77726
77744
  side_panel: OmoSidePanelSettingsLayerSchema.optional(),
77727
77745
  computer: OmoComputerSettingsLayerSchema.optional(),
77728
77746
  disabled_skills: OmoDisabledSkillsSchema.optional(),
@@ -77747,6 +77765,7 @@ var init_config = __esm(() => {
77747
77765
  model_pad: OmoModelPadSchema.optional(),
77748
77766
  memory: OmoMemorySettingsSchema.optional(),
77749
77767
  telemetry: OmoTelemetrySettingsSchema.optional(),
77768
+ device_service: OmoDeviceServiceSettingsSchema.optional(),
77750
77769
  side_panel: OmoSidePanelSettingsSchema.optional(),
77751
77770
  computer: OmoComputerSettingsSchema.optional(),
77752
77771
  disabled_skills: OmoDisabledSkillsSchema.optional(),
@@ -77774,6 +77793,7 @@ var init_config = __esm(() => {
77774
77793
  model_pad: OmoModelPadSchema.optional(),
77775
77794
  memory: OmoMemorySettingsLayerSchema.optional(),
77776
77795
  telemetry: OmoTelemetrySettingsLayerSchema.optional(),
77796
+ device_service: OmoDeviceServiceSettingsLayerSchema.optional(),
77777
77797
  side_panel: OmoSidePanelSettingsLayerSchema.optional(),
77778
77798
  computer: OmoComputerSettingsLayerSchema.optional(),
77779
77799
  disabled_skills: OmoDisabledSkillsSchema.optional(),
@@ -77925,6 +77945,7 @@ var init_schema = __esm(() => {
77925
77945
  init_task();
77926
77946
  init_team();
77927
77947
  init_telemetry();
77948
+ init_device_service();
77928
77949
  init_computer();
77929
77950
  });
77930
77951
 
@@ -92689,7 +92710,7 @@ var package_default2;
92689
92710
  var init_package2 = __esm(() => {
92690
92711
  package_default2 = {
92691
92712
  name: "@oh-my-opencode/omo-codex",
92692
- version: "5.1.60",
92713
+ version: "5.1.62",
92693
92714
  type: "module",
92694
92715
  private: true,
92695
92716
  description: "Codex harness adapter for oh-my-openagent. Vendored Codex plugin namespace (omo) + TypeScript installer + telemetry.",
@@ -100065,6 +100086,7 @@ var REQUIRED_PLUGIN_ARTIFACTS = [
100065
100086
  join66("extensions", "omo-memory-commands.js"),
100066
100087
  join66("extensions", "omo-session-history.js"),
100067
100088
  join66("extensions", "omo-recall-store.js"),
100089
+ join66("extensions", "omo-device-service.js"),
100068
100090
  join66("extensions", "omo-telemetry-posthog.js"),
100069
100091
  join66("extensions", "omo-telemetry-otlp.js"),
100070
100092
  join66("extensions", "omo-memory-sync.js"),
@@ -104351,6 +104373,7 @@ var BuiltinSkillNameSchema = _enum([
104351
104373
  "debugging",
104352
104374
  "security-research",
104353
104375
  "security-review",
104376
+ "hyperplan",
104354
104377
  "visual-qa",
104355
104378
  "team-mode"
104356
104379
  ]);
@@ -109449,8 +109472,8 @@ var package_default3 = {
109449
109472
  },
109450
109473
  dependencies: {
109451
109474
  "@clack/prompts": "^1.8.1",
109452
- "@code-yeongyu/senpi": "2026.11.2-3",
109453
- "@earendil-works/pi-ai": "npm:@code-yeongyu/senpi-ai@2026.11.2-3",
109475
+ "@code-yeongyu/senpi": "2026.11.5-1",
109476
+ "@earendil-works/pi-ai": "npm:@code-yeongyu/senpi-ai@2026.11.5-1",
109454
109477
  "@modelcontextprotocol/sdk": "^1.30.0",
109455
109478
  "@oh-my-opencode/agents-md-core": "workspace:*",
109456
109479
  "@oh-my-opencode/boulder-state": "workspace:*",
@@ -112722,6 +112745,24 @@ function retryOnEintrSync(operation) {
112722
112745
 
112723
112746
  // packages/memory-core/src/fs/rename-contention.ts
112724
112747
  var CONTENTION_CODES = new Set(["EPERM", "EBUSY", "EACCES"]);
112748
+ var CONTENTION_DELAYS_MS = [10, 25, 50, 100, 200, 400];
112749
+ var sleepFor = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
112750
+ async function renameWithContentionRetry(from, to, deps) {
112751
+ const delays = deps.platform === "win32" ? deps.delaysMs ?? CONTENTION_DELAYS_MS : [];
112752
+ const sleep = deps.sleep ?? sleepFor;
112753
+ for (let attempt = 0;; attempt += 1) {
112754
+ try {
112755
+ await retryOnEintr(() => deps.admit === undefined ? deps.rename(from, to) : deps.admit(() => deps.rename(from, to)));
112756
+ return;
112757
+ } catch (error) {
112758
+ const delay = delays[attempt];
112759
+ const code = fsErrorCode(error);
112760
+ if (delay === undefined || code === undefined || !CONTENTION_CODES.has(code))
112761
+ throw error;
112762
+ await sleep(delay);
112763
+ }
112764
+ }
112765
+ }
112725
112766
 
112726
112767
  // packages/memory-core/src/fs/resilient.ts
112727
112768
  function isFunction2(value) {
@@ -112754,6 +112795,13 @@ function resilientNamespace(namespace, kind) {
112754
112795
  }
112755
112796
  var IDEMPOTENT_HANDLE_METHODS = new Set(["stat", "sync", "datasync", "chmod", "chown", "utimes", "truncate"]);
112756
112797
  var promises = resilientNamespace(fsp, "async");
112798
+ function rename8(from, to, admit) {
112799
+ return renameWithContentionRetry(from, to, {
112800
+ rename: (source, target) => fsp.rename(source, target),
112801
+ platform: process.platform,
112802
+ ...admit === undefined ? {} : { admit }
112803
+ });
112804
+ }
112757
112805
  var sync = resilientNamespace(fsSync, "sync");
112758
112806
  var {
112759
112807
  access: access3,
@@ -113649,15 +113697,60 @@ async function loginLoopback(session, options) {
113649
113697
  }
113650
113698
  }
113651
113699
 
113652
- // packages/omo-opencode/src/cli/service-auth/session.ts
113700
+ // packages/memory-core/src/sync/device-retire.ts
113701
+ import { createHash as createHash14, randomBytes as randomBytes6 } from "crypto";
113702
+ import { join as join109 } from "path";
113703
+
113704
+ // packages/memory-core/src/identity/layout.ts
113653
113705
  import { homedir as homedir32 } from "os";
113706
+ import { join as join107, resolve as resolve31 } from "path";
113707
+ var MEMORY_ROOT_ENV_VAR = "OMO_MEMORY_HOME";
113708
+ function defaultMemoryRoot() {
113709
+ return join107(homedir32(), ".omo", "memory");
113710
+ }
113711
+ function resolveMemoryRoot(env, cwd) {
113712
+ const override = env[MEMORY_ROOT_ENV_VAR];
113713
+ if (override === undefined || override.trim() === "") {
113714
+ return defaultMemoryRoot();
113715
+ }
113716
+ return resolve31(cwd, override);
113717
+ }
113718
+ // packages/memory-core/src/sync/pin-dir.ts
113719
+ import { join as join108 } from "path";
113720
+ var syncPinDir = (memoryRoot) => join108(memoryRoot, "sync-device");
113721
+
113722
+ // packages/memory-core/src/sync/device-retire.ts
113723
+ var trustAnchorRoot = (pinDir) => join109(pinDir, "trust-anchor");
113724
+ var trustAnchorKey = (account) => createHash14("sha256").update(account, "utf8").digest("base64url");
113725
+ var trustAnchorDir = (pinDir, account) => join109(trustAnchorRoot(pinDir), trustAnchorKey(account));
113726
+ var hasLiveTrustAnchor = async (pinDir) => {
113727
+ try {
113728
+ return (await readdir17(trustAnchorRoot(pinDir))).some((name) => !name.includes(".retired-"));
113729
+ } catch (error) {
113730
+ if (error instanceof Error && "code" in error && error.code === "ENOENT")
113731
+ return false;
113732
+ throw error;
113733
+ }
113734
+ };
113735
+ var retireSyncDevice = async (input) => {
113736
+ const dir = trustAnchorDir(input.pinDir, input.account);
113737
+ try {
113738
+ await rename8(dir, `${dir}.retired-${Date.now()}-${randomBytes6(4).toString("hex")}`);
113739
+ } catch (error) {
113740
+ if (!(error instanceof Error && ("code" in error) && error.code === "ENOENT"))
113741
+ throw error;
113742
+ }
113743
+ };
113744
+
113745
+ // packages/omo-opencode/src/cli/service-auth/session.ts
113746
+ import { homedir as homedir33 } from "os";
113654
113747
 
113655
113748
  // packages/omo-opencode/src/cli/service-auth/signed-out-marker.ts
113656
113749
  init_zod();
113657
- import { mkdir as mkdir12, readFile as readFile35, rename as rename8, rm as rm17, writeFile as writeFile17 } from "fs/promises";
113658
- import { dirname as dirname43, join as join107 } from "path";
113750
+ import { mkdir as mkdir12, readFile as readFile35, rename as rename9, rm as rm17, writeFile as writeFile17 } from "fs/promises";
113751
+ import { dirname as dirname43, join as join110 } from "path";
113659
113752
  var markerSchema = object({ device: string2().nullable(), at: string2() });
113660
- var signedOutMarkerPath = (home, credential) => join107(home, ".omo", "account-state", `${credential}.signed-out.json`);
113753
+ var signedOutMarkerPath = (home, credential) => join110(home, ".omo", "account-state", `${credential}.signed-out.json`);
113661
113754
  async function readSignedOutMarker(path) {
113662
113755
  const text = await readFile35(path, "utf8").catch(() => null);
113663
113756
  if (text === null)
@@ -113675,7 +113768,7 @@ async function writeSignedOutMarker(path, device) {
113675
113768
  await mkdir12(dirname43(path), { recursive: true, mode: 448 });
113676
113769
  const staging = `${path}.${process.pid}.tmp`;
113677
113770
  await writeFile17(staging, JSON.stringify({ device, at: new Date().toISOString() }), { mode: 384 });
113678
- await rename8(staging, path);
113771
+ await rename9(staging, path);
113679
113772
  }
113680
113773
  var clearSignedOutMarker = (path) => rm17(path, { force: true });
113681
113774
 
@@ -113690,11 +113783,18 @@ class SessionEnded extends SignInError {
113690
113783
  }
113691
113784
  }
113692
113785
  var DEVICE_REVOKING_REFUSALS = new Set(["account_deleted", "reauth_required", "device_revoked"]);
113786
+ var discardedOf = (credentials, cause) => ({
113787
+ kind: "credential",
113788
+ deviceId: credentials.device.id,
113789
+ accountId: credentials.accountId,
113790
+ owner: credentials.owner,
113791
+ cause
113792
+ });
113693
113793
  function createSession(options) {
113694
113794
  const api = serviceOrigin(options.api);
113695
113795
  const now = options.now ?? Date.now;
113696
- const { store, signal } = options;
113697
- const markerPath = signedOutMarkerPath(options.home ?? homedir32(), credentialId(api));
113796
+ const { store, signal, beforeKeysDiscarded } = options;
113797
+ const markerPath = signedOutMarkerPath(options.home ?? homedir33(), credentialId(api));
113698
113798
  async function locked(action) {
113699
113799
  signal?.throwIfAborted();
113700
113800
  return withCredentialLock(api, async () => {
@@ -113703,6 +113803,11 @@ function createSession(options) {
113703
113803
  }, options.home);
113704
113804
  }
113705
113805
  const request = (path, init) => requestApi(api, path, init, signal);
113806
+ const accountOf = async (access) => {
113807
+ const body = await request("/v1/me", { headers: { authorization: `Bearer ${access}` } }).catch(() => null);
113808
+ const id = typeof body === "object" && body !== null && "account" in body && typeof body.account === "object" && body.account !== null && "id" in body.account ? body.account.id : undefined;
113809
+ return typeof id === "string" && id !== "" ? id : undefined;
113810
+ };
113706
113811
  async function refreshed(current) {
113707
113812
  if (current.refreshState === "uncertain" || current.refreshAttempt !== undefined) {
113708
113813
  throw new SessionEnded(`Refresh recovery can no longer be proved safe. ${signInHint("again")}`, false, "refresh_recovery_expired");
@@ -113719,6 +113824,7 @@ function createSession(options) {
113719
113824
  if (error instanceof CredentialStoreError)
113720
113825
  throw error;
113721
113826
  if (error instanceof ApiRefusal && error.status < 500 && ["unauthorized", "account_deleted", "reauth_required", "invalid_grant", "device_revoked"].includes(error.code)) {
113827
+ await beforeKeysDiscarded(discardedOf(current, "refused"));
113722
113828
  await store.clear();
113723
113829
  throw new SessionEnded(error.code === "reauth_required" ? `This session was ended because its refresh token was reused. ${signInHint("again")}` : refusalMessage(refusalGuidance(error.code, error.status)), DEVICE_REVOKING_REFUSALS.has(error.code), error.code);
113724
113830
  }
@@ -113744,6 +113850,17 @@ function createSession(options) {
113744
113850
  },
113745
113851
  async save(value) {
113746
113852
  await locked(async () => {
113853
+ let stored;
113854
+ try {
113855
+ stored = await store.readAuthoritative();
113856
+ } catch (error) {
113857
+ if (!(error instanceof InvalidCredentialState))
113858
+ throw error;
113859
+ await beforeKeysDiscarded({ kind: "unreadable" });
113860
+ stored = null;
113861
+ }
113862
+ if (stored !== null && stored.device.id !== value.device.id)
113863
+ await beforeKeysDiscarded(discardedOf(stored, "replaced"));
113747
113864
  await store.write(value);
113748
113865
  await clearSignedOutMarker(markerPath);
113749
113866
  });
@@ -113770,12 +113887,16 @@ function createSession(options) {
113770
113887
  async logout() {
113771
113888
  return locked(async () => {
113772
113889
  let current = null;
113890
+ let account;
113773
113891
  try {
113774
113892
  current = await store.readAuthoritative();
113775
113893
  if (current !== null) {
113776
113894
  if (current.refreshState === "uncertain")
113777
113895
  return false;
113778
113896
  const access = Date.parse(current.accessTokenExpiresAt) <= now() ? (await refreshed(current)).accessToken : current.accessToken;
113897
+ if (current.accountId === undefined && current.owner === undefined && await beforeKeysDiscarded.wantsAccount?.() === true) {
113898
+ account = await accountOf(access);
113899
+ }
113779
113900
  await request(`/v1/devices/${encodeURIComponent(current.device.id)}`, {
113780
113901
  method: "DELETE",
113781
113902
  headers: { authorization: `Bearer ${access}` }
@@ -113790,6 +113911,9 @@ function createSession(options) {
113790
113911
  throw error;
113791
113912
  } finally {
113792
113913
  await writeSignedOutMarker(markerPath, current?.device.id ?? null);
113914
+ const stored = current === null ? null : await store.read().catch(() => current);
113915
+ if (stored !== null)
113916
+ await beforeKeysDiscarded(discardedOf(stored.accountId === undefined && account !== undefined ? { ...stored, accountId: account } : stored, "logout"));
113793
113917
  await store.clear();
113794
113918
  }
113795
113919
  });
@@ -113826,6 +113950,26 @@ function createSession(options) {
113826
113950
  };
113827
113951
  }
113828
113952
 
113953
+ // packages/omo-opencode/src/cli/service-auth/sync-pin-retire.ts
113954
+ var reason = (error) => error instanceof Error && ("code" in error) && typeof error.code === "string" ? error.code : "unknown";
113955
+ function retireSyncPinOnDiscard(options) {
113956
+ const hook = async (discarded) => {
113957
+ if (discarded.kind === "unreadable") {
113958
+ options.log("memory sync: a stored sign-in could not be read while it was replaced; its sync pin was left in place");
113959
+ return;
113960
+ }
113961
+ const account = discarded.owner?.accountId ?? discarded.accountId;
113962
+ if (account === undefined)
113963
+ return;
113964
+ try {
113965
+ await retireSyncDevice({ pinDir: options.pinDir(), account });
113966
+ } catch (error) {
113967
+ options.log(`memory sync: the sync pin could not be retired (${reason(error)}); it was left in place`);
113968
+ }
113969
+ };
113970
+ return Object.assign(hook, { wantsAccount: () => hasLiveTrustAnchor(options.pinDir()).catch(() => false) });
113971
+ }
113972
+
113829
113973
  // packages/omo-opencode/src/cli/service-auth/commands.ts
113830
113974
  async function ensureServiceAvailable(session, api) {
113831
113975
  try {
@@ -113868,7 +114012,12 @@ async function run2(action, options) {
113868
114012
  try {
113869
114013
  const api = serviceOrigin(options.api ?? process.env.OMO_SERVICE_API_URL ?? "https://api.omo.dev");
113870
114014
  const store = createCredentialStore(api, { wait: INTERACTIVE_READ_WAIT });
113871
- const session = createSession({ api, store, signal: controller.signal });
114015
+ const session = createSession({
114016
+ api,
114017
+ store,
114018
+ signal: controller.signal,
114019
+ beforeKeysDiscarded: retireSyncPinOnDiscard({ pinDir: () => syncPinDir(resolveMemoryRoot(process.env, process.cwd())), log: (line) => console.error(line) })
114020
+ });
113872
114021
  if (action === "logout") {
113873
114022
  const revoked = await session.logout();
113874
114023
  console.log("Signed out of OmO. Stored credentials and device keys were removed.");
@@ -114136,11 +114285,11 @@ async function boulder(options) {
114136
114285
  // packages/omo-opencode/src/cli/codex-ulw-loop.ts
114137
114286
  import { spawn as spawn6 } from "child_process";
114138
114287
  import { existsSync as existsSync67, readFileSync as readFileSync45, realpathSync as realpathSync14 } from "fs";
114139
- import { homedir as homedir33 } from "os";
114288
+ import { homedir as homedir34 } from "os";
114140
114289
  var ULW_LOOP_DELEGATION_SENTINEL = "OMO_ULW_LOOP_DELEGATED";
114141
114290
  function resolveCodexUlwLoopCommand(input = {}) {
114142
114291
  const env = input.env ?? process.env;
114143
- const homeDir = input.homeDir ?? homedir33();
114292
+ const homeDir = input.homeDir ?? homedir34();
114144
114293
  const localComponentBin = resolveLocalUlwLoopBin(env, homeDir);
114145
114294
  if (localComponentBin !== null)
114146
114295
  return { executable: localComponentBin, argsPrefix: [] };
@@ -2,4 +2,5 @@ export { credentialLockPaths, withCredentialLock } from "./credential-lock";
2
2
  export { currentServiceDevice } from "./protocol";
3
3
  export { CredentialIdentityChanged, type CredentialStore, createCredentialStore, KeychainApprovalPendingError, quietNotice } from "./keystore";
4
4
  export { type Credentials, SignInError, serviceOrigin } from "./protocol";
5
- export { createSession, type Session } from "./session";
5
+ export { type BeforeKeysDiscarded, createSession, type DiscardedCredential, type Session } from "./session";
6
+ export { retireSyncPinOnDiscard } from "./sync-pin-retire";
@@ -1,3 +1,4 @@
1
+ import type { CredentialOwner } from "./credential-owner";
1
2
  import { type CredentialStore } from "./keystore";
2
3
  import { type ChooseDevice, type Credentials, SignInError } from "./protocol";
3
4
  export declare class SessionEnded extends SignInError {
@@ -5,12 +6,33 @@ export declare class SessionEnded extends SignInError {
5
6
  readonly code: string;
6
7
  constructor(message: string, deviceRevoked: boolean, code: string);
7
8
  }
9
+ /**
10
+ * A stored principal whose private keys are about to be discarded (#12280), or a stored item that
11
+ * could not be read when a save replaced it. The hook retires that principal's memory-sync pin; it
12
+ * never throws, so a failure to retire never blocks the discard.
13
+ */
14
+ export type DiscardedCredential = {
15
+ readonly kind: "credential";
16
+ readonly deviceId: string;
17
+ readonly accountId: string | undefined;
18
+ readonly owner: CredentialOwner | undefined;
19
+ readonly cause: "refused" | "forget" | "logout" | "replaced";
20
+ } | {
21
+ readonly kind: "unreadable";
22
+ };
23
+ export type BeforeKeysDiscarded = ((discarded: DiscardedCredential) => Promise<void>) & {
24
+ /** Whether a sign-in that names no account should have it read before logout revokes the device. */
25
+ readonly wantsAccount?: () => Promise<boolean>;
26
+ };
27
+ export declare const discardedOf: (credentials: Credentials, cause: "refused" | "forget" | "logout" | "replaced") => DiscardedCredential;
8
28
  export declare function createSession(options: {
9
29
  readonly api: string;
10
30
  readonly store: CredentialStore;
11
31
  readonly home?: string;
12
32
  readonly signal?: AbortSignal;
13
33
  readonly now?: () => number;
34
+ /** Runs inside the credential lock immediately before a stored principal's keys are discarded. */
35
+ readonly beforeKeysDiscarded: BeforeKeysDiscarded;
14
36
  }): {
15
37
  request: (path: string, init: RequestInit) => Promise<unknown>;
16
38
  signal: AbortSignal | undefined;
@@ -26,6 +48,11 @@ export declare function createSession(options: {
26
48
  update<T>(action: (current: Credentials | null) => Promise<T>, options?: {
27
49
  readonly replaceInvalid?: boolean;
28
50
  }): Promise<T>;
51
+ /**
52
+ * Deletes the item without reading it (a corrupt or locked item must still be removable, with one
53
+ * native call), so it cannot name the account whose pin to retire: `omo account forget --device`
54
+ * and `logout` read first and retire; this one leaves the pin (a stale pin is harmless for keys).
55
+ */
29
56
  forget(): Promise<void>;
30
57
  accessSnapshot: () => Promise<Credentials | null>;
31
58
  logout(): Promise<boolean>;
@@ -0,0 +1,7 @@
1
+ import type { BeforeKeysDiscarded } from "./session";
2
+ export declare function retireSyncPinOnDiscard(options: {
3
+ /** The trust-pin directory of the memory root the caller already resolves. */
4
+ readonly pinDir: () => string;
5
+ /** The caller's own logger; one line per pin it could not retire. */
6
+ readonly log: (line: string) => void;
7
+ }): BeforeKeysDiscarded;