@gajae-code/coding-agent 0.18.7 → 0.18.9

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 (344) hide show
  1. package/CHANGELOG.md +377 -1
  2. package/dist/types/async/endpoint-id.d.ts +16 -0
  3. package/dist/types/async/job-manager.d.ts +1 -1
  4. package/dist/types/async/support.d.ts +0 -14
  5. package/dist/types/capability/mcp.d.ts +2 -0
  6. package/dist/types/capability/skill.d.ts +2 -0
  7. package/dist/types/capability/types.d.ts +2 -0
  8. package/dist/types/cli/public-command-errors.d.ts +3 -1
  9. package/dist/types/cli/setup-cli.d.ts +1 -1
  10. package/dist/types/commands/deep-interview.d.ts +3 -0
  11. package/dist/types/commands/mcp-serve.d.ts +4 -0
  12. package/dist/types/config/autorouting-tier-map.d.ts +348 -9
  13. package/dist/types/config/file-lock.d.ts +1 -0
  14. package/dist/types/config/model-bindings-applier.d.ts +2 -0
  15. package/dist/types/config/model-profile-activation.d.ts +11 -3
  16. package/dist/types/config/model-registry.d.ts +4 -9
  17. package/dist/types/config/skill-settings-defaults.d.ts +2 -0
  18. package/dist/types/cursor-delete-path.d.ts +1 -0
  19. package/dist/types/cursor-mcp-name.d.ts +8 -0
  20. package/dist/types/customization/inventory.d.ts +2 -0
  21. package/dist/types/debug/report-bundle-parent.d.ts +2 -0
  22. package/dist/types/defaults/gjc/extensions/grok-cli-vendor/src/provider/stream.d.ts +1 -0
  23. package/dist/types/defaults/gjc/extensions/grok-cli-vendor/src/provider/version-manager.d.ts +31 -0
  24. package/dist/types/defaults/gjc-skills.generated.d.ts +5 -6
  25. package/dist/types/discovery/helpers.d.ts +6 -1
  26. package/dist/types/discovery/mcp-json.d.ts +1 -0
  27. package/dist/types/eval/py/kernel.d.ts +18 -0
  28. package/dist/types/export/html/css-color.d.ts +2 -0
  29. package/dist/types/export/html/html-export-destination.d.ts +2 -0
  30. package/dist/types/export/html/template.generated.d.ts +1 -1
  31. package/dist/types/extensibility/extensions/function-hooks-internal.d.ts +5 -0
  32. package/dist/types/extensibility/extensions/types.d.ts +7 -0
  33. package/dist/types/extensibility/gjc-plugins/runtime-adapters.d.ts +14 -1
  34. package/dist/types/extensibility/plugins/marketplace/cache.d.ts +2 -0
  35. package/dist/types/extensibility/plugins/plugin-link-path.d.ts +2 -0
  36. package/dist/types/extensibility/runtime-skill-discovery.d.ts +3 -1
  37. package/dist/types/extensibility/skill-management.d.ts +4 -1
  38. package/dist/types/extensibility/skills.d.ts +2 -0
  39. package/dist/types/gjc-runtime/deep-interview-crystallize.d.ts +74 -0
  40. package/dist/types/gjc-runtime/deep-interview-runtime.d.ts +11 -0
  41. package/dist/types/gjc-runtime/gc-runtime.d.ts +5 -0
  42. package/dist/types/gjc-runtime/psmux-detect.d.ts +3 -3
  43. package/dist/types/gjc-runtime/ralplan-runtime.d.ts +0 -5
  44. package/dist/types/gjc-runtime/sidecar-bootstrap-env.d.ts +6 -0
  45. package/dist/types/gjc-runtime/state-argv.d.ts +1 -1
  46. package/dist/types/gjc-runtime/state-migrations.d.ts +8 -0
  47. package/dist/types/gjc-runtime/state-runtime.d.ts +95 -0
  48. package/dist/types/gjc-runtime/state-writer.d.ts +14 -1
  49. package/dist/types/gjc-runtime/tmux-common.d.ts +8 -5
  50. package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +8 -0
  51. package/dist/types/internal-urls/skill-path.d.ts +1 -0
  52. package/dist/types/lsp/config.d.ts +8 -5
  53. package/dist/types/lsp/workspace-path.d.ts +1 -0
  54. package/dist/types/modes/acp/acp-agent.d.ts +7 -0
  55. package/dist/types/modes/components/custom-editor.d.ts +6 -0
  56. package/dist/types/modes/components/customization/customization-dashboard.d.ts +1 -0
  57. package/dist/types/modes/components/extensions/state-manager.d.ts +4 -3
  58. package/dist/types/modes/controllers/input-controller.d.ts +9 -0
  59. package/dist/types/modes/interactive-mode.d.ts +1 -0
  60. package/dist/types/modes/utils/interrupt-ownership.d.ts +3 -0
  61. package/dist/types/modes/utils/keybinding-matchers.d.ts +1 -0
  62. package/dist/types/modes/utils/macos-option-forwarding.d.ts +17 -0
  63. package/dist/types/progress/collect-project-progress.d.ts +38 -0
  64. package/dist/types/progress/progress-contract.d.ts +154 -0
  65. package/dist/types/progress/progress-snapshot.d.ts +11 -0
  66. package/dist/types/progress/project-progress.d.ts +141 -0
  67. package/dist/types/progress/render-progress.d.ts +28 -0
  68. package/dist/types/runtime-mcp/manager.d.ts +2 -1
  69. package/dist/types/runtime-mcp/mcp-redirect.d.ts +9 -0
  70. package/dist/types/runtime-mcp/oauth-public-url.d.ts +3 -0
  71. package/dist/types/runtime-mcp/plugin-network-boundary.d.ts +1 -0
  72. package/dist/types/runtime-mcp/project-host-values.d.ts +27 -0
  73. package/dist/types/runtime-mcp/smithery-registry.d.ts +24 -0
  74. package/dist/types/runtime-mcp/types.d.ts +6 -0
  75. package/dist/types/sdk/acp/adapter.d.ts +1 -1
  76. package/dist/types/sdk/broker/broker-exit.d.ts +6 -2
  77. package/dist/types/sdk/broker/broker.d.ts +24 -2
  78. package/dist/types/sdk/broker/doctor-restart.d.ts +5 -0
  79. package/dist/types/sdk/broker/ensure.d.ts +14 -1
  80. package/dist/types/sdk/broker/session-index.d.ts +12 -6
  81. package/dist/types/sdk/bus/index.d.ts +12 -1
  82. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +6 -1
  83. package/dist/types/sdk/client/client.d.ts +2 -0
  84. package/dist/types/sdk/host/query/handlers.d.ts +3 -0
  85. package/dist/types/sdk/index.d.ts +1 -0
  86. package/dist/types/sdk/router/session-router.d.ts +2 -0
  87. package/dist/types/sdk/session-list.d.ts +1 -1
  88. package/dist/types/sdk/session.d.ts +8 -0
  89. package/dist/types/session/agent-session.d.ts +38 -9
  90. package/dist/types/session/artifacts.d.ts +2 -2
  91. package/dist/types/session/internal/managed-gc-retirement-codec.d.ts +32 -0
  92. package/dist/types/session/internal/managed-session-scope.d.ts +79 -2
  93. package/dist/types/session/internal/managed-session-storage.d.ts +26 -1
  94. package/dist/types/session/internal/managed-task-owner-cleanup.d.ts +62 -0
  95. package/dist/types/session/internal/task-artifact-owner-access.d.ts +2 -0
  96. package/dist/types/session/internal/task-artifact-owner-transcript.d.ts +9 -1
  97. package/dist/types/session/session-manager.d.ts +31 -5
  98. package/dist/types/session/session-retirement.d.ts +31 -7
  99. package/dist/types/session/session-storage.d.ts +69 -2
  100. package/dist/types/session/task-artifact-owner-codec.d.ts +2 -0
  101. package/dist/types/setup/credential-auto-import.d.ts +1 -1
  102. package/dist/types/setup/credential-import.d.ts +6 -4
  103. package/dist/types/skill-state/active-state.d.ts +38 -0
  104. package/dist/types/skill-state/workflow-mutation-guard.d.ts +3 -0
  105. package/dist/types/slash-commands/helpers/progress-report.d.ts +8 -0
  106. package/dist/types/task/executor.d.ts +3 -0
  107. package/dist/types/task/isolation-dir.d.ts +26 -0
  108. package/dist/types/tools/ast-edit-write-path.d.ts +13 -0
  109. package/dist/types/tools/bash-skill-urls.d.ts +1 -1
  110. package/dist/types/tools/browser/cdp-url.d.ts +2 -0
  111. package/dist/types/tools/github-side-effect.d.ts +22 -0
  112. package/dist/types/tools/index.d.ts +3 -0
  113. package/dist/types/tools/monitor-mutation.d.ts +9 -0
  114. package/dist/types/tools/python.d.ts +9 -1
  115. package/dist/types/tools/recipe/recipe-guard.d.ts +7 -0
  116. package/dist/types/tools/restricted-cwd.d.ts +1 -0
  117. package/dist/types/tools/todo-write.d.ts +6 -0
  118. package/dist/types/utils/tools-checksum.d.ts +7 -0
  119. package/package.json +7 -7
  120. package/scripts/generate-sdk-operation-inventory.ts +21 -0
  121. package/scripts/verify-managed-empty-stop.ts +28 -0
  122. package/src/async/endpoint-id.ts +26 -0
  123. package/src/async/job-manager.ts +247 -132
  124. package/src/async/support.ts +0 -25
  125. package/src/capability/index.ts +15 -0
  126. package/src/capability/mcp.ts +2 -0
  127. package/src/capability/skill.ts +2 -0
  128. package/src/capability/types.ts +2 -0
  129. package/src/cli/auth-broker-cli.ts +1 -1
  130. package/src/cli/customize-doctor.ts +15 -2
  131. package/src/cli/doctor/repairs.ts +4 -1
  132. package/src/cli/doctor-supervisor.ts +3 -0
  133. package/src/cli/public-command-errors.ts +21 -1
  134. package/src/cli/public-command-registry.ts +28 -6
  135. package/src/cli/setup-cli.ts +4 -4
  136. package/src/cli/skills-cli.ts +5 -0
  137. package/src/commands/deep-interview.ts +47 -8
  138. package/src/commands/mcp-serve.ts +7 -0
  139. package/src/commands/sdk.ts +455 -397
  140. package/src/config/autorouting-tier-map.ts +117 -7
  141. package/src/config/file-lock.ts +316 -79
  142. package/src/config/mcp-schema.json +4 -0
  143. package/src/config/model-bindings-applier.ts +20 -0
  144. package/src/config/model-profile-activation.ts +240 -46
  145. package/src/config/model-registry.ts +47 -153
  146. package/src/config/skill-settings-defaults.ts +7 -0
  147. package/src/coordinator-mcp/policy.ts +3 -2
  148. package/src/coordinator-mcp/server.ts +2 -0
  149. package/src/cursor-delete-path.ts +10 -0
  150. package/src/cursor-mcp-name.ts +15 -0
  151. package/src/cursor.ts +13 -2
  152. package/src/customization/inventory.ts +4 -13
  153. package/src/dap/config.ts +2 -2
  154. package/src/debug/report-bundle-parent.ts +22 -0
  155. package/src/debug/report-bundle.ts +3 -0
  156. package/src/debug/system-info.ts +13 -1
  157. package/src/defaults/gjc/extensions/grok-cli-vendor/src/provider/register.ts +10 -6
  158. package/src/defaults/gjc/extensions/grok-cli-vendor/src/provider/stream.ts +67 -4
  159. package/src/defaults/gjc/extensions/grok-cli-vendor/src/provider/version-manager.ts +80 -0
  160. package/src/defaults/gjc/skills/deep-interview/SKILL.md +105 -10
  161. package/src/defaults/gjc/skills/ralplan/SKILL.md +6 -4
  162. package/src/defaults/gjc-defaults.test.ts +18 -1
  163. package/src/defaults/gjc-defaults.ts +3 -0
  164. package/src/defaults/gjc-skills.generated.ts +58 -36
  165. package/src/discovery/agents.ts +6 -1
  166. package/src/discovery/builtin.ts +13 -1
  167. package/src/discovery/helpers.ts +171 -29
  168. package/src/discovery/mcp-json.ts +26 -12
  169. package/src/discovery/ssh.ts +1 -1
  170. package/src/discovery/substitute-plugin-root.ts +3 -1
  171. package/src/edit/file-read-cache.ts +1 -1
  172. package/src/eval/py/executor.ts +796 -154
  173. package/src/eval/py/kernel.ts +79 -13
  174. package/src/eval/py/tool-bridge.ts +4 -0
  175. package/src/export/html/css-color.ts +9 -0
  176. package/src/export/html/html-export-destination.ts +16 -0
  177. package/src/export/html/index.ts +7 -10
  178. package/src/export/html/template.generated.ts +1 -1
  179. package/src/extensibility/extensions/function-hooks-internal.ts +27 -0
  180. package/src/extensibility/extensions/runner.ts +15 -1
  181. package/src/extensibility/extensions/types.ts +7 -0
  182. package/src/extensibility/gjc-plugins/mcp-policy.ts +2 -1
  183. package/src/extensibility/gjc-plugins/runtime-adapters.ts +85 -8
  184. package/src/extensibility/plugins/manager.ts +3 -2
  185. package/src/extensibility/plugins/marketplace/cache.ts +15 -0
  186. package/src/extensibility/plugins/marketplace/manager.ts +11 -3
  187. package/src/extensibility/plugins/plugin-link-path.ts +12 -0
  188. package/src/extensibility/runtime-skill-discovery.ts +20 -2
  189. package/src/extensibility/skill-management.ts +9 -2
  190. package/src/extensibility/skills.ts +6 -1
  191. package/src/gjc-runtime/deep-interview-crystallize.ts +1814 -0
  192. package/src/gjc-runtime/deep-interview-recorder.ts +20 -2
  193. package/src/gjc-runtime/deep-interview-runtime.ts +1415 -13
  194. package/src/gjc-runtime/deep-interview-stage.ts +98 -21
  195. package/src/gjc-runtime/gc-runtime.ts +206 -9
  196. package/src/gjc-runtime/launch-worktree.ts +70 -9
  197. package/src/gjc-runtime/psmux-detect.ts +28 -4
  198. package/src/gjc-runtime/ralplan-runtime.ts +447 -52
  199. package/src/gjc-runtime/session-state-sidecar.ts +3 -2
  200. package/src/gjc-runtime/sidecar-bootstrap-env.ts +19 -0
  201. package/src/gjc-runtime/state-argv.ts +2 -0
  202. package/src/gjc-runtime/state-migrations.ts +91 -29
  203. package/src/gjc-runtime/state-runtime.ts +3716 -135
  204. package/src/gjc-runtime/state-writer.ts +105 -16
  205. package/src/gjc-runtime/tmux-common.ts +8 -5
  206. package/src/gjc-runtime/ultragoal-runtime.ts +16 -4
  207. package/src/gjc-runtime/workflow-manifest.generated.json +70 -42
  208. package/src/gjc-runtime/workflow-manifest.ts +54 -21
  209. package/src/harness-control-plane/operate.ts +12 -4
  210. package/src/harness-control-plane/owner.ts +5 -1
  211. package/src/hashline/parser.ts +48 -9
  212. package/src/hashline/recovery.ts +13 -4
  213. package/src/internal-urls/docs-index.generated.ts +20 -19
  214. package/src/internal-urls/skill-path.ts +19 -0
  215. package/src/internal-urls/skill-protocol.ts +2 -0
  216. package/src/lsp/config.ts +12 -63
  217. package/src/lsp/edits.ts +6 -0
  218. package/src/lsp/workspace-path.ts +51 -0
  219. package/src/main.ts +195 -31
  220. package/src/memories/index.ts +88 -7
  221. package/src/modes/acp/acp-agent.ts +88 -4
  222. package/src/modes/components/custom-editor.ts +14 -0
  223. package/src/modes/components/customization/customization-dashboard.ts +12 -0
  224. package/src/modes/components/extensions/extension-dashboard.ts +2 -2
  225. package/src/modes/components/extensions/state-manager.ts +15 -5
  226. package/src/modes/components/hook-editor.ts +1 -1
  227. package/src/modes/components/hook-selector.ts +1 -1
  228. package/src/modes/components/model-selector.ts +1 -4
  229. package/src/modes/components/provider-onboarding-selector.ts +1 -1
  230. package/src/modes/components/status-line/segments.ts +4 -0
  231. package/src/modes/controllers/event-controller.ts +11 -4
  232. package/src/modes/controllers/input-controller.ts +76 -31
  233. package/src/modes/controllers/runtime-mcp-command-controller.ts +29 -16
  234. package/src/modes/controllers/selector-controller.ts +24 -15
  235. package/src/modes/controllers/todo-command-controller.ts +1 -1
  236. package/src/modes/interactive-mode.ts +5 -1
  237. package/src/modes/runtime-init.ts +4 -0
  238. package/src/modes/utils/abort-message.ts +3 -1
  239. package/src/modes/utils/interrupt-ownership.ts +12 -0
  240. package/src/modes/utils/keybinding-matchers.ts +4 -0
  241. package/src/modes/utils/macos-option-forwarding.ts +80 -0
  242. package/src/progress/collect-project-progress.ts +153 -0
  243. package/src/progress/progress-contract.ts +172 -0
  244. package/src/progress/progress-snapshot.ts +140 -0
  245. package/src/progress/project-progress.ts +446 -0
  246. package/src/progress/render-progress.ts +209 -0
  247. package/src/prompts/system/master-mode.md +1 -0
  248. package/src/prompts/tools/skill-discovery.md +1 -1
  249. package/src/runtime-mcp/client.ts +4 -2
  250. package/src/runtime-mcp/config-writer.ts +10 -6
  251. package/src/runtime-mcp/config.ts +1 -0
  252. package/src/runtime-mcp/json-rpc.ts +2 -1
  253. package/src/runtime-mcp/manager.ts +29 -11
  254. package/src/runtime-mcp/mcp-redirect.ts +73 -0
  255. package/src/runtime-mcp/oauth-flow.ts +14 -2
  256. package/src/runtime-mcp/oauth-public-url.ts +14 -0
  257. package/src/runtime-mcp/plugin-network-boundary.ts +4 -0
  258. package/src/runtime-mcp/pool.ts +6 -0
  259. package/src/runtime-mcp/project-host-values.ts +46 -0
  260. package/src/runtime-mcp/smithery-registry.ts +22 -3
  261. package/src/runtime-mcp/transports/http.ts +4 -3
  262. package/src/runtime-mcp/types.ts +6 -0
  263. package/src/sdk/acp/adapter.ts +95 -8
  264. package/src/sdk/broker/broker-exit.ts +52 -23
  265. package/src/sdk/broker/broker.ts +81 -6
  266. package/src/sdk/broker/doctor-restart.ts +4 -0
  267. package/src/sdk/broker/ensure.ts +31 -2
  268. package/src/sdk/broker/lifecycle.ts +711 -66
  269. package/src/sdk/broker/session-index.ts +191 -81
  270. package/src/sdk/bus/chat-daemon-cli.ts +38 -1
  271. package/src/sdk/bus/chat-daemon-control.ts +2 -2
  272. package/src/sdk/bus/index.ts +238 -43
  273. package/src/sdk/bus/telegram-daemon-contract.ts +6 -1
  274. package/src/sdk/cli/session-cli.ts +17 -3
  275. package/src/sdk/client/client.ts +28 -8
  276. package/src/sdk/host/query/handlers.ts +9 -1
  277. package/src/sdk/host/session-runtime.test.ts +2705 -303
  278. package/src/sdk/host/session-runtime.ts +490 -143
  279. package/src/sdk/host/surface-policy.ts +1 -0
  280. package/src/sdk/index.ts +8 -0
  281. package/src/sdk/lifecycle-session.ts +3 -1
  282. package/src/sdk/prompt-deadline-manager.ts +15 -0
  283. package/src/sdk/protocol/operation-inventory.generated.json +146 -0
  284. package/src/sdk/protocol/operation-registry.ts +9 -2
  285. package/src/sdk/router/session-router.ts +82 -18
  286. package/src/sdk/session-list.ts +1 -0
  287. package/src/sdk/session.ts +69 -45
  288. package/src/session/agent-session.ts +679 -238
  289. package/src/session/artifacts.ts +176 -71
  290. package/src/session/internal/managed-gc-retirement-codec.ts +319 -0
  291. package/src/session/internal/managed-session-scope.ts +3779 -462
  292. package/src/session/internal/managed-session-storage.ts +501 -78
  293. package/src/session/internal/managed-task-owner-cleanup.ts +473 -0
  294. package/src/session/internal/task-artifact-owner-access.ts +19 -3
  295. package/src/session/internal/task-artifact-owner-transcript.ts +547 -1
  296. package/src/session/session-manager.ts +951 -133
  297. package/src/session/session-retirement.ts +573 -14
  298. package/src/session/session-storage.ts +447 -15
  299. package/src/session/task-artifact-owner-codec.ts +71 -8
  300. package/src/session/task-artifact-owner-retirement.ts +21 -19
  301. package/src/setup/credential-auto-import.ts +12 -3
  302. package/src/setup/credential-import.ts +176 -5
  303. package/src/setup/paseo/announce.ts +6 -1
  304. package/src/skill-state/active-state.ts +145 -2
  305. package/src/skill-state/workflow-mutation-guard.ts +102 -10
  306. package/src/slash-commands/builtin-registry.ts +39 -9
  307. package/src/slash-commands/helpers/mcp.ts +8 -4
  308. package/src/slash-commands/helpers/progress-report.ts +23 -0
  309. package/src/stt/setup.ts +3 -5
  310. package/src/task/commands.ts +3 -1
  311. package/src/task/executor.ts +4 -0
  312. package/src/task/index.ts +6 -0
  313. package/src/task/isolation-dir.ts +143 -0
  314. package/src/task/worktree.ts +16 -7
  315. package/src/tools/ask.ts +205 -6
  316. package/src/tools/ast-edit-write-path.ts +68 -0
  317. package/src/tools/ast-edit.ts +10 -1
  318. package/src/tools/bash-allowed-prefixes.ts +15 -0
  319. package/src/tools/bash-skill-urls.ts +56 -3
  320. package/src/tools/bash.ts +48 -79
  321. package/src/tools/browser/cdp-url.ts +18 -0
  322. package/src/tools/browser.ts +8 -1
  323. package/src/tools/descriptors.ts +5 -1
  324. package/src/tools/eval.ts +56 -36
  325. package/src/tools/gh.ts +10 -0
  326. package/src/tools/github-side-effect.ts +112 -0
  327. package/src/tools/image-gen.ts +1 -1
  328. package/src/tools/index.ts +3 -0
  329. package/src/tools/monitor-mutation.ts +27 -0
  330. package/src/tools/monitor.ts +7 -0
  331. package/src/tools/python.ts +188 -66
  332. package/src/tools/recipe/index.ts +9 -0
  333. package/src/tools/recipe/recipe-guard.ts +19 -0
  334. package/src/tools/restricted-cwd.ts +10 -0
  335. package/src/tools/skill-discovery.ts +5 -0
  336. package/src/tools/skill.ts +28 -1
  337. package/src/tools/todo-write.ts +10 -1
  338. package/src/tools/tool-catalog.generated.ts +1 -1
  339. package/src/tools/write.ts +1 -0
  340. package/src/utils/external-editor.ts +3 -2
  341. package/src/utils/tools-checksum.ts +34 -0
  342. package/src/utils/tools-manager.ts +24 -6
  343. package/src/web/insane/url-guard.ts +2 -1
  344. package/src/web/search/providers/codex.ts +3 -2
