@ikarmic/forge-core 4.4.0 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (573) hide show
  1. package/LICENSE +44 -21
  2. package/README.md +2 -2
  3. package/dist/agent/agent.d.ts +0 -1
  4. package/dist/agent/agent.js +84 -32
  5. package/dist/agent/architect.d.ts +3 -1
  6. package/dist/agent/architect.js +1 -1
  7. package/dist/agent/cache-hints.d.ts +0 -1
  8. package/dist/agent/cache-hints.js +0 -1
  9. package/dist/agent/cost-router.d.ts +0 -1
  10. package/dist/agent/cost-router.js +2 -1
  11. package/dist/agent/enhance-prompt.d.ts +7 -0
  12. package/dist/agent/enhance-prompt.js +30 -0
  13. package/dist/agent/index.d.ts +0 -1
  14. package/dist/agent/index.js +0 -1
  15. package/dist/agent/loop-guard.d.ts +21 -0
  16. package/dist/agent/loop-guard.js +41 -0
  17. package/dist/agent/prompts.d.ts +0 -1
  18. package/dist/agent/prompts.js +0 -1
  19. package/dist/agent/think-tags.d.ts +0 -1
  20. package/dist/agent/think-tags.js +0 -1
  21. package/dist/agent/verify.d.ts +0 -1
  22. package/dist/agent/verify.js +0 -1
  23. package/dist/ai-comments/index.d.ts +0 -1
  24. package/dist/ai-comments/index.js +0 -1
  25. package/dist/attachments.d.ts +46 -0
  26. package/dist/attachments.js +178 -0
  27. package/dist/browser/cdp.d.ts +0 -1
  28. package/dist/browser/cdp.js +0 -1
  29. package/dist/browser/chrome.d.ts +0 -1
  30. package/dist/browser/chrome.js +0 -1
  31. package/dist/browser/session.d.ts +0 -1
  32. package/dist/browser/session.js +0 -1
  33. package/dist/checkpoints/index.d.ts +0 -1
  34. package/dist/checkpoints/index.js +0 -1
  35. package/dist/checkpoints/store.d.ts +0 -1
  36. package/dist/checkpoints/store.js +0 -1
  37. package/dist/checkpoints/types.d.ts +0 -1
  38. package/dist/checkpoints/types.js +0 -1
  39. package/dist/code-index/builder.d.ts +0 -1
  40. package/dist/code-index/builder.js +4 -1
  41. package/dist/code-index/index-store.d.ts +0 -1
  42. package/dist/code-index/index-store.js +0 -1
  43. package/dist/code-index/parser.d.ts +0 -1
  44. package/dist/code-index/parser.js +0 -1
  45. package/dist/code-index/types.d.ts +0 -1
  46. package/dist/code-index/types.js +0 -1
  47. package/dist/commands/custom-commands.d.ts +24 -0
  48. package/dist/commands/custom-commands.js +98 -0
  49. package/dist/config-file.d.ts +4 -1
  50. package/dist/config-file.js +0 -1
  51. package/dist/config.d.ts +0 -1
  52. package/dist/config.js +0 -1
  53. package/dist/context/compaction.d.ts +0 -1
  54. package/dist/context/compaction.js +17 -3
  55. package/dist/context/mask.d.ts +0 -1
  56. package/dist/context/mask.js +1 -2
  57. package/dist/credentials/index.d.ts +0 -1
  58. package/dist/credentials/index.js +0 -1
  59. package/dist/credentials/types.d.ts +0 -1
  60. package/dist/credentials/types.js +0 -1
  61. package/dist/diff/index.d.ts +0 -1
  62. package/dist/diff/index.js +0 -1
  63. package/dist/diff/unified-diff.d.ts +0 -1
  64. package/dist/diff/unified-diff.js +42 -16
  65. package/dist/git/auto-commit.d.ts +1 -2
  66. package/dist/git/auto-commit.js +17 -5
  67. package/dist/git/index.d.ts +0 -1
  68. package/dist/git/index.js +0 -1
  69. package/dist/github/github-tools.d.ts +83 -0
  70. package/dist/github/github-tools.js +175 -0
  71. package/dist/hooks/agent-runner.d.ts +0 -1
  72. package/dist/hooks/agent-runner.js +0 -1
  73. package/dist/hooks/bus.d.ts +0 -1
  74. package/dist/hooks/bus.js +0 -1
  75. package/dist/hooks/config.d.ts +0 -1
  76. package/dist/hooks/config.js +0 -1
  77. package/dist/hooks/events.d.ts +0 -1
  78. package/dist/hooks/events.js +0 -1
  79. package/dist/hooks/index.d.ts +0 -1
  80. package/dist/hooks/index.js +0 -1
  81. package/dist/hooks/loader.d.ts +0 -1
  82. package/dist/hooks/loader.js +0 -1
  83. package/dist/hooks/runner.d.ts +0 -1
  84. package/dist/hooks/runner.js +0 -1
  85. package/dist/hooks/watch-coalescer.d.ts +0 -1
  86. package/dist/hooks/watch-coalescer.js +0 -1
  87. package/dist/hooks/watch-ignore.d.ts +0 -1
  88. package/dist/hooks/watch-ignore.js +0 -1
  89. package/dist/hooks/watcher.d.ts +0 -1
  90. package/dist/hooks/watcher.js +0 -1
  91. package/dist/index.d.ts +21 -9
  92. package/dist/index.js +16 -5
  93. package/dist/lazy-model.d.ts +0 -1
  94. package/dist/lazy-model.js +0 -1
  95. package/dist/lint/auto-lint.d.ts +0 -1
  96. package/dist/lint/auto-lint.js +0 -1
  97. package/dist/lint/index.d.ts +0 -1
  98. package/dist/lint/index.js +0 -1
  99. package/dist/lsp/client.d.ts +0 -1
  100. package/dist/lsp/client.js +0 -1
  101. package/dist/lsp/diagnostics.d.ts +0 -1
  102. package/dist/lsp/diagnostics.js +0 -1
  103. package/dist/lsp/index.d.ts +0 -1
  104. package/dist/lsp/index.js +0 -1
  105. package/dist/mcp/catalog.d.ts +0 -1
  106. package/dist/mcp/catalog.js +0 -1
  107. package/dist/mcp/index.d.ts +0 -1
  108. package/dist/mcp/index.js +0 -1
  109. package/dist/mcp/json-schema-to-zod.d.ts +0 -1
  110. package/dist/mcp/json-schema-to-zod.js +0 -1
  111. package/dist/mcp/manager.d.ts +0 -1
  112. package/dist/mcp/manager.js +0 -1
  113. package/dist/mcp/marketplace-types.d.ts +0 -1
  114. package/dist/mcp/marketplace-types.js +0 -1
  115. package/dist/mcp/marketplace.d.ts +0 -1
  116. package/dist/mcp/marketplace.js +0 -1
  117. package/dist/mcp/mcp-client.d.ts +0 -1
  118. package/dist/mcp/mcp-client.js +0 -1
  119. package/dist/mcp/mcp-config.d.ts +0 -1
  120. package/dist/mcp/mcp-config.js +0 -1
  121. package/dist/mcp/registry.d.ts +0 -1
  122. package/dist/mcp/registry.js +0 -1
  123. package/dist/memory/memory-store.d.ts +57 -11
  124. package/dist/memory/memory-store.js +236 -70
  125. package/dist/memory/rank.d.ts +20 -0
  126. package/dist/memory/rank.js +64 -0
  127. package/dist/memory/stale.d.ts +18 -0
  128. package/dist/memory/stale.js +45 -0
  129. package/dist/model-alias.d.ts +0 -1
  130. package/dist/model-alias.js +0 -1
  131. package/dist/model-catalog.d.ts +0 -1
  132. package/dist/model-catalog.js +0 -1
  133. package/dist/model-list.d.ts +0 -1
  134. package/dist/model-list.js +0 -1
  135. package/dist/orchestrator/board-tools.d.ts +0 -1
  136. package/dist/orchestrator/board-tools.js +0 -1
  137. package/dist/orchestrator/board.d.ts +0 -1
  138. package/dist/orchestrator/board.js +0 -1
  139. package/dist/orchestrator/index.d.ts +0 -1
  140. package/dist/orchestrator/index.js +0 -1
  141. package/dist/orchestrator/orchestrator.d.ts +0 -1
  142. package/dist/orchestrator/orchestrator.js +0 -1
  143. package/dist/orchestrator/router.d.ts +0 -1
  144. package/dist/orchestrator/router.js +0 -1
  145. package/dist/orchestrator/specialists-registry.d.ts +0 -1
  146. package/dist/orchestrator/specialists-registry.js +0 -1
  147. package/dist/orchestrator/specialists.d.ts +0 -1
  148. package/dist/orchestrator/specialists.js +5 -6
  149. package/dist/orchestrator/types.d.ts +0 -1
  150. package/dist/orchestrator/types.js +0 -1
  151. package/dist/plugins/index.d.ts +0 -1
  152. package/dist/plugins/index.js +0 -1
  153. package/dist/plugins/install.d.ts +0 -1
  154. package/dist/plugins/install.js +0 -1
  155. package/dist/plugins/loader.d.ts +0 -1
  156. package/dist/plugins/loader.js +0 -1
  157. package/dist/policy/audit.d.ts +0 -1
  158. package/dist/policy/audit.js +0 -1
  159. package/dist/policy/policy.d.ts +0 -1
  160. package/dist/policy/policy.js +0 -1
  161. package/dist/policy/proxy.d.ts +0 -1
  162. package/dist/policy/proxy.js +0 -1
  163. package/dist/pricing.d.ts +0 -1
  164. package/dist/pricing.js +0 -1
  165. package/dist/providers.d.ts +0 -1
  166. package/dist/providers.js +0 -1
  167. package/dist/repomap/index.d.ts +0 -1
  168. package/dist/repomap/index.js +0 -1
  169. package/dist/repomap/repo-map.d.ts +0 -1
  170. package/dist/repomap/repo-map.js +0 -1
  171. package/dist/semantic/chunker.d.ts +0 -1
  172. package/dist/semantic/chunker.js +0 -1
  173. package/dist/semantic/embedder.d.ts +0 -1
  174. package/dist/semantic/embedder.js +0 -1
  175. package/dist/semantic/semantic-index.d.ts +0 -1
  176. package/dist/semantic/semantic-index.js +4 -1
  177. package/dist/semantic/vector-store.d.ts +0 -1
  178. package/dist/semantic/vector-store.js +0 -1
  179. package/dist/sessions/index.d.ts +2 -1
  180. package/dist/sessions/index.js +2 -1
  181. package/dist/sessions/prune.d.ts +23 -0
  182. package/dist/sessions/prune.js +35 -0
  183. package/dist/sessions/search.d.ts +22 -0
  184. package/dist/sessions/search.js +66 -0
  185. package/dist/sessions/session-export.d.ts +0 -1
  186. package/dist/sessions/session-export.js +0 -1
  187. package/dist/sessions/session-store.d.ts +0 -1
  188. package/dist/sessions/session-store.js +0 -1
  189. package/dist/sessions/watch.d.ts +0 -1
  190. package/dist/sessions/watch.js +0 -1
  191. package/dist/settings-export.d.ts +0 -1
  192. package/dist/settings-export.js +0 -1
  193. package/dist/skills/activator.d.ts +0 -1
  194. package/dist/skills/activator.js +0 -1
  195. package/dist/skills/index.d.ts +0 -1
  196. package/dist/skills/index.js +0 -1
  197. package/dist/skills/loader.d.ts +0 -1
  198. package/dist/skills/loader.js +0 -1
  199. package/dist/skills/marketplace-types.d.ts +0 -1
  200. package/dist/skills/marketplace-types.js +0 -1
  201. package/dist/skills/marketplace.d.ts +0 -1
  202. package/dist/skills/marketplace.js +0 -1
  203. package/dist/skills/parser.d.ts +0 -1
  204. package/dist/skills/parser.js +0 -1
  205. package/dist/skills/types.d.ts +0 -1
  206. package/dist/skills/types.js +0 -1
  207. package/dist/specs/generate.d.ts +0 -1
  208. package/dist/specs/generate.js +0 -1
  209. package/dist/specs/index.d.ts +2 -1
  210. package/dist/specs/index.js +1 -1
  211. package/dist/specs/store.d.ts +7 -1
  212. package/dist/specs/store.js +33 -1
  213. package/dist/specs/sync.d.ts +29 -0
  214. package/dist/specs/sync.js +155 -0
  215. package/dist/specs/tasks-parser.d.ts +0 -1
  216. package/dist/specs/tasks-parser.js +0 -1
  217. package/dist/specs/types.d.ts +2 -1
  218. package/dist/specs/types.js +0 -1
  219. package/dist/steering/glob.d.ts +0 -1
  220. package/dist/steering/glob.js +0 -1
  221. package/dist/steering/index.d.ts +0 -1
  222. package/dist/steering/index.js +0 -1
  223. package/dist/steering/loader.d.ts +0 -1
  224. package/dist/steering/loader.js +0 -1
  225. package/dist/steering/project-instructions.d.ts +0 -1
  226. package/dist/steering/project-instructions.js +0 -1
  227. package/dist/steering/select.d.ts +0 -1
  228. package/dist/steering/select.js +0 -1
  229. package/dist/steering/types.d.ts +0 -1
  230. package/dist/steering/types.js +0 -1
  231. package/dist/structured/index.d.ts +0 -1
  232. package/dist/structured/index.js +0 -1
  233. package/dist/structured/retry.d.ts +0 -1
  234. package/dist/structured/retry.js +0 -1
  235. package/dist/structured/schema.d.ts +0 -1
  236. package/dist/structured/schema.js +0 -1
  237. package/dist/tools/browser-tools.d.ts +0 -1
  238. package/dist/tools/browser-tools.js +0 -1
  239. package/dist/tools/codebase-search.d.ts +0 -1
  240. package/dist/tools/codebase-search.js +0 -1
  241. package/dist/tools/command-allow.d.ts +0 -1
  242. package/dist/tools/command-allow.js +0 -1
  243. package/dist/tools/edit-file.d.ts +0 -1
  244. package/dist/tools/edit-file.js +0 -1
  245. package/dist/tools/fetch-url.d.ts +0 -1
  246. package/dist/tools/fetch-url.js +0 -1
  247. package/dist/tools/find-references.d.ts +0 -1
  248. package/dist/tools/find-references.js +0 -1
  249. package/dist/tools/find-symbol.d.ts +0 -1
  250. package/dist/tools/find-symbol.js +0 -1
  251. package/dist/tools/ignore-rules.d.ts +15 -0
  252. package/dist/tools/ignore-rules.js +84 -0
  253. package/dist/tools/index.d.ts +3 -3
  254. package/dist/tools/index.js +5 -3
  255. package/dist/tools/list-files.d.ts +3 -1
  256. package/dist/tools/list-files.js +8 -1
  257. package/dist/tools/list-symbols.d.ts +0 -1
  258. package/dist/tools/list-symbols.js +0 -1
  259. package/dist/tools/memory.d.ts +34 -2
  260. package/dist/tools/memory.js +118 -26
  261. package/dist/tools/notebook.d.ts +69 -0
  262. package/dist/tools/notebook.js +163 -0
  263. package/dist/tools/policy.d.ts +0 -1
  264. package/dist/tools/policy.js +0 -1
  265. package/dist/tools/read-file.d.ts +8 -2
  266. package/dist/tools/read-file.js +19 -2
  267. package/dist/tools/read-image.d.ts +0 -1
  268. package/dist/tools/read-image.js +0 -1
  269. package/dist/tools/read-only.d.ts +0 -1
  270. package/dist/tools/read-only.js +0 -1
  271. package/dist/tools/redact.d.ts +0 -1
  272. package/dist/tools/redact.js +0 -1
  273. package/dist/tools/result-cache.d.ts +0 -1
  274. package/dist/tools/result-cache.js +0 -1
  275. package/dist/tools/run-command.d.ts +0 -1
  276. package/dist/tools/run-command.js +0 -1
  277. package/dist/tools/sandbox-loader.d.ts +0 -1
  278. package/dist/tools/sandbox-loader.js +0 -1
  279. package/dist/tools/search-files.d.ts +5 -3
  280. package/dist/tools/search-files.js +8 -1
  281. package/dist/tools/shared.d.ts +0 -1
  282. package/dist/tools/shared.js +0 -1
  283. package/dist/tools/sub-agent.d.ts +0 -1
  284. package/dist/tools/sub-agent.js +0 -1
  285. package/dist/tools/web-search.d.ts +55 -0
  286. package/dist/tools/web-search.js +131 -0
  287. package/dist/tools/write-file.d.ts +0 -1
  288. package/dist/tools/write-file.js +0 -1
  289. package/dist/types.d.ts +43 -2
  290. package/dist/types.js +0 -1
  291. package/dist/verify/detect.d.ts +0 -1
  292. package/dist/verify/detect.js +0 -1
  293. package/dist/verify/index.d.ts +0 -1
  294. package/dist/verify/index.js +0 -1
  295. package/dist/worktree/branch-ops.d.ts +0 -1
  296. package/dist/worktree/branch-ops.js +0 -1
  297. package/dist/worktree/index.d.ts +0 -1
  298. package/dist/worktree/index.js +0 -1
  299. package/dist/worktree/worktree.d.ts +0 -1
  300. package/dist/worktree/worktree.js +0 -1
  301. package/package.json +4 -2
  302. package/dist/agent/agent.d.ts.map +0 -1
  303. package/dist/agent/agent.js.map +0 -1
  304. package/dist/agent/architect.d.ts.map +0 -1
  305. package/dist/agent/architect.js.map +0 -1
  306. package/dist/agent/cache-hints.d.ts.map +0 -1
  307. package/dist/agent/cache-hints.js.map +0 -1
  308. package/dist/agent/cost-router.d.ts.map +0 -1
  309. package/dist/agent/cost-router.js.map +0 -1
  310. package/dist/agent/index.d.ts.map +0 -1
  311. package/dist/agent/index.js.map +0 -1
  312. package/dist/agent/prompts.d.ts.map +0 -1
  313. package/dist/agent/prompts.js.map +0 -1
  314. package/dist/agent/think-tags.d.ts.map +0 -1
  315. package/dist/agent/think-tags.js.map +0 -1
  316. package/dist/agent/verify.d.ts.map +0 -1
  317. package/dist/agent/verify.js.map +0 -1
  318. package/dist/ai-comments/index.d.ts.map +0 -1
  319. package/dist/ai-comments/index.js.map +0 -1
  320. package/dist/browser/cdp.d.ts.map +0 -1
  321. package/dist/browser/cdp.js.map +0 -1
  322. package/dist/browser/chrome.d.ts.map +0 -1
  323. package/dist/browser/chrome.js.map +0 -1
  324. package/dist/browser/session.d.ts.map +0 -1
  325. package/dist/browser/session.js.map +0 -1
  326. package/dist/checkpoints/index.d.ts.map +0 -1
  327. package/dist/checkpoints/index.js.map +0 -1
  328. package/dist/checkpoints/store.d.ts.map +0 -1
  329. package/dist/checkpoints/store.js.map +0 -1
  330. package/dist/checkpoints/types.d.ts.map +0 -1
  331. package/dist/checkpoints/types.js.map +0 -1
  332. package/dist/code-index/builder.d.ts.map +0 -1
  333. package/dist/code-index/builder.js.map +0 -1
  334. package/dist/code-index/index-store.d.ts.map +0 -1
  335. package/dist/code-index/index-store.js.map +0 -1
  336. package/dist/code-index/parser.d.ts.map +0 -1
  337. package/dist/code-index/parser.js.map +0 -1
  338. package/dist/code-index/types.d.ts.map +0 -1
  339. package/dist/code-index/types.js.map +0 -1
  340. package/dist/config-file.d.ts.map +0 -1
  341. package/dist/config-file.js.map +0 -1
  342. package/dist/config.d.ts.map +0 -1
  343. package/dist/config.js.map +0 -1
  344. package/dist/context/compaction.d.ts.map +0 -1
  345. package/dist/context/compaction.js.map +0 -1
  346. package/dist/context/mask.d.ts.map +0 -1
  347. package/dist/context/mask.js.map +0 -1
  348. package/dist/credentials/index.d.ts.map +0 -1
  349. package/dist/credentials/index.js.map +0 -1
  350. package/dist/credentials/types.d.ts.map +0 -1
  351. package/dist/credentials/types.js.map +0 -1
  352. package/dist/diff/index.d.ts.map +0 -1
  353. package/dist/diff/index.js.map +0 -1
  354. package/dist/diff/unified-diff.d.ts.map +0 -1
  355. package/dist/diff/unified-diff.js.map +0 -1
  356. package/dist/git/auto-commit.d.ts.map +0 -1
  357. package/dist/git/auto-commit.js.map +0 -1
  358. package/dist/git/index.d.ts.map +0 -1
  359. package/dist/git/index.js.map +0 -1
  360. package/dist/hooks/agent-runner.d.ts.map +0 -1
  361. package/dist/hooks/agent-runner.js.map +0 -1
  362. package/dist/hooks/bus.d.ts.map +0 -1
  363. package/dist/hooks/bus.js.map +0 -1
  364. package/dist/hooks/config.d.ts.map +0 -1
  365. package/dist/hooks/config.js.map +0 -1
  366. package/dist/hooks/events.d.ts.map +0 -1
  367. package/dist/hooks/events.js.map +0 -1
  368. package/dist/hooks/index.d.ts.map +0 -1
  369. package/dist/hooks/index.js.map +0 -1
  370. package/dist/hooks/loader.d.ts.map +0 -1
  371. package/dist/hooks/loader.js.map +0 -1
  372. package/dist/hooks/runner.d.ts.map +0 -1
  373. package/dist/hooks/runner.js.map +0 -1
  374. package/dist/hooks/watch-coalescer.d.ts.map +0 -1
  375. package/dist/hooks/watch-coalescer.js.map +0 -1
  376. package/dist/hooks/watch-ignore.d.ts.map +0 -1
  377. package/dist/hooks/watch-ignore.js.map +0 -1
  378. package/dist/hooks/watcher.d.ts.map +0 -1
  379. package/dist/hooks/watcher.js.map +0 -1
  380. package/dist/index.d.ts.map +0 -1
  381. package/dist/index.js.map +0 -1
  382. package/dist/lazy-model.d.ts.map +0 -1
  383. package/dist/lazy-model.js.map +0 -1
  384. package/dist/lint/auto-lint.d.ts.map +0 -1
  385. package/dist/lint/auto-lint.js.map +0 -1
  386. package/dist/lint/index.d.ts.map +0 -1
  387. package/dist/lint/index.js.map +0 -1
  388. package/dist/lsp/client.d.ts.map +0 -1
  389. package/dist/lsp/client.js.map +0 -1
  390. package/dist/lsp/diagnostics.d.ts.map +0 -1
  391. package/dist/lsp/diagnostics.js.map +0 -1
  392. package/dist/lsp/index.d.ts.map +0 -1
  393. package/dist/lsp/index.js.map +0 -1
  394. package/dist/mcp/catalog.d.ts.map +0 -1
  395. package/dist/mcp/catalog.js.map +0 -1
  396. package/dist/mcp/index.d.ts.map +0 -1
  397. package/dist/mcp/index.js.map +0 -1
  398. package/dist/mcp/json-schema-to-zod.d.ts.map +0 -1
  399. package/dist/mcp/json-schema-to-zod.js.map +0 -1
  400. package/dist/mcp/manager.d.ts.map +0 -1
  401. package/dist/mcp/manager.js.map +0 -1
  402. package/dist/mcp/marketplace-types.d.ts.map +0 -1
  403. package/dist/mcp/marketplace-types.js.map +0 -1
  404. package/dist/mcp/marketplace.d.ts.map +0 -1
  405. package/dist/mcp/marketplace.js.map +0 -1
  406. package/dist/mcp/mcp-client.d.ts.map +0 -1
  407. package/dist/mcp/mcp-client.js.map +0 -1
  408. package/dist/mcp/mcp-config.d.ts.map +0 -1
  409. package/dist/mcp/mcp-config.js.map +0 -1
  410. package/dist/mcp/registry.d.ts.map +0 -1
  411. package/dist/mcp/registry.js.map +0 -1
  412. package/dist/memory/memory-store.d.ts.map +0 -1
  413. package/dist/memory/memory-store.js.map +0 -1
  414. package/dist/model-alias.d.ts.map +0 -1
  415. package/dist/model-alias.js.map +0 -1
  416. package/dist/model-catalog.d.ts.map +0 -1
  417. package/dist/model-catalog.js.map +0 -1
  418. package/dist/model-list.d.ts.map +0 -1
  419. package/dist/model-list.js.map +0 -1
  420. package/dist/orchestrator/board-tools.d.ts.map +0 -1
  421. package/dist/orchestrator/board-tools.js.map +0 -1
  422. package/dist/orchestrator/board.d.ts.map +0 -1
  423. package/dist/orchestrator/board.js.map +0 -1
  424. package/dist/orchestrator/index.d.ts.map +0 -1
  425. package/dist/orchestrator/index.js.map +0 -1
  426. package/dist/orchestrator/orchestrator.d.ts.map +0 -1
  427. package/dist/orchestrator/orchestrator.js.map +0 -1
  428. package/dist/orchestrator/router.d.ts.map +0 -1
  429. package/dist/orchestrator/router.js.map +0 -1
  430. package/dist/orchestrator/specialists-registry.d.ts.map +0 -1
  431. package/dist/orchestrator/specialists-registry.js.map +0 -1
  432. package/dist/orchestrator/specialists.d.ts.map +0 -1
  433. package/dist/orchestrator/specialists.js.map +0 -1
  434. package/dist/orchestrator/types.d.ts.map +0 -1
  435. package/dist/orchestrator/types.js.map +0 -1
  436. package/dist/plugins/index.d.ts.map +0 -1
  437. package/dist/plugins/index.js.map +0 -1
  438. package/dist/plugins/install.d.ts.map +0 -1
  439. package/dist/plugins/install.js.map +0 -1
  440. package/dist/plugins/loader.d.ts.map +0 -1
  441. package/dist/plugins/loader.js.map +0 -1
  442. package/dist/policy/audit.d.ts.map +0 -1
  443. package/dist/policy/audit.js.map +0 -1
  444. package/dist/policy/policy.d.ts.map +0 -1
  445. package/dist/policy/policy.js.map +0 -1
  446. package/dist/policy/proxy.d.ts.map +0 -1
  447. package/dist/policy/proxy.js.map +0 -1
  448. package/dist/pricing.d.ts.map +0 -1
  449. package/dist/pricing.js.map +0 -1
  450. package/dist/providers.d.ts.map +0 -1
  451. package/dist/providers.js.map +0 -1
  452. package/dist/repomap/index.d.ts.map +0 -1
  453. package/dist/repomap/index.js.map +0 -1
  454. package/dist/repomap/repo-map.d.ts.map +0 -1
  455. package/dist/repomap/repo-map.js.map +0 -1
  456. package/dist/semantic/chunker.d.ts.map +0 -1
  457. package/dist/semantic/chunker.js.map +0 -1
  458. package/dist/semantic/embedder.d.ts.map +0 -1
  459. package/dist/semantic/embedder.js.map +0 -1
  460. package/dist/semantic/semantic-index.d.ts.map +0 -1
  461. package/dist/semantic/semantic-index.js.map +0 -1
  462. package/dist/semantic/vector-store.d.ts.map +0 -1
  463. package/dist/semantic/vector-store.js.map +0 -1
  464. package/dist/sessions/index.d.ts.map +0 -1
  465. package/dist/sessions/index.js.map +0 -1
  466. package/dist/sessions/session-export.d.ts.map +0 -1
  467. package/dist/sessions/session-export.js.map +0 -1
  468. package/dist/sessions/session-store.d.ts.map +0 -1
  469. package/dist/sessions/session-store.js.map +0 -1
  470. package/dist/sessions/watch.d.ts.map +0 -1
  471. package/dist/sessions/watch.js.map +0 -1
  472. package/dist/settings-export.d.ts.map +0 -1
  473. package/dist/settings-export.js.map +0 -1
  474. package/dist/skills/activator.d.ts.map +0 -1
  475. package/dist/skills/activator.js.map +0 -1
  476. package/dist/skills/index.d.ts.map +0 -1
  477. package/dist/skills/index.js.map +0 -1
  478. package/dist/skills/loader.d.ts.map +0 -1
  479. package/dist/skills/loader.js.map +0 -1
  480. package/dist/skills/marketplace-types.d.ts.map +0 -1
  481. package/dist/skills/marketplace-types.js.map +0 -1
  482. package/dist/skills/marketplace.d.ts.map +0 -1
  483. package/dist/skills/marketplace.js.map +0 -1
  484. package/dist/skills/parser.d.ts.map +0 -1
  485. package/dist/skills/parser.js.map +0 -1
  486. package/dist/skills/types.d.ts.map +0 -1
  487. package/dist/skills/types.js.map +0 -1
  488. package/dist/specs/generate.d.ts.map +0 -1
  489. package/dist/specs/generate.js.map +0 -1
  490. package/dist/specs/index.d.ts.map +0 -1
  491. package/dist/specs/index.js.map +0 -1
  492. package/dist/specs/store.d.ts.map +0 -1
  493. package/dist/specs/store.js.map +0 -1
  494. package/dist/specs/tasks-parser.d.ts.map +0 -1
  495. package/dist/specs/tasks-parser.js.map +0 -1
  496. package/dist/specs/types.d.ts.map +0 -1
  497. package/dist/specs/types.js.map +0 -1
  498. package/dist/steering/glob.d.ts.map +0 -1
  499. package/dist/steering/glob.js.map +0 -1
  500. package/dist/steering/index.d.ts.map +0 -1
  501. package/dist/steering/index.js.map +0 -1
  502. package/dist/steering/loader.d.ts.map +0 -1
  503. package/dist/steering/loader.js.map +0 -1
  504. package/dist/steering/project-instructions.d.ts.map +0 -1
  505. package/dist/steering/project-instructions.js.map +0 -1
  506. package/dist/steering/select.d.ts.map +0 -1
  507. package/dist/steering/select.js.map +0 -1
  508. package/dist/steering/types.d.ts.map +0 -1
  509. package/dist/steering/types.js.map +0 -1
  510. package/dist/structured/index.d.ts.map +0 -1
  511. package/dist/structured/index.js.map +0 -1
  512. package/dist/structured/retry.d.ts.map +0 -1
  513. package/dist/structured/retry.js.map +0 -1
  514. package/dist/structured/schema.d.ts.map +0 -1
  515. package/dist/structured/schema.js.map +0 -1
  516. package/dist/tools/browser-tools.d.ts.map +0 -1
  517. package/dist/tools/browser-tools.js.map +0 -1
  518. package/dist/tools/codebase-search.d.ts.map +0 -1
  519. package/dist/tools/codebase-search.js.map +0 -1
  520. package/dist/tools/command-allow.d.ts.map +0 -1
  521. package/dist/tools/command-allow.js.map +0 -1
  522. package/dist/tools/edit-file.d.ts.map +0 -1
  523. package/dist/tools/edit-file.js.map +0 -1
  524. package/dist/tools/fetch-url.d.ts.map +0 -1
  525. package/dist/tools/fetch-url.js.map +0 -1
  526. package/dist/tools/find-references.d.ts.map +0 -1
  527. package/dist/tools/find-references.js.map +0 -1
  528. package/dist/tools/find-symbol.d.ts.map +0 -1
  529. package/dist/tools/find-symbol.js.map +0 -1
  530. package/dist/tools/index.d.ts.map +0 -1
  531. package/dist/tools/index.js.map +0 -1
  532. package/dist/tools/list-files.d.ts.map +0 -1
  533. package/dist/tools/list-files.js.map +0 -1
  534. package/dist/tools/list-symbols.d.ts.map +0 -1
  535. package/dist/tools/list-symbols.js.map +0 -1
  536. package/dist/tools/memory.d.ts.map +0 -1
  537. package/dist/tools/memory.js.map +0 -1
  538. package/dist/tools/policy.d.ts.map +0 -1
  539. package/dist/tools/policy.js.map +0 -1
  540. package/dist/tools/read-file.d.ts.map +0 -1
  541. package/dist/tools/read-file.js.map +0 -1
  542. package/dist/tools/read-image.d.ts.map +0 -1
  543. package/dist/tools/read-image.js.map +0 -1
  544. package/dist/tools/read-only.d.ts.map +0 -1
  545. package/dist/tools/read-only.js.map +0 -1
  546. package/dist/tools/redact.d.ts.map +0 -1
  547. package/dist/tools/redact.js.map +0 -1
  548. package/dist/tools/result-cache.d.ts.map +0 -1
  549. package/dist/tools/result-cache.js.map +0 -1
  550. package/dist/tools/run-command.d.ts.map +0 -1
  551. package/dist/tools/run-command.js.map +0 -1
  552. package/dist/tools/sandbox-loader.d.ts.map +0 -1
  553. package/dist/tools/sandbox-loader.js.map +0 -1
  554. package/dist/tools/search-files.d.ts.map +0 -1
  555. package/dist/tools/search-files.js.map +0 -1
  556. package/dist/tools/shared.d.ts.map +0 -1
  557. package/dist/tools/shared.js.map +0 -1
  558. package/dist/tools/sub-agent.d.ts.map +0 -1
  559. package/dist/tools/sub-agent.js.map +0 -1
  560. package/dist/tools/write-file.d.ts.map +0 -1
  561. package/dist/tools/write-file.js.map +0 -1
  562. package/dist/types.d.ts.map +0 -1
  563. package/dist/types.js.map +0 -1
  564. package/dist/verify/detect.d.ts.map +0 -1
  565. package/dist/verify/detect.js.map +0 -1
  566. package/dist/verify/index.d.ts.map +0 -1
  567. package/dist/verify/index.js.map +0 -1
  568. package/dist/worktree/branch-ops.d.ts.map +0 -1
  569. package/dist/worktree/branch-ops.js.map +0 -1
  570. package/dist/worktree/index.d.ts.map +0 -1
  571. package/dist/worktree/index.js.map +0 -1
  572. package/dist/worktree/worktree.d.ts.map +0 -1
  573. package/dist/worktree/worktree.js.map +0 -1
