wingfoil 0.2.1

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 (339) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +334 -0
  3. package/dist/cli/error.d.ts +11 -0
  4. package/dist/cli/error.d.ts.map +1 -0
  5. package/dist/cli/error.js +27 -0
  6. package/dist/cli/error.js.map +1 -0
  7. package/dist/cli/exit.d.ts +19 -0
  8. package/dist/cli/exit.d.ts.map +1 -0
  9. package/dist/cli/exit.js +14 -0
  10. package/dist/cli/exit.js.map +1 -0
  11. package/dist/cli/index.d.ts +28 -0
  12. package/dist/cli/index.d.ts.map +1 -0
  13. package/dist/cli/index.js +36 -0
  14. package/dist/cli/index.js.map +1 -0
  15. package/dist/cli/init-command.d.ts +34 -0
  16. package/dist/cli/init-command.d.ts.map +1 -0
  17. package/dist/cli/init-command.js +100 -0
  18. package/dist/cli/init-command.js.map +1 -0
  19. package/dist/cli/mcp-command.d.ts +24 -0
  20. package/dist/cli/mcp-command.d.ts.map +1 -0
  21. package/dist/cli/mcp-command.js +42 -0
  22. package/dist/cli/mcp-command.js.map +1 -0
  23. package/dist/cli/output.d.ts +13 -0
  24. package/dist/cli/output.d.ts.map +1 -0
  25. package/dist/cli/output.js +28 -0
  26. package/dist/cli/output.js.map +1 -0
  27. package/dist/cli/program.d.ts +12 -0
  28. package/dist/cli/program.d.ts.map +1 -0
  29. package/dist/cli/program.js +279 -0
  30. package/dist/cli/program.js.map +1 -0
  31. package/dist/cli/registrar.d.ts +69 -0
  32. package/dist/cli/registrar.d.ts.map +1 -0
  33. package/dist/cli/registrar.js +82 -0
  34. package/dist/cli/registrar.js.map +1 -0
  35. package/dist/cli.d.ts +3 -0
  36. package/dist/cli.d.ts.map +1 -0
  37. package/dist/cli.js +45 -0
  38. package/dist/cli.js.map +1 -0
  39. package/dist/core/approval-authority.d.ts +83 -0
  40. package/dist/core/approval-authority.d.ts.map +1 -0
  41. package/dist/core/approval-authority.js +112 -0
  42. package/dist/core/approval-authority.js.map +1 -0
  43. package/dist/core/builtin-asset.d.ts +71 -0
  44. package/dist/core/builtin-asset.d.ts.map +1 -0
  45. package/dist/core/builtin-asset.js +137 -0
  46. package/dist/core/builtin-asset.js.map +1 -0
  47. package/dist/core/builtin-integrity.d.ts +32 -0
  48. package/dist/core/builtin-integrity.d.ts.map +1 -0
  49. package/dist/core/builtin-integrity.js +148 -0
  50. package/dist/core/builtin-integrity.js.map +1 -0
  51. package/dist/core/confinement.d.ts +57 -0
  52. package/dist/core/confinement.d.ts.map +1 -0
  53. package/dist/core/confinement.js +108 -0
  54. package/dist/core/confinement.js.map +1 -0
  55. package/dist/core/context.d.ts +187 -0
  56. package/dist/core/context.d.ts.map +1 -0
  57. package/dist/core/context.js +192 -0
  58. package/dist/core/context.js.map +1 -0
  59. package/dist/core/directive-assign.d.ts +131 -0
  60. package/dist/core/directive-assign.d.ts.map +1 -0
  61. package/dist/core/directive-assign.js +352 -0
  62. package/dist/core/directive-assign.js.map +1 -0
  63. package/dist/core/directives-list.d.ts +80 -0
  64. package/dist/core/directives-list.d.ts.map +1 -0
  65. package/dist/core/directives-list.js +148 -0
  66. package/dist/core/directives-list.js.map +1 -0
  67. package/dist/core/exit-code.d.ts +85 -0
  68. package/dist/core/exit-code.d.ts.map +1 -0
  69. package/dist/core/exit-code.js +163 -0
  70. package/dist/core/exit-code.js.map +1 -0
  71. package/dist/core/git-identity.d.ts +32 -0
  72. package/dist/core/git-identity.d.ts.map +1 -0
  73. package/dist/core/git-identity.js +72 -0
  74. package/dist/core/git-identity.js.map +1 -0
  75. package/dist/core/index.d.ts +388 -0
  76. package/dist/core/index.d.ts.map +1 -0
  77. package/dist/core/index.js +1331 -0
  78. package/dist/core/index.js.map +1 -0
  79. package/dist/core/init.d.ts +78 -0
  80. package/dist/core/init.d.ts.map +1 -0
  81. package/dist/core/init.js +167 -0
  82. package/dist/core/init.js.map +1 -0
  83. package/dist/core/loaders.d.ts +174 -0
  84. package/dist/core/loaders.d.ts.map +1 -0
  85. package/dist/core/loaders.js +364 -0
  86. package/dist/core/loaders.js.map +1 -0
  87. package/dist/core/memory-add-type.d.ts +43 -0
  88. package/dist/core/memory-add-type.d.ts.map +1 -0
  89. package/dist/core/memory-add-type.js +151 -0
  90. package/dist/core/memory-add-type.js.map +1 -0
  91. package/dist/core/memory-transition.d.ts +111 -0
  92. package/dist/core/memory-transition.d.ts.map +1 -0
  93. package/dist/core/memory-transition.js +269 -0
  94. package/dist/core/memory-transition.js.map +1 -0
  95. package/dist/core/registry.d.ts +189 -0
  96. package/dist/core/registry.d.ts.map +1 -0
  97. package/dist/core/registry.js +66 -0
  98. package/dist/core/registry.js.map +1 -0
  99. package/dist/core/relevance.d.ts +86 -0
  100. package/dist/core/relevance.d.ts.map +1 -0
  101. package/dist/core/relevance.js +258 -0
  102. package/dist/core/relevance.js.map +1 -0
  103. package/dist/core/require-reason.d.ts +27 -0
  104. package/dist/core/require-reason.d.ts.map +1 -0
  105. package/dist/core/require-reason.js +95 -0
  106. package/dist/core/require-reason.js.map +1 -0
  107. package/dist/core/types.d.ts +45 -0
  108. package/dist/core/types.d.ts.map +1 -0
  109. package/dist/core/types.js +22 -0
  110. package/dist/core/types.js.map +1 -0
  111. package/dist/core/usage-error.d.ts +20 -0
  112. package/dist/core/usage-error.d.ts.map +1 -0
  113. package/dist/core/usage-error.js +29 -0
  114. package/dist/core/usage-error.js.map +1 -0
  115. package/dist/core/write-guard.d.ts +99 -0
  116. package/dist/core/write-guard.d.ts.map +1 -0
  117. package/dist/core/write-guard.js +247 -0
  118. package/dist/core/write-guard.js.map +1 -0
  119. package/dist/directives/create.d.ts +47 -0
  120. package/dist/directives/create.d.ts.map +1 -0
  121. package/dist/directives/create.js +82 -0
  122. package/dist/directives/create.js.map +1 -0
  123. package/dist/directives/index.d.ts +20 -0
  124. package/dist/directives/index.d.ts.map +1 -0
  125. package/dist/directives/index.js +32 -0
  126. package/dist/directives/index.js.map +1 -0
  127. package/dist/directives/roles-edit.d.ts +53 -0
  128. package/dist/directives/roles-edit.d.ts.map +1 -0
  129. package/dist/directives/roles-edit.js +286 -0
  130. package/dist/directives/roles-edit.js.map +1 -0
  131. package/dist/directives/schema.d.ts +65 -0
  132. package/dist/directives/schema.d.ts.map +1 -0
  133. package/dist/directives/schema.js +68 -0
  134. package/dist/directives/schema.js.map +1 -0
  135. package/dist/dna/edit.d.ts +61 -0
  136. package/dist/dna/edit.d.ts.map +1 -0
  137. package/dist/dna/edit.js +429 -0
  138. package/dist/dna/edit.js.map +1 -0
  139. package/dist/dna/index.d.ts +24 -0
  140. package/dist/dna/index.d.ts.map +1 -0
  141. package/dist/dna/index.js +59 -0
  142. package/dist/dna/index.js.map +1 -0
  143. package/dist/dna/mutate.d.ts +74 -0
  144. package/dist/dna/mutate.d.ts.map +1 -0
  145. package/dist/dna/mutate.js +318 -0
  146. package/dist/dna/mutate.js.map +1 -0
  147. package/dist/dna/path.d.ts +175 -0
  148. package/dist/dna/path.d.ts.map +1 -0
  149. package/dist/dna/path.js +289 -0
  150. package/dist/dna/path.js.map +1 -0
  151. package/dist/dna/roles.d.ts +57 -0
  152. package/dist/dna/roles.d.ts.map +1 -0
  153. package/dist/dna/roles.js +50 -0
  154. package/dist/dna/roles.js.map +1 -0
  155. package/dist/dna/schema.d.ts +172 -0
  156. package/dist/dna/schema.d.ts.map +1 -0
  157. package/dist/dna/schema.js +182 -0
  158. package/dist/dna/schema.js.map +1 -0
  159. package/dist/dna/set.d.ts +145 -0
  160. package/dist/dna/set.d.ts.map +1 -0
  161. package/dist/dna/set.js +428 -0
  162. package/dist/dna/set.js.map +1 -0
  163. package/dist/mcp/dna-resource.d.ts +16 -0
  164. package/dist/mcp/dna-resource.d.ts.map +1 -0
  165. package/dist/mcp/dna-resource.js +56 -0
  166. package/dist/mcp/dna-resource.js.map +1 -0
  167. package/dist/mcp/index.d.ts +49 -0
  168. package/dist/mcp/index.d.ts.map +1 -0
  169. package/dist/mcp/index.js +60 -0
  170. package/dist/mcp/index.js.map +1 -0
  171. package/dist/mcp/memory-resource.d.ts +17 -0
  172. package/dist/mcp/memory-resource.d.ts.map +1 -0
  173. package/dist/mcp/memory-resource.js +133 -0
  174. package/dist/mcp/memory-resource.js.map +1 -0
  175. package/dist/mcp/prompt.d.ts +48 -0
  176. package/dist/mcp/prompt.d.ts.map +1 -0
  177. package/dist/mcp/prompt.js +176 -0
  178. package/dist/mcp/prompt.js.map +1 -0
  179. package/dist/mcp/read-only.d.ts +42 -0
  180. package/dist/mcp/read-only.d.ts.map +1 -0
  181. package/dist/mcp/read-only.js +93 -0
  182. package/dist/mcp/read-only.js.map +1 -0
  183. package/dist/mcp/registrar.d.ts +54 -0
  184. package/dist/mcp/registrar.d.ts.map +1 -0
  185. package/dist/mcp/registrar.js +72 -0
  186. package/dist/mcp/registrar.js.map +1 -0
  187. package/dist/mcp/server.d.ts +58 -0
  188. package/dist/mcp/server.d.ts.map +1 -0
  189. package/dist/mcp/server.js +64 -0
  190. package/dist/mcp/server.js.map +1 -0
  191. package/dist/mcp/workflow-resource.d.ts +17 -0
  192. package/dist/mcp/workflow-resource.d.ts.map +1 -0
  193. package/dist/mcp/workflow-resource.js +63 -0
  194. package/dist/mcp/workflow-resource.js.map +1 -0
  195. package/dist/memory/add.d.ts +50 -0
  196. package/dist/memory/add.d.ts.map +1 -0
  197. package/dist/memory/add.js +131 -0
  198. package/dist/memory/add.js.map +1 -0
  199. package/dist/memory/audit.d.ts +177 -0
  200. package/dist/memory/audit.d.ts.map +1 -0
  201. package/dist/memory/audit.js +287 -0
  202. package/dist/memory/audit.js.map +1 -0
  203. package/dist/memory/commit-message.d.ts +146 -0
  204. package/dist/memory/commit-message.d.ts.map +1 -0
  205. package/dist/memory/commit-message.js +203 -0
  206. package/dist/memory/commit-message.js.map +1 -0
  207. package/dist/memory/entry.d.ts +56 -0
  208. package/dist/memory/entry.d.ts.map +1 -0
  209. package/dist/memory/entry.js +28 -0
  210. package/dist/memory/entry.js.map +1 -0
  211. package/dist/memory/frontmatter-edit.d.ts +68 -0
  212. package/dist/memory/frontmatter-edit.d.ts.map +1 -0
  213. package/dist/memory/frontmatter-edit.js +333 -0
  214. package/dist/memory/frontmatter-edit.js.map +1 -0
  215. package/dist/memory/git-log.d.ts +32 -0
  216. package/dist/memory/git-log.d.ts.map +1 -0
  217. package/dist/memory/git-log.js +100 -0
  218. package/dist/memory/git-log.js.map +1 -0
  219. package/dist/memory/history.d.ts +142 -0
  220. package/dist/memory/history.d.ts.map +1 -0
  221. package/dist/memory/history.js +250 -0
  222. package/dist/memory/history.js.map +1 -0
  223. package/dist/memory/index.d.ts +58 -0
  224. package/dist/memory/index.d.ts.map +1 -0
  225. package/dist/memory/index.js +107 -0
  226. package/dist/memory/index.js.map +1 -0
  227. package/dist/memory/query.d.ts +150 -0
  228. package/dist/memory/query.d.ts.map +1 -0
  229. package/dist/memory/query.js +307 -0
  230. package/dist/memory/query.js.map +1 -0
  231. package/dist/memory/reject.d.ts +11 -0
  232. package/dist/memory/reject.d.ts.map +1 -0
  233. package/dist/memory/reject.js +32 -0
  234. package/dist/memory/reject.js.map +1 -0
  235. package/dist/memory/schema.d.ts +104 -0
  236. package/dist/memory/schema.d.ts.map +1 -0
  237. package/dist/memory/schema.js +161 -0
  238. package/dist/memory/schema.js.map +1 -0
  239. package/dist/memory/state-machine.d.ts +166 -0
  240. package/dist/memory/state-machine.d.ts.map +1 -0
  241. package/dist/memory/state-machine.js +431 -0
  242. package/dist/memory/state-machine.js.map +1 -0
  243. package/dist/memory/submit.d.ts +11 -0
  244. package/dist/memory/submit.d.ts.map +1 -0
  245. package/dist/memory/submit.js +44 -0
  246. package/dist/memory/submit.js.map +1 -0
  247. package/dist/storage/builtin-directives.d.ts +54 -0
  248. package/dist/storage/builtin-directives.d.ts.map +1 -0
  249. package/dist/storage/builtin-directives.js +152 -0
  250. package/dist/storage/builtin-directives.js.map +1 -0
  251. package/dist/storage/commit.d.ts +92 -0
  252. package/dist/storage/commit.d.ts.map +1 -0
  253. package/dist/storage/commit.js +201 -0
  254. package/dist/storage/commit.js.map +1 -0
  255. package/dist/storage/confinement.d.ts +93 -0
  256. package/dist/storage/confinement.d.ts.map +1 -0
  257. package/dist/storage/confinement.js +164 -0
  258. package/dist/storage/confinement.js.map +1 -0
  259. package/dist/storage/document.d.ts +27 -0
  260. package/dist/storage/document.d.ts.map +1 -0
  261. package/dist/storage/document.js +52 -0
  262. package/dist/storage/document.js.map +1 -0
  263. package/dist/storage/errors.d.ts +36 -0
  264. package/dist/storage/errors.d.ts.map +1 -0
  265. package/dist/storage/errors.js +46 -0
  266. package/dist/storage/errors.js.map +1 -0
  267. package/dist/storage/frontmatter.d.ts +27 -0
  268. package/dist/storage/frontmatter.d.ts.map +1 -0
  269. package/dist/storage/frontmatter.js +37 -0
  270. package/dist/storage/frontmatter.js.map +1 -0
  271. package/dist/storage/git-root.d.ts +17 -0
  272. package/dist/storage/git-root.d.ts.map +1 -0
  273. package/dist/storage/git-root.js +49 -0
  274. package/dist/storage/git-root.js.map +1 -0
  275. package/dist/storage/index.d.ts +29 -0
  276. package/dist/storage/index.d.ts.map +1 -0
  277. package/dist/storage/index.js +66 -0
  278. package/dist/storage/index.js.map +1 -0
  279. package/dist/storage/init-state.d.ts +9 -0
  280. package/dist/storage/init-state.d.ts.map +1 -0
  281. package/dist/storage/init-state.js +24 -0
  282. package/dist/storage/init-state.js.map +1 -0
  283. package/dist/storage/layout.d.ts +51 -0
  284. package/dist/storage/layout.d.ts.map +1 -0
  285. package/dist/storage/layout.js +88 -0
  286. package/dist/storage/layout.js.map +1 -0
  287. package/dist/storage/memory-path.d.ts +72 -0
  288. package/dist/storage/memory-path.d.ts.map +1 -0
  289. package/dist/storage/memory-path.js +127 -0
  290. package/dist/storage/memory-path.js.map +1 -0
  291. package/dist/storage/snapshot.d.ts +16 -0
  292. package/dist/storage/snapshot.d.ts.map +1 -0
  293. package/dist/storage/snapshot.js +72 -0
  294. package/dist/storage/snapshot.js.map +1 -0
  295. package/dist/storage/templates.d.ts +88 -0
  296. package/dist/storage/templates.d.ts.map +1 -0
  297. package/dist/storage/templates.js +422 -0
  298. package/dist/storage/templates.js.map +1 -0
  299. package/dist/validation/error-mapper.d.ts +16 -0
  300. package/dist/validation/error-mapper.d.ts.map +1 -0
  301. package/dist/validation/error-mapper.js +18 -0
  302. package/dist/validation/error-mapper.js.map +1 -0
  303. package/dist/validation/errors.d.ts +69 -0
  304. package/dist/validation/errors.d.ts.map +1 -0
  305. package/dist/validation/errors.js +69 -0
  306. package/dist/validation/errors.js.map +1 -0
  307. package/dist/validation/id.d.ts +16 -0
  308. package/dist/validation/id.d.ts.map +1 -0
  309. package/dist/validation/id.js +177 -0
  310. package/dist/validation/id.js.map +1 -0
  311. package/dist/validation/index.d.ts +18 -0
  312. package/dist/validation/index.d.ts.map +1 -0
  313. package/dist/validation/index.js +37 -0
  314. package/dist/validation/index.js.map +1 -0
  315. package/dist/validation/secret-scan.d.ts +129 -0
  316. package/dist/validation/secret-scan.d.ts.map +1 -0
  317. package/dist/validation/secret-scan.js +367 -0
  318. package/dist/validation/secret-scan.js.map +1 -0
  319. package/dist/validation/two-pass.d.ts +24 -0
  320. package/dist/validation/two-pass.d.ts.map +1 -0
  321. package/dist/validation/two-pass.js +24 -0
  322. package/dist/validation/two-pass.js.map +1 -0
  323. package/dist/validation/warning.d.ts +31 -0
  324. package/dist/validation/warning.d.ts.map +1 -0
  325. package/dist/validation/warning.js +81 -0
  326. package/dist/validation/warning.js.map +1 -0
  327. package/dist/validation/yaml.d.ts +9 -0
  328. package/dist/validation/yaml.d.ts.map +1 -0
  329. package/dist/validation/yaml.js +30 -0
  330. package/dist/validation/yaml.js.map +1 -0
  331. package/dist/workflow/index.d.ts +10 -0
  332. package/dist/workflow/index.d.ts.map +1 -0
  333. package/dist/workflow/index.js +16 -0
  334. package/dist/workflow/index.js.map +1 -0
  335. package/dist/workflow/schema.d.ts +89 -0
  336. package/dist/workflow/schema.d.ts.map +1 -0
  337. package/dist/workflow/schema.js +73 -0
  338. package/dist/workflow/schema.js.map +1 -0
  339. package/package.json +78 -0
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.startMcpServer = exports.createMcpServer = exports.roleSessionPromptName = exports.registerRolePrompts = exports.WRITE_INTENT_META_KEY = exports.WRITE_REFUSAL_MESSAGE = exports.resourceNotFoundError = exports.refuseIfWriteIntent = exports.registerWriteRefusalHandler = exports.WORKFLOW_DOCUMENT_URI_TEMPLATE = exports.WORKFLOWS_COLLECTION_URI = exports.registerWorkflowResources = exports.DNA_SECTION_URI_TEMPLATE = exports.DNA_WHOLE_URI = exports.registerDnaResources = exports.MEMORY_DOCUMENT_URI_TEMPLATE = exports.MEMORY_COLLECTION_URI_TEMPLATE = exports.registerMemoryResources = exports.deriveMcpResourceUri = exports.deriveMcpToolName = exports.registerCoreModules = exports.MODULE_NAME = void 0;
4
+ exports.registerReadOnlyResources = registerReadOnlyResources;
5
+ /** This module's `dna.yaml` name (`mcp-server`) — the stable identifier surfaces and tests key it by. */
6
+ exports.MODULE_NAME = 'mcp-server';
7
+ var registrar_1 = require("./registrar");
8
+ Object.defineProperty(exports, "registerCoreModules", { enumerable: true, get: function () { return registrar_1.registerCoreModules; } });
9
+ Object.defineProperty(exports, "deriveMcpToolName", { enumerable: true, get: function () { return registrar_1.deriveMcpToolName; } });
10
+ Object.defineProperty(exports, "deriveMcpResourceUri", { enumerable: true, get: function () { return registrar_1.deriveMcpResourceUri; } });
11
+ var memory_resource_1 = require("./memory-resource");
12
+ Object.defineProperty(exports, "registerMemoryResources", { enumerable: true, get: function () { return memory_resource_1.registerMemoryResources; } });
13
+ Object.defineProperty(exports, "MEMORY_COLLECTION_URI_TEMPLATE", { enumerable: true, get: function () { return memory_resource_1.MEMORY_COLLECTION_URI_TEMPLATE; } });
14
+ Object.defineProperty(exports, "MEMORY_DOCUMENT_URI_TEMPLATE", { enumerable: true, get: function () { return memory_resource_1.MEMORY_DOCUMENT_URI_TEMPLATE; } });
15
+ var dna_resource_1 = require("./dna-resource");
16
+ Object.defineProperty(exports, "registerDnaResources", { enumerable: true, get: function () { return dna_resource_1.registerDnaResources; } });
17
+ Object.defineProperty(exports, "DNA_WHOLE_URI", { enumerable: true, get: function () { return dna_resource_1.DNA_WHOLE_URI; } });
18
+ Object.defineProperty(exports, "DNA_SECTION_URI_TEMPLATE", { enumerable: true, get: function () { return dna_resource_1.DNA_SECTION_URI_TEMPLATE; } });
19
+ var workflow_resource_1 = require("./workflow-resource");
20
+ Object.defineProperty(exports, "registerWorkflowResources", { enumerable: true, get: function () { return workflow_resource_1.registerWorkflowResources; } });
21
+ Object.defineProperty(exports, "WORKFLOWS_COLLECTION_URI", { enumerable: true, get: function () { return workflow_resource_1.WORKFLOWS_COLLECTION_URI; } });
22
+ Object.defineProperty(exports, "WORKFLOW_DOCUMENT_URI_TEMPLATE", { enumerable: true, get: function () { return workflow_resource_1.WORKFLOW_DOCUMENT_URI_TEMPLATE; } });
23
+ var read_only_1 = require("./read-only");
24
+ Object.defineProperty(exports, "registerWriteRefusalHandler", { enumerable: true, get: function () { return read_only_1.registerWriteRefusalHandler; } });
25
+ Object.defineProperty(exports, "refuseIfWriteIntent", { enumerable: true, get: function () { return read_only_1.refuseIfWriteIntent; } });
26
+ Object.defineProperty(exports, "resourceNotFoundError", { enumerable: true, get: function () { return read_only_1.resourceNotFoundError; } });
27
+ Object.defineProperty(exports, "WRITE_REFUSAL_MESSAGE", { enumerable: true, get: function () { return read_only_1.WRITE_REFUSAL_MESSAGE; } });
28
+ Object.defineProperty(exports, "WRITE_INTENT_META_KEY", { enumerable: true, get: function () { return read_only_1.WRITE_INTENT_META_KEY; } });
29
+ // task-039-mcp-prompts-role-based-infra adds the spec-004 §3 Prompts channel (REQ-INT-02): one
30
+ // `{role}-session` prompt per `dna.yaml` role, embedding that role's directives, resolved per
31
+ // request. Deliberately NOT folded into `registerReadOnlyResources` below (that call is spec-004 §2's
32
+ // Resources bundle); `createMcpServer` registers it alongside that bundle since
33
+ // `task-058-mcp-prompts-role-based` (P5.2.2, spec-014 §3). See `./prompt.ts`.
34
+ var prompt_1 = require("./prompt");
35
+ Object.defineProperty(exports, "registerRolePrompts", { enumerable: true, get: function () { return prompt_1.registerRolePrompts; } });
36
+ Object.defineProperty(exports, "roleSessionPromptName", { enumerable: true, get: function () { return prompt_1.roleSessionPromptName; } });
37
+ const dna_resource_2 = require("./dna-resource");
38
+ const memory_resource_2 = require("./memory-resource");
39
+ const read_only_2 = require("./read-only");
40
+ const workflow_resource_2 = require("./workflow-resource");
41
+ /**
42
+ * Wire the full spec-004 §2 read-only Resources channel onto `server` in one call: the Memory, DNA,
43
+ * and Workflow Resources plus the structural `resources/write` refusal. Deliberately does not touch
44
+ * `registerCoreModules`/`CORE_MODULES` — a caller building a real server still calls that separately
45
+ * for the (today, zero) Tools/legacy-shaped Resources it derives from `src/core`.
46
+ */
47
+ function registerReadOnlyResources(server, options) {
48
+ (0, read_only_2.registerWriteRefusalHandler)(server);
49
+ (0, memory_resource_2.registerMemoryResources)(server, options);
50
+ (0, dna_resource_2.registerDnaResources)(server, options);
51
+ (0, workflow_resource_2.registerWorkflowResources)(server, options);
52
+ }
53
+ // The production stdio entry point (task-030-implement-mcp-resources, spec-014-mcp-server-entry-point):
54
+ // `createMcpServer` builds a real `McpServer` with the read-only Resources and Prompts channels above wired on,
55
+ // `startMcpServer` connects it over `StdioServerTransport`. Exported here so the `bin`/`wingfoil mcp`
56
+ // seam imports the whole `src/mcp` surface from one module.
57
+ var server_1 = require("./server");
58
+ Object.defineProperty(exports, "createMcpServer", { enumerable: true, get: function () { return server_1.createMcpServer; } });
59
+ Object.defineProperty(exports, "startMcpServer", { enumerable: true, get: function () { return server_1.startMcpServer; } });
60
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":";;;AA8EA,8DAKC;AA7DD,yGAAyG;AAC5F,QAAA,WAAW,GAAG,YAAqB,CAAC;AAEjD,yCAA2F;AAAlF,gHAAA,mBAAmB,OAAA;AAAE,8GAAA,iBAAiB,OAAA;AAAE,iHAAA,oBAAoB,OAAA;AAGrE,qDAI2B;AAHzB,0HAAA,uBAAuB,OAAA;AACvB,iIAAA,8BAA8B,OAAA;AAC9B,+HAAA,4BAA4B,OAAA;AAI9B,+CAA+F;AAAtF,oHAAA,oBAAoB,OAAA;AAAE,6GAAA,aAAa,OAAA;AAAE,wHAAA,wBAAwB,OAAA;AAGtE,yDAI6B;AAH3B,8HAAA,yBAAyB,OAAA;AACzB,6HAAA,wBAAwB,OAAA;AACxB,mIAAA,8BAA8B,OAAA;AAIhC,yCAMqB;AALnB,wHAAA,2BAA2B,OAAA;AAC3B,gHAAA,mBAAmB,OAAA;AACnB,kHAAA,qBAAqB,OAAA;AACrB,kHAAA,qBAAqB,OAAA;AACrB,kHAAA,qBAAqB,OAAA;AAGvB,+FAA+F;AAC/F,8FAA8F;AAC9F,sGAAsG;AACtG,gFAAgF;AAChF,8EAA8E;AAC9E,mCAAsE;AAA7D,6GAAA,mBAAmB,OAAA;AAAE,+GAAA,qBAAqB,OAAA;AAGnD,iDAAsD;AACtD,uDAA4D;AAC5D,2CAA0D;AAC1D,2DAAgE;AAQhE;;;;;GAKG;AACH,SAAgB,yBAAyB,CAAC,MAAiB,EAAE,OAAyC;IACpG,IAAA,uCAA2B,EAAC,MAAM,CAAC,CAAC;IACpC,IAAA,yCAAuB,EAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACzC,IAAA,mCAAoB,EAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC,IAAA,6CAAyB,EAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAC7C,CAAC;AAED,wGAAwG;AACxG,gHAAgH;AAChH,sGAAsG;AACtG,4DAA4D;AAC5D,mCAA2D;AAAlD,yGAAA,eAAe,OAAA;AAAE,wGAAA,cAAc,OAAA"}
@@ -0,0 +1,17 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ /** Options for {@link registerMemoryResources}. */
3
+ export interface RegisterMemoryResourcesOptions {
4
+ /** Resolves the project root each Memory Resource read is served from (an ambient concern, not a request parameter). */
5
+ readonly resolveRoot: () => string;
6
+ }
7
+ /** spec-004 §2.1 — collection listing (frontmatter only, no `{id}`). */
8
+ export declare const MEMORY_COLLECTION_URI_TEMPLATE = "wingfoil://memory/{type}";
9
+ /** spec-004 §2.1 — a single Memory document (full frontmatter + body). */
10
+ export declare const MEMORY_DOCUMENT_URI_TEMPLATE = "wingfoil://memory/{type}/{id}";
11
+ /**
12
+ * Register both Memory Resources on `server`. Reads `.wingfoil/memory.yaml` fresh on every request
13
+ * (no server-lifetime cache) — same "no cold-start cost, no stale-config either" contract the rest of
14
+ * `src/mcp`'s Resources already follow.
15
+ */
16
+ export declare function registerMemoryResources(server: McpServer, options: RegisterMemoryResourcesOptions): void;
17
+ //# sourceMappingURL=memory-resource.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory-resource.d.ts","sourceRoot":"","sources":["../../src/mcp/memory-resource.ts"],"names":[],"mappings":"AAsCA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AASzE,mDAAmD;AACnD,MAAM,WAAW,8BAA8B;IAC7C,wHAAwH;IACxH,QAAQ,CAAC,WAAW,EAAE,MAAM,MAAM,CAAC;CACpC;AAED,wEAAwE;AACxE,eAAO,MAAM,8BAA8B,6BAA6B,CAAC;AACzE,0EAA0E;AAC1E,eAAO,MAAM,4BAA4B,kCAAkC,CAAC;AAE5E;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,8BAA8B,GAAG,IAAI,CAyFxG"}
@@ -0,0 +1,133 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MEMORY_DOCUMENT_URI_TEMPLATE = exports.MEMORY_COLLECTION_URI_TEMPLATE = void 0;
4
+ exports.registerMemoryResources = registerMemoryResources;
5
+ /**
6
+ * `wingfoil://memory/{type}` (collection) and `wingfoil://memory/{type}/{id}` (single document)
7
+ * Resources — task-011-mcp-resources-read-only, REQ-INT-01, spec-004-mcp-surface-contract §2.1/§2.2.
8
+ * This REPLACES task-009-mcp-resource-fetch-latency's placeholder `wingfoil://memory/{id}` adapter
9
+ * (that module's own doc-comment flagged itself as non-conformant and due for replacement, not
10
+ * extension, precisely because its single `{id}` segment collides with spec-004's `{type}` segment —
11
+ * see `src/memory/query.ts`'s `findMemoryDocumentById` doc comment for the full history). REQ-PERF-04
12
+ * coverage is ported forward onto this conformant URI, not dropped (`test/mcp/resource-latency.test.ts`).
13
+ *
14
+ * The two handlers differ deliberately on **archived content** (REQ-STATE-06, the set ratified by
15
+ * `dl-028-archived-states-excluded-from-context`, fixed by
16
+ * `task-069-fix-archived-excluded-from-agent-context` for `bug-010-deprecated-reaches-agent-context`).
17
+ * The **collection** withholds documents whose `status` is archived (`{deprecated, superseded}`), so
18
+ * an agent browsing a type is never handed a replaced or retired decision as if it were current — the
19
+ * same guarantee `wingfoil://memory/search` and default `memory search` already give. The
20
+ * **single-document** Resource does **not** filter: addressing a document by its id is explicit
21
+ * retrieval, which REQ-STATE-06 preserves ("remaining present on disk and in git history"). It is the
22
+ * MCP counterpart of `memory search --status deprecated` on the CLI, whose own opt-in
23
+ * (`memorySearchFn`, `src/core/index.ts`) is gated on the same `isArchivedStatus`. `draft` is not
24
+ * archived and is withheld by neither handler; only the *context* path (`src/core/relevance.ts`)
25
+ * excludes it as well.
26
+ *
27
+ * Both handlers are thin adapters over `src/memory/query.ts`'s primitives
28
+ * (`listMemoryDocumentsByType`, `findMemoryDocumentByTypeAndId`, both new in this task) — no scanning
29
+ * logic lives here, only URI-variable extraction, the read-only guard (`./read-only`), and MCP
30
+ * envelope shaping. Registered directly via `McpServer.registerResource` rather than through
31
+ * `registerCoreModules`'s `CoreModule[]` registry (`src/core/registry.ts`): no `memoryShow`/`memoryList`
32
+ * `CoreOperation` exists in `src/core`'s production `CORE_MODULES` yet (see `src/core/index.ts`'s SCOPE
33
+ * note). This is the same spec-006-core-domain-api §4 (Parity rule) deviation task-009 already
34
+ * documented for this surface — acceptable because it is read-only and has no CLI/Tool counterpart to
35
+ * keep in parity with, to be reconciled (or re-confirmed as permanent) by
36
+ * task-030-implement-mcp-resources, which also wires a real `StdioServerTransport`/`wingfoil mcp`
37
+ * entry point around this registrar (out of this task's scope — see this task's Execution Notes for
38
+ * the task-011-vs-task-030 boundary).
39
+ */
40
+ const path_1 = require("path");
41
+ const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
42
+ const core_1 = require("../core");
43
+ const query_1 = require("../memory/query");
44
+ const state_machine_1 = require("../memory/state-machine");
45
+ const storage_1 = require("../storage");
46
+ const read_only_1 = require("./read-only");
47
+ /** spec-004 §2.1 — collection listing (frontmatter only, no `{id}`). */
48
+ exports.MEMORY_COLLECTION_URI_TEMPLATE = 'wingfoil://memory/{type}';
49
+ /** spec-004 §2.1 — a single Memory document (full frontmatter + body). */
50
+ exports.MEMORY_DOCUMENT_URI_TEMPLATE = 'wingfoil://memory/{type}/{id}';
51
+ /**
52
+ * Register both Memory Resources on `server`. Reads `.wingfoil/memory.yaml` fresh on every request
53
+ * (no server-lifetime cache) — same "no cold-start cost, no stale-config either" contract the rest of
54
+ * `src/mcp`'s Resources already follow.
55
+ */
56
+ function registerMemoryResources(server, options) {
57
+ const collectionTemplate = new mcp_js_1.ResourceTemplate(exports.MEMORY_COLLECTION_URI_TEMPLATE, { list: undefined });
58
+ server.registerResource('memory.list', collectionTemplate, { description: 'Memory documents of one type, frontmatter only (read-only)' }, async (uri, variables, extra) => {
59
+ (0, read_only_1.refuseIfWriteIntent)(extra._meta);
60
+ const root = options.resolveRoot();
61
+ const memoryYaml = (0, core_1.loadMemoryYaml)(root);
62
+ // `variables.type` is typed `string | string[]` (the SDK's generic `Variables` shape), but
63
+ // this template's `{type}` variable has no `*`/`+` explode modifier, so a match always binds
64
+ // it to a single string (see the SDK's `UriTemplate.match`) — the `string[]` case is
65
+ // unreachable here (mirrors task-009's own `{id}` reasoning for this same SDK behaviour).
66
+ const type = variables.type;
67
+ if (!(type in memoryYaml.types))
68
+ throw (0, read_only_1.resourceNotFoundError)(`memory/${type}`);
69
+ // REQ-STATE-06 / `dl-028-archived-states-excluded-from-context` (`bug-010`): this collection is
70
+ // an agent-facing read path, so archived documents — `{deprecated, superseded}`, per the shared
71
+ // `isArchivedStatus` — are withheld here. The filter sits at this call site rather than inside
72
+ // `listMemoryDocumentsByType` because that primitive also serves the single-document Resource's
73
+ // consumers, which must still see archived content; the *policy* belongs to the surface, while
74
+ // the *definition* of "archived" stays single, as dl-028 requires. `status` is already
75
+ // projected to `string | undefined` by the primitive — the shape `isArchivedStatus` takes — so
76
+ // a non-string frontmatter `status` is never archived. `filter` preserves the primitive's
77
+ // id-ascending order (REQ-SYS-07).
78
+ const summaries = (0, query_1.listMemoryDocumentsByType)(root, memoryYaml, type)
79
+ .filter(({ status }) => !(0, state_machine_1.isArchivedStatus)(status))
80
+ .map(({ id, title, status, tags }) => ({
81
+ id,
82
+ title,
83
+ status,
84
+ tags,
85
+ }));
86
+ return (0, read_only_1.jsonResourceResult)(uri, summaries);
87
+ });
88
+ const documentTemplate = new mcp_js_1.ResourceTemplate(exports.MEMORY_DOCUMENT_URI_TEMPLATE, { list: undefined });
89
+ server.registerResource('memory.show', documentTemplate, { description: 'one Memory document, full content + metadata (read-only)' }, async (uri, variables, extra) => {
90
+ (0, read_only_1.refuseIfWriteIntent)(extra._meta);
91
+ const root = options.resolveRoot();
92
+ const memoryYaml = (0, core_1.loadMemoryYaml)(root);
93
+ const type = variables.type;
94
+ const id = variables.id;
95
+ if (!(type in memoryYaml.types))
96
+ throw (0, read_only_1.resourceNotFoundError)(`memory/${type}/${id}`);
97
+ const doc = (0, query_1.findMemoryDocumentByTypeAndId)(root, memoryYaml, type, id);
98
+ if (!doc)
99
+ throw (0, read_only_1.resourceNotFoundError)(`memory/${type}/${id}`);
100
+ // spec-004 §2.2 wants the *full file content* (frontmatter + body), not the re-serialized
101
+ // parsed frontmatter `loadMemoryDocumentSummary` already split apart for the scan — so this
102
+ // re-reads the resolved path's raw bytes via `storage.readDocument` (still a read primitive
103
+ // reuse, not a reimplemented scan: the scan itself already happened inside
104
+ // `findMemoryDocumentByTypeAndId`).
105
+ const fullText = (0, storage_1.readDocument)((0, path_1.join)(root, doc.path));
106
+ // spec-004 §2.2 depicts `metadata` as a sibling of `uri`/`mimeType`/`text`, i.e. flat on the
107
+ // result — not nested inside a `contents[]` entry (whose shape the real MCP wire schema fixes
108
+ // to `{uri, mimeType, text|blob, _meta?}`, `ReadResourceResultSchema`'s `contents` union in the
109
+ // SDK's `types.d.ts`). The top-level `ReadResourceResultSchema` object itself is passthrough
110
+ // (`z.core.$loose`), so this extra top-level `metadata` key is preserved end to end (server ->
111
+ // wire -> client parse) without needing a non-standard content shape. Built via an
112
+ // untyped-at-the-literal `result` variable (assigned, not returned directly) so TypeScript's
113
+ // excess-property check — which only applies to object literals in a contextually-typed
114
+ // position — never triggers on this extra key.
115
+ const result = {
116
+ contents: [
117
+ {
118
+ uri: uri.toString(),
119
+ mimeType: 'text/markdown',
120
+ text: fullText,
121
+ },
122
+ ],
123
+ metadata: {
124
+ id: doc.frontmatter.id,
125
+ type: doc.frontmatter.type,
126
+ status: doc.frontmatter.status,
127
+ title: doc.frontmatter.title,
128
+ },
129
+ };
130
+ return result;
131
+ });
132
+ }
133
+ //# sourceMappingURL=memory-resource.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory-resource.js","sourceRoot":"","sources":["../../src/mcp/memory-resource.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ /** Options for {@link registerRolePrompts}. */
3
+ export interface RegisterRolePromptsOptions {
4
+ /**
5
+ * Resolves the project root each `prompts/get` is served from — invoked per request by the prompt
6
+ * handlers, and once by {@link registerRolePrompts} itself to read the DNA role catalogue (see
7
+ * that function's note on the two different timings spec-004 §3.1 and §3.2 mandate).
8
+ */
9
+ readonly resolveRoot: () => string;
10
+ }
11
+ /**
12
+ * `{role}-session` — spec-004 §3.1's prompt naming convention, as a function so the wire-visible name
13
+ * is derived in exactly one place (the registrar here, and any later consumer such as
14
+ * `task-058-mcp-prompts-role-based`) rather than spelled out per call site.
15
+ */
16
+ export declare function roleSessionPromptName(role: string): string;
17
+ /**
18
+ * Register the role-scoped Prompts channel: one `{role}-session` Prompt per role in `dna.yaml`'s
19
+ * `team.roles` catalogue (spec-004 §3.1), each embedding that role's directives (§3.2), and a refusal
20
+ * for a session prompt naming a role DNA does not declare (P5.2.2's undefined-role scenario).
21
+ *
22
+ * **Nothing is read here — every read happens per request** (task-058 second pass, rejection `ff13321`).
23
+ * spec-014 §2 requires `createMcpServer` to perform "no I/O at construction time beyond wiring
24
+ * handlers", so the DNA role catalogue is loaded inside the `prompts/list` / `prompts/get` handlers,
25
+ * next to the per-request directive resolution spec-004 §3.2 already mandated (REQ-INT-02's "a newly
26
+ * assigned directive appears on the next session start"). Two consequences, both deliberate:
27
+ *
28
+ * - `wingfoil mcp` starts in a git root with no `.wingfoil/dna.yaml` (e.g. a repository that has not
29
+ * run `wingfoil init`) exactly as the Resources channel always has; the missing DNA surfaces as the
30
+ * error of each Prompts request instead of aborting the process start.
31
+ * - spec-004 §3.1's "fixed set derived from DNA at server start" is served as the DNA role set **at
32
+ * request time**: a role added to `dna.yaml` while the server runs is listed on the next
33
+ * `prompts/list`. That tension between spec-014 §2 and spec-004 §3.1 is open for the approver.
34
+ *
35
+ * **Why the low-level handlers, not `McpServer.registerPrompt`.** The high-level API answers an
36
+ * unregistered name with its own `Prompt <name> not found` before any WingFoil code runs, so the BDD's
37
+ * `no prompt for undefined role 'wizard'` cannot be expressed through it (and it would need the role
38
+ * set at registration time). This function therefore owns `prompts/list` and `prompts/get` on
39
+ * `server.server` — the same pattern `./read-only.ts`'s `registerWriteRefusalHandler` uses — and a
40
+ * later `registerPrompt` on the same server fails loudly ("A request handler for prompts/list already
41
+ * exists") instead of being silently shadowed. A requested name that is not `{role}-session`-shaped
42
+ * keeps the SDK-equivalent `Prompt <name> not found` wording: it names no role, so it is not an
43
+ * undefined-role request, and it is answered without reading anything.
44
+ *
45
+ * Call before the server is connected (MCP capabilities cannot be registered after connecting).
46
+ */
47
+ export declare function registerRolePrompts(server: McpServer, options: RegisterRolePromptsOptions): void;
48
+ //# sourceMappingURL=prompt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../../src/mcp/prompt.ts"],"names":[],"mappings":"AA8BA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAQzE,+CAA+C;AAC/C,MAAM,WAAW,0BAA0B;IACzC;;;;OAIG;IACH,QAAQ,CAAC,WAAW,EAAE,MAAM,MAAM,CAAC;CACpC;AAMD;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE1D;AAgGD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,0BAA0B,GAAG,IAAI,CAkBhG"}
@@ -0,0 +1,176 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.roleSessionPromptName = roleSessionPromptName;
4
+ exports.registerRolePrompts = registerRolePrompts;
5
+ /**
6
+ * The role-scoped MCP **Prompts** channel — `{role}-session` prompts that embed the role's assigned
7
+ * directives (task-039-mcp-prompts-role-based-infra, **REQ-INT-02**,
8
+ * `spec-004-mcp-surface-contract` §3). This is the third and last channel type spec-004 §1 names,
9
+ * alongside the Resources channel (`./index.ts`'s `registerReadOnlyResources`, task-011/task-030) and
10
+ * the still-unshipped Tools channel (P5.2.3, v0.4).
11
+ *
12
+ * **Wired into the production server by `task-058-mcp-prompts-role-based` (P5.2.2).** task-039
13
+ * shipped this registrar as infra, exactly like `task-011-mcp-resources-read-only` did for Resources;
14
+ * task-058 adds it to `createMcpServer` (`./server.ts`) per `spec-014-mcp-server-entry-point` §3
15
+ * ("when Prompts ship (P5.2.2, v0.2), it adds their registrar") and implements the undefined-role
16
+ * refusal of `p5-interaction/P5.2.2-mcp-prompts.feature` (`no prompt for undefined role '<role>'`).
17
+ *
18
+ * **Read-only (spec-004 §3.3).** A prompt handler reads `dna.yaml`, `roles.yaml` and the directive
19
+ * files and returns text. There is no code path in this module that writes, and it registers no Tool —
20
+ * so Prompts cannot become the agent write path REQ-SEC-05 reserves for validated Tools
21
+ * (`test/mcp/role-prompts.test.ts` asserts both: files byte-for-byte unchanged after a round trip, and
22
+ * `tools/list` still unroutable on a Prompts-only server).
23
+ *
24
+ * **Nothing is re-implemented here.** Role catalogue via `loadDnaYaml`, bindings via `loadRolesYaml`,
25
+ * directive files via `loadDirectives`, and the role → directive resolution itself via
26
+ * `resolveRoleDirectives` (`src/core/context.ts`, task-037) — the same canonical resolver
27
+ * `assembleExecutionContext` uses, so REQ-INT-02's "100% of R's currently assigned directives" and
28
+ * REQ-STATE-05's "100% of the role's directives and 0 of another role's" stay one guarantee rather than
29
+ * two that can drift apart. The only thing that resolver does not supply is a directive's **body**
30
+ * (`loadDirectives` returns `{path, frontmatter}`), which {@link readDirectiveBody} reads with the
31
+ * `storage` primitives `./memory-resource.ts` already uses for the same reason.
32
+ */
33
+ const path_1 = require("path");
34
+ const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
35
+ const core_1 = require("../core");
36
+ const storage_1 = require("../storage");
37
+ /** spec-004 §3.1's prompt-name suffix: one prompt per role, named `{role}-session`. Module-local —
38
+ * {@link roleSessionPromptName} is the only naming API this channel exposes. */
39
+ const ROLE_PROMPT_NAME_SUFFIX = '-session';
40
+ /**
41
+ * `{role}-session` — spec-004 §3.1's prompt naming convention, as a function so the wire-visible name
42
+ * is derived in exactly one place (the registrar here, and any later consumer such as
43
+ * `task-058-mcp-prompts-role-based`) rather than spelled out per call site.
44
+ */
45
+ function roleSessionPromptName(role) {
46
+ return `${role}${ROLE_PROMPT_NAME_SUFFIX}`;
47
+ }
48
+ /**
49
+ * A `prompts/get` refusal whose JSON-RPC error carries `message` **verbatim** with code `InvalidParams`
50
+ * (-32602, the code the MCP SDK itself uses for an unknown prompt name).
51
+ *
52
+ * Deliberately a plain `Error` with a `code`, not the SDK's `McpError`: `McpError`'s constructor
53
+ * prefixes its own message with `MCP error <code>: `, and the SDK serializes `error.message` as-is, so a
54
+ * client — which adds that prefix again when it rebuilds the error — would read the prefix twice.
55
+ */
56
+ function promptRequestError(message) {
57
+ return Object.assign(new Error(message), { code: types_js_1.ErrorCode.InvalidParams });
58
+ }
59
+ /**
60
+ * The P5.2.2 undefined-role refusal, verbatim from `p5-interaction/P5.2.2-mcp-prompts.feature`
61
+ * (Scenario "Error - requesting a prompt for an undefined role"): `no prompt for undefined role '<role>'`.
62
+ */
63
+ function undefinedRolePromptError(role) {
64
+ return promptRequestError(`no prompt for undefined role '${role}'`);
65
+ }
66
+ /**
67
+ * Read one directive file's body — everything after its YAML frontmatter block, trimmed of
68
+ * surrounding blank lines so the composed prompt is a pure function of the file's content and not of
69
+ * how many trailing newlines its author happened to leave (REQ-SYS-07).
70
+ *
71
+ * `file.path` is root-relative to `.wingfoil/` (`loadDirectives` stores it as `directives/<...>.md`),
72
+ * so it is resolved against `<root>/.wingfoil` here. A file with no frontmatter block cannot reach
73
+ * this function — `loadDirectives` rejects that case with `E_MISSING_FRONTMATTER` before any
74
+ * directive is returned — but `splitFrontmatter` degrades to "whole document is body" anyway.
75
+ */
76
+ function readDirectiveBody(root, file) {
77
+ return (0, storage_1.splitFrontmatter)((0, storage_1.readDocument)((0, path_1.join)(root, storage_1.WINGFOIL_DIR, file.path))).body.trim();
78
+ }
79
+ /**
80
+ * Compose the prompt text for `role` from its already-resolved directives — spec-004 §3.2's shape: a
81
+ * `# Role: {role}` header followed by one `## Directive: {id}` block per directive, each carrying that
82
+ * directive's full body.
83
+ *
84
+ * The heading uses `frontmatter.id`, not `name`: spec-004 §3.2's own example headings read
85
+ * `## Directive: code-quality` / `security-secrets`, which are the `id` values of the real directive
86
+ * files (`code-quality.md` carries `id: code-quality`, `name: "Code Quality"`), and `roles.yaml` binds
87
+ * by id.
88
+ *
89
+ * Block order is `resolveRoleDirectives`' — deduplicated by id and sorted id-ascending per
90
+ * `spec-012-context-loader-relevance-filtering` §5 / REQ-SYS-07 — rather than the "own directives,
91
+ * then globals" grouping spec-004 §3.2's illustrative example happens to print. §3.2 states the
92
+ * resolution itself as a *set* union (`roles.yaml[R].directives` ∪ `global`), which fixes membership,
93
+ * not sequence; an explicit total order is what makes two runs byte-identical.
94
+ */
95
+ function composeRolePromptText(role, directives) {
96
+ const blocks = directives.map(({ id, body }) => `## Directive: ${id}\n${body}`);
97
+ return [`# Role: ${role}`, ...blocks].join('\n\n');
98
+ }
99
+ /**
100
+ * Build the `prompts/get` result for `role`: resolve its directives against the project **now**
101
+ * (spec-004 §3.2 — per request, never cached from server boot) and compose them into one message.
102
+ *
103
+ * `resolveRoleDirectives` also returns operator diagnostics (`warnings`, e.g. dl-029's "no directives
104
+ * assigned to role 'intern'"); they are **not** embedded in the prompt. spec-004 §3.2 defines the
105
+ * prompt payload as role header + directive blocks, and folding a diagnostic into agent-facing
106
+ * instruction text would put an unratified string into the payload — the same reasoning
107
+ * `src/core/context.ts` gives for keeping its own warnings out of the serialized context envelope.
108
+ */
109
+ function buildRolePrompt(root, role) {
110
+ const { directives } = (0, core_1.resolveRoleDirectives)((0, core_1.loadDirectives)(root), (0, core_1.loadRolesYaml)(root), role);
111
+ const text = composeRolePromptText(role, directives.map((file) => ({ id: file.frontmatter.id, body: readDirectiveBody(root, file) })));
112
+ // MCP's `PromptMessage.role` is the two-value enum `"user" | "assistant"` (the SDK's
113
+ // `PromptMessageSchema`), so spec-004 §3.2's illustrative `role: "system"` is not representable on
114
+ // this protocol by any conformant server; `user` is the only wire role that can deliver
115
+ // instructional content. Open as `dl-039-spec-004-prompt-example-corrections`.
116
+ return { messages: [{ role: 'user', content: { type: 'text', text } }] };
117
+ }
118
+ /**
119
+ * The DNA role catalogue as `dna.yaml` declares it **now**, in declaration order. Read per request (see
120
+ * {@link registerRolePrompts}); a missing or invalid `dna.yaml` throws the loader's own error, which the
121
+ * SDK returns to the client as that request's error — the same way `wingfoil://dna` reports it.
122
+ */
123
+ function loadRoleNames(root) {
124
+ return (0, core_1.loadDnaYaml)(root).team.roles.map(({ name }) => name);
125
+ }
126
+ /**
127
+ * Register the role-scoped Prompts channel: one `{role}-session` Prompt per role in `dna.yaml`'s
128
+ * `team.roles` catalogue (spec-004 §3.1), each embedding that role's directives (§3.2), and a refusal
129
+ * for a session prompt naming a role DNA does not declare (P5.2.2's undefined-role scenario).
130
+ *
131
+ * **Nothing is read here — every read happens per request** (task-058 second pass, rejection `ff13321`).
132
+ * spec-014 §2 requires `createMcpServer` to perform "no I/O at construction time beyond wiring
133
+ * handlers", so the DNA role catalogue is loaded inside the `prompts/list` / `prompts/get` handlers,
134
+ * next to the per-request directive resolution spec-004 §3.2 already mandated (REQ-INT-02's "a newly
135
+ * assigned directive appears on the next session start"). Two consequences, both deliberate:
136
+ *
137
+ * - `wingfoil mcp` starts in a git root with no `.wingfoil/dna.yaml` (e.g. a repository that has not
138
+ * run `wingfoil init`) exactly as the Resources channel always has; the missing DNA surfaces as the
139
+ * error of each Prompts request instead of aborting the process start.
140
+ * - spec-004 §3.1's "fixed set derived from DNA at server start" is served as the DNA role set **at
141
+ * request time**: a role added to `dna.yaml` while the server runs is listed on the next
142
+ * `prompts/list`. That tension between spec-014 §2 and spec-004 §3.1 is open for the approver.
143
+ *
144
+ * **Why the low-level handlers, not `McpServer.registerPrompt`.** The high-level API answers an
145
+ * unregistered name with its own `Prompt <name> not found` before any WingFoil code runs, so the BDD's
146
+ * `no prompt for undefined role 'wizard'` cannot be expressed through it (and it would need the role
147
+ * set at registration time). This function therefore owns `prompts/list` and `prompts/get` on
148
+ * `server.server` — the same pattern `./read-only.ts`'s `registerWriteRefusalHandler` uses — and a
149
+ * later `registerPrompt` on the same server fails loudly ("A request handler for prompts/list already
150
+ * exists") instead of being silently shadowed. A requested name that is not `{role}-session`-shaped
151
+ * keeps the SDK-equivalent `Prompt <name> not found` wording: it names no role, so it is not an
152
+ * undefined-role request, and it is answered without reading anything.
153
+ *
154
+ * Call before the server is connected (MCP capabilities cannot be registered after connecting).
155
+ */
156
+ function registerRolePrompts(server, options) {
157
+ server.server.registerCapabilities({ prompts: {} });
158
+ server.server.setRequestHandler(types_js_1.ListPromptsRequestSchema, () => ({
159
+ prompts: loadRoleNames(options.resolveRoot()).map((role) => ({
160
+ name: roleSessionPromptName(role),
161
+ description: `session instructions for the '${role}' role, embedding its assigned directives (read-only)`,
162
+ })),
163
+ }));
164
+ server.server.setRequestHandler(types_js_1.GetPromptRequestSchema, (request) => {
165
+ const { name } = request.params;
166
+ if (!name.endsWith(ROLE_PROMPT_NAME_SUFFIX)) {
167
+ throw promptRequestError(`Prompt ${name} not found`);
168
+ }
169
+ const role = name.slice(0, -ROLE_PROMPT_NAME_SUFFIX.length);
170
+ const root = options.resolveRoot();
171
+ if (!loadRoleNames(root).includes(role))
172
+ throw undefinedRolePromptError(role);
173
+ return buildRolePrompt(root, role);
174
+ });
175
+ }
176
+ //# sourceMappingURL=prompt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt.js","sourceRoot":"","sources":["../../src/mcp/prompt.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ /** spec-004 §2.3's exact, verbatim write-refusal string. */
3
+ export declare const WRITE_REFUSAL_MESSAGE = "resources are read-only";
4
+ /**
5
+ * The `_meta` key WingFoil's own bespoke Resource handlers treat as "this `resources/read` call is
6
+ * carrying a write intent/payload" — not an MCP-defined field (see module doc). Any truthy value
7
+ * under this key refuses the read identically to an unsupported `resources/write` call.
8
+ */
9
+ export declare const WRITE_INTENT_META_KEY = "wingfoil/write-intent";
10
+ /**
11
+ * Refuse a read carrying a write intent (see module doc, case 2). Called first, before any other
12
+ * work, by every bespoke Resource handler this task registers — so the refusal is unconditional and
13
+ * precedes any read/scan/file-access, never a check bolted on after a read already started.
14
+ */
15
+ export declare function refuseIfWriteIntent(meta: Record<string, unknown> | undefined): void;
16
+ /** spec-004 §2.2's "resource not found" shape — distinct wording from the write refusal above, per
17
+ * the BDD scenario (`P5.2.1-mcp-resources.feature`) `resource not found: {identifier}` format. */
18
+ export declare function resourceNotFoundError(identifier: string): Error;
19
+ /**
20
+ * The `ReadResourceResult` shape every JSON-bodied Resource in `memory-resource.ts` (collection
21
+ * listing), `dna-resource.ts`, and `workflow-resource.ts` returns — one `contents[]` entry,
22
+ * `mimeType: 'application/json'`, `value` serialized as its `text`. Factored here purely to avoid
23
+ * re-deriving the same three-line envelope at each of those five call sites; `memory-resource.ts`'s
24
+ * single-document read builds its own `text/markdown` + `metadata` result directly, since that shape
25
+ * differs (spec-004 §2.2).
26
+ */
27
+ export declare function jsonResourceResult(uri: URL, value: unknown): {
28
+ contents: [{
29
+ uri: string;
30
+ mimeType: string;
31
+ text: string;
32
+ }];
33
+ };
34
+ /**
35
+ * Install the `resources/write` refusal (see module doc, case 1). MCP's own protocol does not define
36
+ * `resources/write` at all — no client capability or built-in handler exists for it — so this method
37
+ * name has no default routing on the server; without this handler such a call would fail with a
38
+ * generic JSON-RPC "Method not found" rather than spec-004 §2.3's specific refusal text. There is no
39
+ * write path here to gate: the handler always throws, unconditionally.
40
+ */
41
+ export declare function registerWriteRefusalHandler(server: McpServer): void;
42
+ //# sourceMappingURL=read-only.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read-only.d.ts","sourceRoot":"","sources":["../../src/mcp/read-only.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,4DAA4D;AAC5D,eAAO,MAAM,qBAAqB,4BAA4B,CAAC;AAE/D;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,0BAA0B,CAAC;AAE7D;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAAG,IAAI,CAInF;AAED;kGACkG;AAClG,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,MAAM,GAAG,KAAK,CAE/D;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,OAAO,GAAG;IAAE,QAAQ,EAAE,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,CAU5H;AAUD;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAInE"}
@@ -0,0 +1,93 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WRITE_INTENT_META_KEY = exports.WRITE_REFUSAL_MESSAGE = void 0;
4
+ exports.refuseIfWriteIntent = refuseIfWriteIntent;
5
+ exports.resourceNotFoundError = resourceNotFoundError;
6
+ exports.jsonResourceResult = jsonResourceResult;
7
+ exports.registerWriteRefusalHandler = registerWriteRefusalHandler;
8
+ /**
9
+ * Shared conventions for every bespoke Resource this task registers (`memory-resource`,
10
+ * `dna-resource`, `workflow-resource`): the read-only-channel guarantee — spec-004-mcp-surface-contract
11
+ * §2.3's verbatim write-refusal string, plus the standard MCP "resource not found" shape (§2.2) — and
12
+ * the common JSON-bodied result envelope, factored once so every module refuses/reports/shapes
13
+ * identically rather than re-deriving the same strings/shape per handler
14
+ * (task-011-mcp-resources-read-only, REQ-INT-01 / REQ-SEC-05).
15
+ *
16
+ * Two distinct write-attempt shapes must be refused (spec-004 §2.3):
17
+ *
18
+ * 1. An unsupported `resources/write` JSON-RPC call — {@link registerWriteRefusalHandler} installs a
19
+ * handler for that literal method name (which the MCP protocol itself does not define at all — see
20
+ * the SDK's `types.d.ts`: there is no `ResourceWrite*` schema) that unconditionally refuses. This
21
+ * is structural, not a gated check: the handler has no branch that could ever succeed.
22
+ * 2. A `resources/read` request "carrying a write intent/payload". The real wire schema
23
+ * (`ReadResourceRequestSchema`) strips any unknown key placed directly on `params` before a
24
+ * handler ever sees it (Zod `$strip` mode) — the one part of that schema that is *not* stripped is
25
+ * the nested `_meta` sub-object, which the SDK itself models as passthrough (`$loose`) for
26
+ * out-of-band caller metadata. {@link WRITE_INTENT_META_KEY} is WingFoil's own convention (MCP
27
+ * defines no write-intent field) for exercising that one channel a misbehaving/malicious client
28
+ * could still smuggle a write payload through; {@link refuseIfWriteIntent} is called by every
29
+ * bespoke read handler before it does anything else.
30
+ */
31
+ const zod_1 = require("zod");
32
+ /** spec-004 §2.3's exact, verbatim write-refusal string. */
33
+ exports.WRITE_REFUSAL_MESSAGE = 'resources are read-only';
34
+ /**
35
+ * The `_meta` key WingFoil's own bespoke Resource handlers treat as "this `resources/read` call is
36
+ * carrying a write intent/payload" — not an MCP-defined field (see module doc). Any truthy value
37
+ * under this key refuses the read identically to an unsupported `resources/write` call.
38
+ */
39
+ exports.WRITE_INTENT_META_KEY = 'wingfoil/write-intent';
40
+ /**
41
+ * Refuse a read carrying a write intent (see module doc, case 2). Called first, before any other
42
+ * work, by every bespoke Resource handler this task registers — so the refusal is unconditional and
43
+ * precedes any read/scan/file-access, never a check bolted on after a read already started.
44
+ */
45
+ function refuseIfWriteIntent(meta) {
46
+ if (meta && exports.WRITE_INTENT_META_KEY in meta) {
47
+ throw new Error(exports.WRITE_REFUSAL_MESSAGE);
48
+ }
49
+ }
50
+ /** spec-004 §2.2's "resource not found" shape — distinct wording from the write refusal above, per
51
+ * the BDD scenario (`P5.2.1-mcp-resources.feature`) `resource not found: {identifier}` format. */
52
+ function resourceNotFoundError(identifier) {
53
+ return new Error(`resource not found: ${identifier}`);
54
+ }
55
+ /**
56
+ * The `ReadResourceResult` shape every JSON-bodied Resource in `memory-resource.ts` (collection
57
+ * listing), `dna-resource.ts`, and `workflow-resource.ts` returns — one `contents[]` entry,
58
+ * `mimeType: 'application/json'`, `value` serialized as its `text`. Factored here purely to avoid
59
+ * re-deriving the same three-line envelope at each of those five call sites; `memory-resource.ts`'s
60
+ * single-document read builds its own `text/markdown` + `metadata` result directly, since that shape
61
+ * differs (spec-004 §2.2).
62
+ */
63
+ function jsonResourceResult(uri, value) {
64
+ return {
65
+ contents: [
66
+ {
67
+ uri: uri.toString(),
68
+ mimeType: 'application/json',
69
+ text: JSON.stringify(value),
70
+ },
71
+ ],
72
+ };
73
+ }
74
+ /** The raw JSON-RPC shape of an (unsupported) `resources/write` request — just enough to extract the
75
+ * method literal `setRequestHandler` needs; `params` is never inspected, since every call is refused
76
+ * unconditionally regardless of its payload. */
77
+ const ResourcesWriteRequestSchema = zod_1.z.object({
78
+ method: zod_1.z.literal('resources/write'),
79
+ params: zod_1.z.record(zod_1.z.string(), zod_1.z.unknown()).optional(),
80
+ });
81
+ /**
82
+ * Install the `resources/write` refusal (see module doc, case 1). MCP's own protocol does not define
83
+ * `resources/write` at all — no client capability or built-in handler exists for it — so this method
84
+ * name has no default routing on the server; without this handler such a call would fail with a
85
+ * generic JSON-RPC "Method not found" rather than spec-004 §2.3's specific refusal text. There is no
86
+ * write path here to gate: the handler always throws, unconditionally.
87
+ */
88
+ function registerWriteRefusalHandler(server) {
89
+ server.server.setRequestHandler(ResourcesWriteRequestSchema, async () => {
90
+ throw new Error(exports.WRITE_REFUSAL_MESSAGE);
91
+ });
92
+ }
93
+ //# sourceMappingURL=read-only.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read-only.js","sourceRoot":"","sources":["../../src/mcp/read-only.ts"],"names":[],"mappings":";;;AA0CA,kDAIC;AAID,sDAEC;AAUD,gDAUC;AAiBD,kEAIC;AA7FD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,6BAAwB;AAIxB,4DAA4D;AAC/C,QAAA,qBAAqB,GAAG,yBAAyB,CAAC;AAE/D;;;;GAIG;AACU,QAAA,qBAAqB,GAAG,uBAAuB,CAAC;AAE7D;;;;GAIG;AACH,SAAgB,mBAAmB,CAAC,IAAyC;IAC3E,IAAI,IAAI,IAAI,6BAAqB,IAAI,IAAI,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CAAC,6BAAqB,CAAC,CAAC;IACzC,CAAC;AACH,CAAC;AAED;kGACkG;AAClG,SAAgB,qBAAqB,CAAC,UAAkB;IACtD,OAAO,IAAI,KAAK,CAAC,uBAAuB,UAAU,EAAE,CAAC,CAAC;AACxD,CAAC;AAED;;;;;;;GAOG;AACH,SAAgB,kBAAkB,CAAC,GAAQ,EAAE,KAAc;IACzD,OAAO;QACL,QAAQ,EAAE;YACR;gBACE,GAAG,EAAE,GAAG,CAAC,QAAQ,EAAE;gBACnB,QAAQ,EAAE,kBAAkB;gBAC5B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;aAC5B;SACF;KACF,CAAC;AACJ,CAAC;AAED;;gDAEgD;AAChD,MAAM,2BAA2B,GAAG,OAAC,CAAC,MAAM,CAAC;IAC3C,MAAM,EAAE,OAAC,CAAC,OAAO,CAAC,iBAAiB,CAAC;IACpC,MAAM,EAAE,OAAC,CAAC,MAAM,CAAC,OAAC,CAAC,MAAM,EAAE,EAAE,OAAC,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,EAAE;CACrD,CAAC,CAAC;AAEH;;;;;;GAMG;AACH,SAAgB,2BAA2B,CAAC,MAAiB;IAC3D,MAAM,CAAC,MAAM,CAAC,iBAAiB,CAAC,2BAA2B,EAAE,KAAK,IAAI,EAAE;QACtE,MAAM,IAAI,KAAK,CAAC,6BAAqB,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;AACL,CAAC"}