@gajae-code/coding-agent 0.17.2 → 0.17.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (390) hide show
  1. package/CHANGELOG.md +267 -0
  2. package/dist/types/cli/daemon-cli.d.ts +3 -1
  3. package/dist/types/cli/github-release.d.ts +17 -0
  4. package/dist/types/cli/public-command-entry.d.ts +56 -0
  5. package/dist/types/cli/public-command-errors.d.ts +126 -0
  6. package/dist/types/cli/public-command-evidence.d.ts +99 -0
  7. package/dist/types/cli/public-command-help.d.ts +65 -0
  8. package/dist/types/cli/public-command-registry.d.ts +69 -0
  9. package/dist/types/cli/session-picker.d.ts +1 -1
  10. package/dist/types/cli/setup-cli.d.ts +1 -0
  11. package/dist/types/cli/skills-cli.d.ts +5 -0
  12. package/dist/types/cli.d.ts +3 -0
  13. package/dist/types/commands/daemon.d.ts +4 -50
  14. package/dist/types/commands/sdk.d.ts +20 -37
  15. package/dist/types/commands/setup.d.ts +3 -0
  16. package/dist/types/commands/skills.d.ts +9 -0
  17. package/dist/types/config/autorouting-tier-map.d.ts +1049 -3
  18. package/dist/types/config/file-lock.d.ts +13 -3
  19. package/dist/types/config/model-profile-activation.d.ts +45 -1
  20. package/dist/types/config/model-registry.d.ts +14 -3
  21. package/dist/types/config/model-resolver.d.ts +1 -1
  22. package/dist/types/config/settings-schema.d.ts +11 -0
  23. package/dist/types/coordinator-mcp/question-state.d.ts +6 -1
  24. package/dist/types/daemon/operator-contract.d.ts +5 -1
  25. package/dist/types/eval/js/worker-protocol.d.ts +2 -0
  26. package/dist/types/exec/bash-executor.d.ts +2 -0
  27. package/dist/types/extensibility/extensions/types.d.ts +12 -0
  28. package/dist/types/extensibility/gjc-plugins/registry.d.ts +4 -0
  29. package/dist/types/extensibility/gjc-plugins/runtime-adapters.d.ts +11 -2
  30. package/dist/types/extensibility/runtime-skill-discovery.d.ts +18 -0
  31. package/dist/types/extensibility/shared-events.d.ts +3 -1
  32. package/dist/types/gjc-runtime/session-state-lock.d.ts +61 -0
  33. package/dist/types/gjc-runtime/state-writer.d.ts +14 -1
  34. package/dist/types/harness-control-plane/control-endpoint.d.ts +4 -1
  35. package/dist/types/harness-control-plane/finalize.d.ts +14 -3
  36. package/dist/types/internal-urls/embedded-protocol.d.ts +9 -0
  37. package/dist/types/internal-urls/index.d.ts +1 -0
  38. package/dist/types/internal-urls/parse.d.ts +9 -1
  39. package/dist/types/main.d.ts +23 -1
  40. package/dist/types/modes/acp/acp-agent.d.ts +55 -1
  41. package/dist/types/modes/acp/startup-provenance.d.ts +16 -0
  42. package/dist/types/modes/components/custom-provider-wizard.d.ts +19 -1
  43. package/dist/types/modes/components/session-selector.d.ts +5 -2
  44. package/dist/types/modes/components/user-message-selector.d.ts +5 -2
  45. package/dist/types/modes/controllers/command-controller.d.ts +1 -1
  46. package/dist/types/modes/controllers/selector-controller.d.ts +1 -1
  47. package/dist/types/modes/interactive-mode.d.ts +1 -1
  48. package/dist/types/modes/shared/agent-wire/workflow-gate-broker.d.ts +11 -1
  49. package/dist/types/modes/shared/agent-wire/workflow-gate-types.d.ts +14 -1
  50. package/dist/types/modes/types.d.ts +2 -2
  51. package/dist/types/runtime/process-lifecycle.d.ts +2 -0
  52. package/dist/types/runtime-mcp/loader.d.ts +2 -0
  53. package/dist/types/runtime-mcp/manager.d.ts +69 -6
  54. package/dist/types/runtime-mcp/pool.d.ts +17 -0
  55. package/dist/types/runtime-mcp/redaction.d.ts +20 -0
  56. package/dist/types/runtime-mcp/startup-policy.d.ts +6 -0
  57. package/dist/types/runtime-mcp/tool-bridge.d.ts +9 -0
  58. package/dist/types/runtime-mcp/transports/http.d.ts +11 -0
  59. package/dist/types/sdk/broker/broker.d.ts +17 -4
  60. package/dist/types/sdk/broker/ensure.d.ts +3 -0
  61. package/dist/types/sdk/broker/identity.d.ts +5 -1
  62. package/dist/types/sdk/broker/lifecycle-ledger.d.ts +23 -3
  63. package/dist/types/sdk/broker/lifecycle.d.ts +15 -8
  64. package/dist/types/sdk/broker/managed-task-dag.d.ts +1335 -0
  65. package/dist/types/sdk/broker/managed-task-verification.d.ts +37 -0
  66. package/dist/types/sdk/broker/runtime.d.ts +1 -1
  67. package/dist/types/sdk/broker/session-index.d.ts +22 -3
  68. package/dist/types/sdk/broker/spawn-authority.d.ts +12 -0
  69. package/dist/types/sdk/broker/startup-failure.d.ts +4 -0
  70. package/dist/types/sdk/broker/stderr-drainer.d.ts +13 -0
  71. package/dist/types/sdk/bus/index.d.ts +19 -0
  72. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +7 -1
  73. package/dist/types/sdk/bus/telegram-daemon.d.ts +5 -0
  74. package/dist/types/sdk/cli/master-cli.d.ts +6 -10
  75. package/dist/types/sdk/cli/rows.d.ts +19 -1
  76. package/dist/types/sdk/cli/session-cli.d.ts +22 -5
  77. package/dist/types/sdk/client/client.d.ts +2 -0
  78. package/dist/types/sdk/guides/cli.d.ts +3 -4
  79. package/dist/types/sdk/guides/verify.d.ts +2 -0
  80. package/dist/types/sdk/host/host.d.ts +9 -0
  81. package/dist/types/sdk/host/session-runtime.d.ts +31 -0
  82. package/dist/types/sdk/host/types.d.ts +10 -0
  83. package/dist/types/sdk/index.d.ts +1 -0
  84. package/dist/types/sdk/prompt-deadline-flush.d.ts +85 -0
  85. package/dist/types/sdk/prompt-deadline-manager.d.ts +37 -0
  86. package/dist/types/sdk/prompt-tool-boundary.d.ts +73 -0
  87. package/dist/types/sdk/router/session-router.d.ts +2 -0
  88. package/dist/types/sdk/session.d.ts +3 -3
  89. package/dist/types/sdk/startup-capability.d.ts +2 -0
  90. package/dist/types/sdk/transport/relay.d.ts +1 -0
  91. package/dist/types/sdk/transport/serve-cli.d.ts +48 -4
  92. package/dist/types/sdk/transport/stdio.d.ts +5 -1
  93. package/dist/types/session/agent-session.d.ts +175 -23
  94. package/dist/types/session/fallback-chain-controller.d.ts +6 -6
  95. package/dist/types/session/fold-coordinator.d.ts +17 -3
  96. package/dist/types/session/internal/managed-session-storage.d.ts +7 -1
  97. package/dist/types/session/session-manager.d.ts +64 -1
  98. package/dist/types/session/session-work-lease.d.ts +14 -0
  99. package/dist/types/setup/model-onboarding-guidance.d.ts +1 -1
  100. package/dist/types/setup/provider-onboarding.d.ts +81 -1
  101. package/dist/types/task/types.d.ts +2 -0
  102. package/dist/types/tools/bash-interactive.d.ts +1 -0
  103. package/dist/types/tools/bash.d.ts +37 -11
  104. package/dist/types/tools/fetch.d.ts +10 -1
  105. package/dist/types/tools/job.d.ts +1 -1
  106. package/dist/types/tools/steer-fold.d.ts +31 -0
  107. package/dist/types/tools/subagent.d.ts +8 -1
  108. package/dist/types/utils/git.d.ts +28 -2
  109. package/dist/types/utils/mupdf-embedded.d.ts +2 -0
  110. package/dist/types/utils/mupdf.d.ts +4 -0
  111. package/dist/types/utils/session-title-generation.d.ts +6 -0
  112. package/dist/types/utils/title-generator.d.ts +11 -2
  113. package/dist/types/web/scrapers/types.d.ts +3 -0
  114. package/package.json +18 -10
  115. package/scripts/build-binary.ts +9 -3
  116. package/scripts/compile-args.ts +0 -9
  117. package/scripts/embed-mupdf.ts +52 -0
  118. package/scripts/generate-sdk-operation-inventory.ts +31 -1
  119. package/scripts/vendor-markit.ts +196 -0
  120. package/src/async/job-manager.ts +22 -1
  121. package/src/cli/daemon-cli.ts +53 -18
  122. package/src/cli/github-release.ts +87 -5
  123. package/src/cli/mcp-cli.ts +38 -4
  124. package/src/cli/public-command-entry.ts +450 -0
  125. package/src/cli/public-command-errors.ts +581 -0
  126. package/src/cli/public-command-evidence.ts +717 -0
  127. package/src/cli/public-command-help.ts +360 -0
  128. package/src/cli/public-command-registry.ts +541 -0
  129. package/src/cli/session-picker.ts +2 -1
  130. package/src/cli/setup-cli.ts +10 -1
  131. package/src/cli/skills-cli.ts +46 -2
  132. package/src/cli/stats-cli.ts +11 -1
  133. package/src/cli.ts +61 -1
  134. package/src/commands/daemon.ts +65 -69
  135. package/src/commands/sdk.ts +175 -117
  136. package/src/commands/setup.ts +2 -0
  137. package/src/commands/skills.ts +11 -0
  138. package/src/config/autorouting-tier-map.ts +543 -3
  139. package/src/config/file-lock.ts +206 -65
  140. package/src/config/model-discovery-manager.ts +4 -4
  141. package/src/config/model-profile-activation.ts +417 -66
  142. package/src/config/model-registry.ts +254 -36
  143. package/src/config/model-resolver.ts +6 -1
  144. package/src/config/settings-schema.ts +26 -2
  145. package/src/coordinator-mcp/policy.ts +10 -5
  146. package/src/coordinator-mcp/question-gate-codec.ts +17 -0
  147. package/src/coordinator-mcp/question-state.ts +179 -9
  148. package/src/coordinator-mcp/server.ts +521 -87
  149. package/src/coordinator-mcp/session-reaper.ts +6 -4
  150. package/src/crash/record-loader.ts +6 -2
  151. package/src/daemon/operator-contract.ts +26 -12
  152. package/src/defaults/gjc/skills/ultragoal/SKILL.md +1 -1
  153. package/src/eval/js/context-manager.ts +8 -8
  154. package/src/eval/js/worker-core.ts +9 -4
  155. package/src/eval/js/worker-protocol.ts +2 -0
  156. package/src/exec/bash-executor.ts +3 -0
  157. package/src/extensibility/extensions/runner.ts +52 -4
  158. package/src/extensibility/extensions/types.ts +10 -0
  159. package/src/extensibility/gjc-plugins/registry.ts +196 -37
  160. package/src/extensibility/gjc-plugins/runtime-adapters.ts +46 -8
  161. package/src/extensibility/runtime-skill-discovery.ts +61 -3
  162. package/src/extensibility/shared-events.ts +3 -1
  163. package/src/gjc-runtime/session-state-lock.ts +165 -24
  164. package/src/gjc-runtime/state-writer.ts +317 -6
  165. package/src/gjc-runtime/ultragoal-succession.ts +31 -3
  166. package/src/harness-control-plane/control-endpoint.ts +24 -6
  167. package/src/harness-control-plane/finalize.ts +312 -25
  168. package/src/harness-control-plane/owner.ts +323 -89
  169. package/src/internal-urls/docs-index.generated.ts +23 -20
  170. package/src/internal-urls/embedded-protocol.ts +83 -0
  171. package/src/internal-urls/index.ts +1 -0
  172. package/src/internal-urls/parse.ts +21 -1
  173. package/src/internal-urls/router.ts +4 -2
  174. package/src/main.ts +192 -74
  175. package/src/modes/acp/acp-agent.ts +973 -56
  176. package/src/modes/acp/startup-provenance.ts +59 -0
  177. package/src/modes/components/custom-provider-wizard.ts +308 -7
  178. package/src/modes/components/gjc-bundle-settings.ts +21 -1
  179. package/src/modes/components/oauth-selector.ts +9 -0
  180. package/src/modes/components/session-selector.ts +47 -4
  181. package/src/modes/components/tool-status-header.ts +72 -6
  182. package/src/modes/components/user-message-selector.ts +57 -15
  183. package/src/modes/controllers/command-controller.ts +58 -32
  184. package/src/modes/controllers/extension-ui-controller.ts +33 -7
  185. package/src/modes/controllers/input-controller.ts +4 -0
  186. package/src/modes/controllers/runtime-mcp-command-controller.ts +1 -1
  187. package/src/modes/controllers/selector-controller.ts +161 -15
  188. package/src/modes/interactive-mode.ts +21 -7
  189. package/src/modes/runtime-init.ts +1 -0
  190. package/src/modes/shared/agent-wire/workflow-gate-broker.ts +124 -7
  191. package/src/modes/shared/agent-wire/workflow-gate-types.ts +16 -2
  192. package/src/modes/types.ts +2 -2
  193. package/src/prompts/agent-fragments/browser-aside.md +1 -0
  194. package/src/prompts/system/title-system.md +1 -1
  195. package/src/prompts/tools/bash.md +1 -1
  196. package/src/prompts/tools/job.md +1 -1
  197. package/src/prompts/tools/read.md +2 -0
  198. package/src/runtime/network-prewarm-service.test.ts +36 -1
  199. package/src/runtime/network-prewarm-service.ts +28 -3
  200. package/src/runtime/process-lifecycle.ts +22 -11
  201. package/src/runtime-mcp/config.ts +16 -1
  202. package/src/runtime-mcp/loader.ts +6 -3
  203. package/src/runtime-mcp/manager.ts +845 -109
  204. package/src/runtime-mcp/pool.test.ts +31 -0
  205. package/src/runtime-mcp/pool.ts +304 -28
  206. package/src/runtime-mcp/redaction.ts +42 -0
  207. package/src/runtime-mcp/startup-policy.ts +7 -0
  208. package/src/runtime-mcp/tool-bridge.ts +71 -0
  209. package/src/runtime-mcp/transports/http.ts +108 -25
  210. package/src/sdk/acp/adapter.ts +27 -8
  211. package/src/sdk/broker/broker.ts +1431 -198
  212. package/src/sdk/broker/ensure.ts +21 -3
  213. package/src/sdk/broker/identity.ts +22 -1
  214. package/src/sdk/broker/lifecycle-ledger.ts +95 -31
  215. package/src/sdk/broker/lifecycle.ts +690 -141
  216. package/src/sdk/broker/managed-task-dag.ts +1927 -0
  217. package/src/sdk/broker/managed-task-verification.ts +642 -0
  218. package/src/sdk/broker/runtime.ts +1 -1
  219. package/src/sdk/broker/session-index.ts +97 -4
  220. package/src/sdk/broker/spawn-authority.ts +175 -14
  221. package/src/sdk/broker/startup-failure.ts +80 -1
  222. package/src/sdk/broker/stderr-drainer.ts +59 -0
  223. package/src/sdk/broker/transport.ts +1 -0
  224. package/src/sdk/bus/chat-daemon-control.ts +2 -2
  225. package/src/sdk/bus/chat-daemon-runtime.ts +1 -0
  226. package/src/sdk/bus/index.ts +707 -81
  227. package/src/sdk/bus/telegram-daemon-cli.ts +31 -2
  228. package/src/sdk/bus/telegram-daemon-contract.ts +7 -1
  229. package/src/sdk/bus/telegram-daemon.ts +10 -3
  230. package/src/sdk/cli/master-cli.ts +47 -36
  231. package/src/sdk/cli/rows.ts +30 -7
  232. package/src/sdk/cli/session-cli.ts +705 -184
  233. package/src/sdk/client/client.ts +18 -0
  234. package/src/sdk/guides/catalog.ts +2 -2
  235. package/src/sdk/guides/cli.ts +20 -62
  236. package/src/sdk/guides/verify.ts +14 -0
  237. package/src/sdk/host/host.ts +49 -5
  238. package/src/sdk/host/session-runtime.test.ts +184 -2
  239. package/src/sdk/host/session-runtime.ts +322 -101
  240. package/src/sdk/host/types.ts +12 -1
  241. package/src/sdk/host/websocket-transport.lifecycle.test.ts +84 -0
  242. package/src/sdk/host/websocket-transport.ts +40 -6
  243. package/src/sdk/index.ts +11 -0
  244. package/src/sdk/lifecycle/service.ts +2 -0
  245. package/src/sdk/prompt-deadline-flush.ts +356 -0
  246. package/src/sdk/prompt-deadline-manager.ts +133 -1
  247. package/src/sdk/prompt-tool-boundary.ts +121 -0
  248. package/src/sdk/protocol/operation-inventory.generated.json +106 -0
  249. package/src/sdk/router/session-router.ts +9 -1
  250. package/src/sdk/session.ts +763 -116
  251. package/src/sdk/startup-capability.ts +1 -1
  252. package/src/sdk/transport/relay.ts +71 -6
  253. package/src/sdk/transport/serve-cli.ts +397 -42
  254. package/src/sdk/transport/socket.ts +12 -11
  255. package/src/sdk/transport/stdio.ts +7 -3
  256. package/src/session/agent-session.ts +2472 -407
  257. package/src/session/fallback-chain-controller.ts +6 -7
  258. package/src/session/fold-coordinator.ts +24 -5
  259. package/src/session/internal/managed-session-scope.ts +68 -18
  260. package/src/session/internal/managed-session-storage.ts +334 -12
  261. package/src/session/session-manager.ts +382 -44
  262. package/src/session/session-work-lease.ts +34 -0
  263. package/src/setup/model-onboarding-guidance.ts +1 -1
  264. package/src/setup/provider-onboarding.ts +397 -24
  265. package/src/setup/provider-presets.json +2 -1
  266. package/src/slash-commands/builtin-registry.ts +259 -15
  267. package/src/task/executor.ts +46 -17
  268. package/src/task/index.ts +14 -2
  269. package/src/task/types.ts +2 -0
  270. package/src/tools/bash-interactive.ts +2 -0
  271. package/src/tools/bash.ts +118 -78
  272. package/src/tools/fetch.ts +140 -25
  273. package/src/tools/job.ts +151 -25
  274. package/src/tools/output-meta.ts +15 -2
  275. package/src/tools/path-utils.ts +27 -3
  276. package/src/tools/read.ts +3 -3
  277. package/src/tools/steer-fold.ts +107 -0
  278. package/src/tools/subagent-render.ts +24 -1
  279. package/src/tools/subagent.ts +27 -1
  280. package/src/tools/tool-catalog.generated.ts +29 -2
  281. package/src/tools/tool-errors.ts +4 -0
  282. package/src/utils/git.ts +53 -3
  283. package/src/utils/markit.ts +55 -41
  284. package/src/utils/mupdf-assets.d.ts +4 -0
  285. package/src/utils/mupdf-embedded.ts +4 -0
  286. package/src/utils/mupdf.ts +136 -0
  287. package/src/utils/session-title-generation.ts +29 -0
  288. package/src/utils/title-generator.ts +46 -2
  289. package/src/web/scrapers/types.ts +24 -3
  290. package/vendor/markit-ai/LICENSE +21 -0
  291. package/vendor/markit-ai/MANIFEST.json +412 -0
  292. package/vendor/markit-ai/dist/commands/config.d.ts +4 -0
  293. package/vendor/markit-ai/dist/commands/config.js +139 -0
  294. package/vendor/markit-ai/dist/commands/convert.d.ts +6 -0
  295. package/vendor/markit-ai/dist/commands/convert.js +113 -0
  296. package/vendor/markit-ai/dist/commands/formats.d.ts +2 -0
  297. package/vendor/markit-ai/dist/commands/formats.js +92 -0
  298. package/vendor/markit-ai/dist/commands/init.d.ts +2 -0
  299. package/vendor/markit-ai/dist/commands/init.js +29 -0
  300. package/vendor/markit-ai/dist/commands/onboard.d.ts +2 -0
  301. package/vendor/markit-ai/dist/commands/onboard.js +61 -0
  302. package/vendor/markit-ai/dist/commands/plugin.d.ts +4 -0
  303. package/vendor/markit-ai/dist/commands/plugin.js +58 -0
  304. package/vendor/markit-ai/dist/config.d.ts +26 -0
  305. package/vendor/markit-ai/dist/config.js +42 -0
  306. package/vendor/markit-ai/dist/converters/audio.d.ts +7 -0
  307. package/vendor/markit-ai/dist/converters/audio.js +104 -0
  308. package/vendor/markit-ai/dist/converters/csv.d.ts +7 -0
  309. package/vendor/markit-ai/dist/converters/csv.js +83 -0
  310. package/vendor/markit-ai/dist/converters/docx.d.ts +6 -0
  311. package/vendor/markit-ai/dist/converters/docx.js +57 -0
  312. package/vendor/markit-ai/dist/converters/epub.d.ts +8 -0
  313. package/vendor/markit-ai/dist/converters/epub.js +128 -0
  314. package/vendor/markit-ai/dist/converters/github.d.ts +18 -0
  315. package/vendor/markit-ai/dist/converters/github.js +148 -0
  316. package/vendor/markit-ai/dist/converters/html.d.ts +6 -0
  317. package/vendor/markit-ai/dist/converters/html.js +30 -0
  318. package/vendor/markit-ai/dist/converters/image.d.ts +6 -0
  319. package/vendor/markit-ai/dist/converters/image.js +124 -0
  320. package/vendor/markit-ai/dist/converters/ipynb.d.ts +6 -0
  321. package/vendor/markit-ai/dist/converters/ipynb.js +75 -0
  322. package/vendor/markit-ai/dist/converters/iwork.d.ts +20 -0
  323. package/vendor/markit-ai/dist/converters/iwork.js +391 -0
  324. package/vendor/markit-ai/dist/converters/json.d.ts +6 -0
  325. package/vendor/markit-ai/dist/converters/json.js +21 -0
  326. package/vendor/markit-ai/dist/converters/pdf/columns.d.ts +35 -0
  327. package/vendor/markit-ai/dist/converters/pdf/columns.js +93 -0
  328. package/vendor/markit-ai/dist/converters/pdf/extract.d.ts +19 -0
  329. package/vendor/markit-ai/dist/converters/pdf/extract.js +514 -0
  330. package/vendor/markit-ai/dist/converters/pdf/grid.d.ts +25 -0
  331. package/vendor/markit-ai/dist/converters/pdf/grid.js +795 -0
  332. package/vendor/markit-ai/dist/converters/pdf/headers.d.ts +24 -0
  333. package/vendor/markit-ai/dist/converters/pdf/headers.js +108 -0
  334. package/vendor/markit-ai/dist/converters/pdf/index.d.ts +19 -0
  335. package/vendor/markit-ai/dist/converters/pdf/index.js +136 -0
  336. package/vendor/markit-ai/dist/converters/pdf/mupdf-loader.js +9 -0
  337. package/vendor/markit-ai/dist/converters/pdf/render.d.ts +24 -0
  338. package/vendor/markit-ai/dist/converters/pdf/render.js +513 -0
  339. package/vendor/markit-ai/dist/converters/pdf/types.d.ts +75 -0
  340. package/vendor/markit-ai/dist/converters/pdf/types.js +1 -0
  341. package/vendor/markit-ai/dist/converters/plain-text.d.ts +6 -0
  342. package/vendor/markit-ai/dist/converters/plain-text.js +87 -0
  343. package/vendor/markit-ai/dist/converters/pptx.d.ts +8 -0
  344. package/vendor/markit-ai/dist/converters/pptx.js +289 -0
  345. package/vendor/markit-ai/dist/converters/rss.d.ts +11 -0
  346. package/vendor/markit-ai/dist/converters/rss.js +138 -0
  347. package/vendor/markit-ai/dist/converters/wikipedia.d.ts +6 -0
  348. package/vendor/markit-ai/dist/converters/wikipedia.js +33 -0
  349. package/vendor/markit-ai/dist/converters/xlsx.d.ts +8 -0
  350. package/vendor/markit-ai/dist/converters/xlsx.js +147 -0
  351. package/vendor/markit-ai/dist/converters/xml.d.ts +6 -0
  352. package/vendor/markit-ai/dist/converters/xml.js +18 -0
  353. package/vendor/markit-ai/dist/converters/yaml.d.ts +6 -0
  354. package/vendor/markit-ai/dist/converters/yaml.js +17 -0
  355. package/vendor/markit-ai/dist/converters/zip.d.ts +8 -0
  356. package/vendor/markit-ai/dist/converters/zip.js +57 -0
  357. package/vendor/markit-ai/dist/index.d.ts +30 -0
  358. package/vendor/markit-ai/dist/index.js +26 -0
  359. package/vendor/markit-ai/dist/main.d.ts +2 -0
  360. package/vendor/markit-ai/dist/main.js +191 -0
  361. package/vendor/markit-ai/dist/markit.d.ts +45 -0
  362. package/vendor/markit-ai/dist/markit.js +267 -0
  363. package/vendor/markit-ai/dist/plugins/api.d.ts +7 -0
  364. package/vendor/markit-ai/dist/plugins/api.js +42 -0
  365. package/vendor/markit-ai/dist/plugins/index.d.ts +4 -0
  366. package/vendor/markit-ai/dist/plugins/index.js +3 -0
  367. package/vendor/markit-ai/dist/plugins/installer.d.ts +25 -0
  368. package/vendor/markit-ai/dist/plugins/installer.js +176 -0
  369. package/vendor/markit-ai/dist/plugins/loader.d.ts +6 -0
  370. package/vendor/markit-ai/dist/plugins/loader.js +61 -0
  371. package/vendor/markit-ai/dist/plugins/types.d.ts +25 -0
  372. package/vendor/markit-ai/dist/plugins/types.js +1 -0
  373. package/vendor/markit-ai/dist/providers/anthropic.d.ts +2 -0
  374. package/vendor/markit-ai/dist/providers/anthropic.js +47 -0
  375. package/vendor/markit-ai/dist/providers/index.d.ts +21 -0
  376. package/vendor/markit-ai/dist/providers/index.js +56 -0
  377. package/vendor/markit-ai/dist/providers/openai.d.ts +2 -0
  378. package/vendor/markit-ai/dist/providers/openai.js +76 -0
  379. package/vendor/markit-ai/dist/providers/types.d.ts +26 -0
  380. package/vendor/markit-ai/dist/providers/types.js +1 -0
  381. package/vendor/markit-ai/dist/types.d.ts +36 -0
  382. package/vendor/markit-ai/dist/types.js +1 -0
  383. package/vendor/markit-ai/dist/utils/exit-codes.d.ts +4 -0
  384. package/vendor/markit-ai/dist/utils/exit-codes.js +4 -0
  385. package/vendor/markit-ai/dist/utils/output.d.ts +22 -0
  386. package/vendor/markit-ai/dist/utils/output.js +31 -0
  387. package/vendor/markit-ai/dist/utils/turndown.d.ts +8 -0
  388. package/vendor/markit-ai/dist/utils/turndown.js +70 -0
  389. package/vendor/markit-ai/package.json +74 -0
  390. package/vendor/markit-ai.patch +49 -0
