@zihanw/pi-forge 0.4.0 → 0.5.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 (341) hide show
  1. package/CHANGELOG.md +49 -1
  2. package/README.md +11 -11
  3. package/README.zh-CN.md +4 -6
  4. package/SUBAGENT_ADAPTER_CONTRACT.md +3 -1
  5. package/dist/agent-profile.d.ts +21 -42
  6. package/dist/agent-profile.d.ts.map +1 -1
  7. package/dist/agent-profile.js +82 -194
  8. package/dist/agent-profile.js.map +1 -1
  9. package/dist/catalog.d.ts +27 -0
  10. package/dist/catalog.d.ts.map +1 -0
  11. package/dist/catalog.js +59 -0
  12. package/dist/catalog.js.map +1 -0
  13. package/dist/codecs/agent-profile.d.ts +53 -0
  14. package/dist/codecs/agent-profile.d.ts.map +1 -0
  15. package/dist/codecs/agent-profile.js +176 -0
  16. package/dist/codecs/agent-profile.js.map +1 -0
  17. package/dist/codecs/index.d.ts +5 -0
  18. package/dist/codecs/index.d.ts.map +1 -0
  19. package/dist/codecs/index.js +3 -0
  20. package/dist/codecs/index.js.map +1 -0
  21. package/dist/codecs/prompt-stack.d.ts +18 -0
  22. package/dist/codecs/prompt-stack.d.ts.map +1 -0
  23. package/dist/codecs/prompt-stack.js +479 -0
  24. package/dist/codecs/prompt-stack.js.map +1 -0
  25. package/dist/compile-cycle.d.ts +18 -0
  26. package/dist/compile-cycle.d.ts.map +1 -0
  27. package/dist/compile-cycle.js +13 -0
  28. package/dist/compile-cycle.js.map +1 -0
  29. package/dist/compiler.d.ts +10 -4
  30. package/dist/compiler.d.ts.map +1 -1
  31. package/dist/compiler.js +53 -19
  32. package/dist/compiler.js.map +1 -1
  33. package/dist/extension-registry.d.ts.map +1 -1
  34. package/dist/extension-registry.js +5 -2
  35. package/dist/extension-registry.js.map +1 -1
  36. package/dist/forge-config.d.ts +2 -81
  37. package/dist/forge-config.d.ts.map +1 -1
  38. package/dist/forge-config.js +5 -280
  39. package/dist/forge-config.js.map +1 -1
  40. package/dist/forge-v1/analyzer.d.ts +3 -0
  41. package/dist/forge-v1/analyzer.d.ts.map +1 -0
  42. package/dist/forge-v1/analyzer.js +50 -0
  43. package/dist/forge-v1/analyzer.js.map +1 -0
  44. package/dist/forge-v1/index.d.ts +6 -0
  45. package/dist/forge-v1/index.d.ts.map +1 -0
  46. package/dist/forge-v1/index.js +13 -0
  47. package/dist/forge-v1/index.js.map +1 -0
  48. package/dist/forge-v1/parser.d.ts +3 -0
  49. package/dist/forge-v1/parser.d.ts.map +1 -0
  50. package/dist/forge-v1/parser.js +186 -0
  51. package/dist/forge-v1/parser.js.map +1 -0
  52. package/dist/forge-v1/renderer.d.ts +9 -0
  53. package/dist/forge-v1/renderer.d.ts.map +1 -0
  54. package/dist/forge-v1/renderer.js +181 -0
  55. package/dist/forge-v1/renderer.js.map +1 -0
  56. package/dist/forge-v1/types.d.ts +87 -0
  57. package/dist/forge-v1/types.d.ts.map +1 -0
  58. package/dist/forge-v1/types.js +4 -0
  59. package/dist/forge-v1/types.js.map +1 -0
  60. package/dist/index.d.ts +12 -9
  61. package/dist/index.d.ts.map +1 -1
  62. package/dist/index.js +49 -59
  63. package/dist/index.js.map +1 -1
  64. package/dist/lifecycle.d.ts +7 -5
  65. package/dist/lifecycle.d.ts.map +1 -1
  66. package/dist/lifecycle.js +44 -110
  67. package/dist/lifecycle.js.map +1 -1
  68. package/dist/loader.d.ts +16 -3
  69. package/dist/loader.d.ts.map +1 -1
  70. package/dist/loader.js +42 -440
  71. package/dist/loader.js.map +1 -1
  72. package/dist/macro-engine.d.ts +9 -14
  73. package/dist/macro-engine.d.ts.map +1 -1
  74. package/dist/macro-engine.js +5 -238
  75. package/dist/macro-engine.js.map +1 -1
  76. package/dist/payload-command.d.ts +6 -6
  77. package/dist/payload-command.d.ts.map +1 -1
  78. package/dist/payload-command.js.map +1 -1
  79. package/dist/payload-state.d.ts +16 -0
  80. package/dist/payload-state.d.ts.map +1 -0
  81. package/dist/payload-state.js +14 -0
  82. package/dist/payload-state.js.map +1 -0
  83. package/dist/preset-command.d.ts +4 -4
  84. package/dist/preset-command.d.ts.map +1 -1
  85. package/dist/preset-command.js +55 -98
  86. package/dist/preset-command.js.map +1 -1
  87. package/dist/preview.d.ts +4 -4
  88. package/dist/preview.d.ts.map +1 -1
  89. package/dist/preview.js +17 -8
  90. package/dist/preview.js.map +1 -1
  91. package/dist/profile-command.d.ts +2 -2
  92. package/dist/profile-command.d.ts.map +1 -1
  93. package/dist/profile-command.js +52 -26
  94. package/dist/profile-command.js.map +1 -1
  95. package/dist/profile-service.d.ts +5 -2
  96. package/dist/profile-service.d.ts.map +1 -1
  97. package/dist/profile-service.js +63 -42
  98. package/dist/profile-service.js.map +1 -1
  99. package/dist/prompt-analysis.d.ts +24 -0
  100. package/dist/prompt-analysis.d.ts.map +1 -0
  101. package/dist/prompt-analysis.js +84 -0
  102. package/dist/prompt-analysis.js.map +1 -0
  103. package/dist/prompt-runtime.d.ts +19 -0
  104. package/dist/prompt-runtime.d.ts.map +1 -0
  105. package/dist/prompt-runtime.js +30 -0
  106. package/dist/prompt-runtime.js.map +1 -0
  107. package/dist/regex.js +6 -12
  108. package/dist/regex.js.map +1 -1
  109. package/dist/render-helpers.d.ts +2 -10
  110. package/dist/render-helpers.d.ts.map +1 -1
  111. package/dist/render-helpers.js +3 -53
  112. package/dist/render-helpers.js.map +1 -1
  113. package/dist/repositories/agent-profile.d.ts +36 -0
  114. package/dist/repositories/agent-profile.d.ts.map +1 -0
  115. package/dist/repositories/agent-profile.js +153 -0
  116. package/dist/repositories/agent-profile.js.map +1 -0
  117. package/dist/repositories/index.d.ts +3 -0
  118. package/dist/repositories/index.d.ts.map +1 -0
  119. package/dist/repositories/index.js +3 -0
  120. package/dist/repositories/index.js.map +1 -0
  121. package/dist/repositories/prompt-stack.d.ts +57 -0
  122. package/dist/repositories/prompt-stack.d.ts.map +1 -0
  123. package/dist/repositories/prompt-stack.js +175 -0
  124. package/dist/repositories/prompt-stack.js.map +1 -0
  125. package/dist/resource-identity.d.ts +33 -0
  126. package/dist/resource-identity.d.ts.map +1 -0
  127. package/dist/resource-identity.js +56 -0
  128. package/dist/resource-identity.js.map +1 -0
  129. package/dist/runtime/profile-runtime.d.ts +2 -2
  130. package/dist/runtime/profile-runtime.d.ts.map +1 -1
  131. package/dist/runtime/profile-runtime.js +18 -10
  132. package/dist/runtime/profile-runtime.js.map +1 -1
  133. package/dist/runtime/prompt-stack-runtime.d.ts +5 -4
  134. package/dist/runtime/prompt-stack-runtime.d.ts.map +1 -1
  135. package/dist/runtime/prompt-stack-runtime.js +47 -52
  136. package/dist/runtime/prompt-stack-runtime.js.map +1 -1
  137. package/dist/runtime/tool-policy-runtime.d.ts +2 -2
  138. package/dist/runtime/tool-policy-runtime.d.ts.map +1 -1
  139. package/dist/runtime/tool-policy-runtime.js +3 -3
  140. package/dist/runtime/tool-policy-runtime.js.map +1 -1
  141. package/dist/session-adapter.d.ts +17 -0
  142. package/dist/session-adapter.d.ts.map +1 -0
  143. package/dist/session-adapter.js +57 -0
  144. package/dist/session-adapter.js.map +1 -0
  145. package/dist/slot-renderers.d.ts +16 -3
  146. package/dist/slot-renderers.d.ts.map +1 -1
  147. package/dist/slot-renderers.js +15 -63
  148. package/dist/slot-renderers.js.map +1 -1
  149. package/dist/stack-migration.d.ts +6 -0
  150. package/dist/stack-migration.d.ts.map +1 -1
  151. package/dist/stack-migration.js +49 -52
  152. package/dist/stack-migration.js.map +1 -1
  153. package/dist/storage.d.ts +10 -0
  154. package/dist/storage.d.ts.map +1 -1
  155. package/dist/storage.js +45 -10
  156. package/dist/storage.js.map +1 -1
  157. package/dist/subagent/fingerprints.d.ts +24 -0
  158. package/dist/subagent/fingerprints.d.ts.map +1 -0
  159. package/dist/subagent/fingerprints.js +81 -0
  160. package/dist/subagent/fingerprints.js.map +1 -0
  161. package/dist/subagent/host-port.d.ts +296 -0
  162. package/dist/subagent/host-port.d.ts.map +1 -0
  163. package/dist/subagent/host-port.js +560 -0
  164. package/dist/subagent/host-port.js.map +1 -0
  165. package/dist/subagent/index.d.ts +10 -10
  166. package/dist/subagent/index.d.ts.map +1 -1
  167. package/dist/subagent/index.js +9 -10
  168. package/dist/subagent/index.js.map +1 -1
  169. package/dist/subagent-host.d.ts +99 -18
  170. package/dist/subagent-host.d.ts.map +1 -1
  171. package/dist/subagent-host.js +185 -162
  172. package/dist/subagent-host.js.map +1 -1
  173. package/dist/template-render.d.ts +18 -0
  174. package/dist/template-render.d.ts.map +1 -0
  175. package/dist/template-render.js +232 -0
  176. package/dist/template-render.js.map +1 -0
  177. package/dist/types.d.ts +43 -27
  178. package/dist/types.d.ts.map +1 -1
  179. package/dist/types.js.map +1 -1
  180. package/dist/web-editor/client-script.generated.d.ts.map +1 -1
  181. package/dist/web-editor/client-script.generated.js +1 -1
  182. package/dist/web-editor/client-script.generated.js.map +1 -1
  183. package/dist/web-editor/client-styles.generated.d.ts.map +1 -1
  184. package/dist/web-editor/client-styles.generated.js +1 -1
  185. package/dist/web-editor/client-styles.generated.js.map +1 -1
  186. package/dist/web-editor/server.d.ts.map +1 -1
  187. package/dist/web-editor/server.js +32 -72
  188. package/dist/web-editor/server.js.map +1 -1
  189. package/dist/web-editor/styles.d.ts.map +1 -1
  190. package/dist/web-editor/styles.js +13 -0
  191. package/dist/web-editor/styles.js.map +1 -1
  192. package/dist/web-editor/types.d.ts +10 -37
  193. package/dist/web-editor/types.d.ts.map +1 -1
  194. package/dist/web-host.d.ts +4 -2
  195. package/dist/web-host.d.ts.map +1 -1
  196. package/dist/web-host.js +110 -138
  197. package/dist/web-host.js.map +1 -1
  198. package/dist/workspace.d.ts +74 -0
  199. package/dist/workspace.d.ts.map +1 -0
  200. package/dist/workspace.js +351 -0
  201. package/dist/workspace.js.map +1 -0
  202. package/docs/README.md +6 -4
  203. package/docs/concepts/agent-profiles.md +2 -2
  204. package/docs/concepts/prompt-stacks.md +12 -7
  205. package/docs/design/README.md +21 -3
  206. package/docs/design/architecture-0.5.md +211 -0
  207. package/docs/design/archive/0.5-full-proposal/0.5-consumer-audit.md +62 -0
  208. package/docs/design/archive/0.5-full-proposal/0.5-inventory.md +208 -0
  209. package/docs/design/archive/0.5-full-proposal/0.5-phase0-decision-drafts.md +237 -0
  210. package/docs/design/archive/0.5-full-proposal/README.md +12 -0
  211. package/docs/design/archive/0.5-full-proposal/architecture-0.5.md +423 -0
  212. package/docs/design/archive/0.5-full-proposal/host-discovery-spike.md +103 -0
  213. package/docs/design/archive/0.5-full-proposal/template-language-spike.md +156 -0
  214. package/docs/design/context-diff-plan.md +72 -0
  215. package/docs/design/decision-template.md +33 -0
  216. package/docs/design/roadmap-0.4-archive.md +1 -1
  217. package/docs/design/subagents/interface-design.md +1 -1
  218. package/docs/development/architecture-rules.md +148 -0
  219. package/docs/development/roadmap.md +39 -13
  220. package/docs/development/scoped-global-profiles-stacks.md +325 -0
  221. package/docs/development/setup.md +6 -4
  222. package/docs/getting-started.md +9 -6
  223. package/docs/guides/custom-macros-and-slots.md +8 -7
  224. package/docs/guides/debugging.md +1 -1
  225. package/docs/guides/delegation.md +25 -21
  226. package/docs/guides/migrating-to-0.5.md +107 -0
  227. package/docs/guides/use-cases.md +7 -11
  228. package/docs/guides/web-editor.md +7 -11
  229. package/docs/reference/commands.md +4 -3
  230. package/docs/reference/configuration.md +18 -17
  231. package/docs/reference/features.md +34 -79
  232. package/docs/reference/macros-and-slots.md +70 -49
  233. package/docs/reference/public-api.md +64 -17
  234. package/docs/reference/stack-schema.md +14 -9
  235. package/docs/reference/subagent-host-port.md +49 -0
  236. package/docs/zh-CN/README.md +3 -3
  237. package/docs/zh-CN/concepts/agent-profiles.md +4 -2
  238. package/docs/zh-CN/concepts/prompt-stacks.md +9 -7
  239. package/docs/zh-CN/getting-started.md +10 -7
  240. package/docs/zh-CN/guides/delegation.md +11 -13
  241. package/docs/zh-CN/guides/migrating-to-0.5.md +92 -0
  242. package/docs/zh-CN/guides/web-editor.md +7 -7
  243. package/docs/zh-CN/reference/commands.md +6 -3
  244. package/examples/custom-system-status-extension/README.md +3 -3
  245. package/examples/custom-system-status-extension/index.ts +2 -1
  246. package/examples/custom-system-status-extension/prompt-stack.json +4 -3
  247. package/examples/default-prompt-stack.json +9 -4
  248. package/examples/image-reader-prompt-stack.json +16 -26
  249. package/examples/reviewer-prompt-stack.json +13 -24
  250. package/package.json +101 -120
  251. package/dist/runtime/subagent-runtime.d.ts +0 -45
  252. package/dist/runtime/subagent-runtime.d.ts.map +0 -1
  253. package/dist/runtime/subagent-runtime.js +0 -335
  254. package/dist/runtime/subagent-runtime.js.map +0 -1
  255. package/dist/runtime-state.d.ts +0 -30
  256. package/dist/runtime-state.d.ts.map +0 -1
  257. package/dist/runtime-state.js +0 -17
  258. package/dist/runtime-state.js.map +0 -1
  259. package/dist/sillytavern-importer/items.d.ts +0 -3
  260. package/dist/sillytavern-importer/items.d.ts.map +0 -1
  261. package/dist/sillytavern-importer/items.js +0 -88
  262. package/dist/sillytavern-importer/items.js.map +0 -1
  263. package/dist/sillytavern-importer/macros.d.ts +0 -15
  264. package/dist/sillytavern-importer/macros.d.ts.map +0 -1
  265. package/dist/sillytavern-importer/macros.js +0 -141
  266. package/dist/sillytavern-importer/macros.js.map +0 -1
  267. package/dist/sillytavern-importer/prompt-order.d.ts +0 -6
  268. package/dist/sillytavern-importer/prompt-order.d.ts.map +0 -1
  269. package/dist/sillytavern-importer/prompt-order.js +0 -38
  270. package/dist/sillytavern-importer/prompt-order.js.map +0 -1
  271. package/dist/sillytavern-importer/regex.d.ts +0 -3
  272. package/dist/sillytavern-importer/regex.d.ts.map +0 -1
  273. package/dist/sillytavern-importer/regex.js +0 -275
  274. package/dist/sillytavern-importer/regex.js.map +0 -1
  275. package/dist/sillytavern-importer/report.d.ts +0 -21
  276. package/dist/sillytavern-importer/report.d.ts.map +0 -1
  277. package/dist/sillytavern-importer/report.js +0 -166
  278. package/dist/sillytavern-importer/report.js.map +0 -1
  279. package/dist/sillytavern-importer/types.d.ts +0 -106
  280. package/dist/sillytavern-importer/types.d.ts.map +0 -1
  281. package/dist/sillytavern-importer/types.js +0 -2
  282. package/dist/sillytavern-importer/types.js.map +0 -1
  283. package/dist/sillytavern-importer.d.ts +0 -5
  284. package/dist/sillytavern-importer.d.ts.map +0 -1
  285. package/dist/sillytavern-importer.js +0 -117
  286. package/dist/sillytavern-importer.js.map +0 -1
  287. package/dist/subagent/canonical.d.ts +0 -22
  288. package/dist/subagent/canonical.d.ts.map +0 -1
  289. package/dist/subagent/canonical.js +0 -24
  290. package/dist/subagent/canonical.js.map +0 -1
  291. package/dist/subagent/context.d.ts +0 -8
  292. package/dist/subagent/context.d.ts.map +0 -1
  293. package/dist/subagent/context.js +0 -125
  294. package/dist/subagent/context.js.map +0 -1
  295. package/dist/subagent/contract.d.ts +0 -10
  296. package/dist/subagent/contract.d.ts.map +0 -1
  297. package/dist/subagent/contract.js +0 -10
  298. package/dist/subagent/contract.js.map +0 -1
  299. package/dist/subagent/plan.d.ts +0 -18
  300. package/dist/subagent/plan.d.ts.map +0 -1
  301. package/dist/subagent/plan.js +0 -157
  302. package/dist/subagent/plan.js.map +0 -1
  303. package/dist/subagent/preflight.d.ts +0 -4
  304. package/dist/subagent/preflight.d.ts.map +0 -1
  305. package/dist/subagent/preflight.js +0 -108
  306. package/dist/subagent/preflight.js.map +0 -1
  307. package/dist/subagent/request.d.ts +0 -4
  308. package/dist/subagent/request.d.ts.map +0 -1
  309. package/dist/subagent/request.js +0 -122
  310. package/dist/subagent/request.js.map +0 -1
  311. package/dist/subagent/response.d.ts +0 -8
  312. package/dist/subagent/response.d.ts.map +0 -1
  313. package/dist/subagent/response.js +0 -155
  314. package/dist/subagent/response.js.map +0 -1
  315. package/dist/subagent/tools.d.ts +0 -4
  316. package/dist/subagent/tools.d.ts.map +0 -1
  317. package/dist/subagent/tools.js +0 -42
  318. package/dist/subagent/tools.js.map +0 -1
  319. package/dist/subagent/types.d.ts +0 -268
  320. package/dist/subagent/types.d.ts.map +0 -1
  321. package/dist/subagent/types.js +0 -3
  322. package/dist/subagent/types.js.map +0 -1
  323. package/dist/subagent/validation.d.ts +0 -35
  324. package/dist/subagent/validation.d.ts.map +0 -1
  325. package/dist/subagent/validation.js +0 -314
  326. package/dist/subagent/validation.js.map +0 -1
  327. package/dist/subagent-command.d.ts +0 -4
  328. package/dist/subagent-command.d.ts.map +0 -1
  329. package/dist/subagent-command.js +0 -246
  330. package/dist/subagent-command.js.map +0 -1
  331. package/dist/subagent-profile-tool.d.ts +0 -49
  332. package/dist/subagent-profile-tool.d.ts.map +0 -1
  333. package/dist/subagent-profile-tool.js +0 -124
  334. package/dist/subagent-profile-tool.js.map +0 -1
  335. package/dist/subagent-tool.d.ts +0 -53
  336. package/dist/subagent-tool.d.ts.map +0 -1
  337. package/dist/subagent-tool.js +0 -456
  338. package/dist/subagent-tool.js.map +0 -1
  339. package/docs/guides/sillytavern-import.md +0 -47
  340. package/docs/reference/subagent-adapter.md +0 -204
  341. package/examples/sillytavern-dm-writer-prompt-stack.json +0 -190