@@ -39,6 +39,10 @@ const RETIREMENT_CONTINUATION_KEYS = new Set([
39
39
  const U64_MAX = 18_446_744_073_709_551_615n;
40
40
 
41
41
  type NativeDirectoryTreeEntry = NativeDirectoryTreeSnapshot["entries"][number];
42
+ type ExpectedTreeChildren = {
43
+ readonly direct: Map<string, NativeDirectoryTreeEntry>;
44
+ readonly quarantined: Map<string, NativeDirectoryTreeEntry | null>;
45
+ };
42
46
 
43
47
  export interface TaskArtifactOwnerLocator {
44
48
  readonly schemaVersion: typeof OWNER_SCHEMA_VERSION;
@@ -231,16 +235,66 @@ export function freezeTreeSnapshot(snapshot: NativeDirectoryTreeSnapshot): Nativ
231
235
  return Object.freeze(canonical);
232
236
  }
233
237
 
234
- export function retainedTreeDoesNotExpandAuthority(
238
+ /** Windows native tree removal hashes original path and inode identity for child quarantine names. */
239
+ function treeQuarantineName(entry: NativeDirectoryTreeEntry): string {
240
+ const material = `${entry.relativePath}\0${entry.dev}\0${entry.ino}`;
241
+ return `.pi-tree-detached-${crypto.createHash("sha256").update(material, "utf8").digest("hex")}`;
242
+ }
243
+
244
+ /** Project only authenticated remaining entries; never restore an omitted entry's authority. */
245
+ export function normalizeRetainedTreeSnapshot(
235
246
  expected: NativeDirectoryTreeSnapshot,
236
247
  retained: NativeDirectoryTreeSnapshot,
237
- ): boolean {
238
- if (expected.rootDev !== retained.rootDev || expected.rootIno !== retained.rootIno) return false;
248
+ ): NativeDirectoryTreeSnapshot | undefined {
249
+ if (expected.rootDev !== retained.rootDev || expected.rootIno !== retained.rootIno) return undefined;
239
250
  const expectedEntries = new Map(expected.entries.map(entry => [entry.relativePath, entry]));
240
- if (retained.entries.length > expected.entries.length) return false;
241
- return retained.entries.every(entry => {
242
- if (entry.relativePath === "") return entry.kind === "directory";
243
- const authorized = expectedEntries.get(entry.relativePath);
251
+ if (retained.entries.length > expected.entries.length) return undefined;
252
+
253
+ const childrenByParent = new Map<string, ExpectedTreeChildren>();
254
+ for (const entry of expected.entries) {
255
+ if (entry.relativePath === "") continue;
256
+ const separator = entry.relativePath.lastIndexOf("/");
257
+ const parent = separator < 0 ? "" : entry.relativePath.slice(0, separator);
258
+ const name = separator < 0 ? entry.relativePath : entry.relativePath.slice(separator + 1);
259
+ let children = childrenByParent.get(parent);
260
+ if (!children) {
261
+ children = { direct: new Map(), quarantined: new Map() };
262
+ childrenByParent.set(parent, children);
263
+ }
264
+ children.direct.set(name, entry);
265
+ const quarantineName = treeQuarantineName(entry);
266
+ children.quarantined.set(quarantineName, children.quarantined.has(quarantineName) ? null : entry);
267
+ }
268
+
269
+ const originalPathFor = (retainedPath: string): string | undefined => {
270
+ if (retainedPath === "") return "";
271
+ const components = retainedPath.split("/");
272
+ if (components.some(component => component.length === 0 || component === "." || component === ".."))
273
+ return undefined;
274
+ let parent = "";
275
+ for (const component of components) {
276
+ const children = childrenByParent.get(parent);
277
+ if (!children) return undefined;
278
+ const direct = children.direct.get(component);
279
+ const hasQuarantine = children.quarantined.has(component);
280
+ const quarantined = children.quarantined.get(component);
281
+ if ((direct && hasQuarantine) || quarantined === null) return undefined;
282
+ const matched = direct ?? quarantined;
283
+ if (!matched) return undefined;
284
+ parent = matched.relativePath;
285
+ }
286
+ return parent;
287
+ };
288
+
289
+ const seenOriginalPaths = new Set<string>();
290
+ const entries: NativeDirectoryTreeEntry[] = [];
291
+ const valid = retained.entries.every(entry => {
292
+ const originalPath = originalPathFor(entry.relativePath);
293
+ if (originalPath === undefined || seenOriginalPaths.has(originalPath)) return false;
294
+ seenOriginalPaths.add(originalPath);
295
+ entries.push({ ...entry, relativePath: originalPath });
296
+ if (originalPath === "") return entry.kind === "directory";
297
+ const authorized = expectedEntries.get(originalPath);
244
298
  if (
245
299
  authorized === undefined ||
246
300
  authorized.kind !== entry.kind ||
@@ -257,6 +311,14 @@ export function retainedTreeDoesNotExpandAuthority(
257
311
  entry.sha256 !== undefined || (entry.mtimeNs === authorized.mtimeNs && entry.ctimeNs === authorized.ctimeNs)
258
312
  );
259
313
  });
314
+ return valid ? { rootDev: retained.rootDev, rootIno: retained.rootIno, entries } : undefined;
315
+ }
316
+
317
+ export function retainedTreeDoesNotExpandAuthority(
318
+ expected: NativeDirectoryTreeSnapshot,
319
+ retained: NativeDirectoryTreeSnapshot,
320
+ ): boolean {
321
+ return normalizeRetainedTreeSnapshot(expected, retained) !== undefined;
260
322
  }
261
323
 
262
324
  export function sameTreeContents(left: NativeDirectoryTreeSnapshot, right: NativeDirectoryTreeSnapshot): boolean {
@@ -501,6 +563,7 @@ export function parseTaskArtifactOwnerRetirementOutcome(
501
563
  "windowsErrorCode",
502
564
  ];
503
565
  if (Object.keys(record).some(key => !allowed.includes(key)) || typeof record.ok !== "boolean") return invalid();
566
+ if (record.ok && Object.keys(record).length !== 1) return invalid();
504
567
  for (const [key, paths] of [
505
568
  ["detachedPath", continuation?.detachedPaths],
506
569
  ["retainedSuccessorPath", continuation?.retainedSuccessorPaths],
@@ -547,7 +610,7 @@ export function parseTaskArtifactOwnerRetirementOutcome(
547
610
  if (!nativeOutcome?.ok) return invalid();
548
611
  return Object.freeze({ kind, evidence: original, nativeOutcome });
549
612
  }
550
- if (!continuation || nativeOutcome?.ok) return invalid();
613
+ if (!continuation || (kind !== "uncertain" && nativeOutcome?.ok)) return invalid();
551
614
  if (kind === "payload_retired") {
552
615
  if (
553
616
  value.namespace !== "retained" ||
@@ -5,6 +5,7 @@ import type { ManagedSessionDescendantStore } from "./internal/managed-session-s
5
5
  import {
6
6
  captureOwnerTreeIfPresent,
7
7
  captureValidatedOwnerTree,
8
+ newSessionRootReaderStore,
8
9
  newSessionRootStore,
9
10
  ownerTreeHasPendingManagedPublication,
10
11
  } from "./internal/task-artifact-owner-access";
@@ -12,6 +13,7 @@ import {
12
13
  EMPTY_PAYLOAD_SHA256,
13
14
  isKnownNativeSidePath,
14
15
  isOwnerRetainedRoot,
16
+ normalizeRetainedTreeSnapshot,
15
17
  OWNER_DIRECTORY,
16
18
  OWNER_RETIREMENT_SCHEMA_VERSION,
17
19
  ownerAbsolutePath,
@@ -181,7 +183,7 @@ export function verifyTaskArtifactOwnerPhysicalRetirement(
181
183
  ): void {
182
184
  const outcome = parseTaskArtifactOwnerRetirementOutcome(context, evidence, value);
183
185
  if (outcome.kind !== "completed") throw new Error("task_artifact_owner_physical_retirement_unverified");
184
- const store = newSessionRootStore(context);
186
+ const store = newSessionRootReaderStore(context);
185
187
  try {
186
188
  if (!sameOwnerParentIdentity(store.captureDirectoryIdentity(OWNER_DIRECTORY), evidence.parentIdentity))
187
189
  throw new Error("task_artifact_owner_parent_identity_mismatch");
@@ -204,7 +206,7 @@ export function verifyTaskArtifactOwnerRetirementContinuation(
204
206
  ): TaskArtifactOwnerRetirementContinuation {
205
207
  const evidence = parseTaskArtifactOwnerDeletionEvidence(evidenceValue);
206
208
  const continuation = parseTaskArtifactOwnerRetirementContinuation(context, evidence, value);
207
- const store = newSessionRootStore(context);
209
+ const store = newSessionRootReaderStore(context);
208
210
  try {
209
211
  if (!sameOwnerParentIdentity(store.captureDirectoryIdentity(OWNER_DIRECTORY), evidence.parentIdentity))
210
212
  throw new Error("task_artifact_owner_parent_identity_mismatch");
@@ -214,7 +216,9 @@ export function verifyTaskArtifactOwnerRetirementContinuation(
214
216
  evidence.locator.ownerId,
215
217
  continuation.retainedRootPath,
216
218
  );
217
- if (!snapshot || !retainedTreeDoesNotExpandAuthority(continuation.retainedTreeSnapshot, snapshot))
219
+ const prior = normalizeRetainedTreeSnapshot(evidence.treeSnapshot, continuation.retainedTreeSnapshot);
220
+ const current = snapshot && normalizeRetainedTreeSnapshot(evidence.treeSnapshot, snapshot);
221
+ if (!prior || !current || !retainedTreeDoesNotExpandAuthority(prior, current))
218
222
  throw new Error("task_artifact_owner_retained_tree_mismatch");
219
223
  if (
220
224
  continuation.payloadDurable === true &&
@@ -283,7 +287,9 @@ export function retireTaskArtifactOwner(
283
287
 
284
288
  const ownerPath = ownerAbsolutePath(context, evidence.locator.ownerId);
285
289
  const removingPath = `${ownerPath}.removing`;
286
- const baseline = previous?.retainedTreeSnapshot ?? evidence.treeSnapshot;
290
+ const baseline = previous
291
+ ? normalizeRetainedTreeSnapshot(evidence.treeSnapshot, previous.retainedTreeSnapshot)
292
+ : evidence.treeSnapshot;
287
293
  const candidates = [
288
294
  ...new Set(
289
295
  [previous?.retainedRootPath, removingPath, ownerPath].filter(
@@ -293,6 +299,7 @@ export function retireTaskArtifactOwner(
293
299
  ];
294
300
  let retainedRootPath: string | undefined;
295
301
  let retainedTreeSnapshot: NativeDirectoryTreeSnapshot | undefined;
302
+ let nativeTreeSnapshot: NativeDirectoryTreeSnapshot | undefined;
296
303
  for (const candidate of candidates) {
297
304
  let snapshot: NativeDirectoryTreeSnapshot | undefined;
298
305
  try {
@@ -312,12 +319,8 @@ export function retireTaskArtifactOwner(
312
319
  continuation: fallback,
313
320
  reason: "task_artifact_owner_writer_not_quiescent",
314
321
  };
315
- if (
316
- !snapshot ||
317
- snapshot.rootDev !== evidence.locator.directoryDev ||
318
- snapshot.rootIno !== evidence.locator.directoryIno ||
319
- !retainedTreeDoesNotExpandAuthority(baseline, snapshot)
320
- )
322
+ const normalized = snapshot && normalizeRetainedTreeSnapshot(evidence.treeSnapshot, snapshot);
323
+ if (!snapshot || !normalized || !baseline || !retainedTreeDoesNotExpandAuthority(baseline, normalized))
321
324
  continue;
322
325
  if (candidate === ownerPath && JSON.stringify(snapshot) === JSON.stringify(evidence.treeSnapshot)) {
323
326
  try {
@@ -340,9 +343,10 @@ export function retireTaskArtifactOwner(
340
343
  }
341
344
  retainedRootPath = candidate;
342
345
  retainedTreeSnapshot = snapshot;
346
+ nativeTreeSnapshot = normalized;
343
347
  break;
344
348
  }
345
- if (!retainedRootPath || !retainedTreeSnapshot)
349
+ if (!retainedRootPath || !retainedTreeSnapshot || !nativeTreeSnapshot)
346
350
  return {
347
351
  kind: "uncertain",
348
352
  evidence,
@@ -354,7 +358,7 @@ export function retireTaskArtifactOwner(
354
358
  try {
355
359
  nativeOutcome = rootStore.removeTreeExpectedWithParentIdentity(
356
360
  path.relative(context.sessionsRoot, retainedRootPath).split(path.sep).join("/"),
357
- retainedTreeSnapshot,
361
+ nativeTreeSnapshot,
358
362
  { dev: BigInt(evidence.parentIdentity.dev), ino: BigInt(evidence.parentIdentity.ino) },
359
363
  );
360
364
  } catch {
@@ -391,13 +395,11 @@ export function retireTaskArtifactOwner(
391
395
  let residualValid = reportedRootKnown;
392
396
  try {
393
397
  residualTree = captureOwnerTreeIfPresent(context, rootStore, evidence.locator.ownerId, nextRoot);
394
- if (
395
- residualTree &&
396
- (residualTree.rootDev !== evidence.locator.directoryDev ||
397
- residualTree.rootIno !== evidence.locator.directoryIno ||
398
- !retainedTreeDoesNotExpandAuthority(retainedTreeSnapshot, residualTree))
399
- )
400
- residualValid = false;
398
+ if (residualTree) {
399
+ const normalizedResidual = normalizeRetainedTreeSnapshot(evidence.treeSnapshot, residualTree);
400
+ if (!normalizedResidual || !retainedTreeDoesNotExpandAuthority(nativeTreeSnapshot, normalizedResidual))
401
+ residualValid = false;
402
+ }
401
403
  } catch {
402
404
  residualValid = false;
403
405
  }
@@ -36,7 +36,11 @@ export const CREDENTIAL_AUTO_IMPORT_RETRY_WARNING =
36
36
  export const CREDENTIAL_AUTO_IMPORT_STATE_UNREADABLE_WARNING =
37
37
  "Credential import preference could not be read. External credential discovery was skipped; use /provider to import credentials manually.";
38
38
 
39
- export type CredentialAutoImportSourceLabel = "claude-code-file" | "claude-code-keychain" | "codex-file";
39
+ export type CredentialAutoImportSourceLabel =
40
+ | "claude-code-file"
41
+ | "claude-code-keychain"
42
+ | "codex-file"
43
+ | "kiro-cli-social";
40
44
  export type CredentialAutoImportTrigger = "startup" | "bare-login" | "setup-cli";
41
45
  export type InitialImportResolution = "accepted" | "declined";
42
46
  export type CredentialAutoImportStateProblem =
@@ -259,16 +263,18 @@ export interface CredentialAutoImportResult {
259
263
  globalDiscoveryFailure?: CredentialAutoImportFailure;
260
264
  }
261
265
 
262
- const CREDENTIAL_AUTO_IMPORT_PROMPT_PROVIDERS: readonly ExternalProvider[] = ["anthropic", "openai-codex"];
266
+ const CREDENTIAL_AUTO_IMPORT_PROMPT_PROVIDERS: readonly ExternalProvider[] = ["anthropic", "openai-codex", "kiro"];
263
267
  const CREDENTIAL_AUTO_IMPORT_PROMPT_ORIGINS: readonly CredentialOrigin[] = [
264
268
  "claude-code-file",
265
269
  "claude-code-keychain",
266
270
  "codex-file",
271
+ "kiro-cli-social",
267
272
  ];
268
273
  const CREDENTIAL_AUTO_IMPORT_ORIGIN_LABELS: Record<CredentialOrigin, string> = {
269
274
  "claude-code-file": "Claude Code file",
270
275
  "claude-code-keychain": "Claude Code Keychain",
271
276
  "codex-file": "Codex CLI file",
277
+ "kiro-cli-social": "Kiro CLI social login",
272
278
  };
273
279
  const CREDENTIAL_AUTO_IMPORT_FAILURE_CLASSES = new Set(Object.values(CredentialAutoImportFailureClass));
274
280
 
@@ -413,7 +419,10 @@ export function buildCredentialAutoImportNotice(
413
419
  ...new Set(result.imported.map(c => EXTERNAL_PROVIDER_LABELS[c.provider as ExternalProvider] ?? c.provider)),
414
420
  ];
415
421
  const success = `Imported ${result.imported.length} external OAuth credential(s) into gjc: ${providers.join(", ")}.`;
416
- return `${success}\n${CREDENTIAL_AUTO_IMPORT_ROTATION_WARNING}`;
422
+ const mayRotateExternalRefreshToken = result.imported.some(
423
+ credential => credential.provider === "anthropic" || credential.provider === "openai-codex",
424
+ );
425
+ return mayRotateExternalRefreshToken ? `${success}\n${CREDENTIAL_AUTO_IMPORT_ROTATION_WARNING}` : success;
417
426
  }
418
427
 
419
428
  export function formatCredentialAutoImportResult(result: CredentialAutoImportResult): string[] {
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Discover and import existing Claude Code / Codex CLI credentials.
2
+ * Discover and import existing Claude Code, Codex CLI, and Kiro CLI credentials.
3
3
  *
4
4
  * This is the testable core behind `gjc setup credentials` (CLI, primary entry)
5
5
  * and the TUI provider-onboarding "import existing credentials" action. It never
@@ -12,7 +12,10 @@
12
12
  * Keychain (`Claude Code-credentials`), and env vars.
13
13
  * - Codex CLI: `$CODEX_HOME/auth.json` (defaults to `~/.codex/auth.json`;
14
14
  * OAuth `tokens` block or stored `OPENAI_API_KEY`), and env vars.
15
+ * - Kiro CLI social OAuth: `data.sqlite3` in the platform's app-data directory,
16
+ * read-only from `auth_kv` key `kirocli:social:token`.
15
17
  */
18
+ import { Database } from "bun:sqlite";
16
19
  import * as fs from "node:fs/promises";
17
20
  import * as os from "node:os";
18
21
  import * as path from "node:path";
@@ -21,20 +24,22 @@ import { $credentialEnv, isEnoent } from "@gajae-code/utils";
21
24
  import { redactSecret } from "./provider-onboarding";
22
25
 
23
26
  /** gjc provider ids that external credentials map onto. */
24
- export type ExternalProvider = "anthropic" | "openai-codex";
27
+ export type ExternalProvider = "anthropic" | "openai-codex" | "kiro";
25
28
 
26
29
  /** Where a discovered credential came from. */
27
- export type CredentialOrigin = "claude-code-file" | "claude-code-keychain" | "codex-file";
30
+ export type CredentialOrigin = "claude-code-file" | "claude-code-keychain" | "codex-file" | "kiro-cli-social";
28
31
 
29
32
  export const AUTO_IMPORT_OAUTH_PROVIDER_ORIGINS: Record<ExternalProvider, ReadonlySet<CredentialOrigin>> = {
30
33
  anthropic: new Set<CredentialOrigin>(["claude-code-file", "claude-code-keychain"]),
31
34
  "openai-codex": new Set<CredentialOrigin>(["codex-file"]),
35
+ kiro: new Set<CredentialOrigin>(["kiro-cli-social"]),
32
36
  };
33
37
 
34
38
  /** Human labels for providers, used in redacted summaries. */
35
39
  export const EXTERNAL_PROVIDER_LABELS: Record<ExternalProvider, string> = {
36
40
  anthropic: "Claude (Anthropic)",
37
41
  "openai-codex": "Codex (ChatGPT)",
42
+ kiro: "Kiro",
38
43
  };
39
44
 
40
45
  /** A credential that can be safely imported into gjc's store. */
@@ -98,6 +103,8 @@ export interface DiscoveryOptions {
98
103
  * or `null` when no entry exists.
99
104
  */
100
105
  readClaudeKeychain?: () => Promise<string | null>;
106
+ /** Absolute Kiro CLI data.sqlite3 override, primarily for tests and embedders. */
107
+ kiroCliDatabasePath?: string;
101
108
  }
102
109
 
103
110
  export type CredentialUpserter = (provider: string, credential: AuthCredential) => unknown | Promise<unknown>;
@@ -131,6 +138,7 @@ interface CodexAuthFile {
131
138
 
132
139
  const ANTHROPIC_ENV_KEYS = ["ANTHROPIC_API_KEY", "CLAUDE_CODE_OAUTH_TOKEN"] as const;
133
140
  const OPENAI_ENV_KEYS = ["OPENAI_API_KEY"] as const;
141
+ const KIRO_CLI_SOCIAL_TOKEN_KEY = "kirocli:social:token";
134
142
 
135
143
  // ─── JWT helpers (best-effort identity/expiry extraction) ────────────────────
136
144
 
@@ -368,6 +376,154 @@ async function discoverCodex(home: ResolvedExternalDir, result: CredentialDiscov
368
376
  pushOutcome(result, parseCodexAuth(raw, `Codex CLI (${displayPath})`));
369
377
  }
370
378
 
379
+ interface KiroCliSocialToken {
380
+ access_token?: unknown;
381
+ refresh_token?: unknown;
382
+ expires_at?: unknown;
383
+ profile_arn?: unknown;
384
+ provider?: unknown;
385
+ }
386
+
387
+ function parseKiroCliExpiry(value: unknown): number | undefined {
388
+ if (typeof value === "number" && Number.isFinite(value)) {
389
+ if (value > 1_000_000_000_000) return value;
390
+ if (value > 1_000_000_000) return value * 1000;
391
+ return undefined;
392
+ }
393
+ if (typeof value !== "string" || value.trim().length === 0) return undefined;
394
+ const numericValue = Number(value);
395
+ if (Number.isFinite(numericValue)) return parseKiroCliExpiry(numericValue);
396
+ const parsed = Date.parse(value);
397
+ return Number.isFinite(parsed) ? parsed : undefined;
398
+ }
399
+
400
+ function parseKiroCliSocialToken(raw: string, source: string): ImportableCredential | SkippedCredential {
401
+ let parsed: unknown;
402
+ try {
403
+ parsed = JSON.parse(raw) as KiroCliSocialToken;
404
+ } catch (err) {
405
+ return { origin: "kiro-cli-social", source, reason: sanitizedFailureReason("malformed credential file", err) };
406
+ }
407
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
408
+ return { origin: "kiro-cli-social", source, reason: "unsupported token shape (root is not an object)" };
409
+ }
410
+ const token = parsed as KiroCliSocialToken;
411
+ const access = nonEmptyString(token.access_token);
412
+ const refresh = nonEmptyString(token.refresh_token);
413
+ const profileArn = nonEmptyString(token.profile_arn);
414
+ const provider = nonEmptyString(token.provider);
415
+ if (!access || !refresh || !profileArn || !provider) {
416
+ return { origin: "kiro-cli-social", source, reason: "incomplete Kiro social OAuth token metadata" };
417
+ }
418
+ const expiresAt = parseKiroCliExpiry(token.expires_at);
419
+ const credential: OAuthCredential = {
420
+ type: "oauth",
421
+ access,
422
+ refresh,
423
+ expires: expiresAt ?? Date.now(),
424
+ profileArn,
425
+ };
426
+ return {
427
+ provider: "kiro",
428
+ origin: "kiro-cli-social",
429
+ source,
430
+ kind: "oauth",
431
+ ...(expiresAt === undefined ? {} : { expiresAt }),
432
+ redactedToken: redactSecret(access),
433
+ credential,
434
+ };
435
+ }
436
+
437
+ function resolveKiroCliDatabasePath(
438
+ homeDir: string,
439
+ platform: NodeJS.Platform,
440
+ env: Record<string, string | undefined>,
441
+ ): string {
442
+ if (platform === "darwin") {
443
+ return path.join(homeDir, "Library", "Application Support", "kiro-cli", "data.sqlite3");
444
+ }
445
+ if (platform === "win32") {
446
+ const localAppData = nonEmptyString(env.LOCALAPPDATA);
447
+ const dataDir =
448
+ localAppData && path.isAbsolute(localAppData) ? localAppData : path.join(homeDir, "AppData", "Local");
449
+ return path.join(dataDir, "kiro-cli", "data.sqlite3");
450
+ }
451
+ const xdgDataHome = nonEmptyString(env.XDG_DATA_HOME);
452
+ const dataDir = xdgDataHome && path.isAbsolute(xdgDataHome) ? xdgDataHome : path.join(homeDir, ".local", "share");
453
+ return path.join(dataDir, "kiro-cli", "data.sqlite3");
454
+ }
455
+
456
+ async function discoverKiroCliSocialCredential(
457
+ homeDir: string,
458
+ platform: NodeJS.Platform,
459
+ pathEnv: Record<string, string | undefined>,
460
+ databasePathOverride: string | undefined,
461
+ result: CredentialDiscoveryResult,
462
+ ): Promise<void> {
463
+ const source = "Kiro CLI (social login)";
464
+ if (databasePathOverride && !path.isAbsolute(databasePathOverride)) {
465
+ result.skipped.push({ origin: "kiro-cli-social", source, reason: "Kiro CLI database path must be absolute" });
466
+ return;
467
+ }
468
+ const databasePath = databasePathOverride ?? resolveKiroCliDatabasePath(homeDir, platform, pathEnv);
469
+ let database: Database | undefined;
470
+ try {
471
+ const stat = await fs.stat(databasePath);
472
+ if (!stat.isFile()) {
473
+ result.skipped.push({ origin: "kiro-cli-social", source, reason: "Kiro CLI database is not a regular file" });
474
+ return;
475
+ }
476
+ } catch (err) {
477
+ if (!isEnoent(err)) {
478
+ result.skipped.push({
479
+ origin: "kiro-cli-social",
480
+ source,
481
+ reason: sanitizedFailureReason("unreadable credential file", err),
482
+ });
483
+ }
484
+ return;
485
+ }
486
+
487
+ try {
488
+ database = new Database(databasePath, { readonly: true, create: false, strict: true });
489
+ database.run("PRAGMA busy_timeout = 1000");
490
+ const authTable = database
491
+ .prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = ?")
492
+ .get("auth_kv");
493
+ if (!authTable) {
494
+ result.skipped.push({ origin: "kiro-cli-social", source, reason: "Kiro CLI database is missing auth_kv" });
495
+ return;
496
+ }
497
+ const row = database.prepare("SELECT value FROM auth_kv WHERE key = ?").get(KIRO_CLI_SOCIAL_TOKEN_KEY) as {
498
+ value?: unknown;
499
+ } | null;
500
+ if (!row) return;
501
+ const value =
502
+ typeof row.value === "string"
503
+ ? row.value
504
+ : row.value instanceof Uint8Array
505
+ ? new TextDecoder().decode(row.value)
506
+ : undefined;
507
+ if (value === undefined) {
508
+ result.skipped.push({
509
+ origin: "kiro-cli-social",
510
+ source,
511
+ reason: "Kiro CLI token value has an unsupported type",
512
+ });
513
+ return;
514
+ }
515
+ pushOutcome(result, parseKiroCliSocialToken(value, source));
516
+ } catch (err) {
517
+ result.skipped.push({
518
+ origin: "kiro-cli-social",
519
+ source,
520
+ reason: sanitizedFailureReason("unreadable credential file", err),
521
+ });
522
+ } finally {
523
+ database?.close();
524
+ }
525
+ }
526
+
371
527
  // ─── Environment hints ───────────────────────────────────────────────────────
372
528
 
373
529
  function discoverEnvironment(env: Record<string, string | undefined>, result: CredentialDiscoveryResult): void {
@@ -421,8 +577,8 @@ function resolveExternalDir(
421
577
  }
422
578
 
423
579
  /**
424
- * Discover Claude Code and Codex CLI credentials across files, the macOS
425
- * Keychain, and environment variables. Never throws for individual unreadable or
580
+ * Discover Claude Code, Codex CLI, and Kiro CLI credentials across their local
581
+ * stores and environment variables. Never throws for individual unreadable or
426
582
  * malformed sources — those land in {@link CredentialDiscoveryResult.skipped}.
427
583
  */
428
584
  export async function discoverExternalCredentials(options: DiscoveryOptions = {}): Promise<CredentialDiscoveryResult> {
@@ -436,11 +592,16 @@ export async function discoverExternalCredentials(options: DiscoveryOptions = {}
436
592
  ? { dir: options.codexHome, display: "$CODEX_HOME" }
437
593
  : resolveExternalDir("CODEX_HOME", options.env, path.join(homeDir, ".codex"), "~/.codex");
438
594
  const result: CredentialDiscoveryResult = { importable: [], skipped: [], environment: [] };
595
+ const kiroPathEnv = options.env ?? {
596
+ LOCALAPPDATA: $credentialEnv("LOCALAPPDATA"),
597
+ XDG_DATA_HOME: $credentialEnv("XDG_DATA_HOME"),
598
+ };
439
599
  await discoverClaudeCode(
440
600
  { configDir: claudeConfigDir, platform, readClaudeKeychain: options.readClaudeKeychain },
441
601
  result,
442
602
  );
443
603
  await discoverCodex(codexHome, result);
604
+ await discoverKiroCliSocialCredential(homeDir, platform, kiroPathEnv, options.kiroCliDatabasePath, result);
444
605
  discoverEnvironment(env, result);
445
606
  return result;
446
607
  }
@@ -487,6 +648,16 @@ function hasAutoImportOAuthProviderOrigin(credential: ImportableCredential): boo
487
648
  }
488
649
 
489
650
  export function isAutoImportOAuthCredential(credential: ImportableCredential, now: number = Date.now()): boolean {
651
+ const refreshableKiroSocialCredential =
652
+ credential.provider === "kiro" &&
653
+ credential.origin === "kiro-cli-social" &&
654
+ credential.kind === "oauth" &&
655
+ credential.credential.type === "oauth" &&
656
+ credential.credential.access.length > 0 &&
657
+ credential.credential.refresh.length > 0 &&
658
+ typeof credential.credential.profileArn === "string" &&
659
+ credential.credential.profileArn.length > 0;
660
+ if (refreshableKiroSocialCredential) return true;
490
661
  return (
491
662
  hasAutoImportOAuthProviderOrigin(credential) &&
492
663
  typeof credential.expiresAt === "number" &&
@@ -152,7 +152,12 @@ export function parseDaemonListen(raw: string): PaseoDaemonTarget | undefined {
152
152
  const withoutQuery = authority.split("?")[0] ?? "";
153
153
  const separator = withoutQuery.lastIndexOf(":");
154
154
  if (separator <= 0) return undefined;
155
- const port = Number(withoutQuery.slice(separator + 1));
155
+ // Digits only, like the bare-port branch above: `Number()` also accepts hex
156
+ // (`0x1A0B`), exponents (`1e3`), decimals and padding, which would probe a
157
+ // different port than the raw spelling handed to `paseo import`.
158
+ const portText = withoutQuery.slice(separator + 1);
159
+ if (!/^\d+$/.test(portText)) return undefined;
160
+ const port = Number(portText);
156
161
  if (!Number.isSafeInteger(port) || port < 1 || port > 65_535) return undefined;
157
162
  const host = withoutQuery.slice(0, separator).replace(/^\[|]$/g, "");
158
163
  return host ? { kind: "tcp", host, port } : undefined;