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,364 @@
1
+ import { appendFileSync, existsSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { GateBlock, NotFoundError } from "./errorTaxonomy.js";
3
+ import path from "node:path";
4
+ import { parse as parseYaml, stringify as stringifyYaml } from "./vendorYaml.js";
5
+ import { buildAgreedBudget, estimateLoopBudget, handshakeFloorUsd, hasExternalSources, loadPricing, parseBudget, } from "./loopBudget.js";
6
+ const LOOP_STATES = [
7
+ "draft",
8
+ "ready",
9
+ "active",
10
+ "succeeded",
11
+ "clean_no_op",
12
+ "blocked",
13
+ "approval_required",
14
+ "exhausted",
15
+ "stagnated",
16
+ "retired",
17
+ ];
18
+ function asObject(value, label) {
19
+ if (!value || typeof value !== "object" || Array.isArray(value))
20
+ throw new Error(`${label} must be an object`);
21
+ return value;
22
+ }
23
+ function asArray(value, label) {
24
+ if (!Array.isArray(value))
25
+ throw new Error(`${label} must be an array`);
26
+ return value;
27
+ }
28
+ function requireString(value, label) {
29
+ if (typeof value !== "string" || value.length === 0)
30
+ throw new Error(`${label} must be a nonempty string`);
31
+ return value;
32
+ }
33
+ function stringArray(value, label) {
34
+ return asArray(value, label).map((item, index) => requireString(item, `${label}[${index}]`));
35
+ }
36
+ function requireKeys(value, keys, label) {
37
+ for (const key of keys) {
38
+ if (!(key in value))
39
+ throw new Error(`${label} missing ${key}`);
40
+ }
41
+ }
42
+ function loadTasksDoc(packetDir) {
43
+ const tasksPath = path.join(packetDir, "tasks.yaml");
44
+ if (!existsSync(tasksPath))
45
+ throw new Error("tasks.yaml missing");
46
+ return asObject(parseYaml(readFileSync(tasksPath, "utf8")), "tasks.yaml");
47
+ }
48
+ function taskIds(tasksDoc) {
49
+ return new Set(asArray(tasksDoc.tasks, "tasks.yaml.tasks").map((task, index) => requireString(asObject(task, `tasks.yaml.tasks[${index}]`).id, `tasks.yaml.tasks[${index}].id`)));
50
+ }
51
+ function defaultLoopTask(tasksDoc) {
52
+ const tasks = asArray(tasksDoc.tasks, "tasks.yaml.tasks").map((task, index) => asObject(task, `tasks.yaml.tasks[${index}]`));
53
+ const reconciliationTask = tasks.find((task) => stringArray(task.refs, `task ${String(task.id)} refs`).includes("R-010"));
54
+ const selected = reconciliationTask ?? tasks[0];
55
+ return requireString(selected.id, "selected task id");
56
+ }
57
+ export function renderLoopDesign(packetDir) {
58
+ const tasksDoc = loadTasksDoc(packetDir);
59
+ const specId = requireString(tasksDoc.spec_id, "tasks.yaml.spec_id");
60
+ const taskId = defaultLoopTask(tasksDoc);
61
+ return [
62
+ 'schema_version: "0.1"',
63
+ `spec_id: ${specId}`,
64
+ 'updated: null',
65
+ 'loops:',
66
+ ' - id: L-001',
67
+ ' title: "Reconciliation loop contract"',
68
+ ' status: draft',
69
+ ' owner: product',
70
+ ' refs:',
71
+ ' requirements: [R-010]',
72
+ ` tasks: [${taskId}]`,
73
+ ' events: []',
74
+ ' mode: human-in-loop',
75
+ ' trigger: manual',
76
+ ' goal: Review changed work against agreed tasks without editing canonical packet files.',
77
+ ' lifecycle:',
78
+ ' allowed_states: [draft, ready, active, succeeded, clean_no_op, blocked, approval_required, exhausted, stagnated, retired]',
79
+ ' terminal_states: [succeeded, clean_no_op, blocked, exhausted, stagnated, retired]',
80
+ ' observe:',
81
+ ' sources: [spec.md, tasks.yaml, events.jsonl]',
82
+ ' freshness: read files immediately before each pass',
83
+ ' choose:',
84
+ ' criteria: [highest-risk unmapped change]',
85
+ ' act:',
86
+ ' allowed: [propose one reconciliation finding]',
87
+ ' forbidden:',
88
+ ' - Do not edit canonical packet files without explicit approval',
89
+ ' - Do not import raw private sources',
90
+ ' verify:',
91
+ ' check: "foo asp reconcile <packet-dir> --git-diff"',
92
+ ' method: manual review plus CLI reconciliation',
93
+ ' record:',
94
+ ' event_type: com.adaptivespec.loop.iteration_recorded',
95
+ ' artifact: artifacts/loops/L-001/',
96
+ ' required_fields: [iteration_id, observed_sources, action_taken, verification_result, next_state]',
97
+ ' stop:',
98
+ ' succeeded: all changed work maps to agreed tasks or accepted events',
99
+ ' clean_no_op: no relevant changed work is present',
100
+ ' blocked: approval needed for canonical packet changes',
101
+ ' exhausted: two passes produce no clearer loop contract',
102
+ ' stagnated: a pass produces no new resolvable finding',
103
+ ' ask_user_when:',
104
+ ' - product meaning changes',
105
+ ' - source boundary changes',
106
+ ' - destructive, production, financial, privacy-sensitive, or external-message action would be enabled',
107
+ '',
108
+ ].join("\n");
109
+ }
110
+ export function loadLoopContracts(packetDir) {
111
+ const loopsPath = path.join(packetDir, "loops.yaml");
112
+ if (!existsSync(loopsPath))
113
+ throw new NotFoundError("loops.yaml missing; run foo loop design <packet-dir> > <packet-dir>/loops.yaml", "E_PACKET_NOT_FOUND");
114
+ const tasksDoc = loadTasksDoc(packetDir);
115
+ const specId = requireString(tasksDoc.spec_id, "tasks.yaml.spec_id");
116
+ const ids = taskIds(tasksDoc);
117
+ const doc = asObject(parseYaml(readFileSync(loopsPath, "utf8")), "loops.yaml");
118
+ requireKeys(doc, ["schema_version", "spec_id", "loops"], "loops.yaml");
119
+ if (doc.spec_id !== specId)
120
+ throw new Error("loops.yaml.spec_id must match tasks.yaml.spec_id");
121
+ const loops = asArray(doc.loops, "loops.yaml.loops").map((loop, index) => {
122
+ const loopObject = asObject(loop, `loops.yaml.loops[${index}]`);
123
+ requireKeys(loopObject, ["id", "title", "status", "owner", "refs", "goal", "observe", "choose", "act", "verify", "record", "stop", "ask_user_when"], `loops.yaml.loops[${index}]`);
124
+ const id = requireString(loopObject.id, `loops.yaml.loops[${index}].id`);
125
+ const status = requireString(loopObject.status, `loops.yaml.loops[${index}].status`);
126
+ if (!LOOP_STATES.includes(status))
127
+ throw new Error(`loops.yaml.loops[${index}].status invalid: ${status}`);
128
+ const refs = asObject(loopObject.refs, `loops.yaml.loops[${index}].refs`);
129
+ const tasks = stringArray(refs.tasks, `loops.yaml.loops[${index}].refs.tasks`);
130
+ for (const task of tasks) {
131
+ if (!ids.has(task))
132
+ throw new Error(`loop ${id} references unknown task ${task}`);
133
+ }
134
+ const observe = asObject(loopObject.observe, `loops.yaml.loops[${index}].observe`);
135
+ const record = asObject(loopObject.record, `loops.yaml.loops[${index}].record`);
136
+ return {
137
+ id,
138
+ title: requireString(loopObject.title, `loops.yaml.loops[${index}].title`),
139
+ status,
140
+ owner: requireString(loopObject.owner, `loops.yaml.loops[${index}].owner`),
141
+ refs: {
142
+ requirements: stringArray(refs.requirements, `loops.yaml.loops[${index}].refs.requirements`),
143
+ tasks,
144
+ events: "events" in refs ? stringArray(refs.events, `loops.yaml.loops[${index}].refs.events`) : [],
145
+ },
146
+ goal: requireString(loopObject.goal, `loops.yaml.loops[${index}].goal`),
147
+ observe: {
148
+ sources: stringArray(observe.sources, `loops.yaml.loops[${index}].observe.sources`),
149
+ },
150
+ record: {
151
+ artifact: requireString(record.artifact, `loops.yaml.loops[${index}].record.artifact`),
152
+ },
153
+ ask_user_when: stringArray(loopObject.ask_user_when, `loops.yaml.loops[${index}].ask_user_when`),
154
+ budget: "budget" in loopObject ? parseBudget(loopObject.budget, `loops.yaml.loops[${index}].budget`) : undefined,
155
+ };
156
+ });
157
+ if (loops.length === 0)
158
+ throw new Error("loops.yaml.loops must be a nonempty array");
159
+ return { specId, loops };
160
+ }
161
+ // R-005: an unbudgeted loop is a malformed contract — but enforcement is
162
+ // size-aware (T-004). `--strict-budget` refuses any unbudgeted loop outright.
163
+ // Otherwise foo prices each unbudgeted loop with the cold/structural estimator:
164
+ // a loop under the handshake threshold (FOO_BUDGET_HANDSHAKE_FLOOR, default
165
+ // $0.50) is auto-approved and logged — cheap work keeps its momentum — while a
166
+ // loop at or above the threshold blocks until a human runs the budget handshake.
167
+ // Either way an estimate event is recorded for calibration.
168
+ function emitLoopEstimateEvent(packetDir, loopId, result, meta) {
169
+ const eventsPath = path.join(packetDir, "events.jsonl");
170
+ const id = `evt_loop_budget_estimated_${Date.now()}_${Math.floor(Math.random() * 1e6)}`;
171
+ // UNMEASURABLE MEANS UNKNOWN — here too, not only on the screen.
172
+ //
173
+ // `priced` answers "was pricing.yaml found?", NOT "is the cost knowable?". A loop that
174
+ // reads the web is priced and unknowable at the same time, and this writer only ever asked
175
+ // the first question. So it recorded `expected_usd: 0.11, ceiling_usd: 0.275` on a loop
176
+ // whose own findings, in the same event, said "cost unknown: 5 observation source(s)
177
+ // cannot be sized offline". The ledger asserted a number the estimate had just refused to
178
+ // stand behind.
179
+ //
180
+ // That was already the packet's most-corrected mistake. `foo loop estimate` prints "unknown
181
+ // — this loop reads sources productfoo cannot size", and evt_mo_008 in model-orchestrator-v0 spent
182
+ // a whole event retiring the last fabricated range: "Prior events in this ledger quoting
183
+ // $0.60/$1.50/$0.275 per pass are superseded: the true answer is that productfoo does not know,
184
+ // and now says so." The fix landed on the RENDER path on 2026-07-11 and never reached this
185
+ // one, so the ledger kept accruing exactly the numbers that event retired — including one
186
+ // written three days later, quoting $0.275 again.
187
+ //
188
+ // A screen is read once; a ledger is what a future reader and `foo asp reconcile` treat as
189
+ // fact. Of the two doors, this is the one that had to hold.
190
+ const unknown = result.unmeasurable;
191
+ const summary = unknown
192
+ ? `Estimated loop ${loopId}: cost UNKNOWN — ${result.findings.join("; ") || "this loop reads sources productfoo cannot size offline"}. Treated as at/above the $${meta.floor.toFixed(2)} threshold; handshake required. Authorise with an explicit cap: foo loop estimate <packet-dir> --agree --limit <usd>.`
193
+ : result.priced
194
+ ? `Estimated loop ${loopId}: $${result.usd.expected.toFixed(4)} expected (threshold $${meta.floor.toFixed(2)}); ${meta.autoApproved ? "auto-approved below threshold" : "over threshold, handshake required"}.`
195
+ : `Estimated loop ${loopId}: unpriced (${result.findings.join("; ") || "pricing degraded"}); token-only estimate ${result.tokens.expected} expected — treated as at/above the $${meta.floor.toFixed(2)} threshold, handshake required (fail-closed).`;
196
+ const event = {
197
+ specversion: "0.1",
198
+ id,
199
+ source: "agent://foo/loop-check",
200
+ type: "com.adaptivespec.loop.budget_estimated",
201
+ subject: `loop:${loopId}`,
202
+ time: new Date().toISOString(),
203
+ actor: { type: "agent", id: "foo:loop-check", mode: "human-in-loop" },
204
+ data: {
205
+ summary,
206
+ auto_approved: meta.autoApproved,
207
+ priced: result.priced,
208
+ // Recorded so a reader can tell "productfoo does not know" apart from "foo forgot to write it".
209
+ unmeasurable: unknown,
210
+ findings: result.findings,
211
+ handshake_floor_usd: meta.floor,
212
+ // Omitted entirely when unknown, rather than written as a number nobody stands behind.
213
+ // An absent field cannot be averaged, charted, or quoted back as a prediction.
214
+ ...(unknown
215
+ ? {}
216
+ : { expected_usd: result.usd.expected, ceiling_usd: result.usd.ceiling, expected_tokens: result.tokens.expected }),
217
+ basis: result.basis,
218
+ confidence: result.confidence,
219
+ priced_with: result.priced_with,
220
+ },
221
+ extensions: {},
222
+ };
223
+ appendFileSync(eventsPath, `${JSON.stringify(event)}\n`);
224
+ return id;
225
+ }
226
+ /** Loop states that can act, and so spend. B4's budget handshake is due for
227
+ * these; a loop in any other state is a signal (AGENTS.md B4). */
228
+ export const ARMED_LOOP_STATES = new Set(["ready", "active"]);
229
+ export function checkLoopContracts(root, packetDir, options = {}) {
230
+ // Most packets declare no loops at all, and that is the healthy default — B4 governs
231
+ // packets that HAVE loops. Checking one that has none used to throw a bare Error, which
232
+ // classifies as `command_error`: the one class that pages a human and files a Bug Capsule.
233
+ // So a stranger's first packet reported a defect in foo for being perfectly ordinary (#702).
234
+ // Nothing to check is not a failure; say so and exit 0.
235
+ if (!existsSync(path.join(packetDir, "loops.yaml"))) {
236
+ return "loop contracts ok (0) — this packet declares no loops, so there is nothing to check.";
237
+ }
238
+ const { loops } = loadLoopContracts(packetDir);
239
+ const allUnbudgeted = loops.filter((loop) => !loop.budget?.agreed);
240
+ let base = `loop contracts ok (${loops.length})`;
241
+ if (allUnbudgeted.length === 0)
242
+ return base;
243
+ // Strict mode: any unbudgeted loop is refused, regardless of size.
244
+ if (options.strictBudget) {
245
+ // Strict means every loop, armed or not (AGENTS.md B4 --strict-budget).
246
+ const ids = allUnbudgeted.map((loop) => loop.id).join(", ");
247
+ // B4 refusing an unbudgeted loop is the product WORKING, not breaking. It exits nonzero
248
+ // because it stopped you on purpose — so it is a gate_block, and it never pages anyone.
249
+ // (It was being recorded as a crash, which is exactly the false alarm this taxonomy exists
250
+ // to kill: a pager that fires when the safety rules work correctly gets muted immediately.)
251
+ throw new GateBlock(`loop(s) without an agreed budget: ${ids} — run foo loop estimate <packet-dir> --agree`, "E_GATE_B4_BUDGET");
252
+ }
253
+ // #906 / AGENTS.md B4: "a draft unbudgeted loop is a signal; a ready/active
254
+ // armed loop without budget blocks." A draft cannot act, so it cannot spend:
255
+ // report it and move on — no estimate, no event, no auto-approved budget
256
+ // written into tracked packet files. Arming it is what makes the handshake due.
257
+ const drafts = allUnbudgeted.filter((loop) => !ARMED_LOOP_STATES.has(loop.status));
258
+ const unbudgeted = allUnbudgeted.filter((loop) => ARMED_LOOP_STATES.has(loop.status));
259
+ if (drafts.length > 0) {
260
+ base += `; signal: ${drafts.length} unarmed loop(s) without an agreed budget (${drafts.map((loop) => `${loop.id} ${loop.status}`).join(", ")}) — budget before arming with foo loop estimate <packet-dir> --agree`;
261
+ }
262
+ if (unbudgeted.length === 0)
263
+ return base;
264
+ const floor = handshakeFloorUsd();
265
+ const pricing = loadPricing(root);
266
+ const autoApproved = [];
267
+ const overThreshold = [];
268
+ const degradedFindings = new Set();
269
+ for (const loop of unbudgeted) {
270
+ const result = estimateLoopBudget({ packetDir, sources: loop.observe.sources, pricing, unit: "usd", budget: loop.budget });
271
+ // B4 fail-closed (model-roster-data-v0 R-002): an unpriced estimate (missing
272
+ // pricing.yaml or unknown model) cannot prove the loop is below the floor, so
273
+ // it is treated as at/above it — auto-approval is a convenience that requires
274
+ // priced data; the handshake is never waived by degraded pricing.
275
+ //
276
+ // Same fail-closed rule for UNMEASURABLE sources: a loop that observes the web
277
+ // cannot be sized offline. Such a source used to measure 0 tokens, so a
278
+ // scheduled research loop priced itself at ~$0, fell under the floor, and
279
+ // auto-approved — bypassing the handshake for exactly the loops whose cost is
280
+ // least knowable. An estimate resting on an unmeasurable source is a floor, not
281
+ // a measurement, and can never prove the loop is cheap. Unknown cost => a human
282
+ // decides.
283
+ const unmeasurable = hasExternalSources(result.measured);
284
+ const below = result.priced && !unmeasurable && result.usd.expected < floor;
285
+ emitLoopEstimateEvent(packetDir, loop.id, result, { autoApproved: below, floor });
286
+ if (below) {
287
+ // Auto-approve: write an agreed budget so the cheap loop runs and is not
288
+ // re-estimated next time. Logged, not blocked (C-008).
289
+ const at = new Date().toISOString();
290
+ writeAgreedBudget(packetDir, loop.id, buildAgreedBudget(result, { by: "foo:auto-approve", at }));
291
+ autoApproved.push(loop.id);
292
+ }
293
+ else {
294
+ overThreshold.push(loop.id);
295
+ if (!result.priced)
296
+ for (const finding of result.findings)
297
+ degradedFindings.add(finding);
298
+ if (unmeasurable) {
299
+ const external = result.measured.filter((m) => m.external).map((m) => m.source);
300
+ degradedFindings.add(`loop observes ${external.length} source(s) that cannot be sized offline (${external.slice(0, 3).join("; ")}${external.length > 3 ? "; …" : ""}) — priced at a conservative floor, so the estimate cannot prove the loop is below the threshold`);
301
+ }
302
+ }
303
+ }
304
+ // A loop at or above the threshold is malformed until a human prices it (C-007).
305
+ if (overThreshold.length > 0) {
306
+ const degradedNote = degradedFindings.size > 0
307
+ ? ` [degraded: ${[...degradedFindings].join("; ")} — an unpriced loop cannot be auto-approved and is treated as at/above the floor]`
308
+ : "";
309
+ // B4 stopping an armed loop is the gate working, not a crash (see the
310
+ // strict path above): a GateBlock, never a paging command_error.
311
+ throw new GateBlock(`loop(s) at or above the $${floor.toFixed(2)} handshake threshold without an agreed budget: ${overThreshold.join(", ")} — run foo loop estimate <packet-dir> --agree${degradedNote}`, "E_GATE_B4_BUDGET");
312
+ }
313
+ return `${base}; ${autoApproved.length} auto-approved below the $${floor.toFixed(2)} threshold: ${autoApproved.join(", ")} (estimate logged)`;
314
+ }
315
+ function nextAction(status) {
316
+ if (status === "blocked" || status === "approval_required")
317
+ return "ask";
318
+ if (["succeeded", "clean_no_op", "exhausted", "stagnated", "retired"].includes(status))
319
+ return "stop";
320
+ return "continue";
321
+ }
322
+ export function renderLoopStatus(packetDir) {
323
+ const { loops } = loadLoopContracts(packetDir);
324
+ return loops.map((loop) => ({
325
+ loop: loop.id,
326
+ title: loop.title,
327
+ owner: loop.owner,
328
+ state: loop.status,
329
+ why_it_exists: loop.goal,
330
+ current_evidence: {
331
+ sources: loop.observe.sources,
332
+ last_events: loop.refs.events,
333
+ },
334
+ next_action: nextAction(loop.status),
335
+ approval_boundary: loop.ask_user_when,
336
+ trail: loop.record.artifact,
337
+ // Surface budget only when authored, so status cards for pre-budget loops
338
+ // are unchanged.
339
+ ...(loop.budget
340
+ ? {
341
+ budget: {
342
+ unit: loop.budget.unit,
343
+ limit: loop.budget.limit,
344
+ agreed: loop.budget.agreed ?? null,
345
+ },
346
+ }
347
+ : {}),
348
+ }));
349
+ }
350
+ // Write an agreed budget back into a loop's entry in loops.yaml. The file is
351
+ // re-serialized from its parsed form; callers own when this runs (the
352
+ // dry-run-before-writes handshake in foo loop estimate --agree).
353
+ export function writeAgreedBudget(packetDir, loopId, budget) {
354
+ const loopsPath = path.join(packetDir, "loops.yaml");
355
+ if (!existsSync(loopsPath))
356
+ throw new NotFoundError("loops.yaml missing", "E_PACKET_NOT_FOUND");
357
+ const doc = asObject(parseYaml(readFileSync(loopsPath, "utf8")), "loops.yaml");
358
+ const loops = asArray(doc.loops, "loops.yaml.loops");
359
+ const target = loops.find((loop) => asObject(loop, "loops.yaml.loops[]").id === loopId);
360
+ if (!target)
361
+ throw new NotFoundError(`loop ${loopId} not found in loops.yaml`, "E_PACKET_NOT_FOUND");
362
+ target.budget = budget;
363
+ writeFileSync(loopsPath, stringifyYaml(doc));
364
+ }
@@ -0,0 +1 @@
1
+ export declare function machineStateDir(): string;
@@ -0,0 +1,9 @@
1
+ import { homedir } from "node:os";
2
+ import path from "node:path";
3
+ // Machine-scoped state (event ledger, telemetry config, self-check scan cache)
4
+ // lives under the user's home, never the project dir — foo used to write
5
+ // telemetry INTO the user's git repo and nothing gitignored it (see the ledger
6
+ // history in src/commands/agent.ts). FOO_STATE_DIR overrides for tests.
7
+ export function machineStateDir() {
8
+ return process.env.FOO_STATE_DIR?.trim() || path.join(homedir(), ".foo");
9
+ }
@@ -0,0 +1,93 @@
1
+ export type FetchLike = typeof globalThis.fetch;
2
+ export type NotionRuntimeErrorCode = "not_connected" | "auth_expired" | "access_denied" | "provider_failure" | "network" | "provider_timeout" | "content_too_large" | "budget_exhausted";
3
+ export declare class NotionRuntimeError extends Error {
4
+ readonly code: NotionRuntimeErrorCode;
5
+ constructor(code: NotionRuntimeErrorCode, message: string);
6
+ }
7
+ export type NotionConnection = {
8
+ connection_ref: string;
9
+ broker: "nango" | "direct";
10
+ credential: {
11
+ type: "oauth2";
12
+ access_token: string;
13
+ };
14
+ };
15
+ export declare const NOTION_POLICY: {
16
+ readonly policy_version: "notion-docs-0.1";
17
+ readonly max_response_bytes: number;
18
+ readonly fetch_timeout_ms: 90000;
19
+ readonly max_model_input_tokens: 100000;
20
+ readonly max_list_records: 50;
21
+ readonly min_request_interval_ms: 350;
22
+ };
23
+ export type NotionConnectionEnv = Record<string, string | undefined>;
24
+ export declare function notionConnectionConfigured(env: NotionConnectionEnv): boolean;
25
+ export declare function notionCredentialBroker(env: NotionConnectionEnv): "nango" | "direct" | null;
26
+ /**
27
+ * Resolve the company's Notion credential. Nango is the broker: it holds the
28
+ * OAuth credential, refreshes it, and is where an administrator revokes it.
29
+ * When Nango is not configured, an administrator-issued integration token set
30
+ * directly in this runtime's environment (FOO_NOTION_API_TOKEN) is accepted as
31
+ * the direct fallback — the same read-only surface, minus the central refresh
32
+ * and revoke story, and reported as `direct` so it is never mistaken for the
33
+ * company connection. Either way productfoo receives the credential for one operation
34
+ * and never persists or prints it.
35
+ */
36
+ export declare function resolveNotionConnection(input: {
37
+ env: NotionConnectionEnv;
38
+ fetchImpl: FetchLike;
39
+ }): Promise<NotionConnection>;
40
+ export type NotionPageMeta = {
41
+ id: string;
42
+ title?: string;
43
+ last_edited_time?: string;
44
+ url?: string;
45
+ };
46
+ export type NotionBlock = {
47
+ text?: string;
48
+ has_children?: boolean;
49
+ };
50
+ type NotionClientOptions = {
51
+ fetchImpl: FetchLike;
52
+ baseUrl?: string;
53
+ sleep?: (ms: number) => Promise<void>;
54
+ now?: () => number;
55
+ };
56
+ /**
57
+ * Minimal read-only Notion REST client. Only the three documented read
58
+ * operations are reachable — page metadata, one page's block content, and a
59
+ * bounded database query. Any other method or path routes through the single
60
+ * write-refusal choke point (R-007), and the workspace-wide search endpoint is
61
+ * absent from the allow-list entirely (R-004).
62
+ */
63
+ export declare class NotionClient {
64
+ private readonly credential;
65
+ private readonly options;
66
+ readonly requests: {
67
+ page: number;
68
+ content: number;
69
+ database: number;
70
+ };
71
+ private lastRequestAt;
72
+ private readonly baseUrl;
73
+ private readonly sleep;
74
+ private readonly now;
75
+ constructor(credential: NotionConnection["credential"], options: NotionClientOptions);
76
+ private request;
77
+ /** One page's metadata — title, last-edited time, canonical link. No content. */
78
+ page(pageId: string): Promise<NotionPageMeta>;
79
+ /**
80
+ * Exactly one page's content (R-005): the page's block children flattened to
81
+ * plain text, read once, bounded by the byte ceiling. The caller is the
82
+ * proof-gated summarize flow; no other path may call this.
83
+ */
84
+ pageContent(pageId: string): Promise<string>;
85
+ /** Bounded metadata listing for one approved database selection. No content. */
86
+ queryDatabase(databaseId: string): Promise<Array<{
87
+ id: string;
88
+ title?: string;
89
+ last_edited_time?: string;
90
+ url?: string;
91
+ }>>;
92
+ }
93
+ export {};