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,448 @@
1
+ // Cheap, safe write path for Adaptive Spec Packets (asp-cli-lifecycle-v0).
2
+ //
3
+ // `foo asp` could already read packets well; this closes the write side so a
4
+ // human or coding agent can scaffold a packet, append an event, and move a task
5
+ // without hand-editing events.jsonl or hand-choosing ids. Three guarantees:
6
+ // - append-only: events are appended, prior ledger lines are never rewritten;
7
+ // - collision-safe ids: every event id is a fresh ULID, re-rolled if a
8
+ // (vanishingly unlikely) collision with an existing id is seen;
9
+ // - legible actor identity: agent writers carry full identity, humans record
10
+ // type "human" — and B1 refuses any write that smells like raw secrets.
11
+ import { randomBytes } from "node:crypto";
12
+ import { appendFileSync, existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
13
+ import path from "node:path";
14
+ import { parse as parseYaml } from "./vendorYaml.js";
15
+ import { decisionRequestAuthoringComment } from "./specSections.js";
16
+ import { UsageError } from "./errorTaxonomy.js";
17
+ const TASK_STATUSES = ["todo", "doing", "blocked", "done", "dropped"];
18
+ // --- ULID (Crockford base32, 10 time chars + 16 random) ---------------------
19
+ const CROCKFORD = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
20
+ function ulid(now = Date.now()) {
21
+ let time = now;
22
+ const timeChars = [];
23
+ for (let i = 0; i < 10; i += 1) {
24
+ timeChars.unshift(CROCKFORD[time % 32]);
25
+ time = Math.floor(time / 32);
26
+ }
27
+ const bytes = randomBytes(16);
28
+ let rand = "";
29
+ for (let i = 0; i < 16; i += 1)
30
+ rand += CROCKFORD[bytes[i] % 32];
31
+ return timeChars.join("") + rand;
32
+ }
33
+ function existingEventIds(eventsPath) {
34
+ if (!existsSync(eventsPath))
35
+ return new Set();
36
+ const ids = new Set();
37
+ for (const line of readFileSync(eventsPath, "utf8").split(/\r?\n/)) {
38
+ if (!line.trim())
39
+ continue;
40
+ try {
41
+ const id = JSON.parse(line).id;
42
+ if (typeof id === "string")
43
+ ids.add(id);
44
+ }
45
+ catch {
46
+ // A malformed prior line is a read concern, not a uniqueness concern.
47
+ }
48
+ }
49
+ return ids;
50
+ }
51
+ function freshEventId(eventsPath) {
52
+ const taken = existingEventIds(eventsPath);
53
+ let id = ulid();
54
+ while (taken.has(id))
55
+ id = ulid();
56
+ return id;
57
+ }
58
+ // --- B1 safety: refuse writes that carry raw private material ---------------
59
+ const SECRET_PATTERNS = [
60
+ { re: /-----BEGIN [A-Z ]*PRIVATE KEY-----/, label: "a private key block" },
61
+ { re: /\bAKIA[0-9A-Z]{16}\b/, label: "an AWS access key id" },
62
+ { re: /\bgh[pousr]_[A-Za-z0-9]{20,}\b/, label: "a GitHub token" },
63
+ { re: /\bsk-[A-Za-z0-9]{20,}\b/, label: "an API secret key" },
64
+ { re: /\bxox[baprs]-[A-Za-z0-9-]{10,}\b/, label: "a Slack token" },
65
+ { re: /(?:password|passwd|secret|api[_-]?key|token|bearer)\s*[:=]\s*\S{8,}/i, label: "a secret assignment" },
66
+ ];
67
+ export function findSecretLeak(text) {
68
+ for (const { re, label } of SECRET_PATTERNS) {
69
+ if (re.test(text))
70
+ return label;
71
+ }
72
+ return null;
73
+ }
74
+ function guardSafety(payload) {
75
+ const leak = findSecretLeak(JSON.stringify(payload));
76
+ if (leak) {
77
+ throw new Error(`refusing write: payload looks like raw private material (${leak}). B1 safety blocks committing secrets into the ledger.`);
78
+ }
79
+ }
80
+ // AGENT_EVENT_TYPES require full agent identity in the validator; status_changed
81
+ // is one of them, so an agent writer must present complete identity here.
82
+ function env(name) {
83
+ const value = process.env[name];
84
+ return value && value.trim() !== "" ? value.trim() : undefined;
85
+ }
86
+ export function resolveActor(overrides = {}) {
87
+ const type = overrides.type ?? env("FOO_ACTOR_TYPE") ?? "human";
88
+ if (type === "agent") {
89
+ return {
90
+ type: "agent",
91
+ id: overrides.id ?? env("FOO_ACTOR_ID") ?? "agent:unknown",
92
+ provider: env("FOO_ACTOR_PROVIDER") ?? "unknown",
93
+ model: env("FOO_ACTOR_MODEL") ?? "unknown",
94
+ persona: env("FOO_ACTOR_PERSONA") ?? "unknown",
95
+ skills: env("FOO_ACTOR_SKILLS") ? env("FOO_ACTOR_SKILLS").split(",").map((s) => s.trim()).filter(Boolean) : [],
96
+ adapter: env("FOO_ACTOR_ADAPTER") ?? "unknown",
97
+ mode: env("FOO_ACTOR_MODE") ?? "human-in-loop",
98
+ };
99
+ }
100
+ return { type: "human", id: overrides.id ?? env("FOO_ACTOR_ID") ?? "human" };
101
+ }
102
+ function specIdOf(packetDir) {
103
+ const doc = parseYaml(readFileSync(path.join(packetDir, "tasks.yaml"), "utf8"));
104
+ const id = doc?.spec_id;
105
+ if (typeof id !== "string")
106
+ throw new Error("tasks.yaml is missing a string spec_id");
107
+ return id;
108
+ }
109
+ export function appendEvent(options) {
110
+ if (!existsSync(path.join(options.packetDir, "tasks.yaml"))) {
111
+ throw new Error(`not a packet directory (no tasks.yaml): ${options.packetDir}`);
112
+ }
113
+ const eventsPath = path.join(options.packetDir, "events.jsonl");
114
+ const now = options.now ?? new Date();
115
+ const data = options.data ?? {};
116
+ const actor = resolveActor(options.actor);
117
+ const event = {
118
+ specversion: "1.0",
119
+ id: freshEventId(eventsPath),
120
+ source: "foo-cli",
121
+ type: options.type,
122
+ subject: options.subject ?? `packet:${specIdOf(options.packetDir)}`,
123
+ time: now.toISOString(),
124
+ actor,
125
+ data,
126
+ };
127
+ guardSafety(event);
128
+ // Append-only: a trailing newline is ensured without rewriting prior lines.
129
+ const prefix = existsSync(eventsPath) && readFileSync(eventsPath, "utf8").length > 0 && !readFileSync(eventsPath, "utf8").endsWith("\n") ? "\n" : "";
130
+ appendFileSync(eventsPath, `${prefix}${JSON.stringify(event)}\n`);
131
+ return event;
132
+ }
133
+ function findTaskBlock(text, taskId, tasksPath) {
134
+ const lines = text.split("\n");
135
+ let start = -1;
136
+ let indent = "";
137
+ for (let i = 0; i < lines.length; i += 1) {
138
+ // The locator must accept every id shape the YAML reader accepts: quoted
139
+ // (both styles) and a trailing comment (#776).
140
+ const m = lines[i].match(/^(\s*)-\s+id:\s*(?:"([^"]*)"|'([^']*)'|([^\s#]+))(?:\s+#.*)?\s*$/);
141
+ const id = m?.[2] ?? m?.[3] ?? m?.[4];
142
+ if (m && id === taskId) {
143
+ start = i;
144
+ indent = m[1];
145
+ break;
146
+ }
147
+ }
148
+ if (start === -1) {
149
+ // The reader accepted this id but the writer's locator could not place the
150
+ // block. A usage error names the packet and id and never files a capsule.
151
+ throw new UsageError(`task ${taskId} not found in tasks.yaml (${tasksPath})`, "E_BAD_FLAG");
152
+ }
153
+ // The block runs until the next list item at the same indent, or EOF.
154
+ let end = lines.length;
155
+ for (let i = start + 1; i < lines.length; i += 1) {
156
+ if (new RegExp(`^${indent}-\\s`).test(lines[i])) {
157
+ end = i;
158
+ break;
159
+ }
160
+ }
161
+ return { start, end, indent };
162
+ }
163
+ export function updateTask(options) {
164
+ // `--status bogus` is a typo, not a defect. As a bare Error it classified as
165
+ // command_error, so `foo asp task <p> T-001 --status dnoe` PAGED and filed a
166
+ // Bug Capsule — against productfoo's own promise that "a typo or a blocked gate never
167
+ // produces a capsule at all". A queue full of the reader's spelling mistakes is
168
+ // exactly the noise that teaches people to stop reading the queue.
169
+ if (!TASK_STATUSES.includes(options.status)) {
170
+ throw new UsageError(`invalid status: ${options.status} (expected ${TASK_STATUSES.join(", ")})`, "E_BAD_FLAG");
171
+ }
172
+ const tasksPath = path.join(options.packetDir, "tasks.yaml");
173
+ if (!existsSync(tasksPath))
174
+ throw new Error(`not a packet directory (no tasks.yaml): ${options.packetDir}`);
175
+ const text = readFileSync(tasksPath, "utf8");
176
+ const doc = parseYaml(text);
177
+ const tasks = Array.isArray(doc.tasks) ? doc.tasks : [];
178
+ const task = tasks.find((t) => t && t.id === options.taskId);
179
+ // A typo'd or pasted-quoted id is a usage mistake, not a foo defect —
180
+ // UsageError classifies as command error and never files a Bug Capsule (#776).
181
+ if (!task)
182
+ throw new UsageError(`task ${options.taskId} not found in tasks.yaml (${tasksPath})`, "E_BAD_FLAG");
183
+ const from = typeof task.status === "string" ? task.status : "todo";
184
+ const to = options.status;
185
+ const now = options.now ?? new Date();
186
+ guardSafety({ proof: options.proof, summary: options.summary, reason: options.reason });
187
+ // The block locator is a parallel scan over the raw text, so it can fail where
188
+ // the tolerant YAML reader succeeded (a quoted id, a trailing comment). Resolve
189
+ // it BEFORE the ledger append: on failure nothing has been written yet, so the
190
+ // ledger can never claim a transition tasks.yaml doesn't carry, and a corrected
191
+ // retry appends exactly one event (#776).
192
+ const block = findTaskBlock(text, options.taskId, tasksPath);
193
+ const lines = text.split("\n");
194
+ // The event is appended first so its id can be referenced from the task block;
195
+ // everything fallible between here and the tasks.yaml write is already resolved.
196
+ const event = appendEvent({
197
+ packetDir: options.packetDir,
198
+ type: "com.adaptivespec.task.status_changed",
199
+ subject: `task:${options.taskId}`,
200
+ data: {
201
+ from,
202
+ to,
203
+ ...(options.proof ? { proof: options.proof } : {}),
204
+ ...(options.summary ? { summary: options.summary } : {}),
205
+ },
206
+ actor: options.actor,
207
+ now,
208
+ });
209
+ // Build the replacement task block from the structured object, then splice it
210
+ // back in place so surrounding tasks and ledger lines are untouched.
211
+ const updated = { ...task, status: to };
212
+ if (to === "done") {
213
+ updated.completed = {
214
+ at: now.toISOString(),
215
+ by: event.actor && typeof event.actor === "object" ? event.actor.id : "human",
216
+ summary: options.summary ?? `Marked ${options.taskId} done.`,
217
+ event: event.id,
218
+ };
219
+ updated.blocked = null;
220
+ if (Array.isArray(updated.done_when)) {
221
+ updated.done_when = updated.done_when.map((check) => ({
222
+ ...check,
223
+ done: true,
224
+ ...(options.proof ? { proof: options.proof } : {}),
225
+ }));
226
+ }
227
+ }
228
+ else if (to === "blocked") {
229
+ updated.blocked = {
230
+ reason: options.reason ?? options.summary ?? `${options.taskId} is blocked.`,
231
+ needs: options.needs ?? ["resolve the blocker before continuing"],
232
+ event: event.id,
233
+ };
234
+ }
235
+ const rendered = renderTaskBlock(updated, block.indent);
236
+ const next = [...lines.slice(0, block.start), ...rendered, ...lines.slice(block.end)].join("\n");
237
+ // Temp-plus-rename so a torn write can never leave half a tasks.yaml behind a
238
+ // ledger event that already claims the transition (#776).
239
+ const temp = `${tasksPath}.${process.pid}.${randomBytes(4).toString("hex")}.tmp`;
240
+ try {
241
+ writeFileSync(temp, next);
242
+ renameSync(temp, tasksPath);
243
+ }
244
+ finally {
245
+ if (existsSync(temp))
246
+ rmSync(temp, { force: true });
247
+ }
248
+ return { event, from, to };
249
+ }
250
+ // Minimal, stable YAML renderer for a single task block. Keys are emitted in the
251
+ // canonical packet order so a written task reads like a hand-authored one.
252
+ const TASK_KEY_ORDER = [
253
+ "id", "title", "status", "agreement", "stage", "refs", "depends_on", "owner",
254
+ "autonomy", "created_by", "touches", "do", "done_when", "completed", "blocked",
255
+ "review", "extensions",
256
+ ];
257
+ function renderTaskBlock(task, indent) {
258
+ const lines = [];
259
+ const itemIndent = indent;
260
+ const fieldIndent = `${indent} `;
261
+ const keys = [...TASK_KEY_ORDER.filter((k) => k in task), ...Object.keys(task).filter((k) => !TASK_KEY_ORDER.includes(k))];
262
+ keys.forEach((key, i) => {
263
+ const prefix = i === 0 ? `${itemIndent}- ` : `${fieldIndent}`;
264
+ lines.push(...renderField(key, task[key], prefix, `${fieldIndent} `));
265
+ });
266
+ return lines;
267
+ }
268
+ function renderField(key, value, prefix, childIndent) {
269
+ if (value === null || value === undefined)
270
+ return [`${prefix}${key}: null`];
271
+ if (Array.isArray(value)) {
272
+ if (value.length === 0)
273
+ return [`${prefix}${key}: []`];
274
+ const lines = [`${prefix}${key}:`];
275
+ for (const item of value) {
276
+ if (item && typeof item === "object" && !Array.isArray(item)) {
277
+ const entries = Object.entries(item);
278
+ entries.forEach(([k, v], idx) => {
279
+ const p = idx === 0 ? `${childIndent}- ` : `${childIndent} `;
280
+ lines.push(...renderField(k, v, p, `${childIndent} `));
281
+ });
282
+ }
283
+ else {
284
+ lines.push(`${childIndent}- ${scalar(item)}`);
285
+ }
286
+ }
287
+ return lines;
288
+ }
289
+ if (typeof value === "object") {
290
+ const entries = Object.entries(value);
291
+ if (entries.length === 0)
292
+ return [`${prefix}${key}: {}`];
293
+ const lines = [`${prefix}${key}:`];
294
+ for (const [k, v] of entries)
295
+ lines.push(...renderField(k, v, `${childIndent}`, `${childIndent} `));
296
+ return lines;
297
+ }
298
+ return [`${prefix}${key}: ${scalar(value)}`];
299
+ }
300
+ function scalar(value) {
301
+ if (value === null || value === undefined)
302
+ return "null";
303
+ if (typeof value === "number" || typeof value === "boolean")
304
+ return String(value);
305
+ const s = String(value);
306
+ if (s === "" || /[:#\[\]{}&*!|>'"%@`]/.test(s) || /^\s|\s$/.test(s) || /^(true|false|null|~)$/i.test(s) || /^[-?]/.test(s) || /^\d/.test(s)) {
307
+ return JSON.stringify(s);
308
+ }
309
+ return s;
310
+ }
311
+ // --- Scaffold (foo asp init) ------------------------------------------------
312
+ function titleCase(slug) {
313
+ return slug
314
+ .split(/[-_]/)
315
+ .filter(Boolean)
316
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
317
+ .join(" ");
318
+ }
319
+ export function initPacket(options) {
320
+ const now = options.now ?? new Date();
321
+ const name = options.name;
322
+ if (!name || /[^A-Za-z0-9_./-]/.test(name))
323
+ throw new Error("packet name must be a slug or path (letters, digits, -, _, /)");
324
+ // A name with a separator is treated as a path; otherwise it lands under specs/.
325
+ const relDir = name.includes("/") ? name : path.posix.join("specs", name);
326
+ const packetDir = path.resolve(options.root, relDir);
327
+ if (existsSync(packetDir))
328
+ throw new Error(`refusing to overwrite existing directory: ${relDir}`);
329
+ const base = path.basename(packetDir);
330
+ const specId = base.replace(/-/g, "_");
331
+ const title = titleCase(base);
332
+ const relSpecRef = path.relative(options.root, path.join(packetDir, "spec.md")).split(path.sep).join("/");
333
+ const isoDate = now.toISOString().slice(0, 10);
334
+ mkdirSync(packetDir, { recursive: true });
335
+ const specMd = `---
336
+ spec_id: ${specId}
337
+ title: ${title}
338
+ mode: capability
339
+ lifecycle: draft
340
+ stage: exploring
341
+ owner: product
342
+ autonomy: human-in-loop
343
+ updated: ${isoDate}
344
+ ---
345
+
346
+ # ${title}
347
+
348
+ <!-- Identity (\`spec_id\`) is read from the YAML frontmatter above. Progress is rendered by \`foo asp status\`, never stored here. -->
349
+
350
+ ## Intent
351
+
352
+ State the product bet in one or two sentences: what this packet is for and why now.
353
+
354
+ ## Current Understanding
355
+
356
+ - What is already true in the repo and approved sources.
357
+
358
+ ## Requirements
359
+
360
+ ### R-001 First requirement
361
+
362
+ - Priority: P1
363
+ - Risk: medium
364
+ - Confidence: low
365
+
366
+ Describe the first requirement this packet must satisfy.
367
+
368
+ ## Decisions
369
+
370
+ - D-001 — (open) Record decisions as they are made.
371
+
372
+ ## Risks
373
+
374
+ - RISK-001 — The dominant risk and how it will be surfaced.
375
+
376
+ ## Validation
377
+
378
+ - V-001 — How a reviewer confirms the work matches intent.
379
+
380
+ ## Evidence
381
+
382
+ - Links to repo, approved sources, and proof as it accrues.
383
+
384
+ ## Open Questions
385
+
386
+ ${decisionRequestAuthoringComment()}
387
+ `;
388
+ const tasksYaml = `schema_version: "0.1"
389
+ spec_id: ${specId}
390
+ spec_ref: ${relSpecRef}
391
+ updated: "${now.toISOString()}"
392
+
393
+ defaults:
394
+ autonomy: human-in-loop
395
+ stale_after_days:
396
+ suggested: 7
397
+ discovered: 7
398
+
399
+ ledger:
400
+ segment_order:
401
+ - events.jsonl
402
+
403
+ tasks:
404
+ - id: T-001
405
+ title: Shape the packet intent and first requirement
406
+ status: todo
407
+ agreement: agreed
408
+ stage: shaping
409
+ refs:
410
+ - R-001
411
+ depends_on: []
412
+ owner: agent:any
413
+ autonomy: human-in-loop
414
+ created_by:
415
+ type: human
416
+ id: product
417
+ touches:
418
+ - ${relSpecRef}
419
+ do:
420
+ - Capture the intent and current understanding from approved sources.
421
+ - Write the first requirement and its acceptance check.
422
+ done_when:
423
+ - id: C-001
424
+ text: Intent and R-001 are written into spec.md.
425
+ done: false
426
+ proof: null
427
+ completed: null
428
+ blocked: null
429
+ review:
430
+ owner: product
431
+ due: null
432
+ stale_after_days: null
433
+ extensions: {}
434
+ `;
435
+ writeFileSync(path.join(packetDir, "spec.md"), specMd);
436
+ writeFileSync(path.join(packetDir, "tasks.yaml"), tasksYaml);
437
+ writeFileSync(path.join(packetDir, "events.jsonl"), "");
438
+ // Genesis event: subject is the packet (not a task), so no task-event matching
439
+ // is triggered and the scaffold validates with no manual edits.
440
+ appendEvent({
441
+ packetDir,
442
+ type: "com.adaptivespec.packet.created",
443
+ subject: `packet:${specId}`,
444
+ data: { summary: "Packet scaffolded by foo asp init.", spec_ref: relSpecRef },
445
+ now,
446
+ });
447
+ return { packetDir, specId, relSpecRef };
448
+ }
@@ -0,0 +1,38 @@
1
+ import { type DeepEstimate } from "./research.js";
2
+ export type PitchStage = "auto" | "0to1" | "1ton" | "nx";
3
+ export type SourceStatus = "available" | "absent";
4
+ export interface PitchSources {
5
+ repo: SourceStatus;
6
+ web_free: SourceStatus;
7
+ web_firecrawl: SourceStatus;
8
+ /** Human-readable reason for the firecrawl status (present-and-use vs degrade). */
9
+ web_firecrawl_note: string;
10
+ }
11
+ export interface PitchPlan {
12
+ command: "pitch";
13
+ /** Pre-flight cost of the planned work — bounded by sections x panel, honest about what it excludes. */
14
+ estimate: DeepEstimate;
15
+ opportunity: string;
16
+ stage: PitchStage;
17
+ stage_note: string | null;
18
+ output_path: string;
19
+ from_research: string[];
20
+ to_shape: boolean;
21
+ posture: "read-and-synthesize-only";
22
+ page_budget: string;
23
+ sources: PitchSources;
24
+ evidence_directive: string;
25
+ skill: string;
26
+ references: string[];
27
+ sections: string[];
28
+ panel: string[];
29
+ verdict_options: ["GO", "NOT-NOW", "NO-GO"];
30
+ next: string;
31
+ }
32
+ export declare function detectPitchSources(env?: NodeJS.ProcessEnv): PitchSources;
33
+ export declare function slugifyOpportunity(text: string): string;
34
+ export declare function buildPitchPlan(args: string[], env?: NodeJS.ProcessEnv, root?: string): PitchPlan;
35
+ export declare function runPitchCommand(root: string, args: string[], env?: NodeJS.ProcessEnv): {
36
+ output: string;
37
+ exitCode: number;
38
+ };
@@ -0,0 +1,154 @@
1
+ // pitch-command-v0 — `foo pitch <opportunity>`: the whether & why gate.
2
+ //
3
+ // pitch is an authoring command: its intelligence lives in the skill
4
+ // (skills/pitch/SKILL.md) and the reviewed command doc (commands/pitch.md), not
5
+ // in a heavy CLI engine. This module emits a bounded, deterministic PLAN + the
6
+ // output path the agent then fills — the same "CLI declares, agent authors"
7
+ // shape research uses, minus the source fan-out. It performs no network, no
8
+ // mutation, no outbound action (read-and-synthesize-only, R-005).
9
+ import path from "node:path";
10
+ import { estimatePitch } from "./research.js";
11
+ import { loadPricing } from "./loopBudget.js";
12
+ import { loadModelRoster, resolveActiveModel } from "./activeModel.js";
13
+ import { flagValue, hasFlag } from "./cliArgs.js";
14
+ import { resolveFirecrawlKey } from "./tokenStore.js";
15
+ const STAGES = {
16
+ "0to1": "New product (0→1): net-new solution / new market; highest innovation + market-introduction risk.",
17
+ "1ton": "Major enhancement (1→n): expand an existing product — new features, markets, or value proposition.",
18
+ nx: "Incremental improvement (n^x): refine an established product; smaller changes that compound.",
19
+ };
20
+ const SECTION_COUNT = 7; // the PR/FAQ sections below
21
+ const PANEL_COUNT = 2; // the pitch panel lenses below
22
+ // Detect which external evidence classes this run may use. Mirrors research's
23
+ // source-class contract so pitch can never silently skip an available class:
24
+ // firecrawl is capability-gated on a present key/entitlement and degrades to
25
+ // free web when absent — it is never a block, and private/connected content is
26
+ // never sent to it.
27
+ export function detectPitchSources(env = process.env) {
28
+ // Env-first, then the key saved by `foo login --firecrawl` (tokenStore).
29
+ const firecrawl = Boolean(resolveFirecrawlKey(env).key);
30
+ return {
31
+ repo: "available",
32
+ web_free: "available",
33
+ web_firecrawl: firecrawl ? "available" : "absent",
34
+ web_firecrawl_note: firecrawl
35
+ ? "use it to verify quantified / load-bearing claims; never send private or connected content to Firecrawl"
36
+ : "degrades to web_free; save a key with `foo login --firecrawl <key>` to enrich (never blocks)",
37
+ };
38
+ }
39
+ export function slugifyOpportunity(text) {
40
+ const slug = text
41
+ .toLowerCase()
42
+ .replace(/[^a-z0-9]+/g, "-")
43
+ .replace(/^-+|-+$/g, "")
44
+ .slice(0, 60)
45
+ .replace(/-+$/g, "");
46
+ return slug || "opportunity";
47
+ }
48
+ function todayIso() {
49
+ return new Date().toISOString().slice(0, 10);
50
+ }
51
+ function parseStage(args) {
52
+ if (!hasFlag(args, "--stage"))
53
+ return "auto";
54
+ const value = flagValue(args, "--stage");
55
+ if (value === "0to1" || value === "1ton" || value === "nx")
56
+ return value;
57
+ throw new Error(`unknown --stage: ${value ?? "(missing)"}. Use one of: 0to1, 1ton, nx.`);
58
+ }
59
+ function collectFlagValues(args, flag) {
60
+ const out = [];
61
+ for (let i = 0; i < args.length; i += 1) {
62
+ if (args[i] === flag && args[i + 1] && !args[i + 1].startsWith("--"))
63
+ out.push(args[i + 1]);
64
+ }
65
+ return out;
66
+ }
67
+ export function buildPitchPlan(args, env = process.env, root = process.cwd()) {
68
+ const stage = parseStage(args);
69
+ const fromResearch = collectFlagValues(args, "--from-research");
70
+ const flagValues = new Set([...fromResearch, stage]);
71
+ const opportunity = args
72
+ .filter((a) => !a.startsWith("--") && !flagValues.has(a))
73
+ .join(" ")
74
+ .trim();
75
+ const slug = slugifyOpportunity(opportunity || "opportunity");
76
+ const sources = detectPitchSources(env);
77
+ // Same honest primitive as research: the work is BOUNDED (a ~2-page paper over N
78
+ // sections + a panel), so a range is defensible — but it excludes what the agent
79
+ // actually burns executing it, and says so rather than implying a forecast.
80
+ const active = resolveActiveModel(env, loadModelRoster(root));
81
+ const estimate = estimatePitch(SECTION_COUNT, PANEL_COUNT, loadPricing(root), active.worker);
82
+ return {
83
+ command: "pitch",
84
+ estimate,
85
+ opportunity,
86
+ stage,
87
+ stage_note: stage === "auto" ? null : STAGES[stage],
88
+ output_path: path.posix.join(".foo", "docs", "pitch", `${todayIso()}-${slug}.md`),
89
+ from_research: fromResearch,
90
+ to_shape: args.includes("--to-shape"),
91
+ posture: "read-and-synthesize-only",
92
+ page_budget: "~2 pages, highlights only — early exec/founder read; deeper detail belongs in the full spec.",
93
+ sources,
94
+ evidence_directive: "Gather evidence across every available source class; when web_firecrawl is available, use it to verify quantified / load-bearing claims. Report per-class status in the paper; degrade honestly, never silently skip an available class.",
95
+ // Skill pointers are `foo skill` ARGUMENTS, never filesystem paths (R-003,
96
+ // alpha_tester_fixes_v0). `skills/pitch/SKILL.md` does not exist in a thin
97
+ // install and is not a valid `foo skill` argument either — it was a pointer
98
+ // the agent could not open by any route. A name resolves on disk or over the wire.
99
+ skill: "pitch",
100
+ references: ["pitch/references/prfaq-template.md", "pitch/references/opportunity-assessment.md"],
101
+ sections: [
102
+ "Press Release (worked backwards: heading, precise-customer subheading, summary + real launch date, customer-POV problem, differentiated solution, quotes)",
103
+ "External FAQ",
104
+ "Internal FAQ = staged opportunity assessment (0→1 / 1→n / n^x)",
105
+ "What must be true · Top 3 reasons it fails · Current solution & will they switch",
106
+ "Evidence (every claim typed [source · confidence] or hypothesis)",
107
+ "Recommendation (GO / NOT-NOW / NO-GO + numbered next steps + B3 risk read)",
108
+ "Panel dissent",
109
+ ],
110
+ panel: ["research-tuned lenses", "PR/FAQ reviewer (customer? problem? solution? behavior change? prize?)"],
111
+ verdict_options: ["GO", "NOT-NOW", "NO-GO"],
112
+ next: "Author the Pitch paper per `foo skill pitch`, then hand off with --to-shape or point deeper work at the full spec (foo spec then spec start).",
113
+ };
114
+ }
115
+ function renderPlanText(plan) {
116
+ const lines = [];
117
+ lines.push("foo pitch — Working Backwards PR/FAQ × staged opportunity assessment");
118
+ lines.push("");
119
+ if (!plan.opportunity) {
120
+ lines.push("No opportunity given. Provide one, e.g.:");
121
+ lines.push(' foo pitch "governed PR/FAQ command for coding agents" --stage 0to1 --to-shape');
122
+ lines.push("");
123
+ lines.push("Then author the paper per `foo skill pitch` (frame the customer first, pick the stage).");
124
+ return `${lines.join("\n")}\n`;
125
+ }
126
+ lines.push(`Opportunity : ${plan.opportunity}`);
127
+ lines.push(`Stage : ${plan.stage}${plan.stage_note ? ` — ${plan.stage_note}` : " (confirm 0→1 / 1→n / n^x)"}`);
128
+ lines.push(`Output : ${plan.output_path} (gitignored scratch; promote to commit)`);
129
+ lines.push(`Budget : ${plan.page_budget}`);
130
+ lines.push(plan.estimate.expected_usd === null
131
+ ? `Cost : ${plan.estimate.expected_tokens.toLocaleString("en-US")}–${plan.estimate.ceiling_tokens.toLocaleString("en-US")} tokens (dollars unavailable — ${plan.estimate.priced_with})`
132
+ : `Cost : ~$${plan.estimate.expected_usd.toFixed(2)}–$${plan.estimate.ceiling_usd.toFixed(2)} for the planned paper (${plan.estimate.expected_tokens.toLocaleString("en-US")}–${plan.estimate.ceiling_tokens.toLocaleString("en-US")} tokens, priced with ${plan.estimate.priced_with})`);
133
+ lines.push(` floor, not a forecast — excludes ${plan.estimate.excludes[0]}`);
134
+ lines.push(`Posture : ${plan.posture}`);
135
+ lines.push(`Sources : repo ${plan.sources.repo} · web_free ${plan.sources.web_free} · web_firecrawl ${plan.sources.web_firecrawl} — ${plan.sources.web_firecrawl_note}`);
136
+ if (plan.from_research.length)
137
+ lines.push(`Seeded from : ${plan.from_research.join(", ")}`);
138
+ lines.push(`Hand off : ${plan.to_shape ? "foo spec (carry labeled claims + dissent + verdict)" : "add --to-shape to route into foo spec"}`);
139
+ lines.push("");
140
+ lines.push("Author these sections (run `foo skill pitch` and execute as written):");
141
+ for (const s of plan.sections)
142
+ lines.push(` - ${s}`);
143
+ lines.push("");
144
+ lines.push(`Panel (never blocks): ${plan.panel.join("; ")}`);
145
+ lines.push(`Verdict: one of ${plan.verdict_options.join(" / ")}. ${plan.next}`);
146
+ return `${lines.join("\n")}\n`;
147
+ }
148
+ export function runPitchCommand(root, args, env = process.env) {
149
+ const plan = buildPitchPlan(args, env, root);
150
+ if (args.includes("--json")) {
151
+ return { output: `${JSON.stringify(plan, null, 2)}\n`, exitCode: 0 };
152
+ }
153
+ return { output: renderPlanText(plan), exitCode: 0 };
154
+ }
@@ -0,0 +1,8 @@
1
+ export type MemoEntry<V> = {
2
+ key: string;
3
+ value: V;
4
+ };
5
+ /** Cheap staleness key for a file's current content; "absent" when missing. */
6
+ export declare function fileStatKey(file: string): string;
7
+ export declare function readMemoized<V>(store: Map<string, MemoEntry<V>>, file: string, statKey: string): V | undefined;
8
+ export declare function writeMemoized<V>(store: Map<string, MemoEntry<V>>, file: string, statKey: string, value: V): void;
@@ -0,0 +1,23 @@
1
+ // Per-process memoization for small config files (cli_performance-v0 R-002):
2
+ // within one invocation a config file is read and parsed at most once, keyed
3
+ // on (mtime, size) so an external write between reads in the same process —
4
+ // a test fixture, another tool — invalidates naturally. Absent files memoize
5
+ // under the "absent" key.
6
+ import { statSync } from "node:fs";
7
+ /** Cheap staleness key for a file's current content; "absent" when missing. */
8
+ export function fileStatKey(file) {
9
+ try {
10
+ const st = statSync(file);
11
+ return `${st.mtimeMs}:${st.size}`;
12
+ }
13
+ catch {
14
+ return "absent";
15
+ }
16
+ }
17
+ export function readMemoized(store, file, statKey) {
18
+ const entry = store.get(file);
19
+ return entry && entry.key === statKey ? entry.value : undefined;
20
+ }
21
+ export function writeMemoized(store, file, statKey, value) {
22
+ store.set(file, { key: statKey, value });
23
+ }