@gajae-code/coding-agent 0.18.12 → 0.19.0

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 (305) hide show
  1. package/CHANGELOG.md +467 -0
  2. package/dist/types/capability/rule.d.ts +7 -2
  3. package/dist/types/cli/append-system-prompt.d.ts +6 -0
  4. package/dist/types/cli/args.d.ts +7 -2
  5. package/dist/types/cli/customize-doctor-precedence.d.ts +16 -0
  6. package/dist/types/cli/customize-doctor.d.ts +4 -3
  7. package/dist/types/cli/public-command-errors.d.ts +1 -0
  8. package/dist/types/cli/root-flags.d.ts +0 -12
  9. package/dist/types/cli/update-cli.d.ts +7 -2
  10. package/dist/types/cli-main.d.ts +0 -6
  11. package/dist/types/commands/launch.d.ts +0 -6
  12. package/dist/types/commands/migrate.d.ts +1 -1
  13. package/dist/types/commands/sdk.d.ts +8 -0
  14. package/dist/types/commit/map-reduce/index.d.ts +4 -4
  15. package/dist/types/config/autorouting-tier-map.d.ts +23 -1
  16. package/dist/types/config/config-hot-reload.d.ts +5 -0
  17. package/dist/types/config/file-lock.d.ts +44 -2
  18. package/dist/types/config/model-profile-activation.d.ts +19 -5
  19. package/dist/types/config/model-registry.d.ts +16 -3
  20. package/dist/types/config/model-resolver.d.ts +5 -4
  21. package/dist/types/config/settings-schema.d.ts +11 -1
  22. package/dist/types/coordinator-mcp/server.d.ts +4 -0
  23. package/dist/types/customization/import.d.ts +2 -0
  24. package/dist/types/customization/types.d.ts +1 -1
  25. package/dist/types/dap/session.d.ts +11 -2
  26. package/dist/types/discovery/helpers.d.ts +7 -2
  27. package/dist/types/edit/index.d.ts +5 -0
  28. package/dist/types/edit/modes/patch.d.ts +9 -0
  29. package/dist/types/eval/py/runtime.d.ts +9 -0
  30. package/dist/types/export/ttsr.d.ts +19 -0
  31. package/dist/types/extensibility/extensions/types.d.ts +5 -1
  32. package/dist/types/extensibility/slash-commands.d.ts +1 -0
  33. package/dist/types/gjc-runtime/ralplan-current-final.d.ts +54 -0
  34. package/dist/types/gjc-runtime/ralplan-runtime.d.ts +5 -0
  35. package/dist/types/gjc-runtime/tmux-sessions.d.ts +24 -0
  36. package/dist/types/gjc-runtime/ultragoal-change-set.d.ts +6 -0
  37. package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +1 -0
  38. package/dist/types/harness-control-plane/receipt-spool.d.ts +4 -0
  39. package/dist/types/hindsight/content.d.ts +5 -6
  40. package/dist/types/internal-urls/types.d.ts +2 -0
  41. package/dist/types/lsp/clients/swiftlint-client.d.ts +0 -4
  42. package/dist/types/main.d.ts +23 -18
  43. package/dist/types/migrate/action-planner.d.ts +10 -1
  44. package/dist/types/migrate/adapters/codex.d.ts +1 -1
  45. package/dist/types/migrate/adapters/index.d.ts +35 -3
  46. package/dist/types/migrate/hook-module.d.ts +23 -0
  47. package/dist/types/migrate/report.d.ts +2 -1
  48. package/dist/types/migrate/types.d.ts +69 -2
  49. package/dist/types/modes/components/agent-dashboard.d.ts +1 -1
  50. package/dist/types/modes/components/model-selector.d.ts +43 -0
  51. package/dist/types/modes/prompt-suggestion-controller.d.ts +1 -1
  52. package/dist/types/modes/utils/host-status.d.ts +15 -11
  53. package/dist/types/runtime-mcp/project-host-values.d.ts +11 -5
  54. package/dist/types/sdk/broker/broker-exit.d.ts +1 -1
  55. package/dist/types/sdk/broker/broker.d.ts +22 -1
  56. package/dist/types/sdk/broker/ensure.d.ts +5 -2
  57. package/dist/types/sdk/broker/hop.d.ts +9 -0
  58. package/dist/types/sdk/broker/lifecycle.d.ts +22 -0
  59. package/dist/types/sdk/broker/session-index.d.ts +2 -0
  60. package/dist/types/sdk/broker/transport.d.ts +2 -0
  61. package/dist/types/sdk/bus/index.d.ts +21 -0
  62. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +7 -1
  63. package/dist/types/sdk/bus/telegram-daemon.d.ts +2 -0
  64. package/dist/types/sdk/bus/threaded-render.d.ts +2 -1
  65. package/dist/types/sdk/host/control/operations.d.ts +5 -1
  66. package/dist/types/sdk/host/events.d.ts +4 -0
  67. package/dist/types/sdk/host/host.d.ts +2 -1
  68. package/dist/types/sdk/host/prompt-image-upload.d.ts +43 -0
  69. package/dist/types/sdk/host/session-runtime.d.ts +8 -8
  70. package/dist/types/sdk/host/surface-policy.d.ts +2 -1
  71. package/dist/types/sdk/lifecycle/service.d.ts +12 -0
  72. package/dist/types/sdk/prompt-status.d.ts +11 -4
  73. package/dist/types/session/agent-session.d.ts +50 -8
  74. package/dist/types/session/session-manager.d.ts +16 -0
  75. package/dist/types/skill-state/workflow-mutation-guard.d.ts +13 -1
  76. package/dist/types/slash-commands/helpers/mcp.d.ts +5 -0
  77. package/dist/types/ssh/ssh-executor.d.ts +8 -1
  78. package/dist/types/system-prompt.d.ts +3 -2
  79. package/dist/types/task/role-body.d.ts +11 -0
  80. package/dist/types/tools/awaiting-input.d.ts +28 -0
  81. package/dist/types/tools/bash-allowed-prefixes.d.ts +6 -0
  82. package/dist/types/tools/bash-skill-urls.d.ts +4 -0
  83. package/dist/types/tools/bash.d.ts +7 -0
  84. package/dist/types/tools/descriptors.d.ts +13 -2
  85. package/dist/types/tools/fetch.d.ts +6 -0
  86. package/dist/types/tools/irc.d.ts +5 -3
  87. package/dist/types/tools/tmux-self-injection-guard.d.ts +2 -0
  88. package/dist/types/tools/ultragoal-ask-guard.d.ts +1 -1
  89. package/dist/types/tools/write.d.ts +2 -0
  90. package/dist/types/utils/file-mentions.d.ts +5 -0
  91. package/dist/types/utils/image-limits.d.ts +7 -0
  92. package/dist/types/utils/image-loading.d.ts +0 -1
  93. package/dist/types/utils/open.d.ts +0 -1
  94. package/dist/types/utils/pasted-image-loading.d.ts +1 -5
  95. package/dist/types/utils/prompt-suggestion.d.ts +2 -2
  96. package/dist/types/utils/shell-snapshot.d.ts +2 -0
  97. package/dist/types/utils/title-generator.d.ts +13 -3
  98. package/dist/types/web/search/providers/codex.d.ts +6 -7
  99. package/package.json +9 -8
  100. package/scripts/acp-conformance-agent.ts +12 -2
  101. package/scripts/generate-sdk-operation-inventory.ts +16 -0
  102. package/src/capability/fs.ts +31 -3
  103. package/src/capability/rule.ts +11 -2
  104. package/src/cli/append-system-prompt.ts +12 -0
  105. package/src/cli/args.ts +11 -7
  106. package/src/cli/customize-doctor-precedence.ts +31 -0
  107. package/src/cli/customize-doctor.ts +49 -39
  108. package/src/cli/fast-help.ts +0 -2
  109. package/src/cli/migrate-cli.ts +14 -3
  110. package/src/cli/public-command-errors.ts +2 -0
  111. package/src/cli/root-flags.ts +0 -2
  112. package/src/cli/update-cli.ts +247 -6
  113. package/src/commands/harness.ts +25 -15
  114. package/src/commands/migrate.ts +3 -3
  115. package/src/commands/sdk.ts +81 -11
  116. package/src/commit/agentic/agent.ts +6 -6
  117. package/src/commit/analysis/conventional.ts +14 -5
  118. package/src/commit/map-reduce/index.ts +7 -7
  119. package/src/commit/pipeline.ts +12 -12
  120. package/src/config/autorouting-tier-map.ts +20 -1
  121. package/src/config/config-file.ts +106 -3
  122. package/src/config/config-hot-reload.ts +8 -0
  123. package/src/config/file-lock.ts +1431 -304
  124. package/src/config/keybindings.ts +154 -7
  125. package/src/config/model-profile-activation.ts +177 -39
  126. package/src/config/model-registry.ts +380 -55
  127. package/src/config/model-resolver.ts +49 -21
  128. package/src/config/settings-schema.ts +13 -1
  129. package/src/config/settings.ts +2 -0
  130. package/src/coordinator-mcp/server.ts +37 -2
  131. package/src/crash/sanitize.ts +3 -1
  132. package/src/customization/import.ts +276 -7
  133. package/src/customization/inventory.ts +24 -8
  134. package/src/customization/types.ts +1 -0
  135. package/src/dap/client.ts +3 -2
  136. package/src/dap/session.ts +161 -36
  137. package/src/debug/crash-diagnostics.ts +87 -5
  138. package/src/debug/report-bundle.ts +71 -2
  139. package/src/discovery/builtin.ts +4 -3
  140. package/src/discovery/helpers.ts +24 -14
  141. package/src/edit/index.ts +191 -5
  142. package/src/edit/modes/patch.ts +27 -0
  143. package/src/eval/py/runtime.ts +44 -4
  144. package/src/exec/non-interactive-env.ts +0 -1
  145. package/src/export/html/index.ts +60 -20
  146. package/src/export/ttsr.ts +176 -1
  147. package/src/extensibility/extensions/loader.ts +2 -0
  148. package/src/extensibility/extensions/ouroboros-ooo-bridge.ts +63 -1
  149. package/src/extensibility/extensions/types.ts +5 -1
  150. package/src/extensibility/hooks/loader.ts +10 -2
  151. package/src/extensibility/plugins/marketplace/manager.ts +36 -10
  152. package/src/extensibility/slash-commands.ts +5 -0
  153. package/src/gjc-runtime/gc-runtime.ts +4 -1
  154. package/src/gjc-runtime/launch-tmux.ts +23 -13
  155. package/src/gjc-runtime/ralplan-current-final.ts +294 -0
  156. package/src/gjc-runtime/ralplan-runtime.ts +95 -1
  157. package/src/gjc-runtime/state-writer.ts +109 -5
  158. package/src/gjc-runtime/tmux-sessions.ts +93 -13
  159. package/src/gjc-runtime/ultragoal-change-set.ts +90 -11
  160. package/src/gjc-runtime/ultragoal-guard.ts +9 -1
  161. package/src/gjc-runtime/ultragoal-runtime.ts +15 -5
  162. package/src/harness-control-plane/finalize.ts +11 -0
  163. package/src/harness-control-plane/receipt-spool.ts +105 -28
  164. package/src/harness-control-plane/storage.ts +124 -6
  165. package/src/hindsight/content.ts +116 -16
  166. package/src/hindsight/mental-models.ts +22 -10
  167. package/src/hindsight/state.ts +7 -4
  168. package/src/hooks/native-skill-hook.ts +3 -1
  169. package/src/internal-urls/artifact-protocol.ts +3 -1
  170. package/src/internal-urls/docs-index.generated.ts +14 -14
  171. package/src/internal-urls/local-protocol.ts +28 -3
  172. package/src/internal-urls/types.ts +2 -0
  173. package/src/lsp/client.ts +2 -1
  174. package/src/lsp/clients/biome-client.ts +2 -0
  175. package/src/lsp/clients/swiftlint-client.ts +2 -0
  176. package/src/main.ts +330 -92
  177. package/src/memories/index.ts +25 -2
  178. package/src/migrate/action-planner.ts +517 -2
  179. package/src/migrate/adapters/claude-code.ts +141 -3
  180. package/src/migrate/adapters/codex.ts +57 -5
  181. package/src/migrate/adapters/index.ts +240 -5
  182. package/src/migrate/adapters/opencode.ts +4 -0
  183. package/src/migrate/executor.ts +141 -3
  184. package/src/migrate/hook-module.ts +193 -0
  185. package/src/migrate/report.ts +45 -1
  186. package/src/migrate/types.ts +73 -3
  187. package/src/modes/acp/acp-agent.ts +10 -1
  188. package/src/modes/components/agent-dashboard.ts +20 -4
  189. package/src/modes/components/customization/customization-dashboard.ts +7 -0
  190. package/src/modes/components/customization/import-wizard.ts +29 -3
  191. package/src/modes/components/model-selector.ts +157 -103
  192. package/src/modes/components/welcome.ts +3 -1
  193. package/src/modes/controllers/command-controller.ts +271 -16
  194. package/src/modes/controllers/event-controller.ts +1 -1
  195. package/src/modes/controllers/extension-ui-controller.ts +31 -1
  196. package/src/modes/controllers/goal-mode-controller.ts +79 -10
  197. package/src/modes/controllers/input-controller.ts +2 -0
  198. package/src/modes/controllers/plan-mode-controller.ts +49 -4
  199. package/src/modes/controllers/runtime-mcp-command-controller.ts +7 -6
  200. package/src/modes/controllers/selector-controller.ts +14 -1
  201. package/src/modes/interactive-mode.ts +55 -4
  202. package/src/modes/prompt-suggestion-controller.ts +1 -1
  203. package/src/modes/runtime-init.ts +5 -1
  204. package/src/modes/utils/host-status.ts +21 -10
  205. package/src/prompts/agent-fragments/browser-aside.md +2 -2
  206. package/src/prompts/system/irc-incoming.md +3 -1
  207. package/src/prompts/tools/irc.md +1 -1
  208. package/src/runtime-mcp/manager.ts +8 -3
  209. package/src/runtime-mcp/project-host-values.ts +12 -8
  210. package/src/runtime-mcp/tool-bridge.ts +68 -4
  211. package/src/runtime-mcp/transports/stdio.ts +2 -1
  212. package/src/sdk/broker/broker-exit.ts +2 -0
  213. package/src/sdk/broker/broker.ts +143 -4
  214. package/src/sdk/broker/ensure.ts +74 -6
  215. package/src/sdk/broker/hop.ts +13 -1
  216. package/src/sdk/broker/lifecycle-ledger.ts +3 -0
  217. package/src/sdk/broker/lifecycle.ts +102 -6
  218. package/src/sdk/broker/session-index.ts +29 -4
  219. package/src/sdk/broker/transport.ts +17 -1
  220. package/src/sdk/bus/chat-daemon-control.ts +2 -2
  221. package/src/sdk/bus/index.ts +408 -14
  222. package/src/sdk/bus/session-control.ts +2 -0
  223. package/src/sdk/bus/slack-daemon.ts +105 -9
  224. package/src/sdk/bus/telegram-daemon-contract.ts +7 -1
  225. package/src/sdk/bus/telegram-daemon.ts +10 -2
  226. package/src/sdk/bus/threaded-render.ts +20 -1
  227. package/src/sdk/cli/session-cli.ts +2 -0
  228. package/src/sdk/host/control/dispatch.ts +13 -1
  229. package/src/sdk/host/control/operations.ts +10 -1
  230. package/src/sdk/host/events.ts +67 -4
  231. package/src/sdk/host/host.ts +8 -2
  232. package/src/sdk/host/prompt-image-upload.ts +438 -0
  233. package/src/sdk/host/sdk-surface-parity.test.ts +15 -0
  234. package/src/sdk/host/session-runtime.test.ts +1537 -24
  235. package/src/sdk/host/session-runtime.ts +332 -36
  236. package/src/sdk/host/surface-policy.ts +4 -0
  237. package/src/sdk/host/websocket-transport.lifecycle.test.ts +90 -2
  238. package/src/sdk/host/websocket-transport.ts +19 -7
  239. package/src/sdk/lifecycle/service.ts +14 -1
  240. package/src/sdk/prompt-status.ts +6 -4
  241. package/src/sdk/protocol/adapter-validation.ts +28 -1
  242. package/src/sdk/protocol/operation-inventory.generated.json +160 -0
  243. package/src/sdk/protocol/operation-registry.ts +33 -3
  244. package/src/sdk/session.ts +123 -36
  245. package/src/session/agent-session.ts +1614 -329
  246. package/src/session/history-storage.ts +182 -12
  247. package/src/session/internal/managed-session-scope.ts +47 -18
  248. package/src/session/internal/managed-session-storage.ts +71 -1
  249. package/src/session/session-manager.ts +90 -5
  250. package/src/session-import/redact.ts +53 -2
  251. package/src/skill-state/workflow-mutation-guard.ts +1498 -18
  252. package/src/slash-commands/builtin-registry.ts +6 -3
  253. package/src/slash-commands/helpers/mcp.ts +11 -3
  254. package/src/ssh/ssh-executor.ts +9 -2
  255. package/src/stt/recorder.ts +26 -9
  256. package/src/system-prompt.ts +61 -16
  257. package/src/task/executor.ts +12 -8
  258. package/src/task/role-body.ts +84 -0
  259. package/src/task/token-log-mode.test.ts +162 -0
  260. package/src/task/token-log.ts +91 -2
  261. package/src/tools/archive-reader.ts +650 -37
  262. package/src/tools/ask.ts +1 -0
  263. package/src/tools/ast-grep.ts +7 -2
  264. package/src/tools/auto-generated-guard.ts +12 -3
  265. package/src/tools/awaiting-input.ts +114 -0
  266. package/src/tools/bash-allowed-prefixes.ts +61 -1
  267. package/src/tools/bash-skill-urls.ts +58 -5
  268. package/src/tools/bash.ts +99 -26
  269. package/src/tools/browser/tab-worker.ts +39 -13
  270. package/src/tools/browser.ts +17 -7
  271. package/src/tools/cron.ts +10 -1
  272. package/src/tools/debug.ts +9 -2
  273. package/src/tools/descriptors.test.ts +4 -4
  274. package/src/tools/descriptors.ts +16 -4
  275. package/src/tools/eval.ts +15 -0
  276. package/src/tools/fetch.ts +90 -2
  277. package/src/tools/gh.ts +27 -12
  278. package/src/tools/image-gen.ts +20 -6
  279. package/src/tools/irc.ts +5 -3
  280. package/src/tools/monitor.ts +9 -1
  281. package/src/tools/output-meta.ts +51 -3
  282. package/src/tools/read.ts +9 -2
  283. package/src/tools/recipe/runner.ts +23 -12
  284. package/src/tools/render-utils.ts +2 -2
  285. package/src/tools/search.ts +3 -2
  286. package/src/tools/ssh.ts +274 -8
  287. package/src/tools/subagent.ts +10 -4
  288. package/src/tools/tmux-self-injection-guard.ts +3301 -122
  289. package/src/tools/tool-catalog.generated.ts +1 -1
  290. package/src/tools/ultragoal-ask-guard.ts +13 -1
  291. package/src/tools/write.ts +7 -0
  292. package/src/tui/tree-list.ts +15 -1
  293. package/src/utils/commit-message-generator.ts +3 -2
  294. package/src/utils/external-editor.ts +21 -7
  295. package/src/utils/file-mentions.ts +46 -6
  296. package/src/utils/git.ts +38 -7
  297. package/src/utils/image-limits.ts +8 -0
  298. package/src/utils/image-loading.ts +1 -1
  299. package/src/utils/open.ts +73 -4
  300. package/src/utils/pasted-image-loading.ts +9 -8
  301. package/src/utils/prompt-suggestion.ts +5 -4
  302. package/src/utils/shell-snapshot.ts +9 -1
  303. package/src/utils/title-generator.ts +65 -20
  304. package/src/web/search/index.ts +2 -1
  305. package/src/web/search/providers/codex.ts +29 -32
