@ikarmic/forge-core 4.5.0 → 5.1.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 (643) hide show
  1. package/LICENSE +44 -21
  2. package/README.md +1 -1
  3. package/dist/agent/agent.d.ts +8 -1
  4. package/dist/agent/agent.js +143 -23
  5. package/dist/agent/architect.d.ts +0 -1
  6. package/dist/agent/architect.js +0 -1
  7. package/dist/agent/background.d.ts +58 -0
  8. package/dist/agent/background.js +139 -0
  9. package/dist/agent/cache-hints.d.ts +0 -1
  10. package/dist/agent/cache-hints.js +0 -1
  11. package/dist/agent/cost-router.d.ts +0 -1
  12. package/dist/agent/cost-router.js +0 -1
  13. package/dist/agent/enhance-prompt.d.ts +9 -0
  14. package/dist/agent/enhance-prompt.js +34 -0
  15. package/dist/agent/goal.d.ts +54 -0
  16. package/dist/agent/goal.js +65 -0
  17. package/dist/agent/index.d.ts +0 -1
  18. package/dist/agent/index.js +0 -1
  19. package/dist/agent/loop-guard.d.ts +21 -0
  20. package/dist/agent/loop-guard.js +41 -0
  21. package/dist/agent/prompts.d.ts +0 -1
  22. package/dist/agent/prompts.js +0 -1
  23. package/dist/agent/think-tags.d.ts +0 -1
  24. package/dist/agent/think-tags.js +0 -1
  25. package/dist/agent/verify.d.ts +0 -1
  26. package/dist/agent/verify.js +0 -1
  27. package/dist/agents/agent-files.d.ts +43 -0
  28. package/dist/agents/agent-files.js +109 -0
  29. package/dist/ai-comments/index.d.ts +0 -1
  30. package/dist/ai-comments/index.js +0 -1
  31. package/dist/attachments.d.ts +0 -1
  32. package/dist/attachments.js +0 -1
  33. package/dist/browser/cdp.d.ts +0 -1
  34. package/dist/browser/cdp.js +0 -1
  35. package/dist/browser/chrome.d.ts +0 -1
  36. package/dist/browser/chrome.js +0 -1
  37. package/dist/browser/session.d.ts +0 -1
  38. package/dist/browser/session.js +0 -1
  39. package/dist/checkpoints/index.d.ts +0 -1
  40. package/dist/checkpoints/index.js +0 -1
  41. package/dist/checkpoints/store.d.ts +0 -1
  42. package/dist/checkpoints/store.js +5 -2
  43. package/dist/checkpoints/types.d.ts +0 -1
  44. package/dist/checkpoints/types.js +0 -1
  45. package/dist/code-index/builder.d.ts +0 -1
  46. package/dist/code-index/builder.js +0 -1
  47. package/dist/code-index/index-store.d.ts +0 -1
  48. package/dist/code-index/index-store.js +0 -1
  49. package/dist/code-index/parser.d.ts +0 -1
  50. package/dist/code-index/parser.js +0 -1
  51. package/dist/code-index/types.d.ts +0 -1
  52. package/dist/code-index/types.js +0 -1
  53. package/dist/commands/custom-commands.d.ts +9 -5
  54. package/dist/commands/custom-commands.js +13 -3
  55. package/dist/config-file.d.ts +47 -1
  56. package/dist/config-file.js +249 -6
  57. package/dist/config-merge.d.ts +13 -0
  58. package/dist/config-merge.js +67 -0
  59. package/dist/config-schema.d.ts +340 -0
  60. package/dist/config-schema.js +126 -0
  61. package/dist/config.d.ts +0 -1
  62. package/dist/config.js +2 -2
  63. package/dist/context/compaction.d.ts +0 -1
  64. package/dist/context/compaction.js +10 -2
  65. package/dist/context/mask.d.ts +0 -1
  66. package/dist/context/mask.js +1 -2
  67. package/dist/credentials/index.d.ts +0 -1
  68. package/dist/credentials/index.js +0 -1
  69. package/dist/credentials/types.d.ts +0 -1
  70. package/dist/credentials/types.js +0 -1
  71. package/dist/custom-providers.d.ts +95 -0
  72. package/dist/custom-providers.js +120 -0
  73. package/dist/diff/index.d.ts +0 -1
  74. package/dist/diff/index.js +0 -1
  75. package/dist/diff/unified-diff.d.ts +0 -1
  76. package/dist/diff/unified-diff.js +0 -1
  77. package/dist/git/auto-commit.d.ts +3 -4
  78. package/dist/git/auto-commit.js +8 -7
  79. package/dist/git/index.d.ts +0 -1
  80. package/dist/git/index.js +0 -1
  81. package/dist/github/github-tools.d.ts +2 -3
  82. package/dist/github/github-tools.js +0 -1
  83. package/dist/hooks/agent-runner.d.ts +0 -1
  84. package/dist/hooks/agent-runner.js +0 -1
  85. package/dist/hooks/bus.d.ts +0 -1
  86. package/dist/hooks/bus.js +0 -1
  87. package/dist/hooks/config.d.ts +0 -1
  88. package/dist/hooks/config.js +0 -1
  89. package/dist/hooks/events.d.ts +0 -1
  90. package/dist/hooks/events.js +0 -1
  91. package/dist/hooks/index.d.ts +0 -1
  92. package/dist/hooks/index.js +0 -1
  93. package/dist/hooks/loader.d.ts +0 -1
  94. package/dist/hooks/loader.js +0 -1
  95. package/dist/hooks/runner.d.ts +0 -1
  96. package/dist/hooks/runner.js +3 -3
  97. package/dist/hooks/watch-coalescer.d.ts +0 -1
  98. package/dist/hooks/watch-coalescer.js +0 -1
  99. package/dist/hooks/watch-ignore.d.ts +0 -1
  100. package/dist/hooks/watch-ignore.js +0 -1
  101. package/dist/hooks/watcher.d.ts +0 -1
  102. package/dist/hooks/watcher.js +0 -1
  103. package/dist/import/claude-code.d.ts +39 -0
  104. package/dist/import/claude-code.js +254 -0
  105. package/dist/index.d.ts +37 -7
  106. package/dist/index.js +28 -5
  107. package/dist/lazy-model.d.ts +0 -1
  108. package/dist/lazy-model.js +0 -1
  109. package/dist/lint/auto-lint.d.ts +0 -1
  110. package/dist/lint/auto-lint.js +0 -1
  111. package/dist/lint/index.d.ts +0 -1
  112. package/dist/lint/index.js +0 -1
  113. package/dist/lsp/client.d.ts +5 -1
  114. package/dist/lsp/client.js +39 -4
  115. package/dist/lsp/diagnostics.d.ts +0 -1
  116. package/dist/lsp/diagnostics.js +0 -1
  117. package/dist/lsp/index.d.ts +0 -1
  118. package/dist/lsp/index.js +0 -1
  119. package/dist/mcp/catalog.d.ts +0 -1
  120. package/dist/mcp/catalog.js +0 -1
  121. package/dist/mcp/index.d.ts +5 -2
  122. package/dist/mcp/index.js +3 -2
  123. package/dist/mcp/json-schema-to-zod.d.ts +0 -1
  124. package/dist/mcp/json-schema-to-zod.js +0 -1
  125. package/dist/mcp/manager.d.ts +17 -4
  126. package/dist/mcp/manager.js +27 -3
  127. package/dist/mcp/marketplace-types.d.ts +0 -1
  128. package/dist/mcp/marketplace-types.js +0 -1
  129. package/dist/mcp/marketplace.d.ts +2 -1
  130. package/dist/mcp/marketplace.js +10 -5
  131. package/dist/mcp/mcp-client.d.ts +12 -3
  132. package/dist/mcp/mcp-client.js +74 -18
  133. package/dist/mcp/mcp-config.d.ts +2 -1
  134. package/dist/mcp/mcp-config.js +1 -1
  135. package/dist/mcp/oauth.d.ts +55 -0
  136. package/dist/mcp/oauth.js +197 -0
  137. package/dist/mcp/registry.d.ts +0 -1
  138. package/dist/mcp/registry.js +0 -1
  139. package/dist/mcp/resource-tools.d.ts +8 -0
  140. package/dist/mcp/resource-tools.js +56 -0
  141. package/dist/memory/memory-store.d.ts +0 -1
  142. package/dist/memory/memory-store.js +0 -1
  143. package/dist/memory/rank.d.ts +0 -1
  144. package/dist/memory/rank.js +0 -1
  145. package/dist/memory/session-digest.d.ts +12 -0
  146. package/dist/memory/session-digest.js +47 -0
  147. package/dist/memory/stale.d.ts +0 -1
  148. package/dist/memory/stale.js +2 -2
  149. package/dist/model-alias.d.ts +18 -3
  150. package/dist/model-alias.js +27 -4
  151. package/dist/model-catalog.d.ts +0 -1
  152. package/dist/model-catalog.js +0 -2
  153. package/dist/model-list.d.ts +0 -1
  154. package/dist/model-list.js +2 -2
  155. package/dist/model-overrides.d.ts +30 -0
  156. package/dist/model-overrides.js +48 -0
  157. package/dist/orchestrator/board-tools.d.ts +0 -1
  158. package/dist/orchestrator/board-tools.js +0 -1
  159. package/dist/orchestrator/board.d.ts +0 -1
  160. package/dist/orchestrator/board.js +0 -1
  161. package/dist/orchestrator/index.d.ts +0 -1
  162. package/dist/orchestrator/index.js +0 -1
  163. package/dist/orchestrator/orchestrator.d.ts +0 -1
  164. package/dist/orchestrator/orchestrator.js +0 -1
  165. package/dist/orchestrator/router.d.ts +0 -1
  166. package/dist/orchestrator/router.js +0 -1
  167. package/dist/orchestrator/specialists-registry.d.ts +0 -1
  168. package/dist/orchestrator/specialists-registry.js +2 -4
  169. package/dist/orchestrator/specialists.d.ts +0 -1
  170. package/dist/orchestrator/specialists.js +4 -5
  171. package/dist/orchestrator/types.d.ts +0 -1
  172. package/dist/orchestrator/types.js +0 -1
  173. package/dist/plugins/index.d.ts +0 -1
  174. package/dist/plugins/index.js +0 -1
  175. package/dist/plugins/install.d.ts +0 -1
  176. package/dist/plugins/install.js +0 -1
  177. package/dist/plugins/loader.d.ts +0 -1
  178. package/dist/plugins/loader.js +0 -1
  179. package/dist/policy/audit.d.ts +0 -1
  180. package/dist/policy/audit.js +0 -1
  181. package/dist/policy/ca-certs.d.ts +8 -0
  182. package/dist/policy/ca-certs.js +30 -0
  183. package/dist/policy/policy.d.ts +0 -1
  184. package/dist/policy/policy.js +0 -1
  185. package/dist/policy/proxy.d.ts +10 -4
  186. package/dist/policy/proxy.js +33 -7
  187. package/dist/pricing.d.ts +0 -1
  188. package/dist/pricing.js +4 -1
  189. package/dist/providers.d.ts +7 -1
  190. package/dist/providers.js +39 -6
  191. package/dist/repomap/index.d.ts +0 -1
  192. package/dist/repomap/index.js +0 -1
  193. package/dist/repomap/repo-map.d.ts +0 -1
  194. package/dist/repomap/repo-map.js +0 -1
  195. package/dist/semantic/chunker.d.ts +0 -1
  196. package/dist/semantic/chunker.js +0 -1
  197. package/dist/semantic/embedder.d.ts +15 -1
  198. package/dist/semantic/embedder.js +25 -1
  199. package/dist/semantic/semantic-index.d.ts +10 -3
  200. package/dist/semantic/semantic-index.js +16 -8
  201. package/dist/semantic/vector-store.d.ts +0 -1
  202. package/dist/semantic/vector-store.js +0 -1
  203. package/dist/sessions/index.d.ts +1 -1
  204. package/dist/sessions/index.js +1 -1
  205. package/dist/sessions/prune.d.ts +23 -0
  206. package/dist/sessions/prune.js +35 -0
  207. package/dist/sessions/search.d.ts +0 -1
  208. package/dist/sessions/search.js +0 -1
  209. package/dist/sessions/session-export.d.ts +0 -1
  210. package/dist/sessions/session-export.js +0 -1
  211. package/dist/sessions/session-store.d.ts +0 -1
  212. package/dist/sessions/session-store.js +2 -2
  213. package/dist/sessions/watch.d.ts +0 -1
  214. package/dist/sessions/watch.js +0 -1
  215. package/dist/settings-export.d.ts +0 -1
  216. package/dist/settings-export.js +0 -1
  217. package/dist/skills/activator.d.ts +0 -1
  218. package/dist/skills/activator.js +0 -1
  219. package/dist/skills/builtin.d.ts +2 -0
  220. package/dist/skills/builtin.js +68 -0
  221. package/dist/skills/index.d.ts +2 -1
  222. package/dist/skills/index.js +2 -1
  223. package/dist/skills/loader.d.ts +10 -4
  224. package/dist/skills/loader.js +20 -8
  225. package/dist/skills/marketplace-types.d.ts +0 -1
  226. package/dist/skills/marketplace-types.js +0 -1
  227. package/dist/skills/marketplace.d.ts +0 -1
  228. package/dist/skills/marketplace.js +2 -2
  229. package/dist/skills/parser.d.ts +0 -1
  230. package/dist/skills/parser.js +0 -1
  231. package/dist/skills/remote.d.ts +14 -0
  232. package/dist/skills/remote.js +131 -0
  233. package/dist/skills/types.d.ts +10 -1
  234. package/dist/skills/types.js +0 -1
  235. package/dist/specs/generate.d.ts +0 -1
  236. package/dist/specs/generate.js +0 -1
  237. package/dist/specs/index.d.ts +0 -1
  238. package/dist/specs/index.js +0 -1
  239. package/dist/specs/store.d.ts +0 -1
  240. package/dist/specs/store.js +0 -1
  241. package/dist/specs/sync.d.ts +0 -1
  242. package/dist/specs/sync.js +0 -1
  243. package/dist/specs/tasks-parser.d.ts +0 -1
  244. package/dist/specs/tasks-parser.js +0 -1
  245. package/dist/specs/types.d.ts +0 -1
  246. package/dist/specs/types.js +0 -1
  247. package/dist/steering/extra-instructions.d.ts +8 -0
  248. package/dist/steering/extra-instructions.js +104 -0
  249. package/dist/steering/folder-instructions.d.ts +8 -0
  250. package/dist/steering/folder-instructions.js +28 -0
  251. package/dist/steering/glob.d.ts +0 -1
  252. package/dist/steering/glob.js +0 -1
  253. package/dist/steering/index.d.ts +0 -1
  254. package/dist/steering/index.js +0 -1
  255. package/dist/steering/loader.d.ts +0 -1
  256. package/dist/steering/loader.js +0 -1
  257. package/dist/steering/project-instructions.d.ts +0 -1
  258. package/dist/steering/project-instructions.js +0 -1
  259. package/dist/steering/select.d.ts +0 -1
  260. package/dist/steering/select.js +2 -2
  261. package/dist/steering/types.d.ts +0 -1
  262. package/dist/steering/types.js +0 -1
  263. package/dist/structured/index.d.ts +0 -1
  264. package/dist/structured/index.js +0 -1
  265. package/dist/structured/retry.d.ts +0 -1
  266. package/dist/structured/retry.js +0 -1
  267. package/dist/structured/schema.d.ts +0 -1
  268. package/dist/structured/schema.js +0 -1
  269. package/dist/timed-fetch.d.ts +12 -0
  270. package/dist/timed-fetch.js +83 -0
  271. package/dist/tools/apply-patch.d.ts +52 -0
  272. package/dist/tools/apply-patch.js +197 -0
  273. package/dist/tools/ask-user.d.ts +27 -0
  274. package/dist/tools/ask-user.js +32 -0
  275. package/dist/tools/browser-tools.d.ts +6 -7
  276. package/dist/tools/browser-tools.js +3 -14
  277. package/dist/tools/codebase-search.d.ts +4 -3
  278. package/dist/tools/codebase-search.js +2 -3
  279. package/dist/tools/command-allow.d.ts +0 -1
  280. package/dist/tools/command-allow.js +0 -1
  281. package/dist/tools/edit-file.d.ts +0 -1
  282. package/dist/tools/edit-file.js +5 -4
  283. package/dist/tools/fetch-url.d.ts +7 -1
  284. package/dist/tools/fetch-url.js +52 -20
  285. package/dist/tools/find-references.d.ts +0 -1
  286. package/dist/tools/find-references.js +0 -1
  287. package/dist/tools/find-symbol.d.ts +2 -3
  288. package/dist/tools/find-symbol.js +0 -1
  289. package/dist/tools/ignore-rules.d.ts +0 -1
  290. package/dist/tools/ignore-rules.js +2 -2
  291. package/dist/tools/index.d.ts +5 -2
  292. package/dist/tools/index.js +10 -2
  293. package/dist/tools/list-files.d.ts +0 -1
  294. package/dist/tools/list-files.js +0 -1
  295. package/dist/tools/list-symbols.d.ts +0 -1
  296. package/dist/tools/list-symbols.js +0 -1
  297. package/dist/tools/memory.d.ts +6 -7
  298. package/dist/tools/memory.js +0 -1
  299. package/dist/tools/notebook.d.ts +2 -3
  300. package/dist/tools/notebook.js +0 -1
  301. package/dist/tools/permission-rules.d.ts +32 -0
  302. package/dist/tools/permission-rules.js +182 -0
  303. package/dist/tools/policy.d.ts +0 -1
  304. package/dist/tools/policy.js +0 -1
  305. package/dist/tools/read-file.d.ts +5 -1
  306. package/dist/tools/read-file.js +7 -3
  307. package/dist/tools/read-image.d.ts +0 -1
  308. package/dist/tools/read-image.js +0 -1
  309. package/dist/tools/read-only.d.ts +1 -2
  310. package/dist/tools/read-only.js +2 -1
  311. package/dist/tools/redact.d.ts +0 -1
  312. package/dist/tools/redact.js +0 -1
  313. package/dist/tools/result-cache.d.ts +0 -1
  314. package/dist/tools/result-cache.js +0 -1
  315. package/dist/tools/run-command.d.ts +4 -3
  316. package/dist/tools/run-command.js +12 -9
  317. package/dist/tools/sandbox-loader.d.ts +0 -1
  318. package/dist/tools/sandbox-loader.js +3 -14
  319. package/dist/tools/search-files.d.ts +8 -3
  320. package/dist/tools/search-files.js +43 -1
  321. package/dist/tools/shared.d.ts +5 -1
  322. package/dist/tools/shared.js +30 -3
  323. package/dist/tools/shell-env.d.ts +7 -0
  324. package/dist/tools/shell-env.js +9 -0
  325. package/dist/tools/sub-agent-wait.d.ts +29 -0
  326. package/dist/tools/sub-agent-wait.js +60 -0
  327. package/dist/tools/sub-agent.d.ts +50 -5
  328. package/dist/tools/sub-agent.js +210 -126
  329. package/dist/tools/text-encoding.d.ts +10 -0
  330. package/dist/tools/text-encoding.js +40 -0
  331. package/dist/tools/todo.d.ts +36 -0
  332. package/dist/tools/todo.js +42 -0
  333. package/dist/tools/web-search.d.ts +0 -1
  334. package/dist/tools/web-search.js +0 -1
  335. package/dist/tools/write-file.d.ts +0 -1
  336. package/dist/tools/write-file.js +15 -10
  337. package/dist/tools/write-tools.d.ts +12 -0
  338. package/dist/tools/write-tools.js +18 -0
  339. package/dist/types.d.ts +85 -2
  340. package/dist/types.js +0 -1
  341. package/dist/verify/detect.d.ts +0 -1
  342. package/dist/verify/detect.js +0 -1
  343. package/dist/verify/index.d.ts +0 -1
  344. package/dist/verify/index.js +0 -1
  345. package/dist/worktree/branch-ops.d.ts +0 -1
  346. package/dist/worktree/branch-ops.js +0 -1
  347. package/dist/worktree/index.d.ts +0 -1
  348. package/dist/worktree/index.js +0 -1
  349. package/dist/worktree/worktree.d.ts +3 -1
  350. package/dist/worktree/worktree.js +22 -1
  351. package/package.json +3 -2
  352. package/dist/agent/agent.d.ts.map +0 -1
  353. package/dist/agent/agent.js.map +0 -1
  354. package/dist/agent/architect.d.ts.map +0 -1
  355. package/dist/agent/architect.js.map +0 -1
  356. package/dist/agent/cache-hints.d.ts.map +0 -1
  357. package/dist/agent/cache-hints.js.map +0 -1
  358. package/dist/agent/cost-router.d.ts.map +0 -1
  359. package/dist/agent/cost-router.js.map +0 -1
  360. package/dist/agent/index.d.ts.map +0 -1
  361. package/dist/agent/index.js.map +0 -1
  362. package/dist/agent/prompts.d.ts.map +0 -1
  363. package/dist/agent/prompts.js.map +0 -1
  364. package/dist/agent/think-tags.d.ts.map +0 -1
  365. package/dist/agent/think-tags.js.map +0 -1
  366. package/dist/agent/verify.d.ts.map +0 -1
  367. package/dist/agent/verify.js.map +0 -1
  368. package/dist/ai-comments/index.d.ts.map +0 -1
  369. package/dist/ai-comments/index.js.map +0 -1
  370. package/dist/attachments.d.ts.map +0 -1
  371. package/dist/attachments.js.map +0 -1
  372. package/dist/browser/cdp.d.ts.map +0 -1
  373. package/dist/browser/cdp.js.map +0 -1
  374. package/dist/browser/chrome.d.ts.map +0 -1
  375. package/dist/browser/chrome.js.map +0 -1
  376. package/dist/browser/session.d.ts.map +0 -1
  377. package/dist/browser/session.js.map +0 -1
  378. package/dist/checkpoints/index.d.ts.map +0 -1
  379. package/dist/checkpoints/index.js.map +0 -1
  380. package/dist/checkpoints/store.d.ts.map +0 -1
  381. package/dist/checkpoints/store.js.map +0 -1
  382. package/dist/checkpoints/types.d.ts.map +0 -1
  383. package/dist/checkpoints/types.js.map +0 -1
  384. package/dist/code-index/builder.d.ts.map +0 -1
  385. package/dist/code-index/builder.js.map +0 -1
  386. package/dist/code-index/index-store.d.ts.map +0 -1
  387. package/dist/code-index/index-store.js.map +0 -1
  388. package/dist/code-index/parser.d.ts.map +0 -1
  389. package/dist/code-index/parser.js.map +0 -1
  390. package/dist/code-index/types.d.ts.map +0 -1
  391. package/dist/code-index/types.js.map +0 -1
  392. package/dist/commands/custom-commands.d.ts.map +0 -1
  393. package/dist/commands/custom-commands.js.map +0 -1
  394. package/dist/config-file.d.ts.map +0 -1
  395. package/dist/config-file.js.map +0 -1
  396. package/dist/config.d.ts.map +0 -1
  397. package/dist/config.js.map +0 -1
  398. package/dist/context/compaction.d.ts.map +0 -1
  399. package/dist/context/compaction.js.map +0 -1
  400. package/dist/context/mask.d.ts.map +0 -1
  401. package/dist/context/mask.js.map +0 -1
  402. package/dist/credentials/index.d.ts.map +0 -1
  403. package/dist/credentials/index.js.map +0 -1
  404. package/dist/credentials/types.d.ts.map +0 -1
  405. package/dist/credentials/types.js.map +0 -1
  406. package/dist/diff/index.d.ts.map +0 -1
  407. package/dist/diff/index.js.map +0 -1
  408. package/dist/diff/unified-diff.d.ts.map +0 -1
  409. package/dist/diff/unified-diff.js.map +0 -1
  410. package/dist/git/auto-commit.d.ts.map +0 -1
  411. package/dist/git/auto-commit.js.map +0 -1
  412. package/dist/git/index.d.ts.map +0 -1
  413. package/dist/git/index.js.map +0 -1
  414. package/dist/github/github-tools.d.ts.map +0 -1
  415. package/dist/github/github-tools.js.map +0 -1
  416. package/dist/hooks/agent-runner.d.ts.map +0 -1
  417. package/dist/hooks/agent-runner.js.map +0 -1
  418. package/dist/hooks/bus.d.ts.map +0 -1
  419. package/dist/hooks/bus.js.map +0 -1
  420. package/dist/hooks/config.d.ts.map +0 -1
  421. package/dist/hooks/config.js.map +0 -1
  422. package/dist/hooks/events.d.ts.map +0 -1
  423. package/dist/hooks/events.js.map +0 -1
  424. package/dist/hooks/index.d.ts.map +0 -1
  425. package/dist/hooks/index.js.map +0 -1
  426. package/dist/hooks/loader.d.ts.map +0 -1
  427. package/dist/hooks/loader.js.map +0 -1
  428. package/dist/hooks/runner.d.ts.map +0 -1
  429. package/dist/hooks/runner.js.map +0 -1
  430. package/dist/hooks/watch-coalescer.d.ts.map +0 -1
  431. package/dist/hooks/watch-coalescer.js.map +0 -1
  432. package/dist/hooks/watch-ignore.d.ts.map +0 -1
  433. package/dist/hooks/watch-ignore.js.map +0 -1
  434. package/dist/hooks/watcher.d.ts.map +0 -1
  435. package/dist/hooks/watcher.js.map +0 -1
  436. package/dist/index.d.ts.map +0 -1
  437. package/dist/index.js.map +0 -1
  438. package/dist/lazy-model.d.ts.map +0 -1
  439. package/dist/lazy-model.js.map +0 -1
  440. package/dist/lint/auto-lint.d.ts.map +0 -1
  441. package/dist/lint/auto-lint.js.map +0 -1
  442. package/dist/lint/index.d.ts.map +0 -1
  443. package/dist/lint/index.js.map +0 -1
  444. package/dist/lsp/client.d.ts.map +0 -1
  445. package/dist/lsp/client.js.map +0 -1
  446. package/dist/lsp/diagnostics.d.ts.map +0 -1
  447. package/dist/lsp/diagnostics.js.map +0 -1
  448. package/dist/lsp/index.d.ts.map +0 -1
  449. package/dist/lsp/index.js.map +0 -1
  450. package/dist/mcp/catalog.d.ts.map +0 -1
  451. package/dist/mcp/catalog.js.map +0 -1
  452. package/dist/mcp/index.d.ts.map +0 -1
  453. package/dist/mcp/index.js.map +0 -1
  454. package/dist/mcp/json-schema-to-zod.d.ts.map +0 -1
  455. package/dist/mcp/json-schema-to-zod.js.map +0 -1
  456. package/dist/mcp/manager.d.ts.map +0 -1
  457. package/dist/mcp/manager.js.map +0 -1
  458. package/dist/mcp/marketplace-types.d.ts.map +0 -1
  459. package/dist/mcp/marketplace-types.js.map +0 -1
  460. package/dist/mcp/marketplace.d.ts.map +0 -1
  461. package/dist/mcp/marketplace.js.map +0 -1
  462. package/dist/mcp/mcp-client.d.ts.map +0 -1
  463. package/dist/mcp/mcp-client.js.map +0 -1
  464. package/dist/mcp/mcp-config.d.ts.map +0 -1
  465. package/dist/mcp/mcp-config.js.map +0 -1
  466. package/dist/mcp/registry.d.ts.map +0 -1
  467. package/dist/mcp/registry.js.map +0 -1
  468. package/dist/memory/memory-store.d.ts.map +0 -1
  469. package/dist/memory/memory-store.js.map +0 -1
  470. package/dist/memory/rank.d.ts.map +0 -1
  471. package/dist/memory/rank.js.map +0 -1
  472. package/dist/memory/stale.d.ts.map +0 -1
  473. package/dist/memory/stale.js.map +0 -1
  474. package/dist/model-alias.d.ts.map +0 -1
  475. package/dist/model-alias.js.map +0 -1
  476. package/dist/model-catalog.d.ts.map +0 -1
  477. package/dist/model-catalog.js.map +0 -1
  478. package/dist/model-list.d.ts.map +0 -1
  479. package/dist/model-list.js.map +0 -1
  480. package/dist/orchestrator/board-tools.d.ts.map +0 -1
  481. package/dist/orchestrator/board-tools.js.map +0 -1
  482. package/dist/orchestrator/board.d.ts.map +0 -1
  483. package/dist/orchestrator/board.js.map +0 -1
  484. package/dist/orchestrator/index.d.ts.map +0 -1
  485. package/dist/orchestrator/index.js.map +0 -1
  486. package/dist/orchestrator/orchestrator.d.ts.map +0 -1
  487. package/dist/orchestrator/orchestrator.js.map +0 -1
  488. package/dist/orchestrator/router.d.ts.map +0 -1
  489. package/dist/orchestrator/router.js.map +0 -1
  490. package/dist/orchestrator/specialists-registry.d.ts.map +0 -1
  491. package/dist/orchestrator/specialists-registry.js.map +0 -1
  492. package/dist/orchestrator/specialists.d.ts.map +0 -1
  493. package/dist/orchestrator/specialists.js.map +0 -1
  494. package/dist/orchestrator/types.d.ts.map +0 -1
  495. package/dist/orchestrator/types.js.map +0 -1
  496. package/dist/plugins/index.d.ts.map +0 -1
  497. package/dist/plugins/index.js.map +0 -1
  498. package/dist/plugins/install.d.ts.map +0 -1
  499. package/dist/plugins/install.js.map +0 -1
  500. package/dist/plugins/loader.d.ts.map +0 -1
  501. package/dist/plugins/loader.js.map +0 -1
  502. package/dist/policy/audit.d.ts.map +0 -1
  503. package/dist/policy/audit.js.map +0 -1
  504. package/dist/policy/policy.d.ts.map +0 -1
  505. package/dist/policy/policy.js.map +0 -1
  506. package/dist/policy/proxy.d.ts.map +0 -1
  507. package/dist/policy/proxy.js.map +0 -1
  508. package/dist/pricing.d.ts.map +0 -1
  509. package/dist/pricing.js.map +0 -1
  510. package/dist/providers.d.ts.map +0 -1
  511. package/dist/providers.js.map +0 -1
  512. package/dist/repomap/index.d.ts.map +0 -1
  513. package/dist/repomap/index.js.map +0 -1
  514. package/dist/repomap/repo-map.d.ts.map +0 -1
  515. package/dist/repomap/repo-map.js.map +0 -1
  516. package/dist/semantic/chunker.d.ts.map +0 -1
  517. package/dist/semantic/chunker.js.map +0 -1
  518. package/dist/semantic/embedder.d.ts.map +0 -1
  519. package/dist/semantic/embedder.js.map +0 -1
  520. package/dist/semantic/semantic-index.d.ts.map +0 -1
  521. package/dist/semantic/semantic-index.js.map +0 -1
  522. package/dist/semantic/vector-store.d.ts.map +0 -1
  523. package/dist/semantic/vector-store.js.map +0 -1
  524. package/dist/sessions/index.d.ts.map +0 -1
  525. package/dist/sessions/index.js.map +0 -1
  526. package/dist/sessions/search.d.ts.map +0 -1
  527. package/dist/sessions/search.js.map +0 -1
  528. package/dist/sessions/session-export.d.ts.map +0 -1
  529. package/dist/sessions/session-export.js.map +0 -1
  530. package/dist/sessions/session-store.d.ts.map +0 -1
  531. package/dist/sessions/session-store.js.map +0 -1
  532. package/dist/sessions/watch.d.ts.map +0 -1
  533. package/dist/sessions/watch.js.map +0 -1
  534. package/dist/settings-export.d.ts.map +0 -1
  535. package/dist/settings-export.js.map +0 -1
  536. package/dist/skills/activator.d.ts.map +0 -1
  537. package/dist/skills/activator.js.map +0 -1
  538. package/dist/skills/index.d.ts.map +0 -1
  539. package/dist/skills/index.js.map +0 -1
  540. package/dist/skills/loader.d.ts.map +0 -1
  541. package/dist/skills/loader.js.map +0 -1
  542. package/dist/skills/marketplace-types.d.ts.map +0 -1
  543. package/dist/skills/marketplace-types.js.map +0 -1
  544. package/dist/skills/marketplace.d.ts.map +0 -1
  545. package/dist/skills/marketplace.js.map +0 -1
  546. package/dist/skills/parser.d.ts.map +0 -1
  547. package/dist/skills/parser.js.map +0 -1
  548. package/dist/skills/types.d.ts.map +0 -1
  549. package/dist/skills/types.js.map +0 -1
  550. package/dist/specs/generate.d.ts.map +0 -1
  551. package/dist/specs/generate.js.map +0 -1
  552. package/dist/specs/index.d.ts.map +0 -1
  553. package/dist/specs/index.js.map +0 -1
  554. package/dist/specs/store.d.ts.map +0 -1
  555. package/dist/specs/store.js.map +0 -1
  556. package/dist/specs/sync.d.ts.map +0 -1
  557. package/dist/specs/sync.js.map +0 -1
  558. package/dist/specs/tasks-parser.d.ts.map +0 -1
  559. package/dist/specs/tasks-parser.js.map +0 -1
  560. package/dist/specs/types.d.ts.map +0 -1
  561. package/dist/specs/types.js.map +0 -1
  562. package/dist/steering/glob.d.ts.map +0 -1
  563. package/dist/steering/glob.js.map +0 -1
  564. package/dist/steering/index.d.ts.map +0 -1
  565. package/dist/steering/index.js.map +0 -1
  566. package/dist/steering/loader.d.ts.map +0 -1
  567. package/dist/steering/loader.js.map +0 -1
  568. package/dist/steering/project-instructions.d.ts.map +0 -1
  569. package/dist/steering/project-instructions.js.map +0 -1
  570. package/dist/steering/select.d.ts.map +0 -1
  571. package/dist/steering/select.js.map +0 -1
  572. package/dist/steering/types.d.ts.map +0 -1
  573. package/dist/steering/types.js.map +0 -1
  574. package/dist/structured/index.d.ts.map +0 -1
  575. package/dist/structured/index.js.map +0 -1
  576. package/dist/structured/retry.d.ts.map +0 -1
  577. package/dist/structured/retry.js.map +0 -1
  578. package/dist/structured/schema.d.ts.map +0 -1
  579. package/dist/structured/schema.js.map +0 -1
  580. package/dist/tools/browser-tools.d.ts.map +0 -1
  581. package/dist/tools/browser-tools.js.map +0 -1
  582. package/dist/tools/codebase-search.d.ts.map +0 -1
  583. package/dist/tools/codebase-search.js.map +0 -1
  584. package/dist/tools/command-allow.d.ts.map +0 -1
  585. package/dist/tools/command-allow.js.map +0 -1
  586. package/dist/tools/edit-file.d.ts.map +0 -1
  587. package/dist/tools/edit-file.js.map +0 -1
  588. package/dist/tools/fetch-url.d.ts.map +0 -1
  589. package/dist/tools/fetch-url.js.map +0 -1
  590. package/dist/tools/find-references.d.ts.map +0 -1
  591. package/dist/tools/find-references.js.map +0 -1
  592. package/dist/tools/find-symbol.d.ts.map +0 -1
  593. package/dist/tools/find-symbol.js.map +0 -1
  594. package/dist/tools/ignore-rules.d.ts.map +0 -1
  595. package/dist/tools/ignore-rules.js.map +0 -1
  596. package/dist/tools/index.d.ts.map +0 -1
  597. package/dist/tools/index.js.map +0 -1
  598. package/dist/tools/list-files.d.ts.map +0 -1
  599. package/dist/tools/list-files.js.map +0 -1
  600. package/dist/tools/list-symbols.d.ts.map +0 -1
  601. package/dist/tools/list-symbols.js.map +0 -1
  602. package/dist/tools/memory.d.ts.map +0 -1
  603. package/dist/tools/memory.js.map +0 -1
  604. package/dist/tools/notebook.d.ts.map +0 -1
  605. package/dist/tools/notebook.js.map +0 -1
  606. package/dist/tools/policy.d.ts.map +0 -1
  607. package/dist/tools/policy.js.map +0 -1
  608. package/dist/tools/read-file.d.ts.map +0 -1
  609. package/dist/tools/read-file.js.map +0 -1
  610. package/dist/tools/read-image.d.ts.map +0 -1
  611. package/dist/tools/read-image.js.map +0 -1
  612. package/dist/tools/read-only.d.ts.map +0 -1
  613. package/dist/tools/read-only.js.map +0 -1
  614. package/dist/tools/redact.d.ts.map +0 -1
  615. package/dist/tools/redact.js.map +0 -1
  616. package/dist/tools/result-cache.d.ts.map +0 -1
  617. package/dist/tools/result-cache.js.map +0 -1
  618. package/dist/tools/run-command.d.ts.map +0 -1
  619. package/dist/tools/run-command.js.map +0 -1
  620. package/dist/tools/sandbox-loader.d.ts.map +0 -1
  621. package/dist/tools/sandbox-loader.js.map +0 -1
  622. package/dist/tools/search-files.d.ts.map +0 -1
  623. package/dist/tools/search-files.js.map +0 -1
  624. package/dist/tools/shared.d.ts.map +0 -1
  625. package/dist/tools/shared.js.map +0 -1
  626. package/dist/tools/sub-agent.d.ts.map +0 -1
  627. package/dist/tools/sub-agent.js.map +0 -1
  628. package/dist/tools/web-search.d.ts.map +0 -1
  629. package/dist/tools/web-search.js.map +0 -1
  630. package/dist/tools/write-file.d.ts.map +0 -1
  631. package/dist/tools/write-file.js.map +0 -1
  632. package/dist/types.d.ts.map +0 -1
  633. package/dist/types.js.map +0 -1
  634. package/dist/verify/detect.d.ts.map +0 -1
  635. package/dist/verify/detect.js.map +0 -1
  636. package/dist/verify/index.d.ts.map +0 -1
  637. package/dist/verify/index.js.map +0 -1
  638. package/dist/worktree/branch-ops.d.ts.map +0 -1
  639. package/dist/worktree/branch-ops.js.map +0 -1
  640. package/dist/worktree/index.d.ts.map +0 -1
  641. package/dist/worktree/index.js.map +0 -1
  642. package/dist/worktree/worktree.d.ts.map +0 -1
  643. package/dist/worktree/worktree.js.map +0 -1
