@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
@@ -6,6 +6,7 @@ declare const params: z.ZodObject<{
6
6
  max_entries: z.ZodOptional<z.ZodNumber>;
7
7
  /** Include dotfiles. Default false. */
8
8
  include_hidden: z.ZodOptional<z.ZodBoolean>;
9
+ include_ignored: z.ZodOptional<z.ZodBoolean>;
9
10
  /** Recurse into subdirectories. Default false. */
10
11
  recursive: z.ZodOptional<z.ZodBoolean>;
11
12
  /** Max recursion depth when recursive=true. Default 4. */
@@ -15,12 +16,14 @@ declare const params: z.ZodObject<{
15
16
  recursive?: boolean | undefined;
16
17
  max_entries?: number | undefined;
17
18
  include_hidden?: boolean | undefined;
19
+ include_ignored?: boolean | undefined;
18
20
  max_depth?: number | undefined;
19
21
  }, {
20
22
  path?: string | undefined;
21
23
  recursive?: boolean | undefined;
22
24
  max_entries?: number | undefined;
23
25
  include_hidden?: boolean | undefined;
26
+ include_ignored?: boolean | undefined;
24
27
  max_depth?: number | undefined;
25
28
  }>;
26
29
  export interface ListEntry {
@@ -35,4 +38,3 @@ export interface ListFilesResult {
35
38
  }
36
39
  export declare const listFilesTool: ToolDefinition<z.infer<typeof params>, ListFilesResult>;
37
40
  export {};
38
- //# sourceMappingURL=list-files.d.ts.map
@@ -1,6 +1,7 @@
1
1
  import { readdir, stat } from 'node:fs/promises';
2
2
  import path from 'node:path';
3
3
  import { z } from 'zod';
4
+ import { IgnoreRules } from './ignore-rules.js';
4
5
  import { resolveAndCheckPath, DEFAULT_IGNORED_DIRS } from './shared.js';
5
6
  const params = z.object({
6
7
  path: z
@@ -11,6 +12,10 @@ const params = z.object({
11
12
  max_entries: z.number().int().positive().max(5000).optional().describe('Maximum entries to return.'),
12
13
  /** Include dotfiles. Default false. */
13
14
  include_hidden: z.boolean().optional().describe('Include dotfiles (entries starting with ".").'),
15
+ include_ignored: z
16
+ .boolean()
17
+ .optional()
18
+ .describe('Also list paths matched by .gitignore / .forgeignore (skipped by default).'),
14
19
  /** Recurse into subdirectories. Default false. */
15
20
  recursive: z.boolean().optional().describe('Recurse into subdirectories.'),
16
21
  /** Max recursion depth when recursive=true. Default 4. */
@@ -24,6 +29,7 @@ export const listFilesTool = {
24
29
  const root = resolveAndCheckPath(args.path ?? '.', ctx);
25
30
  const maxEntries = args.max_entries ?? 500;
26
31
  const includeHidden = args.include_hidden ?? false;
32
+ const rules = args.include_ignored ? null : IgnoreRules.forRoot(ctx.cwd);
27
33
  const recursive = args.recursive ?? false;
28
34
  const maxDepth = args.max_depth ?? 4;
29
35
  const out = [];
@@ -53,6 +59,8 @@ export const listFilesTool = {
53
59
  if (DEFAULT_IGNORED_DIRS.has(entry.name))
54
60
  continue;
55
61
  const abs = path.join(dir, entry.name);
62
+ if (rules?.isIgnored(abs, entry.isDirectory()))
63
+ continue;
56
64
  if (entry.isDirectory()) {
57
65
  out.push({ path: abs, type: 'directory' });
58
66
  if (recursive && depth < maxDepth) {
@@ -77,4 +85,3 @@ export const listFilesTool = {
77
85
  return { path: root, entries: out, truncated };
78
86
  },
79
87
  };
80
- //# sourceMappingURL=list-files.js.map
@@ -19,4 +19,3 @@ export interface ListSymbolsResult {
19
19
  }
20
20
  export declare const listSymbolsTool: ToolDefinition<z.infer<typeof params>, ListSymbolsResult>;
21
21
  export {};
22
- //# sourceMappingURL=list-symbols.d.ts.map
@@ -23,4 +23,3 @@ export const listSymbolsTool = {
23
23
  return { path: rel, symbols: topLevel };
24
24
  },
25
25
  };
26
- //# sourceMappingURL=list-symbols.js.map
@@ -1,4 +1,5 @@
1
1
  import { z } from 'zod';
2
+ import { type MemoryType } from '../memory/memory-store.js';
2
3
  import type { ToolDefinition } from '../types.js';
3
4
  declare const readParams: z.ZodObject<{
4
5
  /**
@@ -27,21 +28,32 @@ export interface MemoryReadResult {
27
28
  empty: boolean;
28
29
  }
29
30
  export declare const memoryReadTool: ToolDefinition<z.infer<typeof readParams>, MemoryReadResult>;
31
+ /** Longest body `memory_write` accepts. Memory holds short facts, not documents. */
32
+ export declare const MAX_BODY_CHARS = 1200;
30
33
  declare const writeParams: z.ZodObject<{
31
34
  /** Where to write: 'project' (default) or 'global'. */
32
35
  scope: z.ZodOptional<z.ZodEnum<["project", "global"]>>;
33
- /** Section heading. If the heading already exists, replaces its body. */
36
+ /** Section heading. If the heading already exists (ignoring case and spacing), replaces its body. */
34
37
  heading: z.ZodString;
35
38
  /** Section body. Markdown allowed. */
36
39
  body: z.ZodString;
40
+ type: z.ZodOptional<z.ZodEnum<["convention", "decision", "correction", "reference"]>>;
41
+ refs: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
42
+ pin: z.ZodOptional<z.ZodBoolean>;
37
43
  }, "strip", z.ZodTypeAny, {
38
44
  body: string;
39
45
  heading: string;
46
+ type?: "reference" | "convention" | "decision" | "correction" | undefined;
40
47
  scope?: "project" | "global" | undefined;
48
+ refs?: string[] | undefined;
49
+ pin?: boolean | undefined;
41
50
  }, {
42
51
  body: string;
43
52
  heading: string;
53
+ type?: "reference" | "convention" | "decision" | "correction" | undefined;
44
54
  scope?: "project" | "global" | undefined;
55
+ refs?: string[] | undefined;
56
+ pin?: boolean | undefined;
45
57
  }>;
46
58
  export interface MemoryWriteResult {
47
59
  scope: 'project' | 'global';
@@ -49,7 +61,27 @@ export interface MemoryWriteResult {
49
61
  heading: string;
50
62
  replaced: boolean;
51
63
  bytes: number;
64
+ type: MemoryType;
65
+ /** Headings removed to keep the file under the size cap. */
66
+ dropped: string[];
67
+ /** Unified diff of the file change. */
68
+ diff: string;
52
69
  }
53
70
  export declare const memoryWriteTool: ToolDefinition<z.infer<typeof writeParams>, MemoryWriteResult>;
71
+ declare const forgetParams: z.ZodObject<{
72
+ scope: z.ZodOptional<z.ZodEnum<["project", "global"]>>;
73
+ heading: z.ZodString;
74
+ }, "strip", z.ZodTypeAny, {
75
+ heading: string;
76
+ scope?: "project" | "global" | undefined;
77
+ }, {
78
+ heading: string;
79
+ scope?: "project" | "global" | undefined;
80
+ }>;
81
+ export interface MemoryForgetResult {
82
+ scope: 'project' | 'global';
83
+ heading: string;
84
+ removed: boolean;
85
+ }
86
+ export declare const memoryForgetTool: ToolDefinition<z.infer<typeof forgetParams>, MemoryForgetResult>;
54
87
  export {};
55
- //# sourceMappingURL=memory.d.ts.map
@@ -1,5 +1,8 @@
1
+ import path from 'node:path';
1
2
  import { z } from 'zod';
2
- import { composeSectionUpdate, findProjectMemoryRoot, globalMemoryPath, loadMemory, projectMemoryPath, readMemoryFile, writeMemoryFile, } from '../memory/memory-store.js';
3
+ import { computeUnifiedDiff } from '../diff/unified-diff.js';
4
+ import { DEFAULT_MAX_BYTES, capMemory, composeSectionUpdate, findProjectMemoryRoot, globalMemoryPath, loadMemory, normalizeHeading, parseMemory, projectMemoryPath, readMemoryFile, removeSection, writeMemoryFile, } from '../memory/memory-store.js';
5
+ import { redact } from './redact.js';
3
6
  /**
4
7
  * Resolve the project memory file path from the agent's cwd. Returns null
5
8
  * when no project memory root is found (the tool then falls back to the
@@ -81,42 +84,131 @@ export const memoryReadTool = {
81
84
  return { scope: 'both', content, empty: content.length === 0 };
82
85
  },
83
86
  };
87
+ /** Longest body `memory_write` accepts. Memory holds short facts, not documents. */
88
+ export const MAX_BODY_CHARS = 1200;
89
+ const MEMORY_TYPES = ['convention', 'decision', 'correction', 'reference'];
84
90
  const writeParams = z.object({
85
91
  /** Where to write: 'project' (default) or 'global'. */
86
92
  scope: z.enum(['project', 'global']).optional().describe('Which memory file to write to. Default "project".'),
87
- /** Section heading. If the heading already exists, replaces its body. */
88
- heading: z.string().min(1).describe('Section heading (e.g. "Build commands"). Replaces an existing section with the same name.'),
93
+ /** Section heading. If the heading already exists (ignoring case and spacing), replaces its body. */
94
+ heading: z.string().min(1).describe('Specific one-line heading (e.g. "Package manager"). Replaces an existing section with the same name.'),
89
95
  /** Section body. Markdown allowed. */
90
- body: z.string().describe('Section body in markdown.'),
96
+ body: z.string().describe(`One fact in markdown, under ${MAX_BODY_CHARS} characters. No "## " lines.`),
97
+ type: z
98
+ .enum(MEMORY_TYPES)
99
+ .optional()
100
+ .describe('convention (how the project is built/styled, default), decision (a choice and its reason), correction (something the user told you not to do), reference (where to find something outside the repo).'),
101
+ refs: z
102
+ .array(z.string())
103
+ .optional()
104
+ .describe('Relative paths (or path#symbol) this entry depends on, so Forge can flag it stale when they disappear.'),
105
+ pin: z.boolean().optional().describe('Always include this section in the prompt. Use sparingly: pins share a 2 KB budget.'),
91
106
  });
107
+ function reject(reason) {
108
+ throw new Error(`memory_write rejected: ${reason}`);
109
+ }
110
+ /** Validate and compose a write without touching disk. Throws `memory_write rejected: ...`. */
111
+ async function planWrite(args, ctx) {
112
+ const scope = args.scope ?? 'project';
113
+ // Trim once, up front, so the "was this a replace?" check and
114
+ // composeSectionUpdate's own heading-match agree: otherwise incidental
115
+ // whitespace in args.heading makes a heading never match its own
116
+ // previously-written section, and duplicates accumulate.
117
+ const heading = args.heading.trim();
118
+ if (/[\r\n]/.test(heading))
119
+ reject('heading must be a single line');
120
+ const maxBody = ctx.memoryMaxBodyChars ?? MAX_BODY_CHARS;
121
+ if (args.body.length > maxBody) {
122
+ reject(`body is ${args.body.length} characters; the limit is ${maxBody}. Summarize it or split it into separate sections.`);
123
+ }
124
+ const secrets = redact(`${heading}\n${args.body}`);
125
+ if (secrets.total > 0) {
126
+ reject(`content looks like a secret (${Object.keys(secrets.counts).join(', ')}); never store credentials in memory`);
127
+ }
128
+ if (/^##\s/m.test(args.body)) {
129
+ reject('a body line starts with "## ", which would create a separate section; write each section with its own memory_write call');
130
+ }
131
+ for (const ref of args.refs ?? []) {
132
+ if (path.isAbsolute(ref) || ref.split(/[\\/]/).includes('..')) {
133
+ reject(`refs must be relative paths inside the project (got "${ref}")`);
134
+ }
135
+ // These would split or end the one-line metadata comment the refs are stored in.
136
+ if (/[,;\r\n]|-->/.test(ref)) {
137
+ reject(`refs cannot contain ",", ";", "-->" or a line break (got "${ref}")`);
138
+ }
139
+ }
140
+ const targetPath = scope === 'global' ? globalMemoryPath() : (await resolveProjectMemoryPath(ctx.cwd)) ?? projectMemoryPath(ctx.cwd);
141
+ const current = await readMemoryFile(targetPath);
142
+ const wanted = normalizeHeading(heading);
143
+ const existing = parseMemory(current, targetPath, 0).find((s) => normalizeHeading(s.heading) === wanted);
144
+ const replaced = existing !== undefined;
145
+ // A rewrite that leaves type/refs/pin out keeps what the section already had.
146
+ const type = args.type ?? existing?.type ?? 'convention';
147
+ const refs = args.refs ?? existing?.refs ?? [];
148
+ const pinned = args.pin ?? existing?.pinned ?? false;
149
+ const composed = composeSectionUpdate(current, heading, args.body, {
150
+ type,
151
+ ...(refs.length > 0 ? { refs } : {}),
152
+ ...(pinned ? { pinned: true } : {}),
153
+ });
154
+ const { content: updated, dropped } = capMemory(composed, DEFAULT_MAX_BYTES, heading);
155
+ return { scope, targetPath, current, updated, heading, type, replaced, dropped };
156
+ }
157
+ function fileDiff(before, after) {
158
+ return computeUnifiedDiff(before, after, { filePath: 'MEMORY.md', contextLines: 1 }).text;
159
+ }
92
160
  export const memoryWriteTool = {
93
161
  name: 'memory_write',
94
- description: "Write or replace a section of the project's memory file (`.forge/MEMORY.md`). Use to record project conventions the agent should remember across sessions: build commands, code style, deployment steps, etc. If the heading already exists, its body is replaced; otherwise the section is appended.",
162
+ description: "Write or replace one section of the project's memory file (`.forge/MEMORY.md`), kept across sessions. SAVE: a correction or preference the user stated for the future, a non-obvious project convention, the reason behind a decision, a pointer to an external resource. DO NOT SAVE: anything derivable from the code or git history, one-off task details or run progress, secrets or credentials. One fact per section, a specific heading, short body; replace an existing section instead of adding a near-duplicate. Use `memory_forget` to remove an entry that is wrong.",
95
163
  parameters: writeParams,
164
+ previewApproval: async (args, ctx) => {
165
+ try {
166
+ const plan = await planWrite(args, ctx);
167
+ const note = plan.dropped.length > 0 ? `\n(size cap: would also remove ${plan.dropped.join(', ')})` : '';
168
+ return fileDiff(plan.current, plan.updated) + note;
169
+ }
170
+ catch (err) {
171
+ return err instanceof Error ? err.message : String(err);
172
+ }
173
+ },
96
174
  execute: async (args, ctx) => {
97
- const scope = args.scope ?? 'project';
98
- // Trim once, up front, so the "was this a replace?" check and
99
- // composeSectionUpdate's own heading-match agree: otherwise incidental
100
- // whitespace in args.heading makes a heading never match its own
101
- // previously-written section, and duplicates accumulate.
102
- const heading = args.heading.trim();
103
- const targetPath = scope === 'global'
104
- ? globalMemoryPath()
105
- : (await resolveProjectMemoryPath(ctx.cwd)) ?? projectMemoryPath(ctx.cwd);
106
- const current = await readMemoryFile(targetPath);
107
- const replaced = new RegExp(`^##\\s+${escapeRegExp(heading)}\\s*$`, 'm').test(current);
108
- const updated = composeSectionUpdate(current, heading, args.body);
109
- await writeMemoryFile(targetPath, updated);
175
+ const plan = await planWrite(args, ctx);
176
+ await writeMemoryFile(plan.targetPath, plan.updated);
110
177
  return {
111
- scope,
112
- path: targetPath,
113
- heading,
114
- replaced,
115
- bytes: Buffer.byteLength(updated, 'utf8'),
178
+ scope: plan.scope,
179
+ path: plan.targetPath,
180
+ heading: plan.heading,
181
+ replaced: plan.replaced,
182
+ bytes: Buffer.byteLength(plan.updated, 'utf8'),
183
+ type: plan.type,
184
+ dropped: plan.dropped,
185
+ diff: fileDiff(plan.current, plan.updated),
116
186
  };
117
187
  },
118
188
  };
119
- function escapeRegExp(s) {
120
- return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
189
+ const forgetParams = z.object({
190
+ scope: z.enum(['project', 'global']).optional().describe('Which memory file to edit. Default "project".'),
191
+ heading: z.string().min(1).describe('Heading of the section to remove (case and spacing ignored).'),
192
+ });
193
+ async function planForget(args, ctx) {
194
+ const scope = args.scope ?? 'project';
195
+ const targetPath = scope === 'global' ? globalMemoryPath() : (await resolveProjectMemoryPath(ctx.cwd)) ?? projectMemoryPath(ctx.cwd);
196
+ const current = await readMemoryFile(targetPath);
197
+ return { scope, targetPath, current, ...removeSection(current, args.heading) };
121
198
  }
122
- //# sourceMappingURL=memory.js.map
199
+ export const memoryForgetTool = {
200
+ name: 'memory_forget',
201
+ destructive: true,
202
+ description: "Remove one section from the project's memory file (`.forge/MEMORY.md`). Use it to retire an entry the user says is wrong or that no longer applies.",
203
+ parameters: forgetParams,
204
+ previewApproval: async (args, ctx) => {
205
+ const plan = await planForget(args, ctx);
206
+ return plan.removed ? fileDiff(plan.current, plan.content) : `No section named "${args.heading.trim()}".`;
207
+ },
208
+ execute: async (args, ctx) => {
209
+ const plan = await planForget(args, ctx);
210
+ if (plan.removed)
211
+ await writeMemoryFile(plan.targetPath, plan.content);
212
+ return { scope: plan.scope, heading: args.heading.trim(), removed: plan.removed };
213
+ },
214
+ };
@@ -0,0 +1,69 @@
1
+ import { z } from 'zod';
2
+ import type { ToolDefinition } from '../types.js';
3
+ type CellType = 'code' | 'markdown' | 'raw';
4
+ interface Cell {
5
+ cell_type: CellType;
6
+ id?: string;
7
+ metadata?: Record<string, unknown>;
8
+ source: string | string[];
9
+ outputs?: unknown[];
10
+ execution_count?: number | null;
11
+ [key: string]: unknown;
12
+ }
13
+ interface Notebook {
14
+ cells: Cell[];
15
+ nbformat?: number;
16
+ nbformat_minor?: number;
17
+ metadata?: {
18
+ language_info?: {
19
+ name?: string;
20
+ };
21
+ kernelspec?: {
22
+ language?: string;
23
+ };
24
+ };
25
+ [key: string]: unknown;
26
+ }
27
+ export declare function isNotebookPath(p: string): boolean;
28
+ export declare function parseNotebook(text: string): {
29
+ nb: Notebook;
30
+ indent: number;
31
+ trailingNewline: boolean;
32
+ };
33
+ export declare function sourceText(source: string | string[] | undefined): string;
34
+ /** Jupyter's on-disk form: one string per line, each but the last keeping its newline. */
35
+ export declare function toSourceLines(text: string): string[];
36
+ /** One output as text: streams and text/plain as is, errors as name and message, rich media named only. */
37
+ export declare function outputText(output: unknown): string;
38
+ /** The notebook as numbered cells for the model to read. */
39
+ export declare function renderNotebook(nb: Notebook): string;
40
+ declare const params: z.ZodObject<{
41
+ path: z.ZodString;
42
+ mode: z.ZodOptional<z.ZodEnum<["replace", "insert", "delete"]>>;
43
+ cell_index: z.ZodOptional<z.ZodNumber>;
44
+ cell_id: z.ZodOptional<z.ZodString>;
45
+ source: z.ZodOptional<z.ZodString>;
46
+ cell_type: z.ZodOptional<z.ZodEnum<["code", "markdown", "raw"]>>;
47
+ }, "strip", z.ZodTypeAny, {
48
+ path: string;
49
+ source?: string | undefined;
50
+ cell_type?: "code" | "raw" | "markdown" | undefined;
51
+ mode?: "replace" | "insert" | "delete" | undefined;
52
+ cell_index?: number | undefined;
53
+ cell_id?: string | undefined;
54
+ }, {
55
+ path: string;
56
+ source?: string | undefined;
57
+ cell_type?: "code" | "raw" | "markdown" | undefined;
58
+ mode?: "replace" | "insert" | "delete" | undefined;
59
+ cell_index?: number | undefined;
60
+ cell_id?: string | undefined;
61
+ }>;
62
+ export interface EditNotebookResult {
63
+ path: string;
64
+ mode: 'replace' | 'insert' | 'delete';
65
+ cellIndex: number;
66
+ cells: number;
67
+ }
68
+ export declare const editNotebookTool: ToolDefinition<z.infer<typeof params>, EditNotebookResult>;
69
+ export {};
@@ -0,0 +1,163 @@
1
+ /**
2
+ * Jupyter notebooks (`.ipynb`). `read_file` shows a notebook as numbered cells
3
+ * (source plus a short text form of each output, never base64 images), and the
4
+ * `edit_notebook` tool replaces, inserts or deletes one cell while keeping the rest
5
+ * of the JSON (metadata, other cells' outputs, the file's indentation) as it was.
6
+ */
7
+ import { readFile, writeFile } from 'node:fs/promises';
8
+ import { randomBytes } from 'node:crypto';
9
+ import { z } from 'zod';
10
+ import { resolveAndCheckPath } from './shared.js';
11
+ const OUTPUT_MAX = 2_000;
12
+ export function isNotebookPath(p) {
13
+ return p.toLowerCase().endsWith('.ipynb');
14
+ }
15
+ export function parseNotebook(text) {
16
+ let nb;
17
+ try {
18
+ nb = JSON.parse(text);
19
+ }
20
+ catch (err) {
21
+ throw new Error(`not a valid notebook (bad JSON: ${err.message})`);
22
+ }
23
+ if (!nb || typeof nb !== 'object' || !Array.isArray(nb.cells))
24
+ throw new Error('not a valid notebook (no cells array)');
25
+ // Jupyter writes one space per level; keep whatever the file uses.
26
+ const indent = /^\{\r?\n( +)"/.exec(text)?.[1]?.length ?? 1;
27
+ return { nb: nb, indent, trailingNewline: text.endsWith('\n') };
28
+ }
29
+ export function sourceText(source) {
30
+ return Array.isArray(source) ? source.join('') : (source ?? '');
31
+ }
32
+ /** Jupyter's on-disk form: one string per line, each but the last keeping its newline. */
33
+ export function toSourceLines(text) {
34
+ if (text === '')
35
+ return [];
36
+ const lines = text.split('\n');
37
+ return lines.map((l, i) => (i < lines.length - 1 ? `${l}\n` : l)).filter((l) => l !== '');
38
+ }
39
+ function clip(text) {
40
+ return text.length > OUTPUT_MAX ? `${text.slice(0, OUTPUT_MAX)}\n… (${text.length - OUTPUT_MAX} more characters)` : text;
41
+ }
42
+ /** One output as text: streams and text/plain as is, errors as name and message, rich media named only. */
43
+ export function outputText(output) {
44
+ if (!output || typeof output !== 'object')
45
+ return '';
46
+ const o = output;
47
+ if (o.output_type === 'stream')
48
+ return clip(sourceText(o.text));
49
+ if (o.output_type === 'error')
50
+ return `${o.ename ?? 'Error'}: ${o.evalue ?? ''}`;
51
+ const data = o.data ?? {};
52
+ const plain = data['text/plain'];
53
+ const media = Object.keys(data).filter((k) => k !== 'text/plain');
54
+ const parts = [];
55
+ if (plain !== undefined)
56
+ parts.push(clip(sourceText(plain)));
57
+ if (media.length > 0)
58
+ parts.push(`[${media.join(', ')} output]`);
59
+ return parts.join('\n');
60
+ }
61
+ /** The notebook as numbered cells for the model to read. */
62
+ export function renderNotebook(nb) {
63
+ const lang = nb.metadata?.language_info?.name ?? nb.metadata?.kernelspec?.language ?? 'python';
64
+ const blocks = nb.cells.map((cell, i) => {
65
+ const head = `### cell ${i} (${cell.cell_type}${cell.id ? `, id ${cell.id}` : ''})`;
66
+ const fence = cell.cell_type === 'code' ? lang : cell.cell_type === 'markdown' ? 'markdown' : '';
67
+ const outputs = (cell.outputs ?? []).map(outputText).filter((t) => t.trim().length > 0);
68
+ const out = outputs.length > 0 ? `\nOutput:\n${outputs.join('\n')}` : '';
69
+ return `${head}\n\`\`\`${fence}\n${sourceText(cell.source)}\n\`\`\`${out}`;
70
+ });
71
+ return `Notebook with ${nb.cells.length} cell${nb.cells.length === 1 ? '' : 's'} (language: ${lang}). Edit cells with edit_notebook.\n\n${blocks.join('\n\n')}`;
72
+ }
73
+ function newCellId() {
74
+ return randomBytes(4).toString('hex');
75
+ }
76
+ function findCell(nb, index, id) {
77
+ if (id !== undefined) {
78
+ const at = nb.cells.findIndex((c) => c.id === id);
79
+ if (at === -1)
80
+ throw new Error(`no cell with id ${id}`);
81
+ return at;
82
+ }
83
+ if (index === undefined)
84
+ throw new Error('give cell_index or cell_id');
85
+ if (index < 0 || index >= nb.cells.length)
86
+ throw new Error(`cell_index ${index} is out of range (0-${nb.cells.length - 1})`);
87
+ return index;
88
+ }
89
+ const params = z.object({
90
+ path: z.string().describe('Path of the .ipynb file.'),
91
+ mode: z
92
+ .enum(['replace', 'insert', 'delete'])
93
+ .optional()
94
+ .describe('replace (default) a cell\'s source, insert a new cell, or delete a cell.'),
95
+ cell_index: z
96
+ .number()
97
+ .int()
98
+ .nonnegative()
99
+ .optional()
100
+ .describe('0-based cell number, as read_file shows it. For insert: the new cell goes at this position (default: the end).'),
101
+ cell_id: z.string().optional().describe('The cell id instead of cell_index (for insert: the new cell goes after it).'),
102
+ source: z.string().optional().describe('The new cell source (replace and insert).'),
103
+ cell_type: z.enum(['code', 'markdown', 'raw']).optional().describe('Type for an inserted cell (default code), or to change a replaced cell\'s type.'),
104
+ });
105
+ export const editNotebookTool = {
106
+ name: 'edit_notebook',
107
+ description: 'Edit a Jupyter notebook (.ipynb) one cell at a time: replace a cell\'s source, insert a new cell, or delete one. Read the notebook with read_file first to see the cell numbers. Outputs of an edited code cell are cleared; everything else in the file is kept.',
108
+ parameters: params,
109
+ destructive: false,
110
+ execute: async (args, ctx) => {
111
+ if (!isNotebookPath(args.path))
112
+ throw new Error(`${args.path} is not a .ipynb file; use edit_file for other files`);
113
+ const resolved = resolveAndCheckPath(args.path, ctx);
114
+ const text = await readFile(resolved, 'utf8').catch((err) => {
115
+ if (err.code === 'ENOENT')
116
+ throw new Error(`File not found: ${args.path}`);
117
+ throw err;
118
+ });
119
+ const { nb, indent, trailingNewline } = parseNotebook(text);
120
+ const mode = args.mode ?? 'replace';
121
+ const withIds = (nb.nbformat ?? 4) > 4 || ((nb.nbformat ?? 4) === 4 && (nb.nbformat_minor ?? 0) >= 5);
122
+ let at;
123
+ if (mode === 'insert') {
124
+ if (args.source === undefined)
125
+ throw new Error('insert needs source');
126
+ at = args.cell_id !== undefined ? findCell(nb, undefined, args.cell_id) + 1 : Math.min(args.cell_index ?? nb.cells.length, nb.cells.length);
127
+ const type = args.cell_type ?? 'code';
128
+ const cell = {
129
+ cell_type: type,
130
+ ...(withIds ? { id: newCellId() } : {}),
131
+ metadata: {},
132
+ source: toSourceLines(args.source),
133
+ ...(type === 'code' ? { execution_count: null, outputs: [] } : {}),
134
+ };
135
+ nb.cells.splice(at, 0, cell);
136
+ }
137
+ else if (mode === 'delete') {
138
+ at = findCell(nb, args.cell_index, args.cell_id);
139
+ nb.cells.splice(at, 1);
140
+ }
141
+ else {
142
+ if (args.source === undefined)
143
+ throw new Error('replace needs source');
144
+ at = findCell(nb, args.cell_index, args.cell_id);
145
+ const cell = nb.cells[at];
146
+ cell.source = toSourceLines(args.source);
147
+ if (args.cell_type && args.cell_type !== cell.cell_type) {
148
+ cell.cell_type = args.cell_type;
149
+ if (args.cell_type !== 'code') {
150
+ delete cell.outputs;
151
+ delete cell.execution_count;
152
+ }
153
+ }
154
+ // The old outputs belong to the old code.
155
+ if (cell.cell_type === 'code') {
156
+ cell.outputs = [];
157
+ cell.execution_count = null;
158
+ }
159
+ }
160
+ await writeFile(resolved, JSON.stringify(nb, null, indent) + (trailingNewline ? '\n' : ''), 'utf8');
161
+ return { path: resolved, mode, cellIndex: at, cells: nb.cells.length };
162
+ },
163
+ };
@@ -66,4 +66,3 @@ export declare function normalizePathPattern(pattern: string, _cwd: string): str
66
66
  * project settings files, which concatenate (see sandbox-loader.ts).
67
67
  */
68
68
  export declare function mergeToolSandbox(base: ToolSandbox, override: ToolSandbox): ToolSandbox;
69
- //# sourceMappingURL=policy.d.ts.map
@@ -188,4 +188,3 @@ export function mergeToolSandbox(base, override) {
188
188
  }
189
189
  return merged;
190
190
  }
191
- //# sourceMappingURL=policy.js.map
@@ -22,6 +22,12 @@ export interface ReadFileResult {
22
22
  content: string;
23
23
  truncated: boolean;
24
24
  }
25
- export declare const readFileTool: ToolDefinition<z.infer<typeof params>, ReadFileResult>;
25
+ /** A PDF comes back whole; the agent attaches it so document-capable models read it natively. */
26
+ export interface ReadPdfResult {
27
+ path: string;
28
+ mime: 'application/pdf';
29
+ bytes: number;
30
+ dataUrl: string;
31
+ }
32
+ export declare const readFileTool: ToolDefinition<z.infer<typeof params>, ReadFileResult | ReadPdfResult>;
26
33
  export {};
27
- //# sourceMappingURL=read-file.d.ts.map
@@ -1,5 +1,7 @@
1
1
  import { readFile } from 'node:fs/promises';
2
2
  import { z } from 'zod';
3
+ import { isNotebookPath, parseNotebook, renderNotebook } from './notebook.js';
4
+ import { isPdf, MAX_ATTACHMENT_BYTES } from '../attachments.js';
3
5
  import { resolveAndCheckPath, truncateByLines } from './shared.js';
4
6
  const params = z.object({
5
7
  path: z.string().describe('Path to the file to read, relative to the working directory or absolute.'),
@@ -10,7 +12,7 @@ const params = z.object({
10
12
  });
11
13
  export const readFileTool = {
12
14
  name: 'read_file',
13
- description: 'Read the contents of a file. Returns text with line numbers; supports an optional offset and max_lines to page through large files. Binary files are rejected.',
15
+ description: 'Read the contents of a file. Returns text with line numbers; supports an optional offset and max_lines to page through large files. A Jupyter notebook (.ipynb) is shown as numbered cells with their outputs. A PDF is attached whole so you can read it (text, tables and figures). Other binary files are rejected.',
14
16
  parameters: params,
15
17
  execute: async (args, ctx) => {
16
18
  const resolved = resolveAndCheckPath(args.path, ctx);
@@ -28,6 +30,22 @@ export const readFileTool = {
28
30
  }
29
31
  throw err;
30
32
  }
33
+ if (isNotebookPath(resolved) && !args.offset) {
34
+ // Raw notebook JSON is mostly metadata and base64 output: show the cells instead.
35
+ try {
36
+ const rendered = renderNotebook(parseNotebook(raw.toString('utf8')).nb);
37
+ return { path: resolved, totalLines: rendered.split('\n').length, offset: 1, content: rendered, truncated: false };
38
+ }
39
+ catch {
40
+ // Not valid notebook JSON: fall through and show the text as it is.
41
+ }
42
+ }
43
+ if (isPdf(raw)) {
44
+ if (raw.length > MAX_ATTACHMENT_BYTES) {
45
+ throw new Error(`PDF too large: ${raw.length} bytes exceeds ${MAX_ATTACHMENT_BYTES} (${args.path})`);
46
+ }
47
+ return { path: resolved, mime: 'application/pdf', bytes: raw.length, dataUrl: `data:application/pdf;base64,${raw.toString('base64')}` };
48
+ }
31
49
  // Reject obvious binary content.
32
50
  if (looksBinary(raw)) {
33
51
  throw new Error(`Refusing to read binary file: ${args.path} (${raw.length} bytes)`);
@@ -57,4 +75,3 @@ function looksBinary(buf) {
57
75
  }
58
76
  return false;
59
77
  }
60
- //# sourceMappingURL=read-file.js.map
@@ -59,4 +59,3 @@ export declare const readImageTool: ToolDefinition<z.infer<typeof params>, ReadI
59
59
  */
60
60
  export declare function sniffMime(buf: Buffer, filePath: string): string | undefined;
61
61
  export {};
62
- //# sourceMappingURL=read-image.d.ts.map
@@ -119,4 +119,3 @@ export function sniffMime(buf, filePath) {
119
119
  default: return undefined;
120
120
  }
121
121
  }
122
- //# sourceMappingURL=read-image.js.map
@@ -6,4 +6,3 @@
6
6
  export declare const READ_ONLY_TOOLS: readonly ["read_file", "list_files", "search_files", "find_symbol", "list_symbols", "find_references", "codebase_search", "memory_read"];
7
7
  /** The tools that run without a prompt: the user's list, or the read-only tools when none is set. */
8
8
  export declare function resolveAutoApprove(configured?: readonly string[]): string[];
9
- //# sourceMappingURL=read-only.d.ts.map
@@ -17,4 +17,3 @@ export const READ_ONLY_TOOLS = [
17
17
  export function resolveAutoApprove(configured) {
18
18
  return configured ? [...configured] : [...READ_ONLY_TOOLS];
19
19
  }
20
- //# sourceMappingURL=read-only.js.map
@@ -59,4 +59,3 @@ export declare function redact(text: string, options?: RedactOptions): Redaction
59
59
  * the text and just wants the metric.
60
60
  */
61
61
  export declare function countRedactions(text: string, options?: RedactOptions): number;
62
- //# sourceMappingURL=redact.d.ts.map