@@ -23,9 +23,9 @@ export interface MapReduceInput {
23
23
  model: Model<Api>;
24
24
  apiKey: string;
25
25
  thinkingLevel?: ThinkingLevel;
26
- smolModel: Model<Api>;
27
- smolApiKey: string;
28
- smolThinkingLevel?: ThinkingLevel;
26
+ secondaryModel: Model<Api>;
27
+ secondaryApiKey: string;
28
+ secondaryThinkingLevel?: ThinkingLevel;
29
29
  diff: string;
30
30
  stat: string;
31
31
  scopeCandidates: string;
@@ -45,15 +45,15 @@ export function shouldUseMapReduce(diff: string, settings?: MapReduceSettings):
45
45
  }
46
46
 
47
47
  /**
48
- * Run map-reduce analysis for large diffs using smol + primary models.
48
+ * Run map-reduce analysis for large diffs using the secondary (map) and primary (reduce) models.
49
49
  */
50
50
 
51
51
  export async function runMapReduceAnalysis(input: MapReduceInput): Promise<ConventionalAnalysis> {
52
52
  const fileDiffs = parseFileDiffs(input.diff).filter(file => !isExcludedFile(file.filename));
53
53
  const observations = await runMapPhase({
54
- model: input.smolModel,
55
- apiKey: input.smolApiKey,
56
- thinkingLevel: input.smolThinkingLevel,
54
+ model: input.secondaryModel,
55
+ apiKey: input.secondaryApiKey,
56
+ thinkingLevel: input.secondaryThinkingLevel,
57
57
  files: fileDiffs,
58
58
  config: input.settings,
59
59
  });
@@ -53,9 +53,9 @@ async function runLegacyCommitCommand(args: CommitCommandArgs): Promise<void> {
53
53
  thinkingLevel: primaryThinkingLevel,
54
54
  } = await resolvePrimaryModel(args.model, settings, modelRegistry);
55
55
  const {
56
- model: smolModel,
57
- apiKey: smolApiKey,
58
- thinkingLevel: smolThinkingLevel,
56
+ model: secondaryModel,
57
+ apiKey: secondaryApiKey,
58
+ thinkingLevel: secondaryThinkingLevel,
59
59
  } = await resolveSecondaryCommitModel(settings, modelRegistry, primaryModel, primaryApiKey);
60
60
 
61
61
  let stagedFiles = await git.diff.changedFiles(cwd, { cached: true });
@@ -102,9 +102,9 @@ async function runLegacyCommitCommand(args: CommitCommandArgs): Promise<void> {
102
102
  primaryModel,
103
103
  primaryApiKey,
104
104
  primaryThinkingLevel,
105
- smolModel,
106
- smolApiKey,
107
- smolThinkingLevel,
105
+ secondaryModel,
106
+ secondaryApiKey,
107
+ secondaryThinkingLevel,
108
108
  commitSettings,
109
109
  });