@@ -156,4 +156,3 @@ export class BrowserSession {
156
156
  this.console = [];
157
157
  }
158
158
  }
159
- //# sourceMappingURL=session.js.map
@@ -9,4 +9,3 @@
9
9
  */
10
10
  export { CheckpointStore, type CheckpointStoreLimits } from './store.js';
11
11
  export type { CaptureOptions, Checkpoint, CheckpointFile, CheckpointFileStatus, CheckpointSummary, CheckpointTrigger, PruneResult, RestoreResult, } from './types.js';
12
- //# sourceMappingURL=index.d.ts.map
@@ -8,4 +8,3 @@
8
8
  * surfaces list/show/restore/prune via `forge checkpoint …`.
9
9
  */
10
10
  export { CheckpointStore } from './store.js';
11
- //# sourceMappingURL=index.js.map
@@ -86,4 +86,3 @@ export declare class CheckpointStore {
86
86
  /** Delete every checkpoint for this session. Called on session reset. */
87
87
  clear(): Promise<void>;
88
88
  }
89
- //# sourceMappingURL=store.d.ts.map
@@ -16,6 +16,7 @@ import { existsSync } from 'node:fs';
16
16
  import { mkdir, readdir, readFile, rm, writeFile } from 'node:fs/promises';
17
17
  import path from 'node:path';