@@ -1,14 +1,13 @@
1
1
  /**
2
- * Experimental runner-neutral subagent adapter surface.
2
+ * Versioned `/subagent` host port: the minimal Forge DTO host contract.
3
3
  *
4
- * The package root continues to re-export these names for 0.4 compatibility.
5
- * New adapter integrations should import from `@zihanw/pi-forge/subagent` so
6
- * they do not depend on the Pi extension composition entry point.
7
- *
8
- * Execution ownership (backend registry, sealing, lifecycle, process
9
- * backends) now lives in `@zihanw/pi-subagent-runtime`; this surface keeps
10
- * the Forge host contracts: profiles, compilation, approval, and reporting.
4
+ * Wire messages, recursive validators, transport, and client/host lifecycle,
5
+ * plus the Forge-owned canonical fingerprint helpers used for host-issued
6
+ * profile snapshots. The main package carries no dependency on
7
+ * `@zihanw/pi-subagent-runtime`; the execution contract (request, preflight,
8
+ * plan, response, context, tool negotiation) lives in the optional
9
+ * `@zihanw/pi-forge-subagents` package, which consumes this port.
11
10
  */
12
- export * from "./contract.js";
13
- export { appendProtectedAgentTask, collectMacroCommandNames, collectSubagentPromptDependencies, compileProtectedAgentTaskMessages, currentSubagentPromptRegistrationCatalog, isProtectedAgentTaskPreserved, prepareSubagentHostPlan, resolveSubagentHostProfile, } from "../subagent-host.js";
11
+ export { FORGE_HOST_CHANNEL, FORGE_HOST_PORT_NAMESPACE, FORGE_HOST_PORT_OPERATIONS, FORGE_HOST_PORT_VERSION, ForgeHost, ForgeHostClient, ForgeHostPortError, validateListProfilesRequest, validateListProfilesResponse, validatePrepareRequest, validatePrepareResponse, validateResolveProfileRequest, validateResolveProfileResponse, } from "./host-port.js";
12
+ export { SUBAGENT_FINGERPRINT_PREFIX, canonicalSubagentJson, subagentFingerprint, subagentPromptStackFingerprint, subagentSourceProfileFingerprint, } from "./fingerprints.js";
14
13
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/subagent/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,cAAc,eAAe,CAAC;AAC9B,OAAO,EACN,wBAAwB,EACxB,wBAAwB,EACxB,iCAAiC,EACjC,iCAAiC,EACjC,wCAAwC,EACxC,6BAA6B,EAC7B,uBAAuB,EACvB,0BAA0B,GAI1B,MAAM,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/subagent/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EACN,kBAAkB,EAClB,yBAAyB,EACzB,0BAA0B,EAC1B,uBAAuB,EACvB,SAAS,EACT,eAAe,EACf,kBAAkB,EAClB,2BAA2B,EAC3B,4BAA4B,EAC5B,sBAAsB,EACtB,uBAAuB,EACvB,6BAA6B,EAC7B,8BAA8B,GAC9B,MAAM,gBAAgB,CAAC;AA2BxB,OAAO,EACN,2BAA2B,EAC3B,qBAAqB,EACrB,mBAAmB,EACnB,8BAA8B,EAC9B,gCAAgC,GAEhC,MAAM,mBAAmB,CAAC"}
@@ -1,10 +1,61 @@
1
- import type { AgentMessage } from "@earendil-works/pi-agent-core";
2
1
  import type { LoadedAgentProfile } from "./agent-profile.ts";
