productfoo 0.0.0-stage → 1.0.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 (498) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +338 -2
  3. package/bin/foo +3 -0
  4. package/bin/foo.mjs +42 -0
  5. package/commands/bug.md +31 -0
  6. package/commands/discovery.md +28 -0
  7. package/commands/ideate.md +27 -0
  8. package/commands/init.md +28 -0
  9. package/commands/pitch.md +27 -0
  10. package/commands/preview.md +25 -0
  11. package/commands/research.md +31 -0
  12. package/commands/roast.md +27 -0
  13. package/commands/spec.md +30 -0
  14. package/config/pricing.yaml +198 -0
  15. package/config/routing-policy.yaml +171 -0
  16. package/dist-public/src/activeModel.d.ts +83 -0
  17. package/dist-public/src/activeModel.js +331 -0
  18. package/dist-public/src/agentAdapters.d.ts +122 -0
  19. package/dist-public/src/agentAdapters.js +178 -0
  20. package/dist-public/src/agentState.d.ts +43 -0
  21. package/dist-public/src/agentState.js +177 -0
  22. package/dist-public/src/bugCapsule.d.ts +94 -0
  23. package/dist-public/src/bugCapsule.js +227 -0
  24. package/dist-public/src/bugCapture.d.ts +26 -0
  25. package/dist-public/src/bugCapture.js +251 -0
  26. package/dist-public/src/bugOwnerLog.d.ts +93 -0
  27. package/dist-public/src/bugOwnerLog.js +304 -0
  28. package/dist-public/src/bugReportStore.d.ts +48 -0
  29. package/dist-public/src/bugReportStore.js +860 -0
  30. package/dist-public/src/bugSpecContext.d.ts +7 -0
  31. package/dist-public/src/bugSpecContext.js +129 -0
  32. package/dist-public/src/channelFreshness.d.ts +25 -0
  33. package/dist-public/src/channelFreshness.js +194 -0
  34. package/dist-public/src/cli.d.ts +30 -0
  35. package/dist-public/src/cli.js +1667 -0
  36. package/dist-public/src/cliArgs.d.ts +7 -0
  37. package/dist-public/src/cliArgs.js +44 -0
  38. package/dist-public/src/codeCatalog.d.ts +41 -0
  39. package/dist-public/src/codeCatalog.js +197 -0
  40. package/dist-public/src/commandContract.d.ts +84 -0
  41. package/dist-public/src/commandContract.js +390 -0
  42. package/dist-public/src/commandUsage.d.ts +3 -0
  43. package/dist-public/src/commandUsage.js +30 -0
  44. package/dist-public/src/commands/agent.d.ts +60 -0
  45. package/dist-public/src/commands/agent.js +1353 -0
  46. package/dist-public/src/commands/asp.d.ts +8 -0
  47. package/dist-public/src/commands/asp.js +669 -0
  48. package/dist-public/src/commands/evalCmd.d.ts +4 -0
  49. package/dist-public/src/commands/evalCmd.js +405 -0
  50. package/dist-public/src/commands/login.d.ts +25 -0
  51. package/dist-public/src/commands/login.js +94 -0
  52. package/dist-public/src/commands/loop.d.ts +16 -0
  53. package/dist-public/src/commands/loop.js +619 -0
  54. package/dist-public/src/commands/reconcile.d.ts +41 -0
  55. package/dist-public/src/commands/reconcile.js +292 -0
  56. package/dist-public/src/commands/runtime.d.ts +1 -0
  57. package/dist-public/src/commands/runtime.js +36 -0
  58. package/dist-public/src/commands/scanRedact.d.ts +8 -0
  59. package/dist-public/src/commands/scanRedact.js +266 -0
  60. package/dist-public/src/commands/setup.d.ts +28 -0
  61. package/dist-public/src/commands/setup.js +398 -0
  62. package/dist-public/src/commands/shared.d.ts +17 -0
  63. package/dist-public/src/commands/shared.js +147 -0
  64. package/dist-public/src/commands/source.d.ts +1 -0
  65. package/dist-public/src/commands/source.js +134 -0
  66. package/dist-public/src/commands/specCmd.d.ts +24 -0
  67. package/dist-public/src/commands/specCmd.js +794 -0
  68. package/dist-public/src/commands/update.d.ts +61 -0
  69. package/dist-public/src/commands/update.js +244 -0
  70. package/dist-public/src/comprehensionSignal.d.ts +20 -0
  71. package/dist-public/src/comprehensionSignal.js +166 -0
  72. package/dist-public/src/conductor/diversity.d.ts +48 -0
  73. package/dist-public/src/conductor/diversity.js +423 -0
  74. package/dist-public/src/conductor/engine.d.ts +7 -0
  75. package/dist-public/src/conductor/engine.js +295 -0
  76. package/dist-public/src/conductor/families/ideate.d.ts +2 -0
  77. package/dist-public/src/conductor/families/ideate.js +255 -0
  78. package/dist-public/src/conductor/families/interview.d.ts +2 -0
  79. package/dist-public/src/conductor/families/interview.js +39 -0
  80. package/dist-public/src/conductor/families/specSwarm.d.ts +2 -0
  81. package/dist-public/src/conductor/families/specSwarm.js +146 -0
  82. package/dist-public/src/conductor/familyDelivery.d.ts +6 -0
  83. package/dist-public/src/conductor/familyDelivery.js +37 -0
  84. package/dist-public/src/conductor/familyPackArtifact.d.ts +4 -0
  85. package/dist-public/src/conductor/familyPackArtifact.js +260 -0
  86. package/dist-public/src/conductor/ideateDecision.d.ts +6 -0
  87. package/dist-public/src/conductor/ideateDecision.js +237 -0
  88. package/dist-public/src/conductor/pack.d.ts +26 -0
  89. package/dist-public/src/conductor/pack.js +75 -0
  90. package/dist-public/src/conductor/types.d.ts +111 -0
  91. package/dist-public/src/conductor/types.js +7 -0
  92. package/dist-public/src/configPath.d.ts +2 -0
  93. package/dist-public/src/configPath.js +7 -0
  94. package/dist-public/src/discoveryArtifacts.d.ts +54 -0
  95. package/dist-public/src/discoveryArtifacts.js +467 -0
  96. package/dist-public/src/discoveryCommand.d.ts +127 -0
  97. package/dist-public/src/discoveryCommand.js +2148 -0
  98. package/dist-public/src/discoveryConnections.d.ts +339 -0
  99. package/dist-public/src/discoveryConnections.js +613 -0
  100. package/dist-public/src/discoveryDocs.d.ts +129 -0
  101. package/dist-public/src/discoveryDocs.js +577 -0
  102. package/dist-public/src/discoveryEvidence.d.ts +59 -0
  103. package/dist-public/src/discoveryEvidence.js +198 -0
  104. package/dist-public/src/discoveryFireflies.d.ts +25 -0
  105. package/dist-public/src/discoveryFireflies.js +551 -0
  106. package/dist-public/src/discoveryGmail.d.ts +12 -0
  107. package/dist-public/src/discoveryGmail.js +466 -0
  108. package/dist-public/src/discoveryGong.d.ts +12 -0
  109. package/dist-public/src/discoveryGong.js +491 -0
  110. package/dist-public/src/discoveryLearningRouting.d.ts +90 -0
  111. package/dist-public/src/discoveryLearningRouting.js +405 -0
  112. package/dist-public/src/discoveryMatching.d.ts +26 -0
  113. package/dist-public/src/discoveryMatching.js +73 -0
  114. package/dist-public/src/discoveryOutlook.d.ts +12 -0
  115. package/dist-public/src/discoveryOutlook.js +492 -0
  116. package/dist-public/src/discoveryProcess.d.ts +221 -0
  117. package/dist-public/src/discoveryProcess.js +703 -0
  118. package/dist-public/src/discoveryProof.d.ts +143 -0
  119. package/dist-public/src/discoveryProof.js +529 -0
  120. package/dist-public/src/discoveryProviders.d.ts +152 -0
  121. package/dist-public/src/discoveryProviders.js +756 -0
  122. package/dist-public/src/discoveryReadiness.d.ts +219 -0
  123. package/dist-public/src/discoveryReadiness.js +672 -0
  124. package/dist-public/src/discoveryReconcile.d.ts +57 -0
  125. package/dist-public/src/discoveryReconcile.js +424 -0
  126. package/dist-public/src/discoverySlack.d.ts +12 -0
  127. package/dist-public/src/discoverySlack.js +452 -0
  128. package/dist-public/src/discoverySources.d.ts +56 -0
  129. package/dist-public/src/discoverySources.js +322 -0
  130. package/dist-public/src/discoverySync.d.ts +52 -0
  131. package/dist-public/src/discoverySync.js +151 -0
  132. package/dist-public/src/discoverySynthesis.d.ts +57 -0
  133. package/dist-public/src/discoverySynthesis.js +215 -0
  134. package/dist-public/src/discoveryTeams.d.ts +12 -0
  135. package/dist-public/src/discoveryTeams.js +516 -0
  136. package/dist-public/src/discoveryZoom.d.ts +12 -0
  137. package/dist-public/src/discoveryZoom.js +523 -0
  138. package/dist-public/src/elicitationSurface.d.ts +13 -0
  139. package/dist-public/src/elicitationSurface.js +77 -0
  140. package/dist-public/src/errorReport.d.ts +99 -0
  141. package/dist-public/src/errorReport.js +443 -0
  142. package/dist-public/src/errorTaxonomy.d.ts +84 -0
  143. package/dist-public/src/errorTaxonomy.js +189 -0
  144. package/dist-public/src/evalCalibration.d.ts +82 -0
  145. package/dist-public/src/evalCalibration.js +169 -0
  146. package/dist-public/src/evalChecks.d.ts +21 -0
  147. package/dist-public/src/evalChecks.js +295 -0
  148. package/dist-public/src/evalCompile.d.ts +56 -0
  149. package/dist-public/src/evalCompile.js +58 -0
  150. package/dist-public/src/evalImprove.d.ts +60 -0
  151. package/dist-public/src/evalImprove.js +175 -0
  152. package/dist-public/src/evalJudge.d.ts +47 -0
  153. package/dist-public/src/evalJudge.js +143 -0
  154. package/dist-public/src/evalLabels.d.ts +100 -0
  155. package/dist-public/src/evalLabels.js +287 -0
  156. package/dist-public/src/evalRecord.d.ts +68 -0
  157. package/dist-public/src/evalRecord.js +165 -0
  158. package/dist-public/src/evalRoast.d.ts +88 -0
  159. package/dist-public/src/evalRoast.js +249 -0
  160. package/dist-public/src/evidenceIntake.d.ts +66 -0
  161. package/dist-public/src/evidenceIntake.js +356 -0
  162. package/dist-public/src/feedback.d.ts +78 -0
  163. package/dist-public/src/feedback.js +294 -0
  164. package/dist-public/src/firefliesClient.d.ts +106 -0
  165. package/dist-public/src/firefliesClient.js +258 -0
  166. package/dist-public/src/firstMoveTensions.d.ts +10 -0
  167. package/dist-public/src/firstMoveTensions.js +93 -0
  168. package/dist-public/src/gitRun.d.ts +21 -0
  169. package/dist-public/src/gitRun.js +50 -0
  170. package/dist-public/src/githubReconcile.d.ts +94 -0
  171. package/dist-public/src/githubReconcile.js +205 -0
  172. package/dist-public/src/gmailNango.d.ts +131 -0
  173. package/dist-public/src/gmailNango.js +329 -0
  174. package/dist-public/src/gongNango.d.ts +118 -0
  175. package/dist-public/src/gongNango.js +308 -0
  176. package/dist-public/src/grammarGate.d.ts +13 -0
  177. package/dist-public/src/grammarGate.js +72 -0
  178. package/dist-public/src/harnessGates.d.ts +65 -0
  179. package/dist-public/src/harnessGates.js +168 -0
  180. package/dist-public/src/humanSurfaceEval.d.ts +19 -0
  181. package/dist-public/src/humanSurfaceEval.js +156 -0
  182. package/dist-public/src/ideate.d.ts +43 -0
  183. package/dist-public/src/ideate.js +255 -0
  184. package/dist-public/src/ideateContext.d.ts +11 -0
  185. package/dist-public/src/ideateContext.js +83 -0
  186. package/dist-public/src/index.d.ts +2 -0
  187. package/dist-public/src/index.js +4 -0
  188. package/dist-public/src/initCommand.d.ts +25 -0
  189. package/dist-public/src/initCommand.js +558 -0
  190. package/dist-public/src/interviewGate.d.ts +25 -0
  191. package/dist-public/src/interviewGate.js +126 -0
  192. package/dist-public/src/jsonFile.d.ts +2 -0
  193. package/dist-public/src/jsonFile.js +22 -0
  194. package/dist-public/src/loopBudget.d.ts +182 -0
  195. package/dist-public/src/loopBudget.js +494 -0
  196. package/dist-public/src/loopContracts.d.ts +35 -0
  197. package/dist-public/src/loopContracts.js +364 -0
  198. package/dist-public/src/machineState.d.ts +1 -0
  199. package/dist-public/src/machineState.js +9 -0
  200. package/dist-public/src/notionNango.d.ts +93 -0
  201. package/dist-public/src/notionNango.js +279 -0
  202. package/dist-public/src/orchestrationResult.d.ts +11 -0
  203. package/dist-public/src/orchestrationResult.js +73 -0
  204. package/dist-public/src/outlookNango.d.ts +124 -0
  205. package/dist-public/src/outlookNango.js +327 -0
  206. package/dist-public/src/packetCorrections.d.ts +40 -0
  207. package/dist-public/src/packetCorrections.js +172 -0
  208. package/dist-public/src/packetGlossary.d.ts +6 -0
  209. package/dist-public/src/packetGlossary.js +42 -0
  210. package/dist-public/src/packetIndex.d.ts +54 -0
  211. package/dist-public/src/packetIndex.js +744 -0
  212. package/dist-public/src/packetIndexEntry.d.ts +3 -0
  213. package/dist-public/src/packetIndexEntry.js +128 -0
  214. package/dist-public/src/packetIndexServe.d.ts +13 -0
  215. package/dist-public/src/packetIndexServe.js +113 -0
  216. package/dist-public/src/packetIndexWorker.d.ts +7 -0
  217. package/dist-public/src/packetIndexWorker.js +45 -0
  218. package/dist-public/src/packetLifecycle.d.ts +30 -0
  219. package/dist-public/src/packetLifecycle.js +127 -0
  220. package/dist-public/src/packetReconcile.d.ts +73 -0
  221. package/dist-public/src/packetReconcile.js +386 -0
  222. package/dist-public/src/packetStatus.d.ts +125 -0
  223. package/dist-public/src/packetStatus.js +770 -0
  224. package/dist-public/src/packetValidation.d.ts +17 -0
  225. package/dist-public/src/packetValidation.js +333 -0
  226. package/dist-public/src/packetVerify.d.ts +73 -0
  227. package/dist-public/src/packetVerify.js +303 -0
  228. package/dist-public/src/packetWrite.d.ts +52 -0
  229. package/dist-public/src/packetWrite.js +448 -0
  230. package/dist-public/src/pitch.d.ts +38 -0
  231. package/dist-public/src/pitch.js +154 -0
  232. package/dist-public/src/processMemo.d.ts +8 -0
  233. package/dist-public/src/processMemo.js +23 -0
  234. package/dist-public/src/productDetect.d.ts +30 -0
  235. package/dist-public/src/productDetect.js +376 -0
  236. package/dist-public/src/profile.d.ts +62 -0
  237. package/dist-public/src/profile.js +334 -0
  238. package/dist-public/src/questionModel.d.ts +46 -0
  239. package/dist-public/src/questionModel.js +74 -0
  240. package/dist-public/src/questionText.d.ts +7 -0
  241. package/dist-public/src/questionText.js +38 -0
  242. package/dist-public/src/redactConfig.d.ts +2 -0
  243. package/dist-public/src/redactConfig.js +11 -0
  244. package/dist-public/src/redactEngine.d.ts +59 -0
  245. package/dist-public/src/redactEngine.js +509 -0
  246. package/dist-public/src/redactGate.d.ts +63 -0
  247. package/dist-public/src/redactGate.js +209 -0
  248. package/dist-public/src/repoRead.d.ts +29 -0
  249. package/dist-public/src/repoRead.js +160 -0
  250. package/dist-public/src/research.d.ts +242 -0
  251. package/dist-public/src/research.js +1314 -0
  252. package/dist-public/src/researchCompletion.d.ts +34 -0
  253. package/dist-public/src/researchCompletion.js +123 -0
  254. package/dist-public/src/researchExecution.d.ts +47 -0
  255. package/dist-public/src/researchExecution.js +309 -0
  256. package/dist-public/src/researchFormat.d.ts +21 -0
  257. package/dist-public/src/researchFormat.js +77 -0
  258. package/dist-public/src/researchGate.d.ts +86 -0
  259. package/dist-public/src/researchGate.js +1036 -0
  260. package/dist-public/src/researchReceipt.d.ts +76 -0
  261. package/dist-public/src/researchReceipt.js +148 -0
  262. package/dist-public/src/researchRender.d.ts +2 -0
  263. package/dist-public/src/researchRender.js +267 -0
  264. package/dist-public/src/researchSigningKey.d.ts +19 -0
  265. package/dist-public/src/researchSigningKey.js +95 -0
  266. package/dist-public/src/riskClassify.d.ts +42 -0
  267. package/dist-public/src/riskClassify.js +149 -0
  268. package/dist-public/src/routines.d.ts +42 -0
  269. package/dist-public/src/routines.js +269 -0
  270. package/dist-public/src/routingPolicy.d.ts +172 -0
  271. package/dist-public/src/routingPolicy.js +646 -0
  272. package/dist-public/src/secretInput.d.ts +8 -0
  273. package/dist-public/src/secretInput.js +89 -0
  274. package/dist-public/src/selfCheck.d.ts +7 -0
  275. package/dist-public/src/selfCheck.js +473 -0
  276. package/dist-public/src/selfCheckCache.d.ts +29 -0
  277. package/dist-public/src/selfCheckCache.js +147 -0
  278. package/dist-public/src/severityClass.d.ts +15 -0
  279. package/dist-public/src/severityClass.js +22 -0
  280. package/dist-public/src/skillClientPolicy.d.ts +8 -0
  281. package/dist-public/src/skillClientPolicy.js +16 -0
  282. package/dist-public/src/skillLocal.d.ts +98 -0
  283. package/dist-public/src/skillLocal.js +463 -0
  284. package/dist-public/src/skillTreeDigest.d.ts +9 -0
  285. package/dist-public/src/skillTreeDigest.js +64 -0
  286. package/dist-public/src/slackNango.d.ts +62 -0
  287. package/dist-public/src/slackNango.js +208 -0
  288. package/dist-public/src/social/arxiv.d.ts +19 -0
  289. package/dist-public/src/social/arxiv.js +96 -0
  290. package/dist-public/src/social/github.d.ts +2 -0
  291. package/dist-public/src/social/github.js +78 -0
  292. package/dist-public/src/social/hackernews.d.ts +2 -0
  293. package/dist-public/src/social/hackernews.js +67 -0
  294. package/dist-public/src/social/index.d.ts +10 -0
  295. package/dist-public/src/social/index.js +79 -0
  296. package/dist-public/src/social/reddit.d.ts +2 -0
  297. package/dist-public/src/social/reddit.js +125 -0
  298. package/dist-public/src/social/types.d.ts +73 -0
  299. package/dist-public/src/social/types.js +61 -0
  300. package/dist-public/src/social/xml.d.ts +10 -0
  301. package/dist-public/src/social/xml.js +49 -0
  302. package/dist-public/src/social/youtube.d.ts +7 -0
  303. package/dist-public/src/social/youtube.js +217 -0
  304. package/dist-public/src/sourceIngress.d.ts +488 -0
  305. package/dist-public/src/sourceIngress.js +1651 -0
  306. package/dist-public/src/specAfter.d.ts +187 -0
  307. package/dist-public/src/specAfter.js +814 -0
  308. package/dist-public/src/specBudget.d.ts +124 -0
  309. package/dist-public/src/specBudget.js +424 -0
  310. package/dist-public/src/specDecisionSignals.d.ts +38 -0
  311. package/dist-public/src/specDecisionSignals.js +121 -0
  312. package/dist-public/src/specLinkedCommits.d.ts +7 -0
  313. package/dist-public/src/specLinkedCommits.js +107 -0
  314. package/dist-public/src/specSections.d.ts +105 -0
  315. package/dist-public/src/specSections.js +718 -0
  316. package/dist-public/src/statusGlyphs.d.ts +18 -0
  317. package/dist-public/src/statusGlyphs.js +75 -0
  318. package/dist-public/src/swarmCommand.d.ts +10 -0
  319. package/dist-public/src/swarmCommand.js +96 -0
  320. package/dist-public/src/teamsNango.d.ts +114 -0
  321. package/dist-public/src/teamsNango.js +301 -0
  322. package/dist-public/src/tokenStore.d.ts +10 -0
  323. package/dist-public/src/tokenStore.js +77 -0
  324. package/dist-public/src/trustEnvelope.d.ts +78 -0
  325. package/dist-public/src/trustEnvelope.js +392 -0
  326. package/dist-public/src/untrustedText.d.ts +6 -0
  327. package/dist-public/src/untrustedText.js +20 -0
  328. package/dist-public/src/updateNotice.d.ts +41 -0
  329. package/dist-public/src/updateNotice.js +290 -0
  330. package/dist-public/src/vendorYaml.d.ts +1 -0
  331. package/dist-public/src/vendorYaml.js +7374 -0
  332. package/dist-public/src/workflowRunActuals.d.ts +67 -0
  333. package/dist-public/src/workflowRunActuals.js +184 -0
  334. package/dist-public/src/zendeskDiscovery.d.ts +12 -0
  335. package/dist-public/src/zendeskDiscovery.js +513 -0
  336. package/dist-public/src/zendeskNango.d.ts +131 -0
  337. package/dist-public/src/zendeskNango.js +344 -0
  338. package/dist-public/src/zoomNango.d.ts +106 -0
  339. package/dist-public/src/zoomNango.js +351 -0
  340. package/docs/CHANGELOG.md +32 -0
  341. package/docs/THIRD_PARTY_NOTICES.md +36 -0
  342. package/package.json +71 -4
  343. package/schemas/bug-capsule-receipt.schema.json +54 -0
  344. package/schemas/bug-capsule.schema.json +189 -0
  345. package/schemas/discovery-evidence-envelope.schema.json +79 -0
  346. package/schemas/discovery-processing-receipt.schema.json +71 -0
  347. package/schemas/discovery-service-contract.schema.json +189 -0
  348. package/skills/AGENTS.md +32 -0
  349. package/skills/README.md +287 -0
  350. package/skills/bug/SKILL.md +49 -0
  351. package/skills/build-preview-spec/SKILL.md +103 -0
  352. package/skills/capture-external-artifact/SKILL.md +23 -0
  353. package/skills/capture-external-artifact/agents/openai.yaml +4 -0
  354. package/skills/capture-external-artifact/references/extractor-libraries.md +27 -0
  355. package/skills/check-spec-health/SKILL.md +45 -0
  356. package/skills/check-spec-health/agents/openai.yaml +4 -0
  357. package/skills/competitive-positioning/SKILL.md +86 -0
  358. package/skills/competitive-positioning/agents/openai.yaml +4 -0
  359. package/skills/cpo-lens/SKILL.md +398 -0
  360. package/skills/cpo-lens/agents/openai.yaml +4 -0
  361. package/skills/create-prd/SKILL.md +26 -0
  362. package/skills/create-prd/agents/openai.yaml +4 -0
  363. package/skills/customer-discovery/SKILL.md +192 -0
  364. package/skills/design-system/SKILL.md +49 -0
  365. package/skills/design-system/agents/openai.yaml +4 -0
  366. package/skills/discussion-guide/SKILL.md +75 -0
  367. package/skills/discussion-guide/agents/openai.yaml +4 -0
  368. package/skills/firecrawl-research-papers/SKILL.md +96 -0
  369. package/skills/firecrawl-research-papers/agents/openai.yaml +4 -0
  370. package/skills/foo-roast/SKILL.md +325 -0
  371. package/skills/generate-gtm-brief/SKILL.md +41 -0
  372. package/skills/generate-gtm-brief/agents/openai.yaml +4 -0
  373. package/skills/generate-gtm-brief/references/gtm-brief-template.md +56 -0
  374. package/skills/gong-quotes/SKILL.md +43 -0
  375. package/skills/gong-quotes/agents/openai.yaml +4 -0
  376. package/skills/grill-me/SKILL.md +27 -0
  377. package/skills/grill-me/agents/openai.yaml +4 -0
  378. package/skills/ideate/SKILL.md +180 -0
  379. package/skills/ideate/references/family-packs.md +5 -0
  380. package/skills/initiative-tracker/SKILL.md +23 -0
  381. package/skills/initiative-tracker/agents/openai.yaml +4 -0
  382. package/skills/interop-review/SKILL.md +25 -0
  383. package/skills/interop-review/agents/openai.yaml +4 -0
  384. package/skills/interview-me/SKILL.md +404 -0
  385. package/skills/interview-me/agents/openai.yaml +4 -0
  386. package/skills/loop-library-audit/SKILL.md +123 -0
  387. package/skills/pitch/SKILL.md +110 -0
  388. package/skills/pitch/references/opportunity-assessment.md +136 -0
  389. package/skills/pitch/references/prfaq-template.md +54 -0
  390. package/skills/pmm-release-briefing/SKILL.md +27 -0
  391. package/skills/pmm-release-briefing/agents/openai.yaml +4 -0
  392. package/skills/pmm-release-briefing/references/variant-generalized.md +16 -0
  393. package/skills/positioning-messaging/SKILL.md +70 -0
  394. package/skills/positioning-messaging/agents/openai.yaml +4 -0
  395. package/skills/positioning-messaging/references/guest-insights.md +1400 -0
  396. package/skills/preview-swarm/SKILL.md +418 -0
  397. package/skills/preview-swarm/agents/openai.yaml +4 -0
  398. package/skills/preview-swarm/references/html-effectiveness-build-previews.md +168 -0
  399. package/skills/product-copywriting/SKILL.md +127 -0
  400. package/skills/product-copywriting/agents/openai.yaml +4 -0
  401. package/skills/product-copywriting/references/foo-voice.md +26 -0
  402. package/skills/product-shape-interview/SKILL.md +219 -0
  403. package/skills/product-shape-interview/agents/openai.yaml +4 -0
  404. package/skills/ready-for-release/SKILL.md +39 -0
  405. package/skills/ready-for-release/agents/openai.yaml +4 -0
  406. package/skills/redact-transcripts/SKILL.md +23 -0
  407. package/skills/redact-transcripts/agents/openai.yaml +4 -0
  408. package/skills/research-brief/SKILL.md +48 -0
  409. package/skills/research-brief/agents/openai.yaml +4 -0
  410. package/skills/research-refresh/SKILL.md +63 -0
  411. package/skills/research-refresh/references/worked-cases.md +44 -0
  412. package/skills/review-loop/SKILL.md +200 -0
  413. package/skills/review-spec/SKILL.md +32 -0
  414. package/skills/review-spec/agents/openai.yaml +4 -0
  415. package/skills/rfc-from-research/SKILL.md +42 -0
  416. package/skills/rfc-from-research/agents/openai.yaml +4 -0
  417. package/skills/rfc-from-research/references/rfc-pattern.md +69 -0
  418. package/skills/skill-registry.yaml +810 -0
  419. package/skills/spec-cleanup/SKILL.md +103 -0
  420. package/skills/spec-cleanup/agents/openai.yaml +4 -0
  421. package/skills/spec-swarm/SKILL.md +87 -0
  422. package/skills/spec-swarm/agents/openai.yaml +4 -0
  423. package/skills/spec-swarm/template/SKILL.template.md +94 -0
  424. package/skills/spec-swarm/template/personas/accessibility-inclusion.md +40 -0
  425. package/skills/spec-swarm/template/personas/ai-technical-pm.md +69 -0
  426. package/skills/spec-swarm/template/personas/analytics-engineering.md +39 -0
  427. package/skills/spec-swarm/template/personas/applied-ai-eval.md +64 -0
  428. package/skills/spec-swarm/template/personas/business-gm-pm.md +67 -0
  429. package/skills/spec-swarm/template/personas/consumer-craft-pm.md +68 -0
  430. package/skills/spec-swarm/template/personas/content-design.md +40 -0
  431. package/skills/spec-swarm/template/personas/cpo.md +42 -0
  432. package/skills/spec-swarm/template/personas/data-science.md +42 -0
  433. package/skills/spec-swarm/template/personas/developer-experience.md +65 -0
  434. package/skills/spec-swarm/template/personas/dx-product.md +70 -0
  435. package/skills/spec-swarm/template/personas/field.md +43 -0
  436. package/skills/spec-swarm/template/personas/finance-cfo.md +40 -0
  437. package/skills/spec-swarm/template/personas/growth-pm.md +67 -0
  438. package/skills/spec-swarm/template/personas/platform-pm.md +67 -0
  439. package/skills/spec-swarm/template/personas/pmm.md +43 -0
  440. package/skills/spec-swarm/template/personas/principal-product-designer.md +42 -0
  441. package/skills/spec-swarm/template/personas/product-ops-program.md +41 -0
  442. package/skills/spec-swarm/template/personas/qa-release.md +41 -0
  443. package/skills/spec-swarm/template/personas/responsible-ai-safety.md +64 -0
  444. package/skills/spec-swarm/template/personas/security-privacy-legal.md +40 -0
  445. package/skills/spec-swarm/template/personas/strategy-competitive.md +41 -0
  446. package/skills/spec-swarm/template/personas/technical-architect.md +42 -0
  447. package/skills/spec-swarm/template/personas/technical-lead.md +43 -0
  448. package/skills/spec-swarm/template/personas/user-research.md +41 -0
  449. package/skills/spec-swarm-accessibility-inclusion/SKILL.md +95 -0
  450. package/skills/spec-swarm-accessibility-inclusion/agents/openai.yaml +4 -0
  451. package/skills/spec-swarm-ai-technical-pm/SKILL.md +124 -0
  452. package/skills/spec-swarm-analytics-engineering/SKILL.md +94 -0
  453. package/skills/spec-swarm-analytics-engineering/agents/openai.yaml +4 -0
  454. package/skills/spec-swarm-applied-ai-eval/SKILL.md +120 -0
  455. package/skills/spec-swarm-business-gm-pm/SKILL.md +122 -0
  456. package/skills/spec-swarm-consumer-craft-pm/SKILL.md +122 -0
  457. package/skills/spec-swarm-content-design/SKILL.md +95 -0
  458. package/skills/spec-swarm-content-design/agents/openai.yaml +4 -0
  459. package/skills/spec-swarm-cpo/SKILL.md +94 -0
  460. package/skills/spec-swarm-cpo/agents/openai.yaml +4 -0
  461. package/skills/spec-swarm-data-science/SKILL.md +95 -0
  462. package/skills/spec-swarm-data-science/agents/openai.yaml +4 -0
  463. package/skills/spec-swarm-developer-experience/SKILL.md +121 -0
  464. package/skills/spec-swarm-dx-product/SKILL.md +126 -0
  465. package/skills/spec-swarm-field/SKILL.md +96 -0
  466. package/skills/spec-swarm-field/agents/openai.yaml +4 -0
  467. package/skills/spec-swarm-finance-cfo/SKILL.md +95 -0
  468. package/skills/spec-swarm-finance-cfo/agents/openai.yaml +4 -0
  469. package/skills/spec-swarm-growth-pm/SKILL.md +122 -0
  470. package/skills/spec-swarm-platform-pm/SKILL.md +122 -0
  471. package/skills/spec-swarm-pmm/SKILL.md +96 -0
  472. package/skills/spec-swarm-pmm/agents/openai.yaml +4 -0
  473. package/skills/spec-swarm-principal-product-designer/SKILL.md +95 -0
  474. package/skills/spec-swarm-principal-product-designer/agents/openai.yaml +4 -0
  475. package/skills/spec-swarm-product-ops-program/SKILL.md +96 -0
  476. package/skills/spec-swarm-product-ops-program/agents/openai.yaml +4 -0
  477. package/skills/spec-swarm-qa-release/SKILL.md +96 -0
  478. package/skills/spec-swarm-qa-release/agents/openai.yaml +4 -0
  479. package/skills/spec-swarm-responsible-ai-safety/SKILL.md +120 -0
  480. package/skills/spec-swarm-security-privacy-legal/SKILL.md +95 -0
  481. package/skills/spec-swarm-security-privacy-legal/agents/openai.yaml +4 -0
  482. package/skills/spec-swarm-strategy-competitive/SKILL.md +96 -0
  483. package/skills/spec-swarm-strategy-competitive/agents/openai.yaml +4 -0
  484. package/skills/spec-swarm-technical-architect/SKILL.md +95 -0
  485. package/skills/spec-swarm-technical-architect/agents/openai.yaml +4 -0
  486. package/skills/spec-swarm-technical-lead/SKILL.md +96 -0
  487. package/skills/spec-swarm-technical-lead/agents/openai.yaml +4 -0
  488. package/skills/spec-swarm-user-research/SKILL.md +95 -0
  489. package/skills/spec-swarm-user-research/agents/openai.yaml +4 -0
  490. package/skills/strategy-check/SKILL.md +170 -0
  491. package/skills/strategy-check/agents/openai.yaml +4 -0
  492. package/skills/study-digest/SKILL.md +41 -0
  493. package/skills/synthetic-customer/SKILL.md +68 -0
  494. package/skills/update-cli-spec/SKILL.md +69 -0
  495. package/skills/update-cli-spec/agents/openai.yaml +4 -0
  496. package/skills/voc-researcher/SKILL.md +45 -0
  497. package/skills/voc-researcher/agents/openai.yaml +4 -0
  498. package/skills-lock.json +35 -0