package/LICENSE CHANGED
@@ -1,21 +1,44 @@
1
- MIT License
2
-
3
- Copyright (c) 2025 IKarmic
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ IKarmic Forge Core: Proprietary License
2
+
3
+ Copyright (c) 2025-2026 IKarmic. All rights reserved.
4
+
5
+ This license covers "@ikarmic/forge-core" version 5.0.0 and later
6
+ (the "Software"). Earlier versions (4.5.0 and before) were released under
7
+ the MIT License and stay under it.
8
+
9
+ 1. Grant. IKarmic grants you a non-exclusive, non-transferable, royalty-free
10
+ licence to install and run the Software, in the form distributed by
11
+ IKarmic, as a dependency of the IKarmic Forge VS Code extension and the
12
+ IKarmic Forge command line tool (the "Forge Clients"), for any purpose,
13
+ including commercial use.
14
+
15
+ 2. Restrictions. You may not, and may not let others:
16
+ a. copy, modify, translate or create derivative works of the Software;
17
+ b. redistribute, sublicense, sell, lease or host the Software, alone or
18
+ bundled in another product, except as part of an unmodified Forge
19
+ Client distributed by IKarmic;
20
+ c. reverse engineer, decompile or disassemble the Software, except to the
21
+ extent applicable law forbids this restriction;
22
+ d. use the Software to build a product or service that competes with the
23
+ Forge Clients or with IKarmic's paid editions;
24
+ e. remove or alter any copyright, licence or attribution notice.
25
+
26
+ 3. Enterprise features. Features marked as enterprise features need a valid
27
+ licence key from IKarmic. Using them without one is not permitted.
28
+
29
+ 4. Ownership. IKarmic and its licensors keep all rights not granted here.
30
+ No right is granted by implication or estoppel.
31
+
32
+ 5. Open-source Forge Clients. The Forge Clients' own source code is licensed
33
+ separately under AGPL-3.0-only (see the LICENSE and NOTICE files of the
34
+ Forge Clients). That licence does not extend to this Software, and
35
+ nothing in it lets you redistribute this Software.
36
+
37
+ 6. No warranty. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
38
+ KIND. IKARMIC IS NOT LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY
39
+ ARISING FROM THE SOFTWARE OR ITS USE, TO THE EXTENT THE LAW ALLOWS.
40
+
41
+ 7. Termination. This licence ends automatically if you break it. On
42
+ termination you must stop using and delete all copies of the Software.
43
+
44
+ Contact: ikarmicaiss@gmail.com
package/README.md CHANGED
@@ -14,7 +14,7 @@ The agent engine for [IKarmic AI Forge](https://github.com/ikarmic/forge). Share
14
14
  - **Cost tracking**: `lookupPricing` + `computeCostUsd` against a built-in pricing table; surfaced as `cost` events and `costUsd` on `AgentRunResult`.
15
15
  - **Secret redaction**: `redact()` scrubs provider keys, JWTs, PEM keys, and `.env`-style secrets from tool output before the model sees them.
16
16
  - **Tool result cache**: `ToolResultCache` (LRU + TTL, never caches destructive tools) survives across turns within a session.
17
- - **Project memory**: `buildMemoryBlock()` auto-loads `.forge/MEMORY.md` into the system prompt; `memory_read` / `memory_write` tools let the agent record conventions mid-run.
17
+ - **Project memory**: `buildMemoryBlock()` auto-loads `.forge/MEMORY.md` into the system prompt; `memory_read` / `memory_write` / `memory_forget` tools let the agent record and retire conventions mid-run (typed sections, relevance-ranked injection, stale-ref markers).
18
18
  - **Plan mode**: `AgentConfig.planMode` runs a single-turn, tool-free pass that emits a numbered plan as text. Pair with an approve/edit/cancel flow.
19
19
  - **Context compaction**: opt-in summarization of older turns when approaching the model's context window. `AgentConfig.enableCompaction` toggles it; the rest are knobs.
20
20
  - **Skills system**: `discoverSkills()` finds `SKILL.md` files in `./skills/`, `./.forge/skills/`, `~/.forge/skills/`. `selectSkills()` + `composeSkillsPrompt()` score and inject the top matches for the current task.
@@ -154,4 +154,4 @@ MCP tools appear in the agent's prompt with fully-qualified names like `mcp__fil
154
154
 
155
155
  ## License
156
156
 
157
- MIT
157
+ Proprietary, free to run with the Forge extension and CLI. See [LICENSE](LICENSE). Versions 4.5.0 and earlier stay MIT.
@@ -58,4 +58,3 @@ export declare class Agent {
58
58
  * we don't want to fail just because the user typed a stale name.
59
59
  */
60
60
  export declare function applySandbox(tools: ToolDefinition[], sandbox: ToolSandbox | undefined): ToolDefinition[];
61
- //# sourceMappingURL=agent.d.ts.map
@@ -11,8 +11,11 @@ import { createFileAuditSink } from '../policy/audit.js';
11
11
  import { applyPolicy, getOrgPolicy } from '../policy/policy.js';
12
12
  import { createBrowserTools } from '../tools/browser-tools.js';
13
13
  import { createCodebaseSearchTool } from '../tools/codebase-search.js';
14
+ import { createGitHubTools, githubFromEnv } from '../github/github-tools.js';
15
+ import { createWebSearchTool, webSearchFromEnv } from '../tools/web-search.js';
14
16
  import { embedderFromEnv } from '../semantic/embedder.js';
15
17
  import { DEFAULT_VERIFY_RETRIES, failureMessage, runVerification } from './verify.js';
18
+ import { LoopGuard, resultKeyOf } from './loop-guard.js';
16
19
  import { isListedCommand } from '../tools/command-allow.js';
17
20
  import { createLanguageModel } from '../providers.js';
18
21
  import { BUILTIN_TOOLS } from '../tools/index.js';
@@ -22,17 +25,18 @@ import { redact } from '../tools/redact.js';
22
25
  import { composeSkillsPrompt, selectSkills } from '../skills/activator.js';
23
26
  import { MAX_TOOL_INJECTIONS, selectAtStart, selectOnToolTouch, toWorkspaceRelative, wrapSteering } from '../steering/select.js';
24
27
  import { applyCacheHints } from './cache-hints.js';
28
+ import { attachmentParts, formatBytes, mediaPartTokens } from '../attachments.js';
25
29
  import { CONTINUE_PROMPT, DEFAULT_PLAN_MODE_SUFFIX, DEFAULT_SPEC_MODE_SUFFIX, DEFAULT_SYSTEM_PROMPT } from './prompts.js';
26
30
  /** Read-only tool names whose output flows through the redactor. */
27
31
  const DEFAULT_MAX_CONTINUATIONS = 3;
28
32
  export const DEFAULT_MAX_DURATION_MS = 10 * 60 * 1000;
29
33
  const REDACTABLE_TOOLS = new Set(['read_file', 'search_files', 'list_files']);
30
34
  /** Tools whose successful `path` argument can trigger mid-run fileMatch steering. */
31
- const STEERING_FILE_TOOLS = new Set(['read_file', 'write_file', 'edit_file']);
35
+ const STEERING_FILE_TOOLS = new Set(['read_file', 'write_file', 'edit_file', 'edit_notebook']);
32
36
  /** Tools that change a file, so auto-lint checks their `path` afterwards. */
33
- const FILE_WRITE_TOOLS = new Set(['write_file', 'edit_file']);
37
+ const FILE_WRITE_TOOLS = new Set(['write_file', 'edit_file', 'edit_notebook']);
34
38
  /** Pure reads whose results may be reused within a run. Every other tool invalidates the cache. */
35
- const CACHEABLE_TOOLS = new Set(['read_file', 'read_image', 'list_files', 'search_files', 'find_symbol', 'list_symbols', 'find_references', 'codebase_search', 'memory_read', 'fetch_url']);
39
+ const CACHEABLE_TOOLS = new Set(['read_file', 'read_image', 'list_files', 'search_files', 'find_symbol', 'list_symbols', 'find_references', 'codebase_search', 'memory_read', 'fetch_url', 'web_search']);
36
40
  /**
37
41
  * The agent: orchestrates the model + tool loop. One Agent instance is
38
42
  * single-use; create a new one per user task.
@@ -61,11 +65,17 @@ export class Agent {
61
65
  this.browser = new BrowserSession(config.browser === true ? {} : config.browser);
62
66
  allTools.push(...createBrowserTools(this.browser));
63
67
  }
68
+ const github = config.github === true ? githubFromEnv() : config.github;
69
+ if (github)
70
+ allTools.push(...createGitHubTools(github));
71
+ const webSearch = config.webSearch === true ? webSearchFromEnv() : config.webSearch;
72
+ if (webSearch)
73
+ allTools.push(createWebSearchTool(webSearch));
64
74
  if (config.semanticSearch) {
65
75
  allTools.push(createCodebaseSearchTool(config.semanticSearch.embedder ?? embedderFromEnv()));
66
76
  }
67
77
  const memoryFiltered = config.disableMemory
68
- ? allTools.filter((t) => t.name !== 'memory_read' && t.name !== 'memory_write')
78
+ ? allTools.filter((t) => t.name !== 'memory_read' && t.name !== 'memory_write' && t.name !== 'memory_forget')
69
79
  : allTools;
70
80
  const sandboxedTools = applySandbox(memoryFiltered, config.toolSandbox);
71
81
  this.tools = this.wrapToolsWithCache(sandboxedTools, config.cacheSize, config.cacheTtlMs, config.disableCache);
@@ -86,7 +96,7 @@ export class Agent {
86
96
  const cfg = this.checkpoints?.captureBeforeTools;
87
97
  if (!cfg) {
88
98
  // Default: file-mutating tools + run_command (which can mutate via shell).
89
- return new Set(['write_file', 'edit_file', 'run_command']);
99
+ return new Set(['write_file', 'edit_file', 'edit_notebook', 'run_command']);
90
100
  }
91
101
  return new Set(cfg);
92
102
  }
@@ -163,6 +173,13 @@ export class Agent {
163
173
  const messages = options.history
164
174
  ? [...options.history, { role: 'user', content: userContent }]
165
175
  : await buildInitialMessages(this.config, options.task, this.skills, startSteering.system, userContent);
176
+ if (options.attachments && options.attachments.length > 0) {
177
+ // Attached files ride in this turn's user message as native parts (see attachments.ts).
178
+ messages[messages.length - 1] = {
179
+ role: 'user',
180
+ content: [{ type: 'text', text: userContent }, ...attachmentParts(options.attachments)],
181
+ };
182
+ }
166
183
  // Plan mode: hard-cap iterations to 1 and add a system prompt suffix
167
184
  // telling the model to emit a plan as text and stop. Spec mode: allow
168
185
  // up to `specMaxIterations` turns (default 15) so the model can
@@ -200,6 +217,14 @@ export class Agent {
200
217
  let model = modelFactory(currentModelConfig);
201
218
  let stepPricing = this.pricing;
202
219
  let lastToolNames = [];
220
+ // Stops a run that repeats one identical tool call (off unless `loopGuardThreshold` is set).
221
+ const loopGuard = new LoopGuard(this.config.loopGuardThreshold ?? 0);
222
+ let loopTripped;
223
+ // Every call outcome feeds the guard (results, errors, invalid or denied calls), so a different call in between resets the streak.
224
+ const trackLoop = (tool, args, outcome) => {
225
+ if (loopGuard.record(tool, args, resultKeyOf(outcome)) && !loopTripped)
226
+ loopTripped = { tool, count: loopGuard.streak };
227
+ };
203
228
  // Verify loop state: only run checks when the run actually edited files.
204
229
  let editedSinceVerify = false;
205
230
  const editedFiles = new Set();
@@ -218,6 +243,7 @@ export class Agent {
218
243
  parentModel: this.config.model,
219
244
  ...(this.config.commandRunner ? { commandRunner: this.config.commandRunner } : {}),
220
245
  ...(abortSignal ? { abortSignal } : {}),
246
+ ...(this.config.memoryMaxBodyChars !== undefined ? { memoryMaxBodyChars: this.config.memoryMaxBodyChars } : {}),
221
247
  };
222
248
  // Emit initial cache stats so the UI knows the cache is wired up.
223
249
  emit({ type: 'cache_stats', ...this.cache.getStats() });
@@ -466,19 +492,22 @@ export class Agent {
466
492
  if (!def) {
467
493
  currentToolResults.push(toolResultError(call.toolCallId, call.toolName, `Unknown tool: ${call.toolName}`));
468
494
  emit({ type: 'tool_result', name: call.toolName, id: call.toolCallId, result: `Unknown tool`, isError: true });
495
+ trackLoop(call.toolName, call.input, 'unknown tool');
469
496
  continue;
470
497
  }
471
498
  const argsParsed = def.parameters.safeParse(call.input);
472
499
  if (!argsParsed.success) {
473
500
  const message = `Invalid arguments for ${call.toolName}: ${argsParsed.error.message}`;
501
+ trackLoop(call.toolName, call.input, message);
474
502
  currentToolResults.push(toolResultError(call.toolCallId, call.toolName, message));
475
503
  emit({ type: 'tool_result', name: call.toolName, id: call.toolCallId, result: message, isError: true });
476
504
  continue;
477
505
  }
478
- const approval = await this.requestApproval(def, call.toolCallId, argsParsed.data, abortSignal);
506
+ const approval = await this.requestApproval(def, call.toolCallId, argsParsed.data, abortSignal, ctx);
479
507
  this.audit?.record({ event: 'tool_call', tool: call.toolName, args: approval.args ?? argsParsed.data, approved: approval.approved, auto: this.config.auto === true }, auditCtx);
480
508
  if (!approval.approved) {
481
509
  const denial = approval.note ? `Denied by user. ${approval.note}` : `Denied by user.`;
510
+ trackLoop(call.toolName, argsParsed.data, denial);
482
511
  currentToolResults.push(toolResult(call.toolCallId, call.toolName, denial));
483
512
  emit({ type: 'tool_result', name: call.toolName, id: call.toolCallId, result: denial, isError: false });
484
513
  continue;
@@ -490,6 +519,7 @@ export class Agent {
490
519
  const edited = def.parameters.safeParse(approval.args);
491
520
  if (!edited.success) {
492
521
  const message = `Invalid edited arguments for ${call.toolName}: ${edited.error.message}`;
522
+ trackLoop(call.toolName, approval.args, message);
493
523
  currentToolResults.push(toolResultError(call.toolCallId, call.toolName, message));
494
524
  emit({ type: 'tool_result', name: call.toolName, id: call.toolCallId, result: message, isError: true });
495
525
  continue;
@@ -545,7 +575,7 @@ export class Agent {
545
575
  redactedCount = scrubbed.count;
546
576
  }
547
577
  this.audit?.record({ event: 'tool_result', tool: call.toolName, isError: false, durationMs: Date.now() - toolStartedAt }, auditCtx);
548
- if (call.toolName === 'write_file' || call.toolName === 'edit_file')
578
+ if (FILE_WRITE_TOOLS.has(call.toolName))
549
579
  editedSinceVerify = true;
550
580
  const editedPath = toolArgs.path;
551
581
  if (FILE_WRITE_TOOLS.has(call.toolName) && typeof editedPath === 'string')
@@ -569,6 +599,7 @@ export class Agent {
569
599
  : { result: finalResult, userNote: approval.note };
570
600
  }
571
601
  currentToolResults.push(toolResult(call.toolCallId, call.toolName, finalResult));
602
+ trackLoop(call.toolName, toolArgs, finalResult);
572
603
  if (STEERING_FILE_TOOLS.has(call.toolName)) {
573
604
  const touched = toolArgs.path;
574
605
  if (typeof touched === 'string')
@@ -600,6 +631,7 @@ export class Agent {
600
631
  const message = errorMessageOf(err);
601
632
  currentToolResults.push(toolResultError(call.toolCallId, call.toolName, message));
602
633
  emit({ type: 'tool_result', name: call.toolName, id: call.toolCallId, result: message, isError: true });
634
+ trackLoop(call.toolName, toolArgs, `error:${message}`);
603
635
  if (this.hooks) {
604
636
  await this.hooks.dispatch({
605
637
  type: 'PostToolUse',
@@ -619,6 +651,11 @@ export class Agent {
619
651
  }
620
652
  for (const m of toolResultMessages)
621
653
  messages.push(m);
654
+ if (loopTripped) {
655
+ emit({ type: 'loop_detected', tool: loopTripped.tool, count: loopTripped.count });
656
+ reason = 'loop_detected';
657
+ break;
658
+ }
622
659
  // Mid-run fileMatch steering: one extra user message per round, each doc once per run.
623
660
  if (steeringDocs.length > 0 && touchedPaths.length > 0) {
624
661
  const injected = [];
@@ -846,11 +883,15 @@ export class Agent {
846
883
  return { ...t, execute: invalidating };
847
884
  });
848
885
  }
849
- async requestApproval(def, id, args, abortSignal) {
886
+ async requestApproval(def, id, args, abortSignal, ctx) {
850
887
  // Read-only tools the user chose not to be asked about (never a destructive one).
851
888
  if (!def.destructive && this.config.autoApproveTools?.includes(def.name)) {
852
889
  return { approved: true };
853
890
  }
891
+ // Memory writes the user chose not to be asked about. memory_forget is deleted data: always asked.
892
+ if (def.name === 'memory_write' && this.config.memoryAutoApproveWrites) {
893
+ return { approved: true };
894
+ }
854
895
  // A plain command the user already said "always allow" for: exact match only (see command-allow.ts).
855
896
  if (def.name === 'run_command' && this.config.autoApproveCommands?.length && isListedCommand(args, this.config.autoApproveCommands)) {
856
897
  return { approved: true };
@@ -859,12 +900,22 @@ export class Agent {
859
900
  if (auto && !(def.destructive && !this.config.allowDestructive)) {
860
901
  return { approved: true };
861
902
  }
903
+ let preview;
904
+ if (def.previewApproval && ctx) {
905
+ try {
906
+ preview = (await def.previewApproval(args, ctx)) || undefined;
907
+ }
908
+ catch {
909
+ // A failed preview never blocks the approval prompt.
910
+ }
911
+ }
862
912
  const request = {
863
913
  name: def.name,
864
914
  id,
865
915
  args,
866
916
  destructive: def.destructive === true,
867
917
  description: def.description,
918
+ ...(preview ? { preview } : {}),
868
919
  };
869
920
  if (this.config.approve) {
870
921
  // Stop must work while a prompt is open: an unanswered approval never resolves on its own,
@@ -907,12 +958,12 @@ function toAiSdkTools(tools) {
907
958
  return out;
908
959
  }
909
960
  function toolResult(toolCallId, toolName, result) {
910
- // Detect multimodal content (read_image returns a `dataUrl` +
911
- // `mime`). When found, attach the image so vision-capable models can
912
- // actually see it instead of just reading the base64 string. Providers
913
- // that don't support this will gracefully fall back to the text value.
914
- const image = extractImageAttachment(result);
915
- if (image) {
961
+ // Detect multimodal content (read_image returns an image, read_file a PDF, each as
962
+ // `dataUrl` + `mime`). When found, attach the bytes so vision and document-capable
963
+ // models see them instead of a base64 string. Providers that don't support this
964
+ // gracefully fall back to the text value.
965
+ const media = extractMediaAttachment(result);
966
+ if (media) {
916
967
  return {
917
968
  type: 'tool-result',
918
969
  toolCallId,
@@ -920,8 +971,10 @@ function toolResult(toolCallId, toolName, result) {
920
971
  output: {
921
972
  type: 'content',
922
973
  value: [
923
- { type: 'text', text: image.summary },
924
- { type: 'image-data', data: image.dataUrl, mediaType: image.mime },
974
+ { type: 'text', text: media.summary },
975
+ media.mime.startsWith('image/')
976
+ ? { type: 'image-data', data: media.dataUrl, mediaType: media.mime }
977
+ : { type: 'file', data: { type: 'data', data: media.base64 }, mediaType: media.mime, ...(media.filename ? { filename: media.filename } : {}) },
925
978
  ],
926
979
  },
927
980
  };
@@ -932,11 +985,10 @@ function toolResultError(toolCallId, toolName, message) {
932
985
  return { type: 'tool-result', toolCallId, toolName, output: { type: 'error-text', value: message } };
933
986
  }
934
987
  /**
935
- * Inspect a tool result for multimodal content. Returns the attachment
936
- * to include in `experimental_content` if the result looks like an
937
- * image (dataUrl + mime present); null otherwise.
988
+ * Inspect a tool result for multimodal content: an image or a PDF (dataUrl + mime
989
+ * present). Returns null otherwise.
938
990
  */
939
- function extractImageAttachment(result) {
991
+ function extractMediaAttachment(result) {
940
992
  if (!result || typeof result !== 'object')
941
993
  return null;
942
994
  const r = result;
@@ -946,19 +998,17 @@ function extractImageAttachment(result) {
946
998
  return null;
947
999
  if (!dataUrl.startsWith('data:'))
948
1000
  return null;
1001
+ if (!mime.startsWith('image/') && mime !== 'application/pdf')
1002
+ return null;
949
1003
  // Best-effort summary line so the model has something textual
950
- // alongside the image describing what it's looking at.
1004
+ // alongside the media describing what it's looking at.
951
1005
  const bytes = typeof r.bytes === 'number' ? r.bytes : 0;
952
1006
  const path = typeof r.path === 'string' ? r.path : '<unknown>';
953
- const summary = `Image attached: ${mime} (${formatBytes(bytes)}) at ${path}`;
954
- return { dataUrl, mime, summary };
955
- }
956
- function formatBytes(n) {
957
- if (n < 1024)
958
- return `${n} B`;
959
- if (n < 1024 * 1024)
960
- return `${(n / 1024).toFixed(1)} KB`;
961
- return `${(n / 1024 / 1024).toFixed(2)} MB`;
1007
+ const what = mime.startsWith('image/') ? 'Image' : 'Document';
1008
+ const summary = `${what} attached: ${mime} (${formatBytes(bytes)}) at ${path}`;
1009
+ const comma = dataUrl.indexOf(',');
1010
+ const filename = typeof r.path === 'string' ? r.path.split(/[\\/]/).pop() : undefined;
1011
+ return { dataUrl, base64: dataUrl.slice(comma + 1), mime, ...(filename ? { filename } : {}), summary };
962
1012
  }
963
1013
  function errorMessageOf(err) {
964
1014
  if (err instanceof Error)
@@ -1014,7 +1064,7 @@ async function buildInitialMessages(config, task, skills, steeringSystem = [], u
1014
1064
  let memoryBlock = '';
1015
1065
  if (!config.disableMemory) {
1016
1066
  try {
1017
- memoryBlock = await buildMemoryBlock(cwd, config.memoryInjectionBudget);
1067
+ memoryBlock = await buildMemoryBlock(cwd, config.memoryInjectionBudget, { task });
1018
1068
  }
1019
1069
  catch {
1020
1070
  // Memory load failure shouldn't kill a run: just skip.
@@ -1081,9 +1131,11 @@ function estimateNextPromptTokens(messages) {
1081
1131
  if (typeof text === 'string')
1082
1132
  total += Math.ceil(text.length / 4);
1083
1133
  }
1134
+ else {
1135
+ total += mediaPartTokens(part);
1136
+ }
1084
1137
  }
1085
1138
  }
1086
1139
  }
1087
1140
  return total;
1088
1141
  }
1089
- //# sourceMappingURL=agent.js.map
@@ -4,6 +4,7 @@
4
4
  * normal tools (phase 2). Two ordinary Agent runs; the loop is unchanged.
5
5
  */
6
6
  import type { ModelMessage } from 'ai';
7
+ import type { Attachment } from '../attachments.js';
7
8
  import type { AgentConfig, AgentEvent, AgentRunResult, ModelConfig } from '../types.js';
8
9
  export interface ArchitectOptions {
9
10
  task: string;
@@ -12,6 +13,8 @@ export interface ArchitectOptions {
12
13
  editorModel: ModelConfig;
13
14
  /** Prior conversation, given to both phases. */
14
15
  history?: ModelMessage[];
16
+ /** Files attached to this turn, given to both phases. */
17
+ attachments?: Attachment[];
15
18
  /** Interactive approval of the plan. Omit to apply it without asking (auto mode). */
16
19
  approvePlan?: (plan: string) => Promise<{
17
20
  approved: boolean;
@@ -42,4 +45,3 @@ export declare function editorLimits(base: AgentConfig, architect: {
42
45
  };
43
46
  export declare function editorTask(task: string, plan: string): string;
44
47
  export declare function runArchitect(opts: ArchitectOptions): Promise<AgentRunResult>;
45
- //# sourceMappingURL=architect.d.ts.map
@@ -54,6 +54,7 @@ export async function runArchitect(opts) {
54
54
  const runOptions = (task, history) => ({
55
55
  task,
56
56
  ...(history ? { history } : {}),
57
+ ...(opts.attachments && opts.attachments.length > 0 ? { attachments: opts.attachments } : {}),
57
58
  ...(opts.onEvent ? { onEvent: opts.onEvent } : {}),
58
59
  ...(opts.abortSignal ? { abortSignal: opts.abortSignal } : {}),
59
60
  });
@@ -90,4 +91,3 @@ export async function runArchitect(opts) {
90
91
  costKnown: architect.costKnown && editor.costKnown,
91
92
  };
92
93
  }
93
- //# sourceMappingURL=architect.js.map
@@ -13,4 +13,3 @@ import type { ModelMessage } from 'ai';
13
13
  import type { ModelConfig } from '../types.js';
14
14
  export declare function supportsCacheHints(model: ModelConfig): boolean;
15
15
  export declare function applyCacheHints(messages: ModelMessage[], model: ModelConfig): ModelMessage[];
16
- //# sourceMappingURL=cache-hints.d.ts.map
@@ -28,4 +28,3 @@ export function applyCacheHints(messages, model) {
28
28
  out[last] = withHint(out[last], hint);
29
29
  return out;
30
30
  }
31
- //# sourceMappingURL=cache-hints.js.map
@@ -9,4 +9,3 @@ export declare function createExploreEditRouter(models: {
9
9
  strong: ModelConfig;
10
10
  cheap: ModelConfig;
11
11
  }): ModelRouter;
12
- //# sourceMappingURL=cost-router.d.ts.map
@@ -8,6 +8,8 @@ const READ_ONLY_TOOLS = new Set([
8
8
  'read_image',
9
9
  'memory_read',
10
10
  'fetch_url',
11
+ 'github_pr_read',
12
+ 'web_search',
11
13
  ]);
12
14
  export function createExploreEditRouter(models) {
13
15
  return ({ iteration, lastToolNames }) => {
@@ -16,4 +18,3 @@ export function createExploreEditRouter(models) {
16
18
  return lastToolNames.every((n) => READ_ONLY_TOOLS.has(n)) ? models.cheap : models.strong;
17
19
  };
18
20
  }
19
- //# sourceMappingURL=cost-router.js.map
@@ -0,0 +1,7 @@
1
+ import type { LanguageModel } from 'ai';
2
+ import type { ModelConfig } from '../types.js';
3
+ /**
4
+ * Rewrite a draft chat message into a clearer request using `model` (typically the cheap model).
5
+ * Never throws: an empty input, a missing model, a model error or an empty reply all return `input` unchanged.
6
+ */
7
+ export declare function enhancePrompt(input: string, model: ModelConfig | undefined, modelFactory?: (cfg: ModelConfig) => LanguageModel): Promise<string>;
@@ -0,0 +1,30 @@
1
+ import { generateText } from 'ai';
2
+ import { createLanguageModel } from '../providers.js';
3
+ import { stripThinkTags } from './think-tags.js';
4
+ const ENHANCE_INSTRUCTIONS = 'Rewrite the request below so a coding agent can act on it: say what to change and where, name the expected result, and keep every file, symbol and constraint the user mentioned. ' +
5
+ 'Do not invent requirements or add steps the user did not ask for. Reply with the rewritten request only, no quotes, no code fences, no preface.';
6
+ /**
7
+ * Rewrite a draft chat message into a clearer request using `model` (typically the cheap model).
8
+ * Never throws: an empty input, a missing model, a model error or an empty reply all return `input` unchanged.
9
+ */
10
+ export async function enhancePrompt(input, model, modelFactory = createLanguageModel) {
11
+ if (!model || !input.trim())
12
+ return input;
13
+ try {
14
+ const result = await generateText({ model: modelFactory(model), prompt: `${ENHANCE_INSTRUCTIONS}\n\nRequest:\n${input}` });
15
+ return clean(result.text) || input;
16
+ }
17
+ catch {
18
+ return input;
19
+ }
20
+ }
21
+ function clean(text) {
22
+ // Reasoning models put an inline <think> block in the reply; only what follows it is the rewrite.
23
+ return stripThinkTags(text)
24
+ .trim()
25
+ .replace(/^```[a-z]*\s*\n?/i, '')
26
+ .replace(/\n?```$/, '')
27
+ .trim()
28
+ .replace(/^["'“”](.*)["'“”]$/s, '$1')
29
+ .trim();
30
+ }
@@ -1,3 +1,2 @@
1
1
  export { Agent } from './agent.js';
2
2
  export { DEFAULT_SYSTEM_PROMPT } from './prompts.js';
3
- //# sourceMappingURL=index.d.ts.map
@@ -1,3 +1,2 @@
1
1
  export { Agent } from './agent.js';
2
2
  export { DEFAULT_SYSTEM_PROMPT } from './prompts.js';
3
- //# sourceMappingURL=index.js.map
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Detects a run that is stuck repeating one tool call. A call counts as a repeat only when the tool
3
+ * name, the arguments (key order ignored) and the result all match the previous call, so re-reading
4
+ * a file after an edit changed it never trips the guard.
5
+ */
6
+ export declare class LoopGuard {
7
+ private lastKey;
8
+ private count;
9
+ private readonly threshold;
10
+ /**
11
+ * `threshold` identical calls in a row trip the guard; 0 turns it off. A threshold of 1 would stop
12
+ * every run at its first call, so it counts as 2.
13
+ */
14
+ constructor(threshold: number);
15
+ /** Length of the current run of identical calls. */
16
+ get streak(): number;
17
+ /** Record a finished call. Returns true when the streak has reached the threshold. */
18
+ record(toolName: string, args: unknown, resultKey: string): boolean;
19
+ }
20
+ /** A short stable key for a tool result, so the guard never holds large outputs in memory. */
21
+ export declare function resultKeyOf(value: unknown): string;
@@ -0,0 +1,41 @@
1
+ import { createHash } from 'node:crypto';
2
+ /**
3
+ * Detects a run that is stuck repeating one tool call. A call counts as a repeat only when the tool
4
+ * name, the arguments (key order ignored) and the result all match the previous call, so re-reading
5
+ * a file after an edit changed it never trips the guard.
6
+ */
7
+ export class LoopGuard {
8
+ lastKey;
9
+ count = 0;
10
+ threshold;
11
+ /**
12
+ * `threshold` identical calls in a row trip the guard; 0 turns it off. A threshold of 1 would stop
13
+ * every run at its first call, so it counts as 2.
14
+ */
15
+ constructor(threshold) {
16
+ this.threshold = threshold >= 1 ? Math.max(2, threshold) : 0;
17
+ }
18
+ /** Length of the current run of identical calls. */
19
+ get streak() {
20
+ return this.count;
21
+ }
22
+ /** Record a finished call. Returns true when the streak has reached the threshold. */
23
+ record(toolName, args, resultKey) {
24
+ if (this.threshold <= 0)
25
+ return false;
26
+ const key = `${toolName}\u0000${canonical(args)}\u0000${resultKey}`;
27
+ this.count = key === this.lastKey ? this.count + 1 : 1;
28
+ this.lastKey = key;
29
+ return this.count >= this.threshold;
30
+ }
31
+ }
32
+ /** A short stable key for a tool result, so the guard never holds large outputs in memory. */
33
+ export function resultKeyOf(value) {
34
+ const text = typeof value === 'string' ? value : (JSON.stringify(value) ?? '');
35
+ return createHash('sha1').update(text).digest('hex');
36
+ }
37
+ function canonical(value) {
38
+ return JSON.stringify(value, (_k, v) => v !== null && typeof v === 'object' && !Array.isArray(v)
39
+ ? Object.fromEntries(Object.entries(v).sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0)))
40
+ : v);
41
+ }
@@ -22,4 +22,3 @@ export declare const DEFAULT_SPEC_MODE_SUFFIX = "\n\nSPEC MODE \u2014 IMPORTANT:
22
22
  export declare const CONTINUE_PROMPT = "Continue exactly where you stopped. Do not repeat anything you already wrote.";
23
23
  /** Spec-mode prompt override for architect phase 1 (see agent/architect.ts). */
24
24
  export declare const ARCHITECT_PROMPT = "\n\nYou are the ARCHITECT. Explore the codebase with your read-only tools, then\nreply with a precise change plan for a separate editor model to apply. Do not\nwrite code outside the plan. Your final message must contain only:\n\n1. Files to change \u2014 for each file, the exact edits (what to find, what to\n replace it with, or the new code to add and where).\n2. New files \u2014 path and full contents.\n3. Verification \u2014 the commands to run to check the change.\n\nBe exact: the editor applies your plan literally and cannot ask questions.\n";
25
- //# sourceMappingURL=prompts.d.ts.map
@@ -78,4 +78,3 @@ write code outside the plan. Your final message must contain only:
78
78
 
79
79
  Be exact: the editor applies your plan literally and cannot ask questions.
80
80
  `;
81
- //# sourceMappingURL=prompts.js.map
@@ -26,4 +26,3 @@ export declare class ThinkSplitter {
26
26
  }
27
27
  /** The visible answer: everything outside `<think>…</think>` (an unclosed block runs to the end). */
28
28
  export declare function stripThinkTags(text: string): string;
29
- //# sourceMappingURL=think-tags.d.ts.map
@@ -81,4 +81,3 @@ export function stripThinkTags(text) {
81
81
  .replace(/<think>[\s\S]*$/, '')
82
82
  .trim();
83
83
  }
84
- //# sourceMappingURL=think-tags.js.map
@@ -14,4 +14,3 @@ export interface VerifyOutcome {
14
14
  export declare function runVerification(config: VerifyConfig, ctx: ToolContext, editedFiles?: string[]): Promise<VerifyOutcome>;
15
15
  /** The message shown to the model after a failed verification. */
16
16
  export declare function failureMessage(failures: VerifyFailure[]): string;
17
- //# sourceMappingURL=verify.d.ts.map
@@ -53,4 +53,3 @@ export function failureMessage(failures) {
53
53
  function tail(text) {
54
54
  return text.length <= MAX_FAILURE_CHARS ? text : `...\n${text.slice(text.length - MAX_FAILURE_CHARS)}`;
55
55
  }
56
- //# sourceMappingURL=verify.js.map
@@ -21,4 +21,3 @@ export interface AiCommentFile {
21
21
  }
22
22
  /** Build the agent task for the files that carry AI comments. */
23
23
  export declare function aiCommentTask(files: AiCommentFile[], action: 'change' | 'question'): string;
24
- //# sourceMappingURL=index.d.ts.map
@@ -38,4 +38,3 @@ export function aiCommentTask(files, action) {
38
38
  ? `Apply the instructions left as AI comments in these files, then remove the AI comments you resolved:\n\n${body}`
39
39
  : `Answer the questions left as AI comments in these files. Do not edit any file:\n\n${body}`;
40
40
  }
41
- //# sourceMappingURL=index.js.map