3
- import { type AgentProfileSnapshot, type SubagentDependencyKind, type SubagentDiagnostic, type SubagentPromptDependency, type SubagentPreparationInput, type SubagentPreparationOutput } from "./subagent/contract.ts";
4
- import type { LoadedPromptStack, PromptRuntime, PromptStack } from "./types.ts";
2
+ import type { AgentProfile } from "./codecs/agent-profile.ts";
3
+ import { type SubagentFingerprint } from "./subagent/fingerprints.ts";
4
+ import type { ForgeBackendFacts, ForgeBackendTool, ForgePromptAccessFacts } from "./subagent/host-port.ts";
5
+ import type { LoadedPromptStack, PromptResourcePolicy, PromptStack } from "./types.ts";
6
+ /**
7
+ * Host-owned diagnostic shape for delegation resolution and preparation.
8
+ * Structurally compatible with the optional package's contract diagnostics.
9
+ */
10
+ export interface ForgeDelegationDiagnostic {
11
+ level: "error" | "warning" | "info";
12
+ code: string;
13
+ path?: string;
14
+ message: string;
15
+ }
16
+ export type ForgePromptDependencyKind = "macro" | "slot";
17
+ export interface ForgePromptDependency {
18
+ kind: ForgePromptDependencyKind;
19
+ name: string;
20
+ identity: string;
21
+ source?: string;
22
+ }
23
+ /**
24
+ * Host-owned immutable profile snapshot artifact returned by `resolveProfile`
25
+ * and embedded in `prepare` responses. The optional package validates and
26
+ * binds it into execution plans; the wire schema version is shared with the
27
+ * execution contract by design.
28
+ */
29
+ export declare const FORGE_PROFILE_SNAPSHOT_VERSION: 1;
30
+ export interface ForgeProfileSnapshot {
31
+ schemaVersion: typeof FORGE_PROFILE_SNAPSHOT_VERSION;
32
+ /** Canonical scoped selector of the resolved profile (`project:<id>` or `global:<id>`). */
33
+ profileId: string;
34
+ profile: AgentProfile;
35
+ /** Canonical scoped selector of the resolved prompt stack, or null. */
36
+ promptStackId: string | null;
37
+ promptStack: PromptStack | null;
38
+ dependencies: ForgePromptDependency[];
39
+ profileFingerprint: SubagentFingerprint;
40
+ promptStackFingerprint: SubagentFingerprint | null;
41
+ }
42
+ /**
43
+ * Host-compiled delegation message. Text-only on the host side; the optional
44
+ * package projects these onto the runtime's portable prepared messages.
45
+ */
46
+ export interface ForgeDelegationMessage {
47
+ role: "user" | "assistant" | "custom";
48
+ content: Array<{
49
+ type: "text";
50
+ text: string;
51
+ }>;
52
+ protectedTask?: boolean;
53
+ source?: "prompt-stack" | "delegated-task";
54
+ }
5
55
  export interface SubagentPromptRegistration {
6
56
  name: string;
7
57
  source?: string;
58
+ dependencies?: string[];
8
59
  }