@@ -0,0 +1,327 @@
1
+ // Outlook through Nango (outlook-discovery-connector-v0, local worker mode).
2
+ //
3
+ // Nango is the credential broker (R-001, the email-class shape Gmail's worker
4
+ // established): productfoo asks Nango for the verified user's Outlook credential and
5
+ // then talks to the Microsoft Graph API directly, so message bodies never
6
+ // transit Nango. The connection is per-user (D-002) — a mailbox is personal
7
+ // even at work — so unlike Gong there is no administrator-issued direct-key
8
+ // fallback: a personal OAuth grant through Nango is the only path, and
9
+ // readiness reports that broker truthfully. Credentials are held in process
10
+ // memory for one command, the Nango connection id is never printed (an opaque
11
+ // `connection_ref` stands in for it), and errors carry a typed code plus a
12
+ // bounded message that never embeds a provider response.
13
+ //
14
+ // Microsoft Graph shapes below are beliefs owned by the packet's feasibility
15
+ // task (T-001) and pinned by fixtures in test/discoveryOutlookRuntime.test.ts;
16
+ // nothing here is verified-live, and support stays contract_only.
17
+ import { createHash } from "node:crypto";
18
+ import { refuseSourceWrite } from "./sourceIngress.js";
19
+ export class OutlookRuntimeError extends Error {
20
+ code;
21
+ constructor(code, message) {
22
+ super(message);
23
+ this.code = code;
24
+ this.name = "OutlookRuntimeError";
25
+ }
26
+ }
27
+ // Versioned policy (R-007): hard ceilings the worker enforces and reports, so
28
+ // a later change is explicit rather than silent. quiet_period_hours is the
29
+ // email class's pinned quiet period (D-001, T-005): a conversation is settled
30
+ // evidence once its last message predates the scope window's end by this
31
+ // much, unless an explicit done category (OUTLOOK_DONE_CATEGORIES) marks it
32
+ // sooner.
33
+ export const OUTLOOK_POLICY = {
34
+ policy_version: "outlook-local-worker-0.1",
35
+ max_response_bytes: 8 * 1024 * 1024,
36
+ fetch_timeout_ms: 90_000,
37
+ max_model_input_tokens: 100_000,
38
+ max_list_pages: 5,
39
+ min_request_interval_ms: 350,
40
+ quiet_period_hours: 48,
41
+ };
42
+ // Least-privilege delegated read scopes (R-003). Graph needs one read scope
43
+ // for both bounded metadata listing and reading a selected conversation's
44
+ // message bodies: Mail.Read. Never Mail.ReadWrite, never the full mail grant
45
+ // — there is no write path in this client at all (R-009). A connection
46
+ // without the body scope stays useful for metadata and reports
47
+ // needs_provider_access for reads (R-008).
48
+ const OUTLOOK_BODY_SCOPE = "Mail.Read";
49
+ const DEFAULT_NANGO_HOST = "https://api.nango.dev";
50
+ const DEFAULT_GRAPH_BASE = "https://graph.microsoft.com/v1.0";
51
+ function nangoConfigured(env) {
52
+ return Boolean(env.NANGO_SECRET_KEY?.trim() && env.FOO_OUTLOOK_NANGO_CONNECTION?.trim());
53
+ }
54
+ export function outlookConnectionConfigured(env) {
55
+ return nangoConfigured(env);
56
+ }
57
+ export function outlookCredentialBroker(_env) {
58
+ // Per-user ownership (D-002): Nango is the only broker. The parameter keeps
59
+ // the shared broker signature so callers stay parallel.
60
+ return "nango";
61
+ }
62
+ function opaqueConnectionRef(integration, connectionId) {
63
+ return `outlook:${createHash("sha256").update(`${integration}\n${connectionId}`).digest("hex").slice(0, 16)}`;
64
+ }
65
+ async function fetchWithTimeout(fetchImpl, url, init, timeoutMs) {
66
+ const controller = new AbortController();
67
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
68
+ try {
69
+ return await fetchImpl(url, { ...init, signal: controller.signal });
70
+ }
71
+ catch (error) {
72
+ if (controller.signal.aborted)
73
+ throw new OutlookRuntimeError("provider_timeout", "the provider did not answer within the fetch ceiling");
74
+ throw new OutlookRuntimeError("network", `network failure reaching ${new URL(url).hostname}`);
75
+ }
76
+ finally {
77
+ clearTimeout(timer);
78
+ }
79
+ }
80
+ // Reads a response body while counting toward the byte ceiling, so an
81
+ // oversized conversation is dropped before it is ever materialized in full.
82
+ async function readBounded(response, maxBytes) {
83
+ const declared = Number(response.headers.get("content-length") ?? "0");
84
+ if (Number.isFinite(declared) && declared > maxBytes)
85
+ throw new OutlookRuntimeError("conversation_too_large", "the provider response exceeds the byte ceiling");
86
+ if (!response.body) {
87
+ const buffer = await response.arrayBuffer();
88
+ if (buffer.byteLength > maxBytes)
89
+ throw new OutlookRuntimeError("conversation_too_large", "the provider response exceeds the byte ceiling");
90
+ return new TextDecoder().decode(buffer);
91
+ }
92
+ const reader = response.body.getReader();
93
+ const chunks = [];
94
+ let total = 0;
95
+ for (;;) {
96
+ const { done, value } = await reader.read();
97
+ if (done)
98
+ break;
99
+ total += value.byteLength;
100
+ if (total > maxBytes) {
101
+ await reader.cancel().catch(() => undefined);
102
+ chunks.length = 0;
103
+ throw new OutlookRuntimeError("conversation_too_large", "the provider response exceeds the byte ceiling");
104
+ }
105
+ chunks.push(value);
106
+ }
107
+ return new TextDecoder().decode(Buffer.concat(chunks));
108
+ }
109
+ function parseJson(text, label) {
110
+ try {
111
+ const parsed = JSON.parse(text);
112
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
113
+ throw new Error("not an object");
114
+ return parsed;
115
+ }
116
+ catch {
117
+ throw new OutlookRuntimeError("provider_failure", `${label} returned a response productfoo could not read`);
118
+ }
119
+ }
120
+ /**
121
+ * Resolve the verified user's Outlook credential through Nango. There is no
122
+ * direct fallback (D-002): the mailbox belongs to one person, so the OAuth
123
+ * grant is always brokered, refreshable, and revocable centrally. productfoo receives
124
+ * the token for one command and never persists or prints it.
125
+ */
126
+ export async function resolveOutlookConnection(input) {
127
+ if (!nangoConfigured(input.env)) {
128
+ throw new OutlookRuntimeError("not_connected", "Outlook is not connected: connect the mailbox through Nango and set NANGO_SECRET_KEY and FOO_OUTLOOK_NANGO_CONNECTION (plus NANGO_HOST / FOO_OUTLOOK_NANGO_INTEGRATION when they differ from the defaults)");
129
+ }
130
+ const secret = input.env.NANGO_SECRET_KEY.trim();
131
+ const connectionId = input.env.FOO_OUTLOOK_NANGO_CONNECTION.trim();
132
+ const integration = input.env.FOO_OUTLOOK_NANGO_INTEGRATION?.trim() || "microsoft-outlook";
133
+ const host = (input.env.NANGO_HOST?.trim() || DEFAULT_NANGO_HOST).replace(/\/+$/, "");
134
+ const url = `${host}/connection/${encodeURIComponent(connectionId)}?provider_config_key=${encodeURIComponent(integration)}`;
135
+ const response = await fetchWithTimeout(input.fetchImpl, url, { method: "GET", headers: { authorization: `Bearer ${secret}`, accept: "application/json" } }, OUTLOOK_POLICY.fetch_timeout_ms);
136
+ if (response.status === 401 || response.status === 403)
137
+ throw new OutlookRuntimeError("not_connected", "Nango refused the secret key; reconnect Outlook");
138
+ if (response.status === 404)
139
+ throw new OutlookRuntimeError("not_connected", "Nango has no Outlook connection with that reference; connect Outlook first");
140
+ if (!response.ok)
141
+ throw new OutlookRuntimeError("provider_failure", `Nango answered ${response.status} while resolving the connection`);
142
+ const body = parseJson(await readBounded(response, 256 * 1024), "Nango");
143
+ const credentials = (body.credentials ?? {});
144
+ const type = String(credentials.type ?? "").toUpperCase();
145
+ if (type !== "OAUTH2")
146
+ throw new OutlookRuntimeError("not_connected", "the Nango connection uses a credential type productfoo does not support for Outlook");
147
+ const token = String(credentials.access_token ?? "");
148
+ if (!token)
149
+ throw new OutlookRuntimeError("auth_expired", "the Nango connection carries no usable Outlook access token; refresh or reconnect");
150
+ const raw = (credentials.raw ?? {});
151
+ const scopeValue = typeof raw.scope === "string" ? raw.scope : typeof credentials.scope === "string" ? credentials.scope : "";
152
+ const scopes = scopeValue.split(/[\s,]+/).filter(Boolean);
153
+ const bodyScope = scopes.length === 0 ? "unknown" : scopes.some((scope) => scope.toLowerCase() === OUTLOOK_BODY_SCOPE.toLowerCase() || scope.toLowerCase().startsWith(`${OUTLOOK_BODY_SCOPE.toLowerCase()}.`)) ? "granted" : "missing";
154
+ return { connection_ref: opaqueConnectionRef(integration, connectionId), broker: "nango", credential: { type: "oauth2", access_token: token }, credential_type: "oauth2", body_scope: bodyScope };
155
+ }
156
+ // The metadata $select: every field the adapter and matcher consume, and
157
+ // nothing else — bodies are only ever selected by conversation() (R-004).
158
+ const MESSAGE_METADATA_SELECT = "id,conversationId,subject,receivedDateTime,categories,from,toRecipients,ccRecipients";
159
+ // The full-read select adds the body — and nothing else — over the metadata
160
+ // select (R-004/R-007).
161
+ const MESSAGE_SELECT_WITH_BODY = `${MESSAGE_METADATA_SELECT},body`;
162
+ // OData timestamps are ISO 8601; the approved window's ISO instants pass
163
+ // through unchanged after validation.
164
+ function odataInstant(value, label) {
165
+ const parsed = Date.parse(value);
166
+ if (!Number.isFinite(parsed))
167
+ throw new OutlookRuntimeError("provider_failure", `the approved window is not a valid time range (${label})`);
168
+ return new Date(parsed).toISOString().replace(/\.\d{3}Z$/, "Z");
169
+ }
170
+ /**
171
+ * Minimal read-only Microsoft Graph client. Only documented read operations
172
+ * are reachable — every request method is GET and anything else routes
173
+ * through the single write-refusal choke point (R-009), so the refusal is
174
+ * testable rather than scattered. There is no attachment fetch method at all
175
+ * (D-003): Graph models attachments as separate resources, and this client
176
+ * never asks for them.
177
+ */
178
+ export class OutlookClient {
179
+ credential;
180
+ options;
181
+ requests = { profile: 0, list: 0, metadata: 0, conversation: 0 };
182
+ lastRequestAt = 0;
183
+ baseUrl;
184
+ fetchTimeoutMs;
185
+ sleep;
186
+ now;
187
+ constructor(credential, options) {
188
+ this.credential = credential;
189
+ this.options = options;
190
+ this.baseUrl = (options.baseUrl ?? DEFAULT_GRAPH_BASE).replace(/\/+$/, "");
191
+ this.fetchTimeoutMs = options.fetchTimeoutMs ?? OUTLOOK_POLICY.fetch_timeout_ms;
192
+ this.sleep = options.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
193
+ this.now = options.now ?? (() => Date.now());
194
+ }
195
+ async request(method, pathname, maxBytes = OUTLOOK_POLICY.max_response_bytes, headers = {}) {
196
+ // R-009: the client is GET-shaped by construction; a future caller that
197
+ // tries a write lands here, at the one choke point — the same gate the
198
+ // Gmail client applies to its non-read methods.
199
+ if (method !== "GET")
200
+ refuseSourceWrite(`outlook ${method} ${pathname}`);
201
+ const wait = this.lastRequestAt + OUTLOOK_POLICY.min_request_interval_ms - this.now();
202
+ if (wait > 0)
203
+ await this.sleep(wait);
204
+ this.lastRequestAt = this.now();
205
+ const response = await fetchWithTimeout(this.options.fetchImpl, `${this.baseUrl}${pathname}`, { method: "GET", headers: { authorization: `Bearer ${this.credential.access_token}`, accept: "application/json", ...headers } }, this.fetchTimeoutMs);
206
+ if (response.status === 401)
207
+ throw new OutlookRuntimeError("auth_expired", "Microsoft Graph rejected the credential; refresh or reconnect");
208
+ if (response.status === 403)
209
+ throw new OutlookRuntimeError("access_denied", "Microsoft Graph denied this read; the connection lacks the required scope");
210
+ if (response.status === 429)
211
+ throw new OutlookRuntimeError("budget_exhausted", "Microsoft Graph rate limit reached; no retry was attempted");
212
+ if (response.status === 404)
213
+ throw new OutlookRuntimeError("provider_failure", "Microsoft Graph reported the requested record does not exist");
214
+ if (!response.ok)
215
+ throw new OutlookRuntimeError("provider_failure", `Microsoft Graph answered ${response.status}`);
216
+ return parseJson(await readBounded(response, maxBytes), "Microsoft Graph");
217
+ }
218
+ /** The mailbox owner's address (metadata only) — defines "internal" for a per-user mailbox (R-004). */
219
+ async profile() {
220
+ this.requests.profile += 1;
221
+ const body = await this.request("GET", "/me?$select=mail,userPrincipalName", 16 * 1024);
222
+ const mail = typeof body.mail === "string" && body.mail ? body.mail : typeof body.userPrincipalName === "string" ? body.userPrincipalName : undefined;
223
+ return mail ? { email: mail } : {};
224
+ }
225
+ /**
226
+ * Bounded metadata listing inside ONE explicit approved folder (R-004): a
227
+ * time window expressed as Graph's receivedDateTime range filter, a page
228
+ * ceiling, no message bodies. Pagination re-issues the SAME pinned filter
229
+ * with the next page's skiptoken — the approved window and folder are
230
+ * byte-identical on every page and a listing that exceeds the ceiling
231
+ * returns `truncated` and the run stops; it never widens.
232
+ */
233
+ async listFolderMessages(scope) {
234
+ const from = odataInstant(scope.from, "start");
235
+ const to = odataInstant(scope.to, "end");
236
+ const filter = `receivedDateTime ge ${from} and receivedDateTime le ${to}`;
237
+ const messages = [];
238
+ let skiptoken;
239
+ let pages = 0;
240
+ for (;;) {
241
+ if (pages >= OUTLOOK_POLICY.max_list_pages)
242
+ return { messages, pages, truncated: true };
243
+ const params = new URLSearchParams({ $select: MESSAGE_METADATA_SELECT, $filter: filter, $orderby: "receivedDateTime asc", $top: "100" });
244
+ if (skiptoken)
245
+ params.set("$skiptoken", skiptoken);
246
+ this.requests.list += 1;
247
+ const body = await this.request("GET", `/me/mailFolders/${encodeURIComponent(scope.folder)}/messages?${params.toString()}`, 4 * 1024 * 1024);
248
+ pages += 1;
249
+ for (const entry of Array.isArray(body.value) ? body.value : []) {
250
+ messages.push(this.parseMessage(entry));
251
+ }
252
+ // Follow only Graph's own paging token, never its absolute nextLink —
253
+ // the next page must carry THIS pinned filter, and re-issuing from the
254
+ // approved folder path keeps that true by construction.
255
+ const nextLink = typeof body["@odata.nextLink"] === "string" ? body["@odata.nextLink"] : undefined;
256
+ const token = nextLink ? new URL(nextLink).searchParams.get("$skiptoken") : null;
257
+ skiptoken = token ?? undefined;
258
+ if (!skiptoken)
259
+ return { messages, pages, truncated: false };
260
+ }
261
+ }
262
+ /**
263
+ * One conversation's headers only — the bounded listing read (R-004):
264
+ * participants and dates without any message body. Bodies are fetched
265
+ * solely by `conversation()` under the minted proof (R-007).
266
+ */
267
+ async conversationMetadata(conversationId) {
268
+ if (!conversationId || /\s/.test(conversationId))
269
+ throw new OutlookRuntimeError("provider_failure", "a single well-formed conversation identifier is required");
270
+ this.requests.metadata += 1;
271
+ const params = new URLSearchParams({ $select: MESSAGE_METADATA_SELECT, $filter: `conversationId eq '${conversationId}'`, $orderby: "receivedDateTime asc", $top: "100" });
272
+ const body = await this.request("GET", `/me/messages?${params.toString()}`);
273
+ const messages = (Array.isArray(body.value) ? body.value : []).map((message) => this.parseMessage(message));
274
+ if (messages.length === 0)
275
+ throw new OutlookRuntimeError("access_denied", "Microsoft Graph returned no messages for the selected conversation");
276
+ return messages;
277
+ }
278
+ /**
279
+ * Exactly one conversation's messages (R-007). This method refuses to ask
280
+ * for more than one identifier — a fixture observes that no request ever
281
+ * carries one. Bodies arrive as text (the Prefer header asks Graph for the
282
+ * text twin); an HTML body is dropped, never stored. Attachment resources
283
+ * are never fetched — there is no method for them (D-003).
284
+ */
285
+ async conversation(conversationId) {
286
+ if (!conversationId || /\s/.test(conversationId))
287
+ throw new OutlookRuntimeError("provider_failure", "a single well-formed conversation identifier is required");
288
+ this.requests.conversation += 1;
289
+ const params = new URLSearchParams({ $select: MESSAGE_SELECT_WITH_BODY, $filter: `conversationId eq '${conversationId}'`, $orderby: "receivedDateTime asc", $top: "100" });
290
+ const body = await this.request("GET", `/me/messages?${params.toString()}`, OUTLOOK_POLICY.max_response_bytes, { prefer: 'outlook.body-content-type="Text"' });
291
+ const messages = (Array.isArray(body.value) ? body.value : []).map((message) => this.parseMessage(message));
292
+ if (messages.length === 0)
293
+ throw new OutlookRuntimeError("access_denied", "Microsoft Graph returned no messages for the selected conversation");
294
+ return messages;
295
+ }
296
+ parseMessage(message) {
297
+ const from = parseGraphAddress((message.from ?? {}));
298
+ const to = [
299
+ ...(Array.isArray(message.toRecipients) ? message.toRecipients : []),
300
+ ...(Array.isArray(message.ccRecipients) ? message.ccRecipients : []),
301
+ ].map((entry) => parseGraphAddress(entry)).filter((entry) => Boolean(entry));
302
+ const body = (message.body ?? {});
303
+ // The HTML twin is refused even when Graph ignores the Prefer header: a
304
+ // non-text body content type is dropped, never stored (the Gmail class's
305
+ // html-twin exclusion).
306
+ const bodyText = body.contentType === "text" && typeof body.content === "string" && body.content.trim() ? body.content : undefined;
307
+ return {
308
+ id: typeof message.id === "string" ? message.id : "",
309
+ conversation_id: typeof message.conversationId === "string" ? message.conversationId : undefined,
310
+ received_at: typeof message.receivedDateTime === "string" ? message.receivedDateTime : undefined,
311
+ categories: Array.isArray(message.categories) ? message.categories.filter((category) => typeof category === "string") : undefined,
312
+ ...(from ? { from } : {}),
313
+ to: to.length ? to : undefined,
314
+ subject: typeof message.subject === "string" ? message.subject : undefined,
315
+ body_text: bodyText,
316
+ };
317
+ }
318
+ }
319
+ // Parses Graph's structured { emailAddress: { name, address } } into the
320
+ // adapter's participant shape. Unparseable values are dropped — never guessed.
321
+ function parseGraphAddress(value) {
322
+ const address = (value.emailAddress ?? {});
323
+ const smtp = typeof address.address === "string" ? address.address.trim().toLowerCase() : "";
324
+ if (!smtp || !/^[^\s<>]+@[^\s<>]+$/.test(smtp))
325
+ return undefined;
326
+ return { ...(typeof address.name === "string" && address.name.trim() ? { display_name: address.name.trim().replace(/^"|"$/g, "") } : {}), smtp };
327
+ }
@@ -0,0 +1,40 @@
1
+ import { type GlossaryTerm } from "./packetGlossary.js";
2
+ export interface CorrectionLink {
3
+ kind: "requirement" | "open_question";
4
+ id: string;
5
+ title: string;
6
+ }
7
+ export declare function linkCorrection(packetDir: string, correction: string): CorrectionLink | null;
8
+ export interface DecisionRecord {
9
+ summary: string;
10
+ by: string;
11
+ linked: CorrectionLink | null;
12
+ vocabulary: GlossaryTerm[];
13
+ }
14
+ export interface PendingUserCorrection {
15
+ eventId: string;
16
+ summary: string;
17
+ time?: string;
18
+ }
19
+ export declare function findUnrepresentedUserCorrections(packetDir: string): PendingUserCorrection[];
20
+ export declare function recordDecision(packetDir: string, opts: {
21
+ summary: string;
22
+ by: string;
23
+ now?: Date;
24
+ }): DecisionRecord;
25
+ export interface PatchProposal {
26
+ schema_version: "0.1";
27
+ packet: string;
28
+ correction: string;
29
+ confidence: "low" | "medium";
30
+ requires_approval: true;
31
+ linked: CorrectionLink | null;
32
+ vocabulary: string[];
33
+ patches: Array<{
34
+ file: string;
35
+ anchor: string;
36
+ insert: string;
37
+ }>;
38
+ }
39
+ export declare function proposeSpecPatch(packetDir: string, correction: string): PatchProposal;
40
+ export declare function renderPatchProposal(proposal: PatchProposal): string;
@@ -0,0 +1,172 @@
1
+ // default-agent-routing-v0 T-005 (R-005): capture user corrections as packet
2
+ // contract updates instead of losing them to the chat scrollback. Two moves:
3
+ //
4
+ // - `foo decision add` appends an attributed, append-only decision event,
5
+ // best-effort linked to the requirement or open question it corrects.
6
+ // - `foo spec patch` turns a correction into an INSPECTABLE patch proposal for
7
+ // spec.md / tasks.yaml — exact insertions, a confidence grade, and an
8
+ // explicit approval requirement. It never writes; a human applies.
9
+ //
10
+ // Raw private context stays out: only the correction text the user explicitly
11
+ // provided lands in the packet, and the event writer's safety guard screens it.
12
+ import { existsSync, readFileSync } from "node:fs";
13
+ import path from "node:path";
14
+ import { appendEvent } from "./packetWrite.js";
15
+ import { UsageError } from "./errorTaxonomy.js";
16
+ import { matchGlossaryTerms, readPacketGlossary } from "./packetGlossary.js";
17
+ import { parseOpenQuestions, parseRequirementHeadings } from "./specSections.js";
18
+ const STOP = new Set(["the", "a", "an", "and", "or", "to", "of", "in", "for", "is", "are", "should", "must", "not", "with", "that", "this", "it", "on", "be"]);
19
+ function keywords(text) {
20
+ return new Set(text
21
+ .toLowerCase()
22
+ .split(/[^a-z0-9_-]+/)
23
+ .filter((w) => w.length > 2 && !STOP.has(w)));
24
+ }
25
+ function overlapScore(a, b) {
26
+ let n = 0;
27
+ for (const w of a)
28
+ if (b.has(w))
29
+ n += 1;
30
+ return n;
31
+ }
32
+ // Best-effort: link the correction to the requirement heading or open-question
33
+ // bullet it most plausibly corrects (keyword overlap; ties go to nothing —
34
+ // a wrong link is worse than no link).
35
+ export function linkCorrection(packetDir, correction) {
36
+ const specPath = path.join(packetDir, "spec.md");
37
+ if (!existsSync(specPath))
38
+ return null;
39
+ const text = readFileSync(specPath, "utf8");
40
+ const correctionWords = keywords(correction);
41
+ const candidates = [];
42
+ for (const r of parseRequirementHeadings(text)) {
43
+ candidates.push({ kind: "requirement", id: r.id, title: r.title, score: overlapScore(correctionWords, keywords(r.title)) });
44
+ }
45
+ // Most packets write open questions as plain bullets with no OQ id; a
46
+ // positional id keeps the link addressable (the title is the real anchor).
47
+ parseOpenQuestions(text).forEach((q, i) => {
48
+ candidates.push({ kind: "open_question", id: q.id ?? `OQ-${i + 1}`, title: q.title, score: overlapScore(correctionWords, keywords(q.text)) });
49
+ });
50
+ candidates.sort((a, b) => b.score - a.score);
51
+ const best = candidates[0];
52
+ if (!best || best.score === 0)
53
+ return null;
54
+ if (candidates[1] && candidates[1].score === best.score)
55
+ return null;
56
+ const { score: _score, ...link } = best;
57
+ return link;
58
+ }
59
+ function normalizeRepresentation(text) {
60
+ return text.replace(/\s+/g, " ").trim();
61
+ }
62
+ // Preview trusts only productfoo's explicit correction marker. Historical human and
63
+ // agent decisions are too heterogeneous to infer as pending packet patches
64
+ // without false positives. A correction is represented when the exact summary
65
+ // inserted by `foo spec patch` appears after whitespace normalization.
66
+ export function findUnrepresentedUserCorrections(packetDir) {
67
+ const eventsPath = path.join(packetDir, "events.jsonl");
68
+ if (!existsSync(eventsPath))
69
+ return [];
70
+ const represented = normalizeRepresentation(["spec.md", "tasks.yaml"]
71
+ .map((file) => path.join(packetDir, file))
72
+ .map((file) => (existsSync(file) ? readFileSync(file, "utf8") : ""))
73
+ .join("\n"));
74
+ const pending = [];
75
+ for (const line of readFileSync(eventsPath, "utf8").split(/\r?\n/)) {
76
+ if (!line.trim())
77
+ continue;
78
+ try {
79
+ const event = JSON.parse(line);
80
+ if (event.type !== "com.adaptivespec.decision.recorded" || !event.data || typeof event.data !== "object")
81
+ continue;
82
+ const data = event.data;
83
+ if (data.source !== "user-correction" || typeof data.summary !== "string" || !data.summary.trim())
84
+ continue;
85
+ const summary = data.summary.trim();
86
+ if (represented.includes(normalizeRepresentation(summary)))
87
+ continue;
88
+ pending.push({
89
+ eventId: typeof event.id === "string" ? event.id : "(unknown event)",
90
+ summary,
91
+ ...(typeof event.time === "string" ? { time: event.time } : {}),
92
+ });
93
+ }
94
+ catch {
95
+ // Packet validation owns malformed ledger structure. Preview's preflight
96
+ // stays defensive so a bad line does not become an unexpected crash.
97
+ }
98
+ }
99
+ return pending;
100
+ }
101
+ export function recordDecision(packetDir, opts) {
102
+ // A missing correction is the caller's typo, not productfoo's bug — UsageError keeps it
103
+ // out of the page-worthy command_error bucket and files no Bug Capsule (#778).
104
+ if (!opts.summary.trim())
105
+ throw new UsageError("foo decision add needs --summary <correction>", "E_BAD_FLAG");
106
+ const linked = linkCorrection(packetDir, opts.summary);
107
+ const vocabulary = matchGlossaryTerms(readPacketGlossary(packetDir), opts.summary);
108
+ appendEvent({
109
+ packetDir,
110
+ type: "com.adaptivespec.decision.recorded",
111
+ actor: { type: "human", id: opts.by },
112
+ data: {
113
+ summary: opts.summary,
114
+ linked: linked ? { kind: linked.kind, id: linked.id } : null,
115
+ vocabulary: vocabulary.map((t) => t.term),
116
+ source: "user-correction",
117
+ },
118
+ now: opts.now,
119
+ });
120
+ return { summary: opts.summary, by: opts.by, linked, vocabulary };
121
+ }
122
+ export function proposeSpecPatch(packetDir, correction) {
123
+ if (!correction.trim())
124
+ throw new Error("foo spec patch needs --correction <text>");
125
+ const linked = linkCorrection(packetDir, correction);
126
+ const vocabulary = matchGlossaryTerms(readPacketGlossary(packetDir), correction).map((t) => t.term);
127
+ const date = new Date().toISOString().slice(0, 10);
128
+ const patches = [];
129
+ // spec.md: record the correction as a dated Decision entry, anchored to the
130
+ // linked item when one exists.
131
+ patches.push({
132
+ file: "spec.md",
133
+ anchor: "## Decisions",
134
+ insert: `- ${date} (user correction${linked ? `, ${linked.id}` : ""}): ${correction}`,
135
+ });
136
+ // tasks.yaml: when the correction names a task, propose an explicit review
137
+ // note on it rather than a silent status flip.
138
+ const taskRef = correction.match(/\bT-\d{3}\b/);
139
+ if (taskRef) {
140
+ patches.push({
141
+ file: "tasks.yaml",
142
+ anchor: `id: ${taskRef[0]}`,
143
+ insert: `# user correction (${date}): ${correction} — re-verify done_when before trusting status`,
144
+ });
145
+ }
146
+ return {
147
+ schema_version: "0.1",
148
+ packet: path.basename(packetDir),
149
+ correction,
150
+ // Linked corrections read as targeted (medium); unlinked ones are broad (low).
151
+ confidence: linked ? "medium" : "low",
152
+ requires_approval: true,
153
+ linked,
154
+ vocabulary,
155
+ patches,
156
+ };
157
+ }
158
+ export function renderPatchProposal(proposal) {
159
+ const lines = [
160
+ `Spec patch proposal — ${proposal.packet} (confidence: ${proposal.confidence}; requires human approval, nothing written)`,
161
+ ` correction: ${proposal.correction}`,
162
+ proposal.linked ? ` linked: ${proposal.linked.kind} ${proposal.linked.id} — ${proposal.linked.title}` : " linked: none confidently matched",
163
+ ...(proposal.vocabulary.length ? [` packet vocabulary used: ${proposal.vocabulary.join(", ")}`] : []),
164
+ "",
165
+ ];
166
+ for (const patch of proposal.patches) {
167
+ lines.push(` ${patch.file} @ ${patch.anchor}:`);
168
+ lines.push(` + ${patch.insert}`);
169
+ }
170
+ lines.push("", "Apply by editing the file(s) above, then: foo asp validate <packet-dir>");
171
+ return `${lines.join("\n")}\n`;
172
+ }
@@ -0,0 +1,6 @@
1
+ export interface GlossaryTerm {
2
+ term: string;
3
+ definition: string;
4
+ }
5
+ export declare function readPacketGlossary(packetDir: string): GlossaryTerm[];
6
+ export declare function matchGlossaryTerms(terms: GlossaryTerm[], text: string): GlossaryTerm[];
@@ -0,0 +1,42 @@
1
+ // default-agent-routing-v0 T-006 (R-006): packet-local vocabulary. The final
2
+ // `## Glossary` section of a packet's spec.md is the V0 vocabulary source —
3
+ // accepted domain terms that packet-reading flows (shaping, patching,
4
+ // validating, planning handoffs) may use. Vocabulary is strictly packet-local:
5
+ // nothing here feeds global productfoo command semantics, and a term in one packet
6
+ // never leaks into another.
7
+ import { existsSync, readFileSync } from "node:fs";
8
+ import path from "node:path";
9
+ export function readPacketGlossary(packetDir) {
10
+ const specPath = path.join(packetDir, "spec.md");
11
+ if (!existsSync(specPath))
12
+ return [];
13
+ const text = readFileSync(specPath, "utf8");
14
+ // The FINAL ## Glossary section wins (the spec contract places it last).
15
+ const idx = text.lastIndexOf("\n## Glossary");
16
+ if (idx === -1)
17
+ return [];
18
+ const section = text.slice(idx + 1);
19
+ const body = section.slice(section.indexOf("\n") + 1);
20
+ const end = body.search(/\n## /);
21
+ const content = end === -1 ? body : body.slice(0, end);
22
+ const terms = [];
23
+ for (const line of content.split("\n")) {
24
+ // Accepted bullet shapes: `- term: definition`, `- **term** — definition`,
25
+ // `- term — definition`.
26
+ const match = line.match(/^-\s+(?:\*\*(.+?)\*\*|([^:—]+?))\s*(?:[:—]|--)\s+(.+)$/);
27
+ if (match) {
28
+ const term = (match[1] ?? match[2] ?? "").trim();
29
+ const definition = match[3].trim();
30
+ if (term && definition)
31
+ terms.push({ term, definition });
32
+ }
33
+ }
34
+ return terms;
35
+ }
36
+ // Which packet-local terms appear in a piece of text (case-insensitive, whole
37
+ // word). Used to carry vocabulary context into decisions and patch proposals.
38
+ export function matchGlossaryTerms(terms, text) {
39
+ // Whole-word, case-insensitive, tolerating a simple plural on the last word
40
+ // ("saved filter" matches "Saved filters").
41
+ return terms.filter((t) => new RegExp(`\\b${t.term.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(?:e?s)?\\b`, "i").test(text));
42
+ }
@@ -0,0 +1,54 @@
1
+ import { type SpecDecisionSignals } from "./specDecisionSignals.js";
2
+ import type { PacketStatus } from "./packetStatus.js";
3
+ export declare const PACKET_INDEX_SCHEMA_VERSION = "1.2";
4
+ export interface PacketIndexEntry extends PacketStatus {
5
+ updated: string | null;
6
+ intent: string | null;
7
+ decision_signals: SpecDecisionSignals;
8
+ bucket: "proven" | "progress" | "open" | "retired";
9
+ error?: string;
10
+ }
11
+ export declare function listPackets(root: string): string[];
12
+ export declare function derivePacketIndex(root: string): PacketIndexEntry[];
13
+ export type TriageLane = "needs_you" | "in_flight" | "ready" | "blocked";
14
+ export interface TriageRow {
15
+ packet: string;
16
+ task: string;
17
+ title: string;
18
+ lane: TriageLane;
19
+ prio: string | null;
20
+ unlocks: number;
21
+ unmet: string[];
22
+ owner: string | null;
23
+ agreement: string;
24
+ updated: string | null;
25
+ }
26
+ export declare function deriveTriage(index: PacketIndexEntry[]): TriageRow[];
27
+ export declare const MISPRICED_UNLOCK_THRESHOLD = 7;
28
+ export interface PortfolioRow {
29
+ packet: string;
30
+ spec_id: string;
31
+ open_tasks: number;
32
+ total_tasks: number;
33
+ lanes: TriageLane[];
34
+ priority: string | null;
35
+ unlocks_sum: number;
36
+ unlocks_max: number;
37
+ mispriced: boolean;
38
+ lifecycle_drift: boolean;
39
+ updated: string | null;
40
+ }
41
+ export declare function derivePacketPortfolio(index: PacketIndexEntry[]): PortfolioRow[];
42
+ export declare function taskGlyph(t: {
43
+ status: string;
44
+ checksDone: number;
45
+ checksTotal: number;
46
+ }): "p" | "d" | "w" | "o" | "b";
47
+ export declare function renderIndexHtml(index: PacketIndexEntry[]): string;
48
+ export interface IndexOptions {
49
+ json?: boolean;
50
+ html?: boolean;
51
+ htmlPath?: string;
52
+ glyphs?: boolean;
53
+ }
54
+ export declare function runAspIndex(root: string, options: IndexOptions): string;