110
110
 
@@ -148,9 +148,9 @@ async function generateAnalysis(input: {
148
148
  primaryModel: Model<Api>;
149
149
  primaryApiKey: string;
150
150
  primaryThinkingLevel?: ThinkingLevel;
151
- smolModel: Model<Api>;
152
- smolApiKey: string;
153
- smolThinkingLevel?: ThinkingLevel;
151
+ secondaryModel: Model<Api>;
152
+ secondaryApiKey: string;
153
+ secondaryThinkingLevel?: ThinkingLevel;
154
154
  commitSettings: {
155
155
  mapReduceEnabled: boolean;
156
156
  mapReduceMinFiles: number;
@@ -172,9 +172,9 @@ async function generateAnalysis(input: {
172
172
  model: input.primaryModel,
173
173
  apiKey: input.primaryApiKey,
174
174
  thinkingLevel: input.primaryThinkingLevel,
175
- smolModel: input.smolModel,
176
- smolApiKey: input.smolApiKey,
177
- smolThinkingLevel: input.smolThinkingLevel,
175
+ secondaryModel: input.secondaryModel,
176
+ secondaryApiKey: input.secondaryApiKey,
177
+ secondaryThinkingLevel: input.secondaryThinkingLevel,
178
178
  diff: input.diff,
179
179
  stat: input.stat,
180
180
  scopeCandidates: input.scopeCandidates,
@@ -44,7 +44,8 @@ type NormalizedAutoroutingCuratedTierMap = {
44
44
  export const TIER_MAP_VERSION = 1;
45
45
 
46
46
  export const CURATED_TIER_LABELS = {
47
- "anthropic/claude-haiku-4-5": [{ tier: "fast", rank: 1 }],
47
+ "anthropic/claude-haiku-5-5": [{ tier: "fast", rank: 1 }],
48
+ "anthropic/claude-haiku-4-5": [{ tier: "fast", rank: 2 }],
48
49
  "anthropic/claude-sonnet-5-5": [{ tier: "balanced", rank: 1 }],
49
50
  "anthropic/claude-sonnet-5": [{ tier: "balanced", rank: 2 }],
50
51
  "anthropic/claude-sonnet-4-6": [{ tier: "balanced", rank: 3 }],
@@ -77,6 +78,24 @@ export const CURATED_TIER_LABELS = {
77
78
 
78
79
  /** Generated from packages/ai/src/models.json at feature land: 3936 in-scope baseline skips. */
79
80
  export const TIER_MAP_SKIP_LIST = {
81
+ "amazon-bedrock/anthropic.claude-haiku-5-5": {
82
+ rationale: "Haiku 5.5 Bedrock catalog addition; not yet curated",
83
+ },
84
+ "amazon-bedrock/au.anthropic.claude-haiku-5-5": {
85
+ rationale: "Haiku 5.5 Bedrock catalog addition; not yet curated",
86
+ },
87
+ "amazon-bedrock/eu.anthropic.claude-haiku-5-5": {
88
+ rationale: "Haiku 5.5 Bedrock catalog addition; not yet curated",
89
+ },
90
+ "amazon-bedrock/global.anthropic.claude-haiku-5-5": {
91
+ rationale: "Haiku 5.5 Bedrock catalog addition; not yet curated",
92
+ },
93
+ "amazon-bedrock/jp.anthropic.claude-haiku-5-5": {
94
+ rationale: "Haiku 5.5 Bedrock catalog addition; not yet curated",
95
+ },
96
+ "amazon-bedrock/us.anthropic.claude-haiku-5-5": {
97
+ rationale: "Haiku 5.5 Bedrock catalog addition; not yet curated",
98
+ },
80
99
  "amazon-bedrock/au.anthropic.claude-sonnet-5-5": {
81
100
  rationale: "Sonnet 5.5 catalog addition (#6111); not yet curated",
82
101
  },
@@ -1,18 +1,121 @@
1
+ import { randomBytes } from "node:crypto";
1
2
  import * as fs from "node:fs";
2
3
  import * as path from "node:path";
3
- import { getAgentDir, isEnoent, logger } from "@gajae-code/utils";
4
+ import { renameNoReplacePath } from "@gajae-code/natives";
5
+ import { getAgentDir, isEnoent, isFsError, logger } from "@gajae-code/utils";
4
6
  import { JSONC, YAML } from "bun";
5
7
  import type { ZodType } from "zod/v4";
6
8
 
9
+ // Volumes without hard links fail `link`. Windows maps FAT ERROR_INVALID_FUNCTION to EISDIR.
10
+ const HARD_LINK_UNAVAILABLE = new Set(["EACCES", "EISDIR", "ENOSYS", "ENOTSUP", "EOPNOTSUPP", "EPERM", "EXDEV"]);
11
+
7
12
  /** Minimal subset of the AJV ConfigSchemaError shape this module actually relies on. */
8
13
  interface ConfigSchemaError {
9
14
  instancePath: string;
10
15
  message: string | undefined;
11
16
  }
12
17
 
18
+ /** True when the final path component exists, including a dangling symlink. */
19
+ function ymlPathPresent(ymlPath: string): boolean {
20
+ try {
21
+ fs.lstatSync(ymlPath);
22
+ return true;
23
+ } catch (error) {
24
+ if (isEnoent(error)) return false;
25
+ throw error;
26
+ }
27
+ }
28
+
29
+ function hardLinkUnavailable(error: unknown): boolean {
30
+ return isFsError(error) && HARD_LINK_UNAVAILABLE.has(error.code);
31
+ }
32
+
33
+ function stagedRegularFile(tmpPath: string): boolean {
34
+ try {
35
+ return fs.lstatSync(tmpPath).isFile();
36
+ } catch {
37
+ return false;
38
+ }
39
+ }
40
+
41
+ function discardStaged(tmpPath: string): void {
42
+ try {
43
+ fs.unlinkSync(tmpPath);
44
+ } catch {
45
+ // Unpublished, or the no-replace rename already moved this name.
46
+ }
47
+ }
48
+
49
+ /** Publish the completed private file when `link` is not supported. Never replaces `ymlPath`. */
50
+ function publishStagedWithoutHardLink(tmpPath: string, ymlPath: string): void {
51
+ const published = renameNoReplacePath(tmpPath, ymlPath);
52
+ if (!published.ok && published.reason !== "destination_exists") {
53
+ discardStaged(tmpPath);
54
+ throw new Error(`config migration could not publish without a hard link (${published.reason})`);
55
+ }
56
+ discardStaged(tmpPath);
57
+ }
58
+
59
+ /**
60
+ * Publish a new regular file as mode 0600. The bytes go to a private inode
61
+ * opened with O_EXCL and O_NOFOLLOW. `link` then attaches that inode to
62
+ * `ymlPath` and fails when the name exists, so a final-component symlink is
63
+ * not followed and an existing file is not replaced. A volume without hard
64
+ * links publishes that same completed file with a no-replace rename. The
65
+ * destination name stays absent until the bytes are complete.
66
+ */
67
+ function writeNewOwnerOnlyNoFollow(ymlPath: string, content: string): void {
68
+ // Ancestor symlinks only. The final component stays unresolved so no-follow still applies.
69
+ ymlPath = path.join(fs.realpathSync(path.dirname(ymlPath)), path.basename(ymlPath));
70
+ const noFollow = process.platform === "win32" ? 0 : (fs.constants.O_NOFOLLOW ?? 0);
71
+ const tmpPath = path.join(
72
+ path.dirname(ymlPath),
73
+ `.${path.basename(ymlPath)}.${process.pid}.${randomBytes(8).toString("hex")}.tmp`,
74
+ );
75
+ let fd: number | undefined;
76
+ try {
77
+ fd = fs.openSync(tmpPath, fs.constants.O_WRONLY | fs.constants.O_CREAT | fs.constants.O_EXCL | noFollow, 0o600);
78
+ if (process.platform !== "win32") fs.fchmodSync(fd, 0o600);
79
+ fs.writeFileSync(fd, content);
80
+ fs.fsyncSync(fd);
81
+ fs.closeSync(fd);
82
+ fd = undefined;
83
+ } catch (error) {
84
+ if (fd !== undefined) {
85
+ try {
86
+ fs.closeSync(fd);
87
+ } catch {
88
+ // The original failure is the one that must surface.
89
+ }
90
+ try {
91
+ fs.unlinkSync(tmpPath);
92
+ } catch {
93
+ // The destination name was not published.
94
+ }
95
+ }
96
+ throw error;
97
+ }
98
+ try {
99
+ fs.linkSync(tmpPath, ymlPath);
100
+ } catch (error) {
101
+ // The name is already present: a finished peer publish, or a file or symlink we must not replace.
102
+ if (isFsError(error) && (error.code === "EEXIST" || error.code === "ELOOP")) {
103
+ discardStaged(tmpPath);
104
+ return;
105
+ }
106
+ if (hardLinkUnavailable(error) && stagedRegularFile(tmpPath)) {
107
+ publishStagedWithoutHardLink(tmpPath, ymlPath);
108
+ return;
109
+ }
110
+ discardStaged(tmpPath);
111
+ throw error;
112
+ }
113
+ discardStaged(tmpPath);
114
+ }
115
+
13
116
  function migrateJsonToYml(jsonPath: string, ymlPath: string) {
14
117
  try {
15
- if (fs.existsSync(ymlPath)) return;
118
+ if (ymlPathPresent(ymlPath)) return;
16
119
  if (!fs.existsSync(jsonPath)) return;
17
120
 
18
121
  const content = fs.readFileSync(jsonPath, "utf-8");
@@ -21,7 +124,7 @@ function migrateJsonToYml(jsonPath: string, ymlPath: string) {
21
124
  logger.warn("migrateJsonToYml: invalid json structure", { path: jsonPath });
22
125
  return;
23
126
  }
24
- fs.writeFileSync(ymlPath, YAML.stringify(parsed, null, 2));
127
+ writeNewOwnerOnlyNoFollow(ymlPath, YAML.stringify(parsed, null, 2));
25
128
  } catch (error) {
26
129
  logger.warn("migrateJsonToYml: migration failed", { error: String(error) });
27
130
  }
@@ -242,6 +242,14 @@ export class ConfigHotReloadWatcher {
242
242
  await this.#initializeBinding(binding);
243
243
  }
244
244
 
245
+ /**
246
+ * Test-only: request the same scan an fs event would schedule. Tests that
247
+ * exercise the watcher cannot rely on platform fs-event delivery timing.
248
+ */
249
+ __testRequestScan(): void {
250
+ if (this.#binding && this.#isCurrent(this.#binding)) this.#scheduleScan(this.#binding);
251
+ }
252
+
245
253
  /** Closes all watches and cancels or fences pending and in-flight callbacks. */
246
254
  dispose(): void {
247
255
  if (this.#disposed) return;