9
60
  export interface SubagentPromptRegistrationCatalog {
10
61
  macros: SubagentPromptRegistration[];
@@ -12,33 +63,63 @@ export interface SubagentPromptRegistrationCatalog {
12
63
  }
13
64
  export interface SubagentHostResolution {
14
65
  profileId: string;
15
- snapshot?: AgentProfileSnapshot;
16
- dependencies: SubagentPromptDependency[];
66
+ snapshot?: ForgeProfileSnapshot;
67
+ dependencies: ForgePromptDependency[];
17
68
  missingDependencies: Array<{
18
- kind: SubagentDependencyKind;
69
+ kind: ForgePromptDependencyKind;
19
70
  name: string;
20
71
  }>;
21
- diagnostics: SubagentDiagnostic[];
72
+ diagnostics: ForgeDelegationDiagnostic[];
73
+ }
74
+ export interface ForgeDelegationPreparationInput {
75
+ snapshot: ForgeProfileSnapshot;
76
+ task: {
77
+ text: string;
78
+ };
79
+ access: ForgePromptAccessFacts;
80
+ backend: ForgeBackendFacts;
81
+ cwd: string;
82
+ }
83
+ export interface ForgeDelegationPreparation {
84
+ systemPrompt: string;
85
+ messages: ForgeDelegationMessage[];
86
+ effectiveToolIds: string[];
87
+ effectiveToolNames: string[];
88
+ diagnostics: ForgeDelegationDiagnostic[];
89
+ preparedAt: string;
22
90
  }
23
91
  export declare function currentSubagentPromptRegistrationCatalog(): SubagentPromptRegistrationCatalog;
24
92
  export declare function resolveSubagentHostProfile(loaded: LoadedAgentProfile, resources: {
25
93
  promptStacks: readonly LoadedPromptStack[];
26
94
  registrations?: SubagentPromptRegistrationCatalog;
27
95
  }): SubagentHostResolution;
28
- export declare function prepareSubagentHostPlan(input: SubagentPreparationInput): SubagentPreparationOutput;
96
+ /**
97
+ * Forge-native host-owned preparation: negotiate the client tool catalog
98
+ * against stack policy and access facts, compile the resolved stack through
99
+ * one compilation context, and append the protected delegated task. No
100
+ * execution/runtime material (AgentRequest, preflight, limits, or plan
101
+ * fingerprints) is involved; the optional package owns those.
102
+ */
103
+ export declare function prepareForgeDelegation(input: ForgeDelegationPreparationInput): ForgeDelegationPreparation;
104
+ interface ForgeToolNegotiation {
105
+ effectiveToolIds: string[];
106
+ effectiveToolNames: string[];
107
+ diagnostics: ForgeDelegationDiagnostic[];
108
+ }
109
+ /**
110
+ * Intersect the client-supplied tool catalog with stack tool policy and the
111
+ * prompt-compilation access facts. Semantics mirror the execution contract's
112
+ * tool negotiation in the optional package, which recomputes them as the
113
+ * plan-creation integrity check.
114
+ */
115
+ export declare function negotiateForgeDelegationTools(catalog: readonly ForgeBackendTool[], policy: PromptResourcePolicy | undefined, access: ForgePromptAccessFacts): ForgeToolNegotiation;
29
116
  export declare function collectSubagentPromptDependencies(stack: PromptStack, registrations?: SubagentPromptRegistrationCatalog): {
30
- dependencies: SubagentPromptDependency[];
117
+ dependencies: ForgePromptDependency[];
31
118
  missingDependencies: Array<{
32
- kind: SubagentDependencyKind;
119
+ kind: ForgePromptDependencyKind;
33
120
  name: string;
34
121
  }>;
35
- diagnostics: SubagentDiagnostic[];
36
- };
37
- export declare function collectMacroCommandNames(text: string): string[];
38
- export declare function appendProtectedAgentTask(compiledMessages: readonly AgentMessage[], protectedTask: AgentMessage): AgentMessage[];
39
- export declare function compileProtectedAgentTaskMessages(stack: LoadedPromptStack, runtime: PromptRuntime, originalMessages: readonly AgentMessage[]): {
40
- messages: AgentMessage[];
41
- diagnostics: import("./types.ts").PromptStackDiagnostic[];
122
+ diagnostics: ForgeDelegationDiagnostic[];
42
123
  };
43
- export declare function isProtectedAgentTaskPreserved(messages: readonly AgentMessage[], task: AgentMessage): boolean;
124
+ export {};
44
125
  //# sourceMappingURL=subagent-host.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"subagent-host.d.ts","sourceRoot":"","sources":["../src/subagent-host.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAUlE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAE7D,OAAO,EAKN,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,EAC3B,KAAK,kBAAkB,EACvB,KAAK,wBAAwB,EAC7B,KAAK,wBAAwB,EAC7B,KAAK,yBAAyB,EAE9B,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,iBAAiB,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEhF,MAAM,WAAW,0BAA0B;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,iCAAiC;IACjD,MAAM,EAAE,0BAA0B,EAAE,CAAC;IACrC,KAAK,EAAE,0BAA0B,EAAE,CAAC;CACpC;AAED,MAAM,WAAW,sBAAsB;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,oBAAoB,CAAC;IAChC,YAAY,EAAE,wBAAwB,EAAE,CAAC;IACzC,mBAAmB,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,sBAAsB,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC3E,WAAW,EAAE,kBAAkB,EAAE,CAAC;CAClC;AAcD,wBAAgB,wCAAwC,IAAI,iCAAiC,CAK5F;AAED,wBAAgB,0BAA0B,CACzC,MAAM,EAAE,kBAAkB,EAC1B,SAAS,EAAE;IACV,YAAY,EAAE,SAAS,iBAAiB,EAAE,CAAC;IAC3C,aAAa,CAAC,EAAE,iCAAiC,CAAC;CAClD,GACC,sBAAsB,CAyDxB;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,wBAAwB,GAAG,yBAAyB,CA4ClG;AAED,wBAAgB,iCAAiC,CAChD,KAAK,EAAE,WAAW,EAClB,aAAa,GAAE,iCAA8E,GAC3F;IACF,YAAY,EAAE,wBAAwB,EAAE,CAAC;IACzC,mBAAmB,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,sBAAsB,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC3E,WAAW,EAAE,kBAAkB,EAAE,CAAC;CAClC,CAyBA;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAI/D;AAED,wBAAgB,wBAAwB,CACvC,gBAAgB,EAAE,SAAS,YAAY,EAAE,EACzC,aAAa,EAAE,YAAY,GACzB,YAAY,EAAE,CAGhB;AAED,wBAAgB,iCAAiC,CAChD,KAAK,EAAE,iBAAiB,EACxB,OAAO,EAAE,aAAa,EACtB,gBAAgB,EAAE,SAAS,YAAY,EAAE,GACvC;IAAE,QAAQ,EAAE,YAAY,EAAE,CAAC;IAAC,WAAW,EAAE,OAAO,YAAY,EAAE,qBAAqB,EAAE,CAAA;CAAE,CAOzF;AAED,wBAAgB,6BAA6B,CAAC,QAAQ,EAAE,SAAS,YAAY,EAAE,EAAE,IAAI,EAAE,YAAY,GAAG,OAAO,CAM5G"}
1
+ {"version":3,"file":"subagent-host.d.ts","sourceRoot":"","sources":["../src/subagent-host.ts"],"names":[],"mappings":"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"}
@@ -1,16 +1,20 @@
1
1
  import { getRegisteredMacros, } from "./macro-engine.js";
2
2
  import { getRegisteredSlots, } from "./slot-renderers.js";
3
- import { compileMessages, compileSystemPrompt, createPromptVariableStore } from "./compiler.js";
4
- import { subagentPromptStackFingerprint, subagentSourceProfileFingerprint, negotiateSubagentTools, prepareSubagentInitialMessages, } from "./subagent/contract.js";
5
- const BUILT_IN_MACROS = new Set([
6
- "cwd", "date", "time", "lastUserMessage", "selectedTools", "tools", "activeModel",
7
- "setvar", "setturnvar", "setsessionvar", "getvar", "var", "getturnvar", "getsessionvar",
8
- "clearvar", "clearturnvar", "clearsessionvar", "trim", "upper", "lower", "json", "xml",
9
- "ifvar", "ifeq", "iftools", "ifslot",
10
- ]);
3
+ import { PromptCompilationContext } from "./compiler.js";
4
+ import { applyResourcePolicy, resourcePatternMatches } from "./policy.js";
5
+ import { subagentPromptStackFingerprint, subagentSourceProfileFingerprint, } from "./subagent/fingerprints.js";
6
+ import { formatResourceKey, parseResourceSelector } from "./resource-identity.js";
7
+ import { analyzePromptStack } from "./prompt-analysis.js";
8
+ /**
9
+ * Host-owned immutable profile snapshot artifact returned by `resolveProfile`
10
+ * and embedded in `prepare` responses. The optional package validates and
11
+ * binds it into execution plans; the wire schema version is shared with the
12
+ * execution contract by design.
13
+ */
14
+ export const FORGE_PROFILE_SNAPSHOT_VERSION = 1;
11
15
  const BUILT_IN_SLOTS = new Set([
12
16
  "chat-history", "tools", "tool-guidelines", "skills", "project-context", "append-system-prompt",
13
- "date", "cwd", "date-cwd", "active-model", "pi-docs", "variables",
17
+ "date", "cwd", "date-cwd", "active-model", "pi-docs",
14
18
  ]);
15
19
  export function currentSubagentPromptRegistrationCatalog() {
16
20
  return {
@@ -27,31 +31,54 @@ export function resolveSubagentHostProfile(loaded, resources) {
27
31
  }));
28
32
  const registrations = resources.registrations ?? currentSubagentPromptRegistrationCatalog();
29
33
  let promptStack;
34
+ let promptStackId = null;
30
35
  if (loaded.profile.promptStack !== null) {
31
- const matches = resources.promptStacks.filter((candidate) => candidate.stack.id === loaded.profile.promptStack);
32
- if (matches.length !== 1) {
36
+ const reference = loaded.profile.promptStack;
37
+ const parsed = parseResourceSelector(reference);
38
+ if (!parsed.ok) {
39
+ diagnostics.push({
40
+ level: "error",
41
+ code: "profile.stack-reference",
42
+ path: "profile.promptStack",
43
+ message: parsed.error,
44
+ });
45
+ }
46
+ else if (loaded.scope === "global" && parsed.selector.scope === "project") {
33
47
  diagnostics.push({
34
48
  level: "error",
35
- code: matches.length === 0 ? "profile.stack-missing" : "profile.stack-ambiguous",
49
+ code: "profile.stack-reference",
36
50
  path: "profile.promptStack",
37
- message: matches.length === 0
38
- ? `Unknown prompt stack: ${loaded.profile.promptStack}`
39
- : `Prompt stack id is ambiguous: ${loaded.profile.promptStack}`,
51
+ message: `Global profile ${loaded.profile.id} cannot reference project prompt stack ${parsed.selector.id}.`,
40
52
  });
41
53
  }
42
54
  else {
43
- promptStack = matches[0];
44
- for (const diagnostic of promptStack.diagnostics) {
55
+ const scope = parsed.selector.scope ?? loaded.scope;
56
+ const matches = resources.promptStacks.filter((candidate) => candidate.scope === scope && candidate.stack.id === parsed.selector.id);
57
+ if (matches.length !== 1) {
45
58
  diagnostics.push({
46
- level: diagnostic.level,
47
- code: "profile.stack-validation",
48
- path: diagnostic.itemId ? `promptStack.items.${diagnostic.itemId}` : "promptStack",
49
- message: diagnostic.message,
59
+ level: "error",
60
+ code: matches.length === 0 ? "profile.stack-missing" : "profile.stack-ambiguous",
61
+ path: "profile.promptStack",
62
+ message: matches.length === 0
63
+ ? `Unknown prompt stack: ${reference}`
64
+ : `Prompt stack id is ambiguous: ${reference}`,
50
65
  });
51
66
  }
52
- if (!promptStack.stack.mode || !["replace", "append", "prepend"].includes(promptStack.stack.mode)) {
53
- if (promptStack.stack.mode !== undefined)
54
- diagnostics.push({ level: "error", code: "profile.stack-mode", path: "promptStack.mode", message: `Unsupported prompt stack mode: ${String(promptStack.stack.mode)}` });
67
+ else {
68
+ promptStack = matches[0];
69
+ promptStackId = formatResourceKey({ scope, id: parsed.selector.id });
70
+ for (const diagnostic of promptStack.diagnostics) {
71
+ diagnostics.push({
72
+ level: diagnostic.level,
73
+ code: "profile.stack-validation",
74
+ path: diagnostic.itemId ? `promptStack.items.${diagnostic.itemId}` : "promptStack",
75
+ message: diagnostic.message,
76
+ });
77
+ }
78
+ if (!promptStack.stack.mode || !["replace", "append", "prepend"].includes(promptStack.stack.mode)) {
79
+ if (promptStack.stack.mode !== undefined)
80
+ diagnostics.push({ level: "error", code: "profile.stack-mode", path: "promptStack.mode", message: `Unsupported prompt stack mode: ${String(promptStack.stack.mode)}` });
81
+ }
55
82
  }
56
83
  }
57
84
  }
@@ -60,15 +87,17 @@ export function resolveSubagentHostProfile(loaded, resources) {
60
87
  : { dependencies: [], missingDependencies: [], diagnostics: [] };
61
88
  diagnostics.push(...dependencyResult.diagnostics);
62
89
  const resolution = {
63
- profileId: loaded.profile.id,
90
+ profileId: formatResourceKey(loaded.key),
64
91
  dependencies: dependencyResult.dependencies,
65
92
  missingDependencies: dependencyResult.missingDependencies,
66
93
  diagnostics,
67
94
  };
68
95
  if (!diagnostics.some((diagnostic) => diagnostic.level === "error")) {
69
96
  resolution.snapshot = {
70
- schemaVersion: 1,
97
+ schemaVersion: FORGE_PROFILE_SNAPSHOT_VERSION,
98
+ profileId: formatResourceKey(loaded.key),
71
99
  profile: structuredClone(loaded.profile),
100
+ promptStackId,
72
101
  promptStack: promptStack ? structuredClone(promptStack.stack) : null,
73
102
  dependencies: structuredClone(dependencyResult.dependencies),
74
103
  profileFingerprint: subagentSourceProfileFingerprint(loaded.profile),
@@ -77,107 +106,171 @@ export function resolveSubagentHostProfile(loaded, resources) {
77
106
  }
78
107
  return resolution;
79
108
  }
80
- export function prepareSubagentHostPlan(input) {
81
- const toolNegotiation = negotiateSubagentTools(input.preflight.toolCatalog, input.snapshot.promptStack?.tools, input.request.access);
82
- const options = {
83
- ...structuredClone(input.runtime.options),
84
- selectedTools: [...toolNegotiation.effectiveToolNames],
85
- toolSnippets: Object.fromEntries(Object.entries(input.runtime.options.toolSnippets)
86
- .filter(([name]) => toolNegotiation.effectiveToolNames.includes(name))),
87
- promptGuidelines: toolNegotiation.effectiveToolNames.length > 0
88
- ? [...input.runtime.options.promptGuidelines]
89
- : [],
90
- skills: structuredClone(input.runtime.options.skills),
91
- contextFiles: [...input.runtime.options.contextFiles],
92
- };
93
- const model = {
94
- provider: input.runtime.model.provider,
95
- id: input.runtime.model.id,
96
- api: "unknown",
97
- };
109
+ /**
110
+ * Forge-native host-owned preparation: negotiate the client tool catalog
111
+ * against stack policy and access facts, compile the resolved stack through
112
+ * one compilation context, and append the protected delegated task. No
113
+ * execution/runtime material (AgentRequest, preflight, limits, or plan
114
+ * fingerprints) is involved; the optional package owns those.
115
+ */
116
+ export function prepareForgeDelegation(input) {
117
+ const negotiation = negotiateForgeDelegationTools(input.backend.toolCatalog, input.snapshot.promptStack?.tools, input.access);
118
+ const preparedAt = new Date().toISOString();
98
119
  const runtime = {
99
- options,
100
- ctx: { model },
101
- latestUserMessage: input.request.input.text,
102
- now: new Date(input.runtime.preparedAt),
103
- variables: createPromptVariableStore(),
120
+ options: {
121
+ cwd: input.cwd,
122
+ selectedTools: negotiation.effectiveToolNames,
123
+ toolSnippets: {},
124
+ promptGuidelines: [],
125
+ contextFiles: [],
126
+ skills: [],
127
+ },
128
+ model: {
129
+ provider: input.backend.model.provider,
130
+ id: input.backend.model.id,
131
+ api: "unknown",
132
+ },
133
+ latestUserMessage: input.task.text,
134
+ now: new Date(preparedAt),
104
135
  };
105
- let systemPrompt = input.runtime.baseSystemPrompt;
136
+ const diagnostics = [...negotiation.diagnostics];
137
+ let systemPrompt = "";
106
138
  let stackMessages = [];
107
- const diagnostics = [];
108
- if (input.snapshot.promptStack) {
109
- const system = compileSystemPrompt(input.snapshot.promptStack, runtime, input.runtime.baseSystemPrompt);
139
+ const stack = input.snapshot.promptStack;
140
+ if (stack) {
141
+ const compilation = new PromptCompilationContext(stack, runtime);
142
+ const system = compilation.compileSystemPrompt("");
110
143
  systemPrompt = system.systemPrompt;
111
144
  diagnostics.push(...system.diagnostics.map((item) => promptDiagnostic("system", item)));
112
- const messages = compileMessages(input.snapshot.promptStack, runtime, []);
145
+ const messages = compilation.compileMessages([]);
113
146
  stackMessages = messages.messages.map(preparedPromptStackMessage);
114
147
  diagnostics.push(...messages.diagnostics.map((item) => promptDiagnostic("messages", item)));
115
148
  }
116
- const initial = prepareSubagentInitialMessages(input.request, stackMessages);
117
149
  return {
118
150
  systemPrompt,
119
- messages: initial.messages,
120
- contextBudget: initial.contextBudget,
121
- toolNegotiation,
122
- diagnostics: [...diagnostics, ...initial.diagnostics],
151
+ messages: appendProtectedDelegationTask(stackMessages, input.task),
152
+ effectiveToolIds: negotiation.effectiveToolIds,
153
+ effectiveToolNames: negotiation.effectiveToolNames,
154
+ diagnostics,
155
+ preparedAt,
156
+ };
157
+ }
158
+ /**
159
+ * Intersect the client-supplied tool catalog with stack tool policy and the
160
+ * prompt-compilation access facts. Semantics mirror the execution contract's
161
+ * tool negotiation in the optional package, which recomputes them as the
162
+ * plan-creation integrity check.
163
+ */
164
+ export function negotiateForgeDelegationTools(catalog, policy, access) {
165
+ const diagnostics = [];
166
+ const tools = catalog.map((tool) => ({
167
+ id: tool.id,
168
+ name: tool.name ?? tool.id,
169
+ effects: [...(tool.effects ?? [])],
170
+ }));
171
+ const names = tools.map((tool) => tool.name);
172
+ const stackSelectedToolNames = applyResourcePolicy(names, policy);
173
+ const selected = new Set(stackSelectedToolNames);
174
+ const effective = tools.filter((tool) => selected.has(tool.name) && toolAllowedByAccess(tool, access));
175
+ const unmatchedAllowPatterns = policy && "allow" in policy
176
+ ? (policy.allow ?? []).filter((pattern) => pattern !== "*" && !names.some((name) => resourcePatternMatches(name, pattern)))
177
+ : [];
178
+ for (const pattern of unmatchedAllowPatterns) {
179
+ diagnostics.push({ level: "warning", code: "tools.unmatched-allow", path: "tools.allow", message: `Tool allow pattern matches no backend tools: ${pattern}` });
180
+ }
181
+ for (const tool of tools) {
182
+ if (selected.has(tool.name) && !effective.includes(tool)) {
183
+ diagnostics.push({ level: "info", code: "tools.access-filtered", path: `tools.${tool.name}`, message: `Tool ${tool.name} was removed by request access policy.` });
184
+ }
185
+ }
186
+ return {
187
+ effectiveToolIds: effective.map((tool) => tool.id),
188
+ effectiveToolNames: effective.map((tool) => tool.name),
189
+ diagnostics,
123
190
  };
124
191
  }
192
+ function toolAllowedByAccess(tool, access) {
193
+ for (const effect of tool.effects) {
194
+ if (effect === "network" && access.network !== "allow")
195
+ return false;
196
+ if (effect === "process" && access.allowProcess !== true)
197
+ return false;
198
+ if (effect === "filesystem-read" && access.level === "none")
199
+ return false;
200
+ if (effect === "filesystem-write" && access.level !== "workspace-write")
201
+ return false;
202
+ }
203
+ return true;
204
+ }
125
205
  export function collectSubagentPromptDependencies(stack, registrations = currentSubagentPromptRegistrationCatalog()) {
126
206
  const diagnostics = [];
127
207
  const dependencies = new Map();
128
208
  const missing = new Map();
129
209
  const macroCatalog = new Map(registrations.macros.map((entry) => [entry.name, entry]));
130
210
  const slotCatalog = new Map(registrations.slots.map((entry) => [entry.name, entry]));
131
- const staticVariables = new Set(Object.keys(stack.variables ?? {}));
211
+ const parameters = new Set([
212
+ ...Object.keys(stack.parameters ?? {}),
213
+ ...Object.keys(stack.variables ?? {}),
214
+ ]);
215
+ const analysis = analyzePromptStack(stack, registrations);
216
+ for (const error of analysis.diagnostics) {
217
+ diagnostics.push({
218
+ level: "error",
219
+ code: "prompt-stack.template-analyze",
220
+ path: "promptStack",
221
+ message: error.message,
222
+ });
223
+ }
132
224
  for (const item of stack.items) {
133
225
  if (item.kind === "slot") {
134
226
  if (BUILT_IN_SLOTS.has(item.slot))
135
227
  continue;
136
228
  addDependency("slot", item.slot, slotCatalog, dependencies, missing, diagnostics, `promptStack.items.${item.id}`);
137
- continue;
138
229
  }
139
- for (const name of collectMacroCommandNames(item.content)) {
140
- if (BUILT_IN_MACROS.has(name) || staticVariables.has(name))
230
+ }
231
+ for (const block of analysis.blocks) {
232
+ for (const dependency of block.dependencies) {
233
+ let name;
234
+ if (dependency.kind === "extensions")
235
+ name = dependency.path?.[1];
236
+ if (dependency.kind === "legacy") {
237
+ const candidate = dependency.path?.[0];
238
+ if (!candidate || parameters.has(candidate) || LEGACY_BUILTIN_RUNTIME.has(candidate))
239
+ continue;
240
+ name = candidate;
241
+ }
242
+ if (!name)
141
243
  continue;
142
- addDependency("macro", name, macroCatalog, dependencies, missing, diagnostics, `promptStack.items.${item.id}`);
244
+ addDependency("macro", name, macroCatalog, dependencies, missing, diagnostics, `promptStack.items.${block.itemId}`);
143
245
  }
144
246
  }
247
+ for (const name of analysis.transitiveExtensions) {
248
+ if (!name || macroCatalog.has(name))
249
+ continue;
250
+ addDependency("macro", name, macroCatalog, dependencies, missing, diagnostics, "promptStack");
251
+ }
145
252
  return {
146
253
  dependencies: [...dependencies.values()].sort(compareDependencies),
147
254
  missingDependencies: [...missing.values()].sort(compareDependencies),
148
255
  diagnostics,
149
256
  };
150
257
  }
151
- export function collectMacroCommandNames(text) {
152
- const names = new Set();
153
- collectMacroCommandsInto(text, names);
154
- return [...names].sort();
155
- }
156
- export function appendProtectedAgentTask(compiledMessages, protectedTask) {
157
- if (protectedTask.role !== "user")
158
- throw new Error("Protected delegated task must be a user message.");
159
- return [...structuredClone(compiledMessages), structuredClone(protectedTask)];
160
- }
161
- export function compileProtectedAgentTaskMessages(stack, runtime, originalMessages) {
162
- const taskIndex = findLastUserMessageIndex(originalMessages);
163
- if (taskIndex === -1)
164
- throw new Error("Delegated context contains no final user task.");
165
- const protectedTask = structuredClone(originalMessages[taskIndex]);
166
- const history = originalMessages.filter((_message, index) => index !== taskIndex);
167
- const compiled = compileMessages(stack.stack, runtime, history);
168
- return { messages: appendProtectedAgentTask(compiled.messages, protectedTask), diagnostics: compiled.diagnostics };
169
- }
170
- export function isProtectedAgentTaskPreserved(messages, task) {
171
- if (!messages.length || task.role !== "user")
172
- return false;
173
- const finalMessage = messages.at(-1);
174
- if (finalMessage?.role !== "user")
175
- return false;
176
- return normalizeUserContent(finalMessage.content)
177
- === normalizeUserContent(task.content);
258
+ const LEGACY_BUILTIN_RUNTIME = new Set([
259
+ "cwd", "date", "time", "lastUserMessage", "selectedTools", "tools", "activeModel",
260
+ ]);
261
+ function appendProtectedDelegationTask(messages, task) {
262
+ return [
263
+ ...structuredClone(messages),
264
+ {
265
+ role: "user",
266
+ content: [{ type: "text", text: task.text }],
267
+ protectedTask: true,
268
+ source: "delegated-task",
269
+ },
270
+ ];
178
271
  }
179
272
  function registrationEntry(definition) {
180
- return { name: definition.name, source: definition.source };
273
+ return { name: definition.name, source: definition.source, dependencies: definition.dependencies };
181
274
  }
182
275
  function addDependency(kind, name, catalog, dependencies, missing, diagnostics, path) {
183
276
  const key = `${kind}:${name}`;
@@ -192,76 +285,6 @@ function addDependency(kind, name, catalog, dependencies, missing, diagnostics,
192
285
  if (!registration.source)
193
286
  diagnostics.push({ level: "warning", code: "profile.dependency-anonymous", path, message: `Custom ${kind} ${name} has no stable source identity.` });
194
287
  }
195
- function collectMacroCommandsInto(text, names) {
196
- let index = 0;
197
- while (index < text.length) {
198
- const start = text.indexOf("{{", index);
199
- if (start === -1)
200
- return;
201
- const end = findMacroEnd(text, start + 2);
202
- if (end === undefined)
203
- return;
204
- const expression = text.slice(start + 2, end).trim();
205
- const parts = splitMacroExpression(expression);
206
- const command = parts[0]?.trim();
207
- if (command && /^[A-Za-z][A-Za-z0-9_.-]*$/.test(command))
208
- names.add(command);
209
- for (const argument of parts.slice(1))
210
- collectMacroCommandsInto(argument, names);
211
- index = end + 2;
212
- }
213
- }
214
- function findMacroEnd(text, start) {
215
- let depth = 1;
216
- for (let index = start; index < text.length - 1; index++) {
217
- const pair = text.slice(index, index + 2);
218
- if (pair === "{{") {
219
- depth++;
220
- index++;
221
- }
222
- else if (pair === "}}") {
223
- depth--;
224
- if (depth === 0)
225
- return index;
226
- index++;
227
- }
228
- }
229
- return undefined;
230
- }
231
- function splitMacroExpression(expression) {
232
- const parts = [];
233
- let start = 0;
234
- let depth = 0;
235
- for (let index = 0; index < expression.length - 1; index++) {
236
- const pair = expression.slice(index, index + 2);
237
- if (pair === "{{") {
238
- depth++;
239
- index++;
240
- }
241
- else if (pair === "}}" && depth > 0) {
242
- depth--;
243
- index++;
244
- }
245
- else if (pair === "::" && depth === 0) {
246
- parts.push(expression.slice(start, index));
247
- start = index + 2;
248
- index++;
249
- }
250
- }
251
- parts.push(expression.slice(start));
252
- return parts;
253
- }
254
- function findLastUserMessageIndex(messages) {
255
- for (let index = messages.length - 1; index >= 0; index--) {
256
- if (messages[index]?.role === "user")
257
- return index;
258
- }
259
- return -1;
260
- }
261
- function normalizeUserContent(content) {
262
- const normalized = typeof content === "string" ? [{ type: "text", text: content }] : Array.isArray(content) ? content : [content];
263
- return JSON.stringify(normalized);
264
- }
265
288
  function preparedPromptStackMessage(message) {
266
289
  if (message.role !== "user" && message.role !== "assistant" && message.role !== "custom") {
267
290
  throw new Error(`Unsupported prompt-stack message role for subagent preparation: ${message.role}`);