18
18
  import { snapshotWorktreeContext } from '../worktree/worktree.js';
19
+ import { isOutsideRel } from '../tools/shared.js';
19
20
  const MANIFEST_FILENAME = 'manifest.json';
20
21
  const FILES_SUBDIR = 'files';
21
22
  /** Default retention for prune. Keeps the last 20 checkpoints. */
@@ -128,7 +129,7 @@ export class CheckpointStore {
128
129
  const abs = path.resolve(this.cwd, options.focusPath);
129
130
  const rel = path.relative(this.cwd, abs);
130
131
  // Skip files outside cwd (security: never capture /etc/passwd).
131
- if (!rel.startsWith('..') && !path.isAbsolute(rel)) {
132
+ if (!isOutsideRel(rel)) {
132
133
  await this.captureFile(rel, files, dir);
133
134
  }
134
135
  }
@@ -316,6 +317,9 @@ export class CheckpointStore {
316
317
  };
317
318
  for (const file of checkpoint.files) {
318
319
  const abs = path.join(this.cwd, file.path);
320
+ // A manifest is data on disk: an entry leading out of the workspace (damaged or edited) is never written or removed.
321
+ if (isOutsideRel(path.relative(this.cwd, abs)))
322
+ continue;
319
323
  const contentPath = path.join(dir, FILES_SUBDIR, encodePath(file.path));
320
324
  if (file.status === 'deleted') {
321
325
  if (existsSync(abs)) {
@@ -408,4 +412,3 @@ function defaultDescription(options) {
408
412
  }
409
413
  return 'manual checkpoint';
410
414
  }
411
- //# sourceMappingURL=store.js.map
@@ -159,4 +159,3 @@ export interface CaptureOptions {
159
159
  */
160
160
  worktreeContextOverride?: import('./types.js').CheckpointWorktreeContext | null;
161
161
  }
162
- //# sourceMappingURL=types.d.ts.map
@@ -18,4 +18,3 @@
18
18
  * checkpoints travel with sessions when they're saved / resumed.
19
19
  */
20
20
  export {};
21
- //# sourceMappingURL=types.js.map
@@ -6,4 +6,3 @@ import type { IndexManifest } from './types.js';
6
6
  * (only when something actually changed): never once per file.
7
7
  */
8
8
  export declare function ensureFresh(cwd: string): Promise<IndexManifest>;
9
- //# sourceMappingURL=builder.d.ts.map
@@ -64,4 +64,3 @@ export async function ensureFresh(cwd) {
64
64
  await saveManifest(cwd, manifest);
65
65
  return manifest;
66
66
  }
67
- //# sourceMappingURL=builder.js.map
@@ -9,4 +9,3 @@ export declare function saveManifest(cwd: string, manifest: IndexManifest): Prom
9
9
  export declare function getEntry(manifest: IndexManifest, relPath: string): IndexFileEntry | undefined;
10
10
  export declare function setEntry(manifest: IndexManifest, relPath: string, entry: IndexFileEntry): void;
11
11
  export declare function deleteEntry(manifest: IndexManifest, relPath: string): void;
12
- //# sourceMappingURL=index-store.d.ts.map
@@ -41,4 +41,3 @@ function isValidManifest(value) {
41
41
  const v = value;
42
42
  return v.version === 1 && typeof v.files === 'object' && v.files !== null;
43
43
  }
44
- //# sourceMappingURL=index-store.js.map
@@ -19,4 +19,3 @@ export interface SyntaxProblem {
19
19
  * and an empty array when the file parses cleanly.
20
20
  */
21
21
  export declare function findSyntaxErrors(source: string, ext: string): Promise<SyntaxProblem[] | null>;
22
- //# sourceMappingURL=parser.d.ts.map
@@ -286,4 +286,3 @@ function unwrapExport(node) {
286
286
  const inner = node.namedChildren.find((c) => c && c.type !== 'export_clause' && c.type !== 'string');
287
287
  return inner ?? node;
288
288
  }
289
- //# sourceMappingURL=parser.js.map
@@ -21,4 +21,3 @@ export interface IndexManifest {
21
21
  version: 1;
22
22
  files: Record<string, IndexFileEntry>;
23
23
  }
24
- //# sourceMappingURL=types.d.ts.map
@@ -3,4 +3,3 @@
3
3
  * list_symbols, find_references) and the index that backs them.
4
4
  */
5
5
  export {};
6
- //# sourceMappingURL=types.js.map
@@ -2,6 +2,14 @@ export interface CustomCommand {
2
2
  /** Lowercase name used after the slash. */
3
3
  name: string;
4
4
  description?: string;
5
+ /** Front matter `agent`: the agent (mode) this command runs as. */
6
+ agent?: string;
7
+ /** Front matter `model`: a model for this command. */
8
+ model?: string;
9
+ /** Front matter `variant`: reasoning effort for this command. */
10
+ variant?: 'low' | 'medium' | 'high';
11
+ /** Front matter `subtask: true`: hand the work to `agent` through sub_agent instead of switching to it. */
12
+ subtask?: boolean;
5
13
  template: string;
6
14
  source: 'user' | 'project';
7
15
  /** Absolute path of the template file. */
@@ -12,14 +20,10 @@ export declare function commandDirs(cwd: string, home?: string): Array<{
12
20
  source: 'user' | 'project';
13
21
  }>;
14
22
  /** Split optional `---` front matter from the body and read its `description`. */
15
- export declare function parseCommandFile(text: string): {
16
- description?: string;
17
- template: string;
18
- };
23
+ export declare function parseCommandFile(text: string): Pick<CustomCommand, 'description' | 'agent' | 'model' | 'variant' | 'subtask' | 'template'>;
19
24
  /** Every custom command, keyed by name; project commands replace personal ones. */
20
25
  export declare function loadCustomCommands(cwd: string, home?: string): Promise<Map<string, CustomCommand>>;
21
26
  /** The message a command sends for these arguments. */
22
27
  export declare function expandCustomCommand(command: Pick<CustomCommand, 'template'>, args: string): string;
23
28
  /** `/name — description` lines for help output. */
24
29
  export declare function formatCustomCommands(commands: Map<string, CustomCommand>): string;
25
- //# sourceMappingURL=custom-commands.d.ts.map
@@ -34,8 +34,19 @@ export function parseCommandFile(text) {
34
34
  const m = /^---\n([\s\S]*?)\n---\n?/.exec(normalized);
35
35
  if (!m)
36
36
  return { template: normalized.trim() };
37
- const desc = /^description:\s*(.+)$/m.exec(m[1])?.[1]?.trim().replace(/^(['"])(.*)\1$/, '$2');
38
- return { ...(desc ? { description: desc } : {}), template: normalized.slice(m[0].length).trim() };
37
+ const field = (key) => new RegExp('^' + key + ':\\s*(.+)$', 'm').exec(m[1])?.[1]?.trim().replace(/^(['"])(.*)\1$/, '$2');
38
+ const desc = field('description');
39
+ const agent = field('agent');
40
+ const model = field('model');
41
+ const variant = field('variant');
42
+ return {
43
+ ...(desc ? { description: desc } : {}),
44
+ ...(agent ? { agent } : {}),
45
+ ...(model ? { model } : {}),
46
+ ...(variant === 'low' || variant === 'medium' || variant === 'high' ? { variant } : {}),
47
+ ...(field('subtask') === 'true' ? { subtask: true } : {}),
48
+ template: normalized.slice(m[0].length).trim(),
49
+ };
39
50
  }
40
51
  /** Every custom command, keyed by name; project commands replace personal ones. */
41
52
  export async function loadCustomCommands(cwd, home) {
@@ -96,4 +107,3 @@ export function formatCustomCommands(commands) {
96
107
  .map((c) => `/${c.name}${c.description ? ` — ${c.description}` : ''}${c.source === 'project' ? ' (project)' : ''}`)
97
108
  .join('\n');
98
109
  }
99
- //# sourceMappingURL=custom-commands.js.map
@@ -1,4 +1,7 @@
1
1
  import type { ModelAliases } from './model-alias.js';
2
+ import { type CustomProviderConfig } from './custom-providers.js';
3
+ import type { ModelOverride } from './model-overrides.js';
4
+ import type { PermissionConfig } from './tools/permission-rules.js';
2
5
  import type { ProviderName } from './types.js';
3
6
  /**
4
7
  * Shape of `~/.forge/config.json`: cross-surface provider/model/display
@@ -20,12 +23,48 @@ export interface ForgeConfigFile {
20
23
  command: string;
21
24
  fingerprint?: string;
22
25
  }>>;
26
+ /**
27
+ * Ordered permission rules (`read`, `edit`, `bash`, `webfetch`, `websearch`, `task`, `external_directory`): each maps
28
+ * to an action or to a pattern → action map; the last matching rule wins. See tools/permission-rules.ts.
29
+ */
30
+ permission?: PermissionConfig;
31
+ /**
32
+ * Providers beyond the built-in eleven, by id: `groq` and other presets need only a key, anything else needs a
33
+ * `baseUrl`. A model on one is written `id:model` (e.g. `acme:fast`). See custom-providers.ts.
34
+ */
35
+ customProviders?: Record<string, CustomProviderConfig>;
36
+ /** Context and output limits and prices per model, keyed `provider:model`, `id:model` or a bare model id. */
37
+ modelOverrides?: Record<string, ModelOverride>;
38
+ /** Per provider, which model ids the pickers list: `whitelist` (only these) then `blacklist` (not these). */
39
+ modelFilters?: Record<string, {
40
+ whitelist?: string[];
41
+ blacklist?: string[];
42
+ }>;
43
+ /** The model sub-agents use when the model does not name one; blank means the parent's model. */
44
+ subagentModel?: string;
45
+ /** Extra instruction sources added to the system prompt: files, globs (workspace-relative) and http(s) URLs. User config only. */
46
+ instructions?: string[];
47
+ /** Extra places to read skills from: folders (absolute, `~/...`, or relative to the workspace) or http(s) URLs of a skill file or a skill index. User config only. */
48
+ skillPaths?: string[];
49
+ /** PEM files of extra certificate authorities to trust (absolute or `~/...`), for company networks that re-sign TLS. User config only. */
50
+ caCertificates?: string[];
23
51
  /** Short names for models: `"fast": "anthropic:claude-haiku-4-5"`. See model-alias.ts. */
24
52
  aliases?: ModelAliases;
53
+ /** Model for a chat mode that has none of its own: mode id → `provider:model`, bare model id or alias. */
54
+ modeModels?: Record<string, string>;
55
+ /** Delete saved sessions not updated for this many days, when the VS Code extension starts. Unset keeps everything. */
56
+ sessionRetentionDays?: number;
25
57
  display?: {
26
58
  blockDefault?: 'collapsed' | 'expanded';
27
59
  detail?: 'compact' | 'full';
28
60
  showReasoning?: boolean;
61
+ /** Per kind of block; overrides the two settings above for that kind. */
62
+ blocks?: {
63
+ reasoning?: 'hidden' | 'collapsed' | 'expanded';
64
+ terminal?: 'collapsed' | 'expanded';
65
+ edit?: 'collapsed' | 'expanded';
66
+ mcp?: 'collapsed' | 'expanded';
67
+ };
29
68
  };
30
69
  }
31
70
  export interface LoadForgeConfigFileResult {
@@ -41,4 +80,11 @@ export declare function loadForgeConfigFile(configPath?: string): Promise<LoadFo
41
80
  * Fields not present in `partial` are left untouched.
42
81
  */
43
82
  export declare function saveForgeConfigFile(partial: ForgeConfigFile, configPath?: string): Promise<void>;
44
- //# sourceMappingURL=config-file.d.ts.map
83
+ /**
84
+ * Read-modify-write of a JSON settings file, safely:
85
+ * - merged over the file as written, not the cleaned config, so keys this version drops or does not know survive;
86
+ * - a file that exists but is not valid JSON is never overwritten (that would replace every setting with one);
87
+ * - writes to one path from this process run one after another, so two saves at once both land;
88
+ * - written to a temporary file and renamed, so a crash cannot leave half a file.
89
+ */
90
+ export declare function updateJsonFile(filePath: string, update: (existing: Record<string, unknown>) => Record<string, unknown>): Promise<void>;
@@ -1,7 +1,178 @@
1
- import { mkdir, readFile, writeFile } from 'node:fs/promises';
1
+ import { mkdir, readFile, rename, writeFile } from 'node:fs/promises';
2
2
  import { existsSync } from 'node:fs';
3
3
  import { homedir } from 'node:os';
4
4
  import path from 'node:path';
5
+ import { customProviderProblems } from './custom-providers.js';
6
+ const PERMISSION_ACTIONS = new Set(['allow', 'ask', 'deny']);
7
+ const isObject = (v) => v !== null && typeof v === 'object' && !Array.isArray(v);
8
+ const positiveNumber = (n) => typeof n === 'number' && Number.isFinite(n) && n > 0;
9
+ const nonNegativeNumber = (n) => typeof n === 'number' && Number.isFinite(n) && n >= 0;
10
+ const stringList = (v) => (Array.isArray(v) ? v.filter((x) => typeof x === 'string') : undefined);
11
+ const BLOCK_KINDS = {
12
+ reasoning: ['hidden', 'collapsed', 'expanded'],
13
+ terminal: ['collapsed', 'expanded'],
14
+ edit: ['collapsed', 'expanded'],
15
+ mcp: ['collapsed', 'expanded'],
16
+ };
17
+ /** `display.blocks`: keep the kinds and values the chat understands, warn once about each thing it would silently ignore. */
18
+ function cleanDisplayBlocks(config, filePath, warnings) {
19
+ const blocks = config.display?.blocks;
20
+ if (blocks === undefined)
21
+ return;
22
+ const display = config.display;
23
+ if (!isObject(blocks)) {
24
+ warnings.push(`${filePath}: display.blocks must be an object (reasoning, terminal, edit, mcp); ignored`);
25
+ delete display.blocks;
26
+ return;
27
+ }
28
+ const kept = {};
29
+ for (const [kind, value] of Object.entries(blocks)) {
30
+ const allowed = BLOCK_KINDS[kind];
31
+ if (!allowed)
32
+ warnings.push(`${filePath}: display.blocks.${kind} is not a block kind (${Object.keys(BLOCK_KINDS).join(', ')}); ignored`);
33
+ else if (typeof value !== 'string' || !allowed.includes(value))
34
+ warnings.push(`${filePath}: display.blocks.${kind} must be ${allowed.join(', ')}; ignored`);
35
+ else
36
+ kept[kind] = value;
37
+ }
38
+ if (Object.keys(kept).length)
39
+ display.blocks = kept;
40
+ else
41
+ delete display.blocks;
42
+ }
43
+ /** Validate `customProviders`, `modelOverrides`, `modelFilters` and `subagentModel`, dropping what cannot be used with one warning each. */
44
+ function cleanProviderKeys(config, filePath, warnings) {
45
+ if (config.customProviders !== undefined) {
46
+ const raw = config.customProviders;
47
+ if (!isObject(raw)) {
48
+ warnings.push(`${filePath}: "customProviders" must be an object of provider id → settings; ignored`);
49
+ delete config.customProviders;
50
+ }
51
+ else {
52
+ const kept = {};
53
+ const bad = new Set(customProviderProblems(raw).map((p) => p.id));
54
+ for (const p of customProviderProblems(raw))
55
+ warnings.push(`${filePath}: ${p.message} Ignored.`);
56
+ for (const [id, value] of Object.entries(raw)) {
57
+ if (bad.has(id) || !isObject(value))
58
+ continue;
59
+ const entry = { ...value };
60
+ if (entry.headers !== undefined && !(isObject(entry.headers) && Object.values(entry.headers).every((h) => typeof h === 'string'))) {
61
+ warnings.push(`${filePath}: customProviders.${id}.headers must be text values; headers ignored`);
62
+ delete entry.headers;
63
+ }
64
+ kept[id] = entry;
65
+ }
66
+ if (Object.keys(kept).length)
67
+ config.customProviders = kept;
68
+ else
69
+ delete config.customProviders;
70
+ }
71
+ }
72
+ if (config.modelOverrides !== undefined) {
73
+ const raw = config.modelOverrides;
74
+ if (!isObject(raw)) {
75
+ warnings.push(`${filePath}: "modelOverrides" must be an object of model → numbers; ignored`);
76
+ delete config.modelOverrides;
77
+ }
78
+ else {
79
+ const kept = {};
80
+ for (const [model, value] of Object.entries(raw)) {
81
+ if (!isObject(value)) {
82
+ warnings.push(`${filePath}: modelOverrides.${model} must be an object; ignored`);
83
+ continue;
84
+ }
85
+ const out = {};
86
+ const limit = isObject(value.limit) ? value.limit : undefined;
87
+ if (limit) {
88
+ const l = {};
89
+ for (const k of ['context', 'output']) {
90
+ if (limit[k] === undefined)
91
+ continue;
92
+ if (positiveNumber(limit[k]))
93
+ l[k] = limit[k];
94
+ else
95
+ warnings.push(`${filePath}: modelOverrides.${model}.limit.${k} must be a positive number; ignored`);
96
+ }
97
+ if (Object.keys(l).length)
98
+ out.limit = l;
99
+ }
100
+ const cost = isObject(value.cost) ? value.cost : undefined;
101
+ if (cost) {
102
+ const c = {};
103
+ for (const k of ['input', 'output']) {
104
+ if (cost[k] === undefined)
105
+ continue;
106
+ if (nonNegativeNumber(cost[k]))
107
+ c[k] = cost[k];
108
+ else
109
+ warnings.push(`${filePath}: modelOverrides.${model}.cost.${k} must be a number of 0 or more; ignored`);
110
+ }
111
+ if (Object.keys(c).length)
112
+ out.cost = c;
113
+ }
114
+ if (value.limit !== undefined && !limit)
115
+ warnings.push(`${filePath}: modelOverrides.${model}.limit must be an object; ignored`);
116
+ if (Object.keys(out).length)
117
+ kept[model] = out;
118
+ }
119
+ if (Object.keys(kept).length)
120
+ config.modelOverrides = kept;
121
+ else
122
+ delete config.modelOverrides;
123
+ }
124
+ }
125
+ if (config.modelFilters !== undefined) {
126
+ const raw = config.modelFilters;
127
+ if (!isObject(raw)) {
128
+ warnings.push(`${filePath}: "modelFilters" must be an object of provider → lists; ignored`);
129
+ delete config.modelFilters;
130
+ }
131
+ else {
132
+ const kept = {};
133
+ for (const [provider, value] of Object.entries(raw)) {
134
+ if (!isObject(value))
135
+ continue;
136
+ const whitelist = stringList(value.whitelist);
137
+ const blacklist = stringList(value.blacklist);
138
+ if (whitelist?.length || blacklist?.length)
139
+ kept[provider] = { ...(whitelist?.length ? { whitelist } : {}), ...(blacklist?.length ? { blacklist } : {}) };
140
+ }
141
+ if (Object.keys(kept).length)
142
+ config.modelFilters = kept;
143
+ else
144
+ delete config.modelFilters;
145
+ }
146
+ }
147
+ if (config.instructions !== undefined) {
148
+ const list = stringList(config.instructions)?.map((s) => s.trim()).filter(Boolean);
149
+ if (list?.length)
150
+ config.instructions = list;
151
+ else
152
+ delete config.instructions;
153
+ }
154
+ if (config.skillPaths !== undefined) {
155
+ const list = stringList(config.skillPaths)?.map((s) => s.trim()).filter(Boolean);
156
+ if (list?.length)
157
+ config.skillPaths = list;
158
+ else
159
+ delete config.skillPaths;
160
+ }
161
+ if (config.caCertificates !== undefined) {
162
+ const list = stringList(config.caCertificates)?.map((s) => s.trim()).filter(Boolean);
163
+ if (list?.length)
164
+ config.caCertificates = list;
165
+ else
166
+ delete config.caCertificates;
167
+ }
168
+ if (config.subagentModel !== undefined) {
169
+ const v = typeof config.subagentModel === 'string' ? config.subagentModel.trim() : '';
170
+ if (v)
171
+ config.subagentModel = v;
172
+ else
173
+ delete config.subagentModel;
174
+ }
175
+ }
5
176
  /** Returns `~/.forge/config.json` for the current user. */
6
177
  export function defaultForgeConfigPath() {
7
178
  return path.join(homedir(), '.forge', 'config.json');
@@ -40,6 +211,41 @@ export async function loadForgeConfigFile(configPath) {
40
211
  }
41
212
  }
42
213
  }
214
+ if (config.permission !== undefined) {
215
+ const raw = config.permission;
216
+ if (raw === null || typeof raw !== 'object' || Array.isArray(raw)) {
217
+ warnings.push(`${filePath}: "permission" must be an object of permission → action or pattern map; ignored`);
218
+ delete config.permission;
219
+ }
220
+ else {
221
+ const kept = {};
222
+ for (const [perm, value] of Object.entries(raw)) {
223
+ if (typeof value === 'string') {
224
+ if (PERMISSION_ACTIONS.has(value))
225
+ kept[perm] = value;
226
+ else
227
+ warnings.push(`${filePath}: permission.${perm} is "${value}", not allow, ask or deny; ignored`);
228
+ }
229
+ else if (value !== null && typeof value === 'object' && !Array.isArray(value)) {
230
+ const patterns = {};
231
+ for (const [pattern, action] of Object.entries(value)) {
232
+ if (typeof action === 'string' && PERMISSION_ACTIONS.has(action))
233
+ patterns[pattern] = action;
234
+ else
235
+ warnings.push(`${filePath}: permission.${perm}["${pattern}"] is "${String(action)}", not allow, ask or deny; ignored`);
236
+ }
237
+ if (Object.keys(patterns).length)
238
+ kept[perm] = patterns;
239
+ }
240
+ else {
241
+ warnings.push(`${filePath}: permission.${perm} must be allow, ask, deny or a pattern map; ignored`);
242
+ }
243
+ }
244
+ config.permission = kept;
245
+ }
246
+ }
247
+ cleanProviderKeys(config, filePath, warnings);
248
+ cleanDisplayBlocks(config, filePath, warnings);
43
249
  return { config, warnings };
44
250
  }
45
251
  catch (err) {
@@ -52,9 +258,46 @@ export async function loadForgeConfigFile(configPath) {
52
258
  */
53
259
  export async function saveForgeConfigFile(partial, configPath) {
54
260
  const filePath = configPath ?? defaultForgeConfigPath();
55
- const { config: existing } = await loadForgeConfigFile(filePath);
56
- const merged = { ...existing, ...partial };
57
- await mkdir(path.dirname(filePath), { recursive: true });
58
- await writeFile(filePath, JSON.stringify(merged, null, 2) + '\n', 'utf8');
261
+ await updateJsonFile(filePath, (existing) => ({ ...existing, ...partial }));
262
+ }
263
+ const fileQueues = new Map();
264
+ /**
265
+ * Read-modify-write of a JSON settings file, safely:
266
+ * - merged over the file as written, not the cleaned config, so keys this version drops or does not know survive;
267
+ * - a file that exists but is not valid JSON is never overwritten (that would replace every setting with one);
268
+ * - writes to one path from this process run one after another, so two saves at once both land;
269
+ * - written to a temporary file and renamed, so a crash cannot leave half a file.
270
+ */
271
+ export function updateJsonFile(filePath, update) {
272
+ const key = path.resolve(filePath);
273
+ const run = async () => {
274
+ let existing = {};
275
+ let text;
276
+ try {
277
+ text = await readFile(filePath, 'utf8');
278
+ }
279
+ catch (err) {
280
+ if (err.code !== 'ENOENT')
281
+ throw err;
282
+ }
283
+ if (text !== undefined && text.trim()) {
284
+ let parsed;
285
+ try {
286
+ parsed = JSON.parse(text);
287
+ }
288
+ catch (err) {
289
+ throw new Error(`${filePath} is not valid JSON (${err.message}); fix it before saving, so your other settings are not lost`);
290
+ }
291
+ if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed))
292
+ throw new Error(`${filePath} must hold a JSON object; not saving over it`);
293
+ existing = parsed;
294
+ }
295
+ await mkdir(path.dirname(filePath), { recursive: true });
296
+ const tmp = `${filePath}.${process.pid}.tmp`;
297
+ await writeFile(tmp, JSON.stringify(update(existing), null, 2) + '\n', 'utf8');
298
+ await rename(tmp, filePath);
299
+ };
300
+ const next = (fileQueues.get(key) ?? Promise.resolve()).then(run, run);
301
+ fileQueues.set(key, next.catch(() => undefined));
302
+ return next;
59
303
  }
60
- //# sourceMappingURL=config-file.js.map
@@ -0,0 +1,13 @@
1
+ import { type ForgeConfigFile, type LoadForgeConfigFileResult } from './config-file.js';
2
+ /**
3
+ * The shared config as one object: `~/.forge/config.json`, then the workspace's `.forge/config.json` on top.
4
+ * A project file can pick the model and add stricter rules, but it can never loosen what the user decided:
5
+ * its `allow` permission rules are dropped, and the keys that hold approvals or delete data are only read
6
+ * from the user file. An untrusted workspace contributes nothing.
7
+ */
8
+ export declare function projectConfigPath(cwd: string): string;
9
+ export declare const USER_ONLY_CONFIG_KEYS: ReadonlyArray<keyof ForgeConfigFile>;
10
+ export declare function loadMergedForgeConfig(cwd: string, opts: {
11
+ trusted: boolean;
12
+ userPath?: string;
13
+ }): Promise<LoadForgeConfigFileResult>;
@@ -0,0 +1,67 @@
1
+ import { existsSync } from 'node:fs';
2
+ import path from 'node:path';
3
+ import { loadForgeConfigFile } from './config-file.js';
4
+ /**
5
+ * The shared config as one object: `~/.forge/config.json`, then the workspace's `.forge/config.json` on top.
6
+ * A project file can pick the model and add stricter rules, but it can never loosen what the user decided:
7
+ * its `allow` permission rules are dropped, and the keys that hold approvals or delete data are only read
8
+ * from the user file. An untrusted workspace contributes nothing.
9
+ */
10
+ export function projectConfigPath(cwd) {
11
+ return path.join(cwd, '.forge', 'config.json');
12
+ }
13
+ // customProviders is user-only because an entry names a URL and the environment variable whose value is sent there:
14
+ // a repository must not be able to point a key at a host of its choosing.
15
+ export const USER_ONLY_CONFIG_KEYS = ['autoApproveTools', 'autoApproveCommands', 'sessionRetentionDays', 'customProviders', 'instructions', 'skillPaths', 'caCertificates'];
16
+ export async function loadMergedForgeConfig(cwd, opts) {
17
+ const user = await loadForgeConfigFile(opts.userPath);
18
+ const file = projectConfigPath(cwd);
19
+ if (!opts.trusted || !existsSync(file))
20
+ return user;
21
+ const project = await loadForgeConfigFile(file);
22
+ const warnings = [...user.warnings, ...project.warnings];
23
+ const p = project.config;
24
+ const merged = { ...user.config };
25
+ for (const key of USER_ONLY_CONFIG_KEYS) {
26
+ if (p[key] !== undefined)
27
+ warnings.push(`${file}: "${key}" is only read from the user config (~/.forge/config.json); ignored`);
28
+ }
29
+ for (const key of ['provider', 'model', 'completionModel', 'compactionModel', 'reasoningEffort', 'subagentModel']) {
30
+ if (p[key] !== undefined)
31
+ merged[key] = p[key];
32
+ }
33
+ if (p.modelOverrides)
34
+ merged.modelOverrides = { ...user.config.modelOverrides, ...p.modelOverrides };
35
+ if (p.aliases)
36
+ merged.aliases = { ...user.config.aliases, ...p.aliases };
37
+ if (p.modeModels)
38
+ merged.modeModels = { ...user.config.modeModels, ...p.modeModels };
39
+ if (p.display)
40
+ merged.display = { ...user.config.display, ...p.display };
41
+ if (p.disabledProviders)
42
+ merged.disabledProviders = [...new Set([...(user.config.disabledProviders ?? []), ...p.disabledProviders])];
43
+ if (p.permission) {
44
+ const permission = tighten(user.config.permission, p.permission);
45
+ if (permission)
46
+ merged.permission = permission;
47
+ }
48
+ return { config: merged, warnings };
49
+ }
50
+ /** User rules first, then the project's `ask` and `deny` rules (an `allow` is dropped), each after everything of the user's. */
51
+ function tighten(user, project) {
52
+ const out = { ...(user ?? {}) };
53
+ for (const [permission, value] of Object.entries(project)) {
54
+ const rules = typeof value === 'string' ? [['*', value]] : Object.entries(value);
55
+ const kept = rules.filter(([, action]) => action !== 'allow');
56
+ if (kept.length === 0)
57
+ continue;
58
+ const existing = out[permission];
59
+ const target = typeof existing === 'string' ? { '*': existing } : { ...(existing ?? {}) };
60
+ for (const [pattern, action] of kept) {
61
+ delete target[pattern];
62
+ target[pattern] = action;
63
+ }
64
+ out[permission] = target;
65
+ }
66
+ return Object.keys(out).length > 0 ? out : undefined;
67
+ }