package/src/tools/read.ts CHANGED
@@ -14,7 +14,7 @@ import type { RenderResultOptions } from "../extensibility/custom-tools/types";
14
14
  import { getActiveSkills } from "../extensibility/skills";
15
15
  import { formatHashLine, formatHashLines, formatLineHash, HL_BODY_SEP } from "../hashline/hash";
16
16
  import { InternalUrlRouter } from "../internal-urls";
17
- import { parseInternalUrl } from "../internal-urls/parse";
17
+ import { normalizeInternalUrlInput, parseInternalUrl } from "../internal-urls/parse";
18
18
  import type { InternalUrl } from "../internal-urls/types";
19
19
  import { getLanguageFromPath, type Theme } from "../modes/theme/theme";
20
20
  import readDescription from "../prompts/tools/read.md" with { type: "text" };
@@ -2745,7 +2745,7 @@ export class ReadTool implements AgentTool<typeof readSchema, ReadToolDetails> {
2745
2745
  // off the URL and surfaced via parseSel rather than confusing handlers.
2746
2746
  const internalRouter = InternalUrlRouter.instance();
2747
2747
  if (internalRouter.canHandle(readPath)) {
2748
- const internalTarget = splitInternalUrlSel(readPath, {
2748
+ const internalTarget = splitInternalUrlSel(normalizeInternalUrlInput(readPath), {
2749
2749
  activeSkillNames: getActiveSkills().map(skill => skill.name),
2750
2750
  });
2751
2751
  const parsed = parseSel(internalTarget.sel);
@@ -3590,7 +3590,7 @@ export class ReadTool implements AgentTool<typeof readSchema, ReadToolDetails> {
3590
3590
  sourcePath: resource.sourcePath,
3591
3591
  sourceInternal: url,
3592
3592
  entityLabel: "resource",
3593
- ignoreResultLimits: scheme === "skill",
3593
+ ignoreResultLimits: scheme === "skill" || scheme === "embedded",
3594
3594
  immutable: resource.immutable,
3595
3595
  raw,
3596
3596
  truncationDirection: direction,
@@ -0,0 +1,107 @@
1
+ import { logger } from "@gajae-code/utils";
2
+ import type { FoldReason } from "../async/job-manager";
3
+ import type { ToolSession } from ".";
4
+
5
+ /** A short foreground wait stays in the foreground even when a steer is admitted. */
6
+ export const STEER_FOLD_GRACE_MS = 2_000;
7
+
8
+ /** Model-facing line appended to a steer-folded background-start result. */
9
+ export function steerFoldReasonLine(jobId: string): string {
10
+ return `Folded into background job ${jobId} because a user steer arrived; the command keeps running with its original timeout and its result will wake a later turn.`;
11
+ }
12
+
13
+ /** Model-facing cause clause for a fold, keyed by the recorded {@link FoldReason}. */
14
+ export function foldReasonClause(reason: FoldReason): string {
15
+ switch (reason) {
16
+ case "steer":
17
+ return "because a user steer arrived";
18
+ case "chord":
19
+ return "because the user pressed the fold chord";
20
+ case "sdk_control":
21
+ return "because an SDK client requested it";
22
+ case "timer":
23
+ return "because the auto-background threshold elapsed";
24
+ }
25
+ }
26
+
27
+ /** Model-facing line used when the `job` tool's own wait is folded; states the real trigger. */
28
+ export function foldAwaitReasonLine(folded: ReadonlyMap<string, FoldReason>): string {
29
+ const jobIds = [...folded.keys()];
30
+ const names = jobIds.map(id => `\`${id}\``).join(", ");
31
+ const reasons = [...new Set(folded.values())];
32
+ const single = reasons.length === 1 ? reasons[0] : undefined;
33
+ const cause = single ? foldReasonClause(single) : "because the waits were folded";
34
+ const plural = jobIds.length !== 1;
35
+ return `Folded the job await for ${names} ${cause}; the job${plural ? "s keep" : " keeps"} running with ${plural ? "their original deadlines" : "its original deadline"}, and ${plural ? "their results" : "its result"} will wake a later turn.`;
36
+ }
37
+
38
+ type SteerFoldSession = Pick<ToolSession, "settings" | "waitForUserSteering" | "requestForegroundBashBackground">;
39
+
40
+ /** The session hooks a steer fold needs, resolved once so callers never re-read and non-null-assert them. */
41
+ interface SteerFoldHooks {
42
+ waitForSteer: NonNullable<ToolSession["waitForUserSteering"]>;
43
+ requestFold: NonNullable<ToolSession["requestForegroundBashBackground"]>;
44
+ }
45
+
46
+ /**
47
+ * Whether a queued user steer may fold the running foreground wait. Mirrors
48
+ * the loop's steer admission: `busyPromptMode=queue` never admits a steer
49
+ * into the busy run, so it never folds. `toolInterruptPolicy` is
50
+ * deliberately NOT a gate: `finish_tools` means "do not kill the batch to
51
+ * deliver a steer", and a fold kills nothing. It is the one way to deliver
52
+ * the steer now AND let the command finish, so it applies under both
53
+ * policies; the policy only decides what the loop does with sibling tools
54
+ * after the fold returns. The auto-background setting is likewise not
55
+ * consulted: like the chord, a steer fold is a user action.
56
+ *
57
+ * Fails closed: a session that cannot report newly admitted steering or
58
+ * accept a fold request is not steer-foldable.
59
+ */
60
+ function steerFoldHooks(session: SteerFoldSession): SteerFoldHooks | undefined {
61
+ const { waitForUserSteering, requestForegroundBashBackground } = session;
62
+ if (!waitForUserSteering || !requestForegroundBashBackground) return undefined;
63
+ if (session.settings.get("busyPromptMode") !== "steer") return undefined;
64
+ return { waitForSteer: waitForUserSteering, requestFold: requestForegroundBashBackground };
65
+ }
66
+
67
+ /**
68
+ * Fold on the first user steer that ARRIVES after the wait has run for
69
+ * {@link STEER_FOLD_GRACE_MS} since `startedAt`. A steer already queued when
70
+ * the wait starts, or one that arrives inside the grace window, never folds:
71
+ * the wait finishes normally and that steer is consumed at the ordinary tool
72
+ * boundary. The watcher keeps observing so a later qualifying steer still
73
+ * folds, and re-checks the gate at that moment so a `busyPromptMode` change
74
+ * during the wait is honored. `requestFold` receives the session's resolved
75
+ * fold request so the caller targets its own adapter without re-reading the
76
+ * optional session hook.
77
+ * Returns a stop function; call it when the wait settles. No-op when steer
78
+ * folding is gated off at start.
79
+ */
80
+ export function watchSteerForFold(
81
+ session: SteerFoldSession,
82
+ startedAt: number,
83
+ requestFold: (fold: SteerFoldHooks["requestFold"]) => Promise<unknown>,
84
+ jobId?: string,
85
+ ): () => void {
86
+ const hooks = steerFoldHooks(session);
87
+ if (!hooks) return () => {};
88
+ const watch = new AbortController();
89
+ const observe = async (): Promise<void> => {
90
+ while (!watch.signal.aborted) {
91
+ await hooks.waitForSteer(watch.signal);
92
+ if (watch.signal.aborted) return;
93
+ if (Date.now() - startedAt < STEER_FOLD_GRACE_MS) continue;
94
+ const current = steerFoldHooks(session);
95
+ if (!current) continue;
96
+ await requestFold(current.requestFold);
97
+ return;
98
+ }
99
+ };
100
+ observe().catch((error: unknown) => {
101
+ logger.warn("Steer-triggered fold failed", {
102
+ ...(jobId ? { jobId } : {}),
103
+ error: error instanceof Error ? error.message : String(error),
104
+ });
105
+ });
106
+ return () => watch.abort();
107
+ }
@@ -9,6 +9,7 @@
9
9
  */
10
10
  import type { Component } from "@gajae-code/tui";
11
11
  import { Text } from "@gajae-code/tui";
12
+ import { formatNumber } from "@gajae-code/utils";
12
13
  import type { RenderResultOptions } from "../extensibility/custom-tools/types";
13
14
  import type { Theme } from "../modes/theme/theme";
14
15
  import { providerRetryPhaseLabel } from "../task/provider-retry-status";
@@ -22,6 +23,7 @@ import {
22
23
  truncateToWidth,
23
24
  } from "./render-utils";
24
25
  import {
26
+ SUBAGENT_ACTIVITY_BUCKET_MS,
25
27
  type SubagentLiveProgress,
26
28
  type SubagentSnapshot,
27
29
  type SubagentToolDetails,
@@ -186,7 +188,28 @@ function renderSubagentStatusLine(snapshot: SubagentSnapshot, theme: Theme, spin
186
188
  )
187
189
  : theme.fg("dim", snapshot.status);
188
190
  const duration = theme.fg("dim", formatDuration(snapshot.durationMs));
189
- return `${icon} ${id} ${status} ${duration}`;
191
+ const live = snapshot.liveProgressAvailable !== false ? snapshot.progress : undefined;
192
+ return `${icon} ${id} ${status} ${duration}${live ? formatLiveStats(live, theme, Date.now()) : ""}`;
193
+ }
194
+
195
+ // Live stats ride the cheap status line (rebuilt every render), never the cached
196
+ // body. Quantize age to the producer cadence so incidental renders do not churn it.
197
+ function formatLiveStats(progress: SubagentLiveProgress, theme: Theme, nowMs: number): string {
198
+ const parts: string[] = [];
199
+ if (progress.toolCount) parts.push(`${progress.toolCount} ${progress.toolCount === 1 ? "tool" : "tools"}`);
200
+ if (progress.contextTokens) {
201
+ parts.push(
202
+ progress.contextWindow
203
+ ? `${formatNumber(progress.contextTokens)}/${formatNumber(progress.contextWindow)} ctx`
204
+ : `${formatNumber(progress.contextTokens)} ctx`,
205
+ );
206
+ }
207
+ if (progress.lastActivityMs !== undefined && progress.status === "running") {
208
+ const ageMs = Math.max(0, nowMs - progress.lastActivityMs);
209
+ const ageBucketMs = Math.floor(ageMs / SUBAGENT_ACTIVITY_BUCKET_MS) * SUBAGENT_ACTIVITY_BUCKET_MS;
210
+ parts.push(`last activity ${formatDuration(ageBucketMs)} ago`);
211
+ }
212
+ return parts.map(part => `${theme.sep.dot}${theme.fg("dim", part)}`).join("");
190
213
  }
191
214
 
192
215
  function renderSubagentLiveProgress(
@@ -120,6 +120,10 @@ export interface SubagentLiveProgress {
120
120
  currentTool?: string;
121
121
  recentTool?: string;
122
122
  recentOutputSummary?: { lineCount: number };
123
+ toolCount?: number;
124
+ contextTokens?: number;
125
+ contextWindow?: number;
126
+ lastActivityMs?: number;
123
127
  fastMode?: boolean;
124
128
  retryState?: {
125
129
  attempt: number;
@@ -145,6 +149,14 @@ function toSubagentLiveProgress(progress: AgentProgress): SubagentLiveProgress {
145
149
  ...(progress.recentOutput.length > 0
146
150
  ? { recentOutputSummary: { lineCount: Math.min(progress.recentOutput.length, 6) } }
147
151
  : {}),
152
+ ...(progress.toolCount > 0 ? { toolCount: progress.toolCount } : {}),
153
+ ...(progress.contextTokens !== undefined && progress.contextTokens > 0
154
+ ? { contextTokens: progress.contextTokens }
155
+ : {}),
156
+ ...(progress.contextWindow !== undefined && progress.contextWindow > 0
157
+ ? { contextWindow: progress.contextWindow }
158
+ : {}),
159
+ ...(progress.lastActivityMs !== undefined ? { lastActivityMs: progress.lastActivityMs } : {}),
148
160
  ...(progress.fastMode ? { fastMode: true } : {}),
149
161
  ...(progress.retryState
150
162
  ? {
@@ -1104,11 +1116,15 @@ function previewJobOutput(
1104
1116
  * unsafe.
1105
1117
  *
1106
1118
  * Time-derived fields are intentionally excluded so the panel does not churn while
1107
- * idle: raw durations (`durationMs`), current-tool elapsed (`currentToolStartMs`),
1119
+ * idle (the child's last-event timestamp is included; it moves only on real
1120
+ * activity): raw durations (`durationMs`), current-tool elapsed (`currentToolStartMs`),
1108
1121
  * and retry countdowns (`retryState.startedAtMs`) are omitted. Idle duration and
1109
1122
  * countdown ticking is sacrificed by design; every real transition still changes
1110
1123
  * the signature.
1111
1124
  */
1125
+ /** Shared cadence for await progress refreshes and rendered last-activity age. */
1126
+ export const SUBAGENT_ACTIVITY_BUCKET_MS = 5_000;
1127
+
1112
1128
  export function subagentAwaitRenderedStateSignature(
1113
1129
  subagents: readonly SubagentSnapshot[],
1114
1130
  receipt?: Pick<SubagentToolDetails, "awaitOutcome" | "interrupted">,
@@ -1156,6 +1172,16 @@ function canonicalizeProgressForSignature(progress: SubagentLiveProgress): unkno
1156
1172
  currentTool: progress.currentTool ?? null,
1157
1173
  recentTool: progress.recentTool ?? null,
1158
1174
  recentOutputSummary: progress.recentOutputSummary ?? null,
1175
+ toolCount: progress.toolCount ?? 0,
1176
+ contextTokens: progress.contextTokens ?? null,
1177
+ contextWindow: progress.contextWindow ?? null,
1178
+ // Event timestamp, bucketed: it only moves when the child actually does
1179
+ // something (idle gating holds), and the bucket keeps a streaming child from
1180
+ // re-emitting on every delta. The status-line age is quantized to this cadence.
1181
+ lastActivityBucket:
1182
+ progress.lastActivityMs === undefined
1183
+ ? null
1184
+ : Math.floor(progress.lastActivityMs / SUBAGENT_ACTIVITY_BUCKET_MS),
1159
1185
  fastMode: progress.fastMode ?? false,
1160
1186
  retryFailure: progress.retryFailure ?? null,
1161
1187
  retryState: progress.retryState
@@ -27,7 +27,7 @@ export const TOOL_CATALOG: Readonly<Record<string, ToolCatalogEntry>> = {
27
27
  "read": {
28
28
  "name": "read",
29
29
  "label": "Read",
30
- "description": "Read files, directories, archives, SQLite databases, images, documents, internal resources, and web URLs through a single `path` string.\n\n<instruction>\n- One tool for filesystem, archives, SQLite, images, documents (PDF/DOCX/PPTX/XLSX/RTF/EPUB/ipynb), internal URIs, and web URLs (reader-mode by default).\n- You SHOULD parallelize independent reads when exploring related files.\n- You SHOULD reach for `read` — not a browser/puppeteer tool — for fetching web content.\n</instruction>\n\n## Parameters\n\n- `path` — required. Local path, internal URI (`agent://`, `artifact://`, `rule://`, `local://`), or URL. Append `:<sel>` for line ranges, raw mode, or special modes (e.g. `src/foo.ts:50-200`, `src/foo.ts:raw`, `db.sqlite:users:42`).\n- `truncation` — optional `head` | `last` | `both`; selects which end of an over-budget result to retain. Configured default: last (factory default: `last`); structural summaries and routes such as URLs, directories and converted documents default to `head`. A line-range selector still bounds the selection — this only picks which end of that selection survives the byte/line cap. SQLite row queries page via their own `limit`/`offset` and ignore it.\n## Selectors\nAppend `:<sel>` to `path`. The bare path falls back to the default mode.\n\n- _(none)_ — parseable code → structural summary (signatures kept, bodies elided); a plain text file → a bounded receipt of about undefined lines or undefined KiB, whichever is smaller; the configured truncation direction is last (factory default: last). Line+hash anchors keep their real file line numbers and a footer names the omitted range. Archive members use the larger 3000-line / 50 KiB budget. Converted documents, notebooks, URLs and directory listings still start from the beginning.\n- `:50` / `:50-` — read from line 50 onward.\n- `:50-200` — lines 50–200 inclusive.\n- `:50+150` — 150 lines starting at line 50.\n- `:20+1` — exactly one line.\n- `:5-16,960-973` — multiple ranges in one call (sorted, overlaps merged).\n- `:raw` — verbatim text; no anchors, no summary, no line prefixes.\n- `:2-4:raw` or `:raw:2-4` — range AND verbatim; the two compose in either order.\n- `:conflicts` — one-line-per-block index of every unresolved git merge conflict.\n\n# Files\n\n- Reading a directory path returns a depth-limited dirent listing.\n- Parseable code without a selector returns a **structural summary**: declarations kept, large bodies collapsed to `..` (merged brace pair) or `…` (standalone). Summarized output ends with a footer of the form:\n\n `[NN lines across MM elided regions; read <path>:raw or a line range like <path>:1-9999 for verbatim content]`\n\n If the elided body is what you actually need, re-issue the **exact selector the footer names**. NEVER guess what's inside `..` / `…` — those markers carry no content.\n- Structural summaries honor explicit `truncation`: `head` retains the beginning, `last` the end, and `both` both ends within the summary byte budget. Complete summary units and their original source anchors stay intact and in source order; budget omissions are marked where they occur. This does not switch to raw source. Summaries that fit are unchanged by direction.\n- Directional windows identify the retained first/last lines and the omitted range; use the `re-read <path>:1-<total>` or `:raw` hint in the footer to recover the full content.\n\n# Documents & Notebooks\n\nExtracts text from PDF, Word, PowerPoint, Excel, RTF, and EPUB. Notebooks (`.ipynb`) are shown as editable `# %% [type] cell:N` text; edits round-trip back to the underlying JSON preserving notebook metadata. Add `:raw` to a notebook to bypass the converter and read the JSON directly.\n\n# Images\n\nReading an image path returns the image itself for visual inspection by a vision-capable model.\n\n# Archives\n\nSupports `.tar`, `.tar.gz`, `.tgz`, `.zip`. Use `archive.ext:path/inside/archive` to read a member, and append a normal selector to the inner path: `archive.zip:dir/file.ts:50-60`.\n\n# SQLite\n\nFor `.sqlite`, `.sqlite3`, `.db`, `.db3`:\n- `file.db` — list tables with row counts\n- `file.db:table` — schema + sample rows\n- `file.db:table:key` — single row by primary key\n- `file.db:table?limit=50&offset=100` — paginated rows\n- `file.db:table?where=status='active'&order=created:desc` — filtered rows\n- `file.db?q=SELECT …` — read-only SELECT query\n\n# URLs\n\n- Default reader-mode: HTML pages, GitHub issues/PRs, Stack Overflow, Wikipedia, Reddit, NPM, arXiv, RSS/Atom, JSON endpoints, PDFs → clean text/markdown.\n- `:raw` returns untouched HTML; line selectors (`:50`, `:50-100`, `:50+150`) paginate the cached fetched output.\n- Bare `host:port` URLs collide with the selector grammar — add a trailing slash before the selector: `https://example.com/:80`.\n\n# Internal URIs\n\n`agent://<id>`, `artifact://<id>`, `rule://<name>`, and `local://<name>.md` resolve transparently and accept the same line selectors as filesystem paths. Use `artifact://<id>` to recover full output that a previous bash/eval/tool result spilled or truncated.\n\n<critical>\n- Always include `path`; never call `read` with `{}`.\n- For line ranges, append the selector to `path`.\n- Re-issue the selector named by a summary footer before relying on elided content.\n</critical>",
30
+ "description": "Read files, directories, archives, SQLite databases, images, documents, internal resources, and web URLs through a single `path` string.\n\n<instruction>\n- One tool for filesystem, archives, SQLite, images, documents (PDF/DOCX/PPTX/XLSX/RTF/EPUB/ipynb), internal URIs, and web URLs (reader-mode by default).\n- You SHOULD parallelize independent reads when exploring related files.\n- You SHOULD reach for `read` — not a browser/puppeteer tool — for fetching web content.\n</instruction>\n\n## Parameters\n\n- `path` — required. Local path, internal URI (`agent://`, `artifact://`, `rule://`, `local://`), or URL. Append `:<sel>` for line ranges, raw mode, or special modes (e.g. `src/foo.ts:50-200`, `src/foo.ts:raw`, `db.sqlite:users:42`).\n- `truncation` — optional `head` | `last` | `both`; selects which end of an over-budget result to retain. Configured default: last (factory default: `last`); structural summaries and routes such as URLs, directories and converted documents default to `head`. A line-range selector still bounds the selection — this only picks which end of that selection survives the byte/line cap. SQLite row queries page via their own `limit`/`offset` and ignore it.\n## Selectors\nAppend `:<sel>` to `path`. The bare path falls back to the default mode.\n\n- _(none)_ — parseable code → structural summary (signatures kept, bodies elided); a plain text file → a bounded receipt of about undefined lines or undefined KiB, whichever is smaller; the configured truncation direction is last (factory default: last). Line+hash anchors keep their real file line numbers and a footer names the omitted range. Archive members use the larger 3000-line / 50 KiB budget. Converted documents, notebooks, URLs and directory listings still start from the beginning.\n- `:50` / `:50-` — read from line 50 onward.\n- `:50-200` — lines 50–200 inclusive.\n- `:50+150` — 150 lines starting at line 50.\n- `:20+1` — exactly one line.\n- `:5-16,960-973` — multiple ranges in one call (sorted, overlaps merged).\n- `:raw` — verbatim text; no anchors, no summary, no line prefixes.\n- `:2-4:raw` or `:raw:2-4` — range AND verbatim; the two compose in either order.\n- `:conflicts` — one-line-per-block index of every unresolved git merge conflict.\n\n# Files\n\n- Reading a directory path returns a depth-limited dirent listing.\n- Parseable code without a selector returns a **structural summary**: declarations kept, large bodies collapsed to `..` (merged brace pair) or `…` (standalone). Summarized output ends with a footer of the form:\n\n `[NN lines across MM elided regions; read <path>:raw or a line range like <path>:1-9999 for verbatim content]`\n\n If the elided body is what you actually need, re-issue the **exact selector the footer names**. NEVER guess what's inside `..` / `…` — those markers carry no content.\n- Structural summaries honor explicit `truncation`: `head` retains the beginning, `last` the end, and `both` both ends within the summary byte budget. Complete summary units and their original source anchors stay intact and in source order; budget omissions are marked where they occur. This does not switch to raw source. Summaries that fit are unchanged by direction.\n- Directional windows identify the retained first/last lines and the omitted range; use the `re-read <path>:1-<total>` or `:raw` hint in the footer to recover the full content.\n\n# Documents & Notebooks\n\nExtracts text from PDF, Word, PowerPoint, Excel, RTF, and EPUB. Notebooks (`.ipynb`) are shown as editable `# %% [type] cell:N` text; edits round-trip back to the underlying JSON preserving notebook metadata. Add `:raw` to a notebook to bypass the converter and read the JSON directly.\n\n# Images\n\nReading an image path returns the image itself for visual inspection by a vision-capable model.\n\n# Archives\n\nSupports `.tar`, `.tar.gz`, `.tgz`, `.zip`. Use `archive.ext:path/inside/archive` to read a member, and append a normal selector to the inner path: `archive.zip:dir/file.ts:50-60`.\n\n# SQLite\n\nFor `.sqlite`, `.sqlite3`, `.db`, `.db3`:\n- `file.db` — list tables with row counts\n- `file.db:table` — schema + sample rows\n- `file.db:table:key` — single row by primary key\n- `file.db:table?limit=50&offset=100` — paginated rows\n- `file.db:table?where=status='active'&order=created:desc` — filtered rows\n- `file.db?q=SELECT …` — read-only SELECT query\n\n# URLs\n\n- Default reader-mode: HTML pages, GitHub issues/PRs, Stack Overflow, Wikipedia, Reddit, NPM, arXiv, RSS/Atom, JSON endpoints, PDFs → clean text/markdown.\n- `:raw` returns untouched HTML; line selectors (`:50`, `:50-100`, `:50+150`) paginate the cached fetched output.\n- Bare `host:port` URLs collide with the selector grammar — add a trailing slash before the selector: `https://example.com/:80`.\n\n# Internal URIs\n\n`agent://<id>`, `artifact://<id>`, `rule://<name>`, and `local://<name>.md` resolve transparently and accept the same line selectors as filesystem paths. Use `artifact://<id>` to recover full output that a previous bash/eval/tool result spilled or truncated.\n\nBundled skills have no filesystem home, so the skill tool and skill discovery report them as `embedded:gjc/skills/<name>/SKILL.md`; read that identifier verbatim. Bundled skill fragments, when surfaced, likewise use `embedded:gjc/skill-fragments/...` identifiers.\n\n<critical>\n- Always include `path`; never call `read` with `{}`.\n- For line ranges, append the selector to `path`.\n- Re-issue the selector named by a summary footer before relying on elided content.\n</critical>",
31
31
  "parameters": {
32
32
  "type": "object",
33
33
  "properties": {
@@ -89,6 +89,33 @@ export const TOOL_CATALOG: Readonly<Record<string, ToolCatalogEntry>> = {
89
89
  "pty": {
90
90
  "type": "boolean",
91
91
  "description": "run in pty mode"
92
+ },
93
+ "activity": {
94
+ "description": "declare browser activity for the aside browser backend: repl or exec",
95
+ "type": "object",
96
+ "properties": {
97
+ "kind": {
98
+ "type": "string",
99
+ "const": "browser"
100
+ },
101
+ "provider": {
102
+ "type": "string",
103
+ "const": "aside"
104
+ },
105
+ "mode": {
106
+ "type": "string",
107
+ "enum": [
108
+ "repl",
109
+ "exec"
110
+ ]
111
+ }
112
+ },
113
+ "required": [
114
+ "kind",
115
+ "provider",
116
+ "mode"
117
+ ],
118
+ "additionalProperties": false
92
119
  }
93
120
  },
94
121
  "required": [
@@ -2326,7 +2353,7 @@ export const TOOL_CATALOG: Readonly<Record<string, ToolCatalogEntry>> = {
2326
2353
  "job": {
2327
2354
  "name": "job",
2328
2355
  "label": "Job",
2329
- "description": "Inspects, waits, or cancels async jobs.\n\nBackground job results are delivered automatically when complete. Jobs that back task subagents should be controlled via the `subagent` tool when it is available; use `job` for non-subagent jobs (async bash, monitors) and as a compatibility fallback. Running job output stays quiet by default to avoid flooding the conversation; use `tail` when you explicitly want to show/reopen retained output. Reach for this tool only when you need to inspect or intervene.\n\nIn the interactive TUI, a running foreground command can be folded into a background job by pressing the fold chord twice (default `Alt+Shift+B`, plus `Cmd+B` on macOS; remappable via `app.tool.backgroundFold`), or automatically when the user sends a steer after the command has run for at least 2 seconds (with `busyPromptMode=steer` (`toolInterruptPolicy` is not a gate)). This covers managed non-PTY bash, editor/ACP client-terminal commands, and PTY-mode commands. A folded job keeps its original deadline, is never killed or restarted by folding, and its result wakes a later turn automatically; a folded PTY continues output-only and no longer accepts input. Job listings expose `foldReason` (`steer`, `chord`, `timer`, or `sdk_control`) beside `backgrounded` so you can tell why a job left the foreground. `task`/`subagent` waits are not foldable. Raw shell `Ctrl+Z`/`bg` is not the supported path inside GJC because it bypasses job ownership and output-routing contracts.\n\n# Operations\n\n## `list: true`\nUse to inspect what's running.\n\n## `tail: [id, …]`\nShow the retained output buffer for one or more background jobs without waiting.\n- Use this to reopen/tail a backgrounded long-running bash/tool output after folding it away.\n- Output is bounded by the manager retention window; stale cursors may report that only the retained tail is available.\n- Prefer `tail` over polling when you only need to peek at progress, so the conversation can continue without flooding the TUI.\n\n## `poll: [id, …]`\nBlock until the specified jobs finish or the wait window (~30 s, not configurable) elapses.\n- Use when you are genuinely blocked on a result and have no other work to do.\n- Returns the current snapshot when the timer elapses; running jobs remain running.\n- Completed jobs include their final output in the returned snapshot.\n\n## `cancel: [id, …]`\nStop running jobs.\n- Use when a job is stalled, hung, or no longer needed.\n- Returns immediately after cancelling.",
2356
+ "description": "Inspects, waits, or cancels async jobs.\n\nBackground job results are delivered automatically when complete. Jobs that back task subagents should be controlled via the `subagent` tool when it is available; use `job` for non-subagent jobs (async bash, monitors) and as a compatibility fallback. Running job output stays quiet by default to avoid flooding the conversation; use `tail` when you explicitly want to show/reopen retained output. Reach for this tool only when you need to inspect or intervene.\n\nIn the interactive TUI, a running foreground command can be folded into a background job by pressing the fold chord twice (default `Alt+Shift+B`, plus `Cmd+B` on macOS; remappable via `app.tool.backgroundFold`), or automatically when the user sends a steer after the command has run for at least 2 seconds (with `busyPromptMode=steer` (`toolInterruptPolicy` is not a gate)). This covers managed non-PTY bash, editor/ACP client-terminal commands, and PTY-mode commands. A folded job keeps its original deadline, is never killed or restarted by folding, and its result wakes a later turn automatically; a folded PTY continues output-only and no longer accepts input. A `job` await also folds after the same 2-second grace window when a steer arrives, returning immediately with the still-running job id(s) while those jobs keep their original deadlines and wake a later turn with their results. Job listings expose `foldReason` (`steer`, `chord`, `timer`, or `sdk_control`) beside `backgrounded` so you can tell why a job left the foreground. `task`/`subagent` waits are not foldable. Raw shell `Ctrl+Z`/`bg` is not the supported path inside GJC because it bypasses job ownership and output-routing contracts.\n\n# Operations\n\n## `list: true`\nUse to inspect what's running.\n\n## `tail: [id, …]`\nShow the retained output buffer for one or more background jobs without waiting.\n- Use this to reopen/tail a backgrounded long-running bash/tool output after folding it away.\n- Output is bounded by the manager retention window; stale cursors may report that only the retained tail is available.\n- Prefer `tail` over polling when you only need to peek at progress, so the conversation can continue without flooding the TUI.\n\n## `poll: [id, …]`\nBlock until the specified jobs finish or the wait window (~30 s, not configurable) elapses.\n- Use when you are genuinely blocked on a result and have no other work to do.\n- Returns the current snapshot when the timer elapses; running jobs remain running.\n- Completed jobs include their final output in the returned snapshot.\n\n## `cancel: [id, …]`\nStop running jobs.\n- Use when a job is stalled, hung, or no longer needed.\n- Returns immediately after cancelling.",
2330
2357
  "parameters": {
2331
2358
  "type": "object",
2332
2359
  "properties": {
@@ -1,3 +1,5 @@
1
+ import { markDesignedError } from "@gajae-code/utils/error-classification";
2
+
1
3
  /**
2
4
  * Standardized error types for tool execution.
3
5
  *
@@ -16,6 +18,7 @@ export class ToolError extends Error {
16
18
  ) {
17
19
  super(message);
18
20
  this.name = "ToolError";
21
+ markDesignedError(this);
19
22
  }
20
23
 
21
24
  /** Render error for LLM consumption. Override for custom formatting. */
@@ -33,6 +36,7 @@ export class ToolAbortError extends Error {
33
36
  constructor(message: string = ToolAbortError.MESSAGE) {
34
37
  super(message);
35
38
  this.name = "ToolAbortError";
39
+ markDesignedError(this);
36
40
  }
37
41
  }
38
42
 
package/src/utils/git.ts CHANGED
@@ -805,10 +805,18 @@ export const status = Object.assign(
805
805
  // ════════════════════════════════════════════════════════════════════════════
806
806
 
807
807
  export const stage = {
808
- /** Stage files. Empty array stages all (`git add -A`). */
809
- async files(cwd: string, files: readonly string[] = [], signal?: AbortSignal): Promise<void> {
808
+ /**
809
+ * Stage files. Empty array stages all (`git add -A`). Accepts a bare signal or
810
+ * `{ env, signal }`; `env` exists so a caller can stage into an isolated
811
+ * `GIT_INDEX_FILE` instead of the repository's real index.
812
+ */
813
+ async files(
814
+ cwd: string,
815
+ files: readonly string[] = [],
816
+ options: AbortSignal | Pick<CommandOptions, "env" | "signal"> = {},
817
+ ): Promise<void> {
810
818
  const args = files.length === 0 ? ["add", "-A"] : ["add", "--", ...files];
811
- await runEffect(cwd, args, { signal });
819
+ await runEffect(cwd, args, options instanceof AbortSignal ? { signal: options } : options);
812
820
  },
813
821
 
814
822
  /** Selectively stage hunks from the provided diff or the current working tree diff. */
@@ -902,6 +910,28 @@ export async function writeTree(cwd: string, options: Pick<CommandOptions, "env"
902
910
  return (await runText(cwd, ["write-tree"], options)).trim();
903
911
  }
904
912
 
913
+ export interface CommitTreeOptions {
914
+ readonly env?: Record<string, string | undefined>;
915
+ readonly parents?: readonly string[];
916
+ readonly signal?: AbortSignal;
917
+ }
918
+
919
+ /**
920
+ * Create a commit object from an existing tree and return its SHA. Plumbing:
921
+ * unlike `commit` this touches neither the index nor any ref, and runs no
922
+ * `pre-commit`/`commit-msg` hook.
923
+ */
924
+ export async function commitTree(
925
+ cwd: string,
926
+ tree: string,
927
+ message: string,
928
+ options: CommitTreeOptions = {},
929
+ ): Promise<string> {
930
+ const args = ["commit-tree", tree];
931
+ for (const parent of options.parents ?? []) args.push("-p", parent);
932
+ return (await runText(cwd, args, { env: options.env, signal: options.signal, stdin: message })).trim();
933
+ }
934
+
905
935
  // ════════════════════════════════════════════════════════════════════════════
906
936
  // API: show
907
937
  // ════════════════════════════════════════════════════════════════════════════
@@ -1075,6 +1105,26 @@ export const ref = {
1075
1105
  return result.stdout.trim() || null;
1076
1106
  },
1077
1107
 
1108
+ /**
1109
+ * Move a ref to `newValue`, but only while it still holds `expectedOldValue`
1110
+ * (the empty string asserts the ref does not exist yet). Git verifies the old
1111
+ * value and writes the new one under its own ref lock, so this is an atomic
1112
+ * compare-and-swap: a concurrent writer that moved the ref first makes this
1113
+ * throw instead of silently clobbering their commit.
1114
+ */
1115
+ async update(
1116
+ cwd: string,
1117
+ refName: string,
1118
+ newValue: string,
1119
+ expectedOldValue: string,
1120
+ options: { reason?: string; signal?: AbortSignal } = {},
1121
+ ): Promise<void> {
1122
+ const args = ["update-ref"];
1123
+ if (options.reason) args.push("-m", options.reason);
1124
+ args.push(refName, newValue, expectedOldValue);
1125
+ await runEffect(cwd, args, { signal: options.signal });
1126
+ },
1127
+
1078
1128
  /** Tags pointing at a ref. */
1079
1129
  async tags(cwd: string, refName = "HEAD", signal?: AbortSignal): Promise<string[]> {
1080
1130
  return splitLines(
@@ -1,7 +1,7 @@
1
1
  import { untilAborted } from "@gajae-code/utils";
2
- import type { Markit, StreamInfo } from "markit-ai";
2
+ import type { Markit, StreamInfo } from "../../vendor/markit-ai/dist/index.js";
3
3
  import { ToolAbortError } from "../tools/tool-errors";
4
- import { ensureMupdfWasmResolution } from "./mupdf-wasm";
4
+ import { prepareMuPdf, sanitizeMuPdfDiagnostic, withMuPdfDiagnostic } from "./mupdf";
5
5
 
6
6
  export interface MarkitConversionResult {
7
7
  content: string;
@@ -9,20 +9,23 @@ export interface MarkitConversionResult {
9
9
  error?: string;
10
10
  }
11
11
 
12
- let markit: () => Markit | Promise<Markit> = async () => {
13
- const promise = import("markit-ai").then(({ Markit }) => {
14
- const instance = new Markit();
15
- markit = () => instance;
16
- return instance;
17
- });
18
- markit = () => promise;
19
- return promise;
20
- };
12
+ let instance: Markit | undefined;
13
+ let instancePromise: Promise<Markit> | undefined;
21
14
 
22
- // #5433: mupdf's wasm asset is not reachable at the Emscripten loader's
23
- // default bunfs path in compiled binaries. Seed the embedded-asset hook
24
- // before any markit conversion (and therefore before any mupdf import).
25
- ensureMupdfWasmResolution();
15
+ async function loadMarkit(): Promise<Markit> {
16
+ if (instancePromise === undefined) {
17
+ instancePromise = import("../../vendor/markit-ai/dist/index.js")
18
+ .then(({ Markit: MarkitConstructor }) => {
19
+ instance = new MarkitConstructor();
20
+ return instance;
21
+ })
22
+ .catch(error => {
23
+ instancePromise = undefined;
24
+ throw error;
25
+ });
26
+ }
27
+ return instancePromise;
28
+ }
26
29
 
27
30
  function normalizeExtension(extension: string): string {
28
31
  const trimmed = extension.trim().toLowerCase();
@@ -30,33 +33,27 @@ function normalizeExtension(extension: string): string {
30
33
  return trimmed.startsWith(".") ? trimmed : `.${trimmed}`;
31
34
  }
32
35
 
33
- function normalizeError(error: unknown): string {
34
- if (error instanceof Error && error.message.trim().length > 0) {
35
- return error.message.trim();
36
- }
37
- return "Conversion failed";
38
- }
39
-
40
- /**
41
- * markit-ai's PDF converter swallows the real mupdf import failure behind a
42
- * generic "Install it" message (#5433). Re-run the import here so release
43
- * diagnostics carry the actual module/asset/initialization error.
44
- */
45
- async function describeConversionError(error: unknown): Promise<string> {
46
- const base = normalizeError(error);
47
- if (!base.includes("PDF support requires 'mupdf'")) return base;
48
- try {
49
- await import("mupdf");
50
- } catch (cause) {
51
- return `${base} (mupdf import failed: ${normalizeError(cause)})`;
36
+ function normalizeError(error: unknown, pdf = false): string {
37
+ const messages: string[] = [];
38
+ const seen = new Set<unknown>();
39
+ while (error !== undefined && !seen.has(error)) {
40
+ seen.add(error);
41
+ if (error instanceof Error) {
42
+ const message = `${error.name}: ${error.message}`;
43
+ messages.push(pdf ? sanitizeMuPdfDiagnostic(message) : message);
44
+ error = error.cause;
45
+ } else {
46
+ messages.push(pdf ? sanitizeMuPdfDiagnostic(String(error)) : String(error));
47
+ break;
48
+ }
52
49
  }
53
- return base;
50
+ return messages.join("; caused by: ") || "Conversion failed";
54
51
  }
55
52
 
56
53
  async function runMarkitConversion<T>(task: (markit: Markit) => Promise<T>, signal?: AbortSignal): Promise<T> {
57
54
  try {
58
- const instance = await markit();
59
- return signal ? await untilAborted(signal, () => task(instance)) : await task(instance);
55
+ const markit = instance ?? (await loadMarkit());
56
+ return signal ? await untilAborted(signal, () => task(markit)) : await task(markit);
60
57
  } catch (error) {
61
58
  if (error instanceof ToolAbortError) {
62
59
  throw error;
@@ -78,13 +75,22 @@ function finalizeConversion(markdown?: string): MarkitConversionResult {
78
75
 
79
76
  export async function convertFileWithMarkit(filePath: string, signal?: AbortSignal): Promise<MarkitConversionResult> {
80
77
  try {
81
- const result = await runMarkitConversion(markit => markit.convertFile(filePath), signal);
78
+ if (filePath.toLowerCase().endsWith(".pdf")) await prepareMuPdf();
79
+ const result = await runMarkitConversion(async markit => {
80
+ return markit.convertFile(filePath);
81
+ }, signal);
82
82
  return finalizeConversion(result.markdown);
83
83
  } catch (error) {
84
84
  if (error instanceof ToolAbortError) {
85
85
  throw error;
86
86
  }
87
- return { content: "", ok: false, error: await describeConversionError(error) };
87
+ return {
88
+ content: "",
89
+ ok: false,
90
+ error: filePath.toLowerCase().endsWith(".pdf")
91
+ ? normalizeError(withMuPdfDiagnostic(error), true)
92
+ : normalizeError(error),
93
+ };
88
94
  }
89
95
  }
90
96
 
@@ -100,12 +106,20 @@ export async function convertBufferWithMarkit(
100
106
  };
101
107
 
102
108
  try {
103
- const result = await runMarkitConversion(markit => markit.convert(Buffer.from(buffer), streamInfo), signal);
109
+ if (normalizedExtension === ".pdf") await prepareMuPdf();
110
+ const result = await runMarkitConversion(async markit => {
111
+ return markit.convert(Buffer.from(buffer), streamInfo);
112
+ }, signal);
104
113
  return finalizeConversion(result.markdown);
105
114
  } catch (error) {
106
115
  if (error instanceof ToolAbortError) {
107
116
  throw error;
108
117
  }
109
- return { content: "", ok: false, error: await describeConversionError(error) };
118
+ return {
119
+ content: "",
120
+ ok: false,
121
+ error:
122
+ normalizedExtension === ".pdf" ? normalizeError(withMuPdfDiagnostic(error), true) : normalizeError(error),
123
+ };
110
124
  }
111
125
  }
@@ -0,0 +1,4 @@
1
+ declare module "*.wasm" {
2
+ const assetPath: string;
3
+ export default assetPath;
4
+ }
@@ -0,0 +1,4 @@
1
+ // AUTOGENERATED FILE -- DO NOT EDIT DIRECTLY
2
+ // See scripts/embed-mupdf.ts. Source installs resolve the package lazily.
3
+ export const embeddedMuPdfWasm: string | undefined = undefined;
4
+ export const embeddedMuPdfModule: string | undefined = undefined;