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,294 @@
1
+ // alpha-distribution-telemetry-v0 (T-009 / T-010 / T-011) — satisfaction signal,
2
+ // friction-triggered error feedback, and the consented eval-capture lane.
3
+ //
4
+ // D-011: reuse the existing telemetry substrate — the append-only
5
+ // `.foo/agent-events.jsonl` ledger, the pseudonymous tester id, and the
6
+ // enabled/opt-out gate — never a parallel ledger. Existing ledger readers
7
+ // filter by `event_type`, so the new `feedback` events are additive and ignored
8
+ // by `foo agent logs`.
9
+ //
10
+ // D-010: every default signal is CONTENT-FREE. Solicited free-text is
11
+ // redacted-before-store (same engine as B1). The ONLY place raw (idea, record)
12
+ // content is retained is the explicit opt-in eval lane (T-011) — encrypted at
13
+ // rest, TTL'd, and tester-deletable. Not opted in ⇒ nothing beyond the envelope.
14
+ import { appendFileSync, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs";
15
+ import { readJson } from "./jsonFile.js";
16
+ import path from "node:path";
17
+ import { createCipheriv, createDecipheriv, randomBytes } from "node:crypto";
18
+ import { agentLogPath, nextAgentEventId, readAgentTelemetryConfig, resolveTesterId } from "./commands/agent.js";
19
+ import { redactText } from "./redactEngine.js";
20
+ // Gate: opted-in config AND not DO_NOT_TRACK — the same posture as recordCliUsage,
21
+ // so feedback honors the exact opt-out testers already have (OQ-4 / D-010).
22
+ export function feedbackEnabled(root, env = process.env) {
23
+ if (env.DO_NOT_TRACK === "1" || env.DO_NOT_TRACK === "true")
24
+ return false;
25
+ return readAgentTelemetryConfig(root).config.enabled;
26
+ }
27
+ // Redact a tester-authored note before it is ever stored (D-010). Returns the
28
+ // redacted text and the count of spans removed — never the secret value.
29
+ export function redactNote(note) {
30
+ const result = redactText(note, { threshold: "medium" });
31
+ return { text: result.redactedText, redactions: result.receipt.redactions };
32
+ }
33
+ // Append a content-free feedback event to the shared ledger. Fire-and-forget:
34
+ // like recordCliUsage, a failure here never alters CLI behavior.
35
+ export function recordFeedback(root, event, env = process.env) {
36
+ try {
37
+ if (!feedbackEnabled(root, env))
38
+ return null;
39
+ const testerId = resolveTesterId(root);
40
+ const full = {
41
+ schema_version: "0.1",
42
+ event_type: "feedback",
43
+ id: nextAgentEventId(),
44
+ timestamp: new Date().toISOString(),
45
+ ...event,
46
+ ...(testerId ? { tester_id: testerId } : {}),
47
+ };
48
+ const logPath = agentLogPath(root);
49
+ mkdirSync(path.dirname(logPath), { recursive: true });
50
+ appendFileSync(logPath, `${JSON.stringify(full)}\n`);
51
+ return full;
52
+ }
53
+ catch {
54
+ return null;
55
+ }
56
+ }
57
+ // Revealed preference (T-009): behavioral, zero-friction, no content. The
58
+ // strongest satisfaction signal — what the tester DID with the output.
59
+ export function recordRevealed(root, kind, ctx = {}, env = process.env) {
60
+ return recordFeedback(root, { signal: "revealed", kind, ...ctx }, env);
61
+ }
62
+ // Sampled solicited micro-poll (T-009): one keystroke → a small integer rating.
63
+ export function recordRating(root, rating, ctx = {}, env = process.env) {
64
+ return recordFeedback(root, { signal: "solicited", kind: "rating", rating, ...ctx }, env);
65
+ }
66
+ // Spontaneous `foo feedback "..."` (T-009): tester-authored product feedback,
67
+ // redacted-before-store. The text is the tester's, about the product — never
68
+ // their idea/prompt — but it is scrubbed for secrets all the same (B1).
69
+ export function recordSpontaneous(root, note, env = process.env) {
70
+ const { text, redactions } = redactNote(note);
71
+ return recordFeedback(root, { signal: "solicited", kind: "spontaneous", note: text, redactions }, env);
72
+ }
73
+ // Revealed preference from an ideate record (T-009): the strongest signal is
74
+ // whether the human kept the AI's recommendation or overrode it. Content-free —
75
+ // it compares the record's `recommendation:` and `pick:` fields and returns only
76
+ // the CLASS ("override" | "kept"), never either value. "undecided" = no pick yet;
77
+ // null = decided but nothing to compare against.
78
+ export function classifyDecision(recordText) {
79
+ const grab = (re) => recordText.match(re)?.[1] ?? null;
80
+ const norm = (v) => {
81
+ if (v == null)
82
+ return null;
83
+ const t = v.trim().replace(/^["']|["']$/g, "").trim();
84
+ return t === "" || t === "null" ? null : t;
85
+ };
86
+ const rec = norm(grab(/^recommendation:\s*(.+)$/m));
87
+ const pick = norm(grab(/^pick:\s*(.+)$/m));
88
+ if (pick == null)
89
+ return "undecided";
90
+ if (rec == null)
91
+ return null;
92
+ return rec === pick ? "kept" : "override";
93
+ }
94
+ // Fire-and-forget instrumentation for `foo ideate check`: read the record,
95
+ // classify the decision, and record the content-free revealed event. Never
96
+ // throws, never alters the caller's exit code (mirrors recordCliUsage).
97
+ export function recordIdeateDecision(root, recordPath, env = process.env) {
98
+ try {
99
+ if (!feedbackEnabled(root, env))
100
+ return null;
101
+ const full = path.resolve(root, recordPath);
102
+ if (!existsSync(full))
103
+ return null;
104
+ const kind = classifyDecision(readFileSync(full, "utf8"));
105
+ if (kind === "override" || kind === "kept") {
106
+ recordRevealed(root, kind, { domain: "ideate", command: "ideate check" }, env);
107
+ return kind;
108
+ }
109
+ return null;
110
+ }
111
+ catch {
112
+ return null;
113
+ }
114
+ }
115
+ // --- friction-triggered feedback (T-010) -------------------------------------
116
+ // Error classes that are transient / auto-recovered — never worth interrupting
117
+ // a tester over. A blip that recovers is not a satisfaction event.
118
+ export const TRANSIENT_ERROR_CLASSES = new Set(["offline", "network", "io_error", "none"]);
119
+ // Decide whether to interrupt the tester after an error. Only on a real
120
+ // (non-transient) failure, and only a sampled fraction of the time — over-
121
+ // prompting trains reflexive dismissal and destroys the signal (D-012).
122
+ export function shouldPromptOnError(errorClass, opts = {}) {
123
+ if (TRANSIENT_ERROR_CLASSES.has(errorClass))
124
+ return false;
125
+ const rate = opts.sampleRate ?? 0.5;
126
+ const draw = (opts.sampler ?? Math.random)();
127
+ return draw < rate;
128
+ }
129
+ export const ERROR_REASON_CODES = ["too_slow", "wrong", "crashed", "other"];
130
+ // Record the tester's answer to "what happened?". The structured reason is the
131
+ // analyzable label (D-012); an optional free-text note (on "other") is redacted
132
+ // before it is stored. The content-free cli_usage error event fires separately
133
+ // and unconditionally (recordCliUsage) — this only adds the human's intent.
134
+ export function recordErrorFeedback(root, input, env = process.env) {
135
+ let note;
136
+ let redactions;
137
+ if (input.note && input.note.trim()) {
138
+ const r = redactNote(input.note);
139
+ note = r.text;
140
+ redactions = r.redactions;
141
+ }
142
+ return recordFeedback(root, {
143
+ signal: "friction",
144
+ kind: "error",
145
+ reason_code: input.reason_code,
146
+ ...(input.error_class ? { error_class: input.error_class } : {}),
147
+ ...(input.domain ? { domain: input.domain } : {}),
148
+ ...(input.command ? { command: input.command } : {}),
149
+ ...(note !== undefined ? { note, redactions } : {}),
150
+ }, env);
151
+ }
152
+ // The one-keystroke prompt the CLI renders after a real error. Kept as a pure
153
+ // string so the copy is testable; the TTY read is a thin wrapper in the CLI.
154
+ export function renderErrorPrompt() {
155
+ return "That didn't work. What happened? [1] too slow [2] output wrong [3] crashed [4] other (enter to skip)";
156
+ }
157
+ export function reasonForKey(key) {
158
+ return { "1": "too_slow", "2": "wrong", "3": "crashed", "4": "other" }[key.trim()] ?? null;
159
+ }
160
+ // Feedback is durably recorded in the local ledger without network access.
161
+ export function feedbackIsOfflineDurable() {
162
+ return true;
163
+ }
164
+ // --- consented eval-capture lane (T-011) -------------------------------------
165
+ // The "separate consent gate" R-005/D-004 deferred, made concrete. Opt-in only.
166
+ // Retains the (idea, record, label) triple for consenting testers — redacted,
167
+ // AES-256-GCM encrypted at rest, TTL'd, and tester-visible/deletable.
168
+ const EVAL_DIR = ".foo/eval-capture";
169
+ const CONSENT_FILE = ".foo/eval-consent.json";
170
+ function evalDir(root) {
171
+ return path.join(root, EVAL_DIR);
172
+ }
173
+ function consentPath(root) {
174
+ return path.join(root, CONSENT_FILE);
175
+ }
176
+ export function readEvalConsent(root) {
177
+ const p = consentPath(root);
178
+ if (!existsSync(p))
179
+ return false; // opt-IN: default is no capture
180
+ try {
181
+ return readJson(p).opted_in === true;
182
+ }
183
+ catch {
184
+ return false;
185
+ }
186
+ }
187
+ export function setEvalConsent(root, optedIn) {
188
+ mkdirSync(path.dirname(consentPath(root)), { recursive: true });
189
+ writeFileSync(consentPath(root), `${JSON.stringify({ schema_version: "0.1", opted_in: optedIn, updated: new Date().toISOString() }, null, 2)}\n`);
190
+ }
191
+ // Local at-rest key: 32 random bytes, mode 0600, gitignored under .foo. Genuine
192
+ // encryption for the local skeleton (the hosted lane would use a managed key).
193
+ function evalKey(root) {
194
+ const keyPath = path.join(evalDir(root), ".key");
195
+ if (existsSync(keyPath))
196
+ return Buffer.from(readFileSync(keyPath, "utf8"), "hex");
197
+ mkdirSync(evalDir(root), { recursive: true });
198
+ const key = randomBytes(32);
199
+ writeFileSync(keyPath, key.toString("hex"), { mode: 0o600 });
200
+ return key;
201
+ }
202
+ const DEFAULT_TTL_MS = 30 * 24 * 60 * 60 * 1000; // 30 days
203
+ // Capture a run for eval — ONLY if the tester opted in. Idea + record are
204
+ // redacted (B1) then encrypted at rest. Returns the capture id, or null when
205
+ // not consented (nothing is written). The label is the satisfaction signal
206
+ // (e.g. "bad", "override") that makes this a curated example, not noise.
207
+ export function captureForEval(root, triple, opts = {}) {
208
+ if (!readEvalConsent(root))
209
+ return null; // not opted in ⇒ retain nothing
210
+ const idea = redactNote(triple.idea);
211
+ const record = redactNote(triple.record);
212
+ const now = opts.now ?? Date.now();
213
+ const id = `ev_${now.toString(36)}_${randomBytes(4).toString("hex")}`;
214
+ const payload = JSON.stringify({ idea: idea.text, record: record.text, label: triple.label });
215
+ const key = evalKey(root);
216
+ const iv = randomBytes(12);
217
+ const cipher = createCipheriv("aes-256-gcm", key, iv);
218
+ const enc = Buffer.concat([cipher.update(payload, "utf8"), cipher.final()]);
219
+ const tag = cipher.getAuthTag();
220
+ const meta = {
221
+ id,
222
+ captured_at: new Date(now).toISOString(),
223
+ expires_at: new Date(now + (opts.ttlMs ?? DEFAULT_TTL_MS)).toISOString(),
224
+ label: triple.label,
225
+ redactions: idea.redactions + record.redactions,
226
+ };
227
+ mkdirSync(evalDir(root), { recursive: true });
228
+ writeFileSync(path.join(evalDir(root), `${id}.enc`), JSON.stringify({ meta, iv: iv.toString("hex"), tag: tag.toString("hex"), data: enc.toString("hex") }));
229
+ return id;
230
+ }
231
+ // Tester-visible: list metadata only (never decrypts). This is the "show me
232
+ // what's retained" surface the consent story requires.
233
+ export function listEvalCaptures(root) {
234
+ const dir = evalDir(root);
235
+ if (!existsSync(dir))
236
+ return [];
237
+ const out = [];
238
+ for (const f of readdirSync(dir)) {
239
+ if (!f.endsWith(".enc"))
240
+ continue;
241
+ try {
242
+ out.push(readJson(path.join(dir, f)).meta);
243
+ }
244
+ catch {
245
+ continue;
246
+ }
247
+ }
248
+ return out.sort((a, b) => a.captured_at.localeCompare(b.captured_at));
249
+ }
250
+ // Tester-deletable: forget one capture, or all of them.
251
+ export function deleteEvalCapture(root, id) {
252
+ const p = path.join(evalDir(root), `${id}.enc`);
253
+ if (!existsSync(p))
254
+ return false;
255
+ rmSync(p);
256
+ return true;
257
+ }
258
+ export function forgetAllEvalCaptures(root) {
259
+ const before = listEvalCaptures(root);
260
+ for (const m of before)
261
+ deleteEvalCapture(root, m.id);
262
+ return before.length;
263
+ }
264
+ // TTL enforcement: drop expired captures. The maintainer (or a cron) calls this;
265
+ // retention is a promise, so it must be mechanical, not aspirational.
266
+ export function pruneExpiredEvalCaptures(root, now = Date.now()) {
267
+ let pruned = 0;
268
+ for (const m of listEvalCaptures(root)) {
269
+ if (new Date(m.expires_at).getTime() <= now) {
270
+ if (deleteEvalCapture(root, m.id))
271
+ pruned += 1;
272
+ }
273
+ }
274
+ return pruned;
275
+ }
276
+ // Decrypt one capture — the eval-set builder's read path (maintainer-side, with
277
+ // the local key). Returns null if expired, tampered, or missing.
278
+ export function readEvalCapture(root, id, now = Date.now()) {
279
+ const p = path.join(evalDir(root), `${id}.enc`);
280
+ if (!existsSync(p))
281
+ return null;
282
+ try {
283
+ const box = readJson(p);
284
+ if (new Date(box.meta.expires_at).getTime() <= now)
285
+ return null;
286
+ const decipher = createDecipheriv("aes-256-gcm", evalKey(root), Buffer.from(box.iv, "hex"));
287
+ decipher.setAuthTag(Buffer.from(box.tag, "hex"));
288
+ const dec = Buffer.concat([decipher.update(Buffer.from(box.data, "hex")), decipher.final()]).toString("utf8");
289
+ return JSON.parse(dec);
290
+ }
291
+ catch {
292
+ return null;
293
+ }
294
+ }
@@ -0,0 +1,106 @@
1
+ export type FetchLike = typeof globalThis.fetch;
2
+ export type FirefliesRuntimeErrorCode = "not_connected" | "auth_expired" | "access_denied" | "provider_failure" | "network" | "provider_timeout" | "transcript_too_large" | "budget_exhausted";
3
+ export declare class FirefliesRuntimeError extends Error {
4
+ readonly code: FirefliesRuntimeErrorCode;
5
+ constructor(code: FirefliesRuntimeErrorCode, message: string);
6
+ }
7
+ export declare const FIREFLIES_POLICY: {
8
+ readonly policy_version: "fireflies-local-worker-0.1";
9
+ readonly max_response_bytes: number;
10
+ readonly fetch_timeout_ms: 90000;
11
+ readonly max_model_input_tokens: 100000;
12
+ readonly max_list_pages: 5;
13
+ readonly min_request_interval_ms: 350;
14
+ };
15
+ export type FirefliesConnectionEnv = Record<string, string | undefined>;
16
+ export type FirefliesConnection = {
17
+ connection_ref: string;
18
+ broker: "direct";
19
+ credential: {
20
+ type: "key";
21
+ api_key: string;
22
+ };
23
+ transcript_access: "granted" | "unknown";
24
+ };
25
+ export declare function firefliesConnectionConfigured(env: FirefliesConnectionEnv): boolean;
26
+ export declare function firefliesCredentialBroker(env: FirefliesConnectionEnv): "direct" | null;
27
+ /**
28
+ * Resolve the user's Fireflies connection from the environment. No network, no
29
+ * broker: a direct read of FOO_FIREFLIES_API_KEY for one command. The key is
30
+ * never logged; the connection_ref is a stable hash of it so reports can name
31
+ * the connection without exposing it.
32
+ */
33
+ export declare function resolveFirefliesConnection(input: {
34
+ env: FirefliesConnectionEnv;
35
+ }): FirefliesConnection;
36
+ export type FirefliesViewer = {
37
+ user_id?: string;
38
+ email?: string;
39
+ };
40
+ export type FirefliesListedTranscript = {
41
+ id: string;
42
+ title?: string;
43
+ started_at?: string;
44
+ ended?: string;
45
+ status?: string;
46
+ participants?: Array<{
47
+ display_name?: string;
48
+ email?: string;
49
+ }>;
50
+ };
51
+ export type FirefliesTranscript = {
52
+ title?: string;
53
+ speakers?: Array<{
54
+ name?: string;
55
+ }>;
56
+ sentences?: Array<{
57
+ text?: string;
58
+ start_date?: string;
59
+ end_date?: string;
60
+ speaker_id?: string;
61
+ }>;
62
+ };
63
+ type FirefliesClientOptions = {
64
+ fetchImpl: FetchLike;
65
+ baseUrl?: string;
66
+ sleep?: (ms: number) => Promise<void>;
67
+ now?: () => number;
68
+ };
69
+ /**
70
+ * Minimal read-only Fireflies GraphQL client. The single request() function is
71
+ * the write-refusal choke point (R-009): GraphQL speaks over POST, so a
72
+ * mutation is refused by inspecting the query text — the only read operations
73
+ * reachable are the three query constants above.
74
+ */
75
+ export declare class FirefliesClient {
76
+ private readonly credential;
77
+ private readonly options;
78
+ readonly requests: {
79
+ viewer: number;
80
+ list: number;
81
+ transcript: number;
82
+ };
83
+ private lastRequestAt;
84
+ private readonly baseUrl;
85
+ private readonly sleep;
86
+ private readonly now;
87
+ constructor(credential: FirefliesConnection["credential"], options: FirefliesClientOptions);
88
+ private request;
89
+ /** Identity probe for readiness (R-005): the connection answers for one user. The result is never printed. */
90
+ probe(): Promise<FirefliesViewer>;
91
+ /** Bounded metadata listing: one time window, a page ceiling, no content fields requested. */
92
+ listTranscripts(window: {
93
+ from: string;
94
+ to: string;
95
+ }): Promise<{
96
+ transcripts: FirefliesListedTranscript[];
97
+ pages: number;
98
+ truncated: boolean;
99
+ }>;
100
+ /**
101
+ * Exactly one transcript's content (R-007). A fixture observes that the
102
+ * request carries a single well-formed identifier and nothing else.
103
+ */
104
+ transcript(id: string): Promise<FirefliesTranscript>;
105
+ }
106
+ export {};
@@ -0,0 +1,258 @@
1
+ // Fireflies direct-key client (fireflies-discovery-connector-v0, local worker
2
+ // mode, D-001).
3
+ //
4
+ // There is no broker: the credential is the user's own Fireflies API key (D-002
5
+ // granola rule), read from this runtime's environment for one command, held in
6
+ // process memory, never persisted or printed — an opaque `connection_ref` (a
7
+ // hash of the key) stands in for it on every report. This is the structural
8
+ // difference from gongNango (R-004: no Nango OAuth for this source): the broker
9
+ // type is `"direct" | null`, so a nango-brokered Fireflies connection is not
10
+ // even expressible here.
11
+ //
12
+ // Everything is content-free on every surface productfoo owns: errors carry a typed
13
+ // code plus a bounded message that never embeds a provider response or key
14
+ // material, responses are read under a byte ceiling, and the only HTTP paths
15
+ // are the read queries below — any GraphQL mutation routes through the single
16
+ // write-refusal choke point (R-009) so the refusal is testable, not scattered.
17
+ //
18
+ // Every provider shape below — the GraphQL endpoint, the auth header scheme,
19
+ // the field names, offset pagination — is a BELIEF owned by the packet's
20
+ // feasibility task (T-001, still open), pinned by fixtures in
21
+ // test/discoveryFireflies.test.ts. Nothing here has ever spoken to the live
22
+ // Fireflies API; the dogfood run (T-008) is what would promote these beliefs,
23
+ // with receipts.
24
+ import { createHash } from "node:crypto";
25
+ import { refuseSourceWrite } from "./sourceIngress.js";
26
+ export class FirefliesRuntimeError extends Error {
27
+ code;
28
+ constructor(code, message) {
29
+ super(message);
30
+ this.code = code;
31
+ this.name = "FirefliesRuntimeError";
32
+ }
33
+ }
34
+ // Versioned policy fields (R-006): hard ceilings the worker enforces and
35
+ // reports, kept identical to GONG_POLICY's values so a later divergence is an
36
+ // explicit decision — test/discoveryFireflies.test.ts pins the equality.
37
+ export const FIREFLIES_POLICY = {
38
+ policy_version: "fireflies-local-worker-0.1",
39
+ max_response_bytes: 8 * 1024 * 1024,
40
+ fetch_timeout_ms: 90_000,
41
+ max_model_input_tokens: 100_000,
42
+ max_list_pages: 5,
43
+ min_request_interval_ms: 350,
44
+ };
45
+ const DEFAULT_FIREFLIES_BASE = "https://api.fireflies.ai";
46
+ export function firefliesConnectionConfigured(env) {
47
+ return Boolean(env.FOO_FIREFLIES_API_KEY?.trim());
48
+ }
49
+ export function firefliesCredentialBroker(env) {
50
+ return firefliesConnectionConfigured(env) ? "direct" : null;
51
+ }
52
+ /**
53
+ * Resolve the user's Fireflies connection from the environment. No network, no
54
+ * broker: a direct read of FOO_FIREFLIES_API_KEY for one command. The key is
55
+ * never logged; the connection_ref is a stable hash of it so reports can name
56
+ * the connection without exposing it.
57
+ */
58
+ export function resolveFirefliesConnection(input) {
59
+ const api_key = input.env.FOO_FIREFLIES_API_KEY?.trim();
60
+ if (!api_key) {
61
+ throw new FirefliesRuntimeError("not_connected", "Fireflies is not connected: set FOO_FIREFLIES_API_KEY to your own Fireflies API key");
62
+ }
63
+ return {
64
+ connection_ref: `fireflies:direct:${createHash("sha256").update(api_key).digest("hex").slice(0, 16)}`,
65
+ broker: "direct",
66
+ credential: { type: "key", api_key },
67
+ transcript_access: "unknown",
68
+ };
69
+ }
70
+ async function fetchWithTimeout(fetchImpl, url, init, timeoutMs) {
71
+ const controller = new AbortController();
72
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
73
+ try {
74
+ return await fetchImpl(url, { ...init, signal: controller.signal });
75
+ }
76
+ catch (error) {
77
+ if (controller.signal.aborted)
78
+ throw new FirefliesRuntimeError("provider_timeout", "the provider did not answer within the fetch ceiling");
79
+ throw new FirefliesRuntimeError("network", `network failure reaching ${new URL(url).hostname}`);
80
+ }
81
+ finally {
82
+ clearTimeout(timer);
83
+ }
84
+ }
85
+ // Reads a response body while counting toward the byte ceiling, so an
86
+ // oversized payload is dropped before it is ever materialized in full.
87
+ async function readBounded(response, maxBytes) {
88
+ const declared = Number(response.headers.get("content-length") ?? "0");
89
+ if (Number.isFinite(declared) && declared > maxBytes)
90
+ throw new FirefliesRuntimeError("transcript_too_large", "the provider response exceeds the byte ceiling");
91
+ if (!response.body) {
92
+ const buffer = await response.arrayBuffer();
93
+ if (buffer.byteLength > maxBytes)
94
+ throw new FirefliesRuntimeError("transcript_too_large", "the provider response exceeds the byte ceiling");
95
+ return new TextDecoder().decode(buffer);
96
+ }
97
+ const reader = response.body.getReader();
98
+ const chunks = [];
99
+ let total = 0;
100
+ for (;;) {
101
+ const { done, value } = await reader.read();
102
+ if (done)
103
+ break;
104
+ total += value.byteLength;
105
+ if (total > maxBytes) {
106
+ await reader.cancel().catch(() => undefined);
107
+ chunks.length = 0;
108
+ throw new FirefliesRuntimeError("transcript_too_large", "the provider response exceeds the byte ceiling");
109
+ }
110
+ chunks.push(value);
111
+ }
112
+ return new TextDecoder().decode(Buffer.concat(chunks));
113
+ }
114
+ function parseJson(text, label) {
115
+ try {
116
+ const parsed = JSON.parse(text);
117
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
118
+ throw new Error("not an object");
119
+ return parsed;
120
+ }
121
+ catch {
122
+ throw new FirefliesRuntimeError("provider_failure", `${label} returned a response productfoo could not read`);
123
+ }
124
+ }
125
+ // BELIEF (T-001): Fireflies' API is GraphQL at /graphql, bearer-key auth,
126
+ // offset pagination, and the field names below. The query strings are the
127
+ // single place to correct if the live API differs.
128
+ const FIREFLIES_VIEWER_QUERY = "query FooViewer { viewer { user_id email } }";
129
+ const FIREFLIES_LIST_QUERY = "query FooListTranscripts($from: String!, $to: String!, $limit: Int!, $offset: Int!) { transcripts(fromDate: $from, toDate: $to, limit: $limit, offset: $offset) { id title date end_date status participants { display_name email } } }";
130
+ const FIREFLIES_TRANSCRIPT_QUERY = "query FooTranscript($id: ID!) { transcript(id: $id) { title speakers { name } sentences { text start_date end_date speaker_id } } }";
131
+ const LIST_PAGE_SIZE = 50;
132
+ function epochToIso(value) {
133
+ if (typeof value === "number" && Number.isFinite(value))
134
+ return new Date(value).toISOString();
135
+ if (typeof value === "string" && value.trim())
136
+ return value;
137
+ return undefined;
138
+ }
139
+ function stringOrUndefined(value) {
140
+ return typeof value === "string" && value.trim() ? value : undefined;
141
+ }
142
+ /**
143
+ * Minimal read-only Fireflies GraphQL client. The single request() function is
144
+ * the write-refusal choke point (R-009): GraphQL speaks over POST, so a
145
+ * mutation is refused by inspecting the query text — the only read operations
146
+ * reachable are the three query constants above.
147
+ */
148
+ export class FirefliesClient {
149
+ credential;
150
+ options;
151
+ requests = { viewer: 0, list: 0, transcript: 0 };
152
+ lastRequestAt = 0;
153
+ baseUrl;
154
+ sleep;
155
+ now;
156
+ constructor(credential, options) {
157
+ this.credential = credential;
158
+ this.options = options;
159
+ this.baseUrl = (options.baseUrl ?? DEFAULT_FIREFLIES_BASE).replace(/\/+$/, "");
160
+ this.sleep = options.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
161
+ this.now = options.now ?? (() => Date.now());
162
+ }
163
+ async request(query, variables, maxBytes = FIREFLIES_POLICY.max_response_bytes) {
164
+ // GraphQL rides over POST, so the read-only rule is the query text: a
165
+ // mutation never leaves this process (R-009).
166
+ if (/\bmutation\b/i.test(query))
167
+ refuseSourceWrite(`fireflies graphql mutation`);
168
+ const wait = this.lastRequestAt + FIREFLIES_POLICY.min_request_interval_ms - this.now();
169
+ if (wait > 0)
170
+ await this.sleep(wait);
171
+ this.lastRequestAt = this.now();
172
+ const response = await fetchWithTimeout(this.options.fetchImpl, `${this.baseUrl}/graphql`, {
173
+ method: "POST",
174
+ headers: { authorization: `Bearer ${this.credential.api_key}`, "content-type": "application/json", accept: "application/json" },
175
+ body: JSON.stringify({ query, variables }),
176
+ }, FIREFLIES_POLICY.fetch_timeout_ms);
177
+ if (response.status === 401)
178
+ throw new FirefliesRuntimeError("auth_expired", "Fireflies rejected the API key; check the key or replace it");
179
+ if (response.status === 403)
180
+ throw new FirefliesRuntimeError("access_denied", "Fireflies denied this read; the key lacks the required access");
181
+ if (response.status === 429)
182
+ throw new FirefliesRuntimeError("budget_exhausted", "Fireflies rate limit reached; no retry was attempted");
183
+ if (!response.ok)
184
+ throw new FirefliesRuntimeError("provider_failure", `Fireflies answered ${response.status}`);
185
+ const body = parseJson(await readBounded(response, maxBytes), "Fireflies");
186
+ const errors = Array.isArray(body.errors) ? body.errors : [];
187
+ if (errors.length > 0)
188
+ throw new FirefliesRuntimeError("provider_failure", "Fireflies reported the query could not be served");
189
+ const data = (body.data ?? {});
190
+ return data;
191
+ }
192
+ /** Identity probe for readiness (R-005): the connection answers for one user. The result is never printed. */
193
+ async probe() {
194
+ this.requests.viewer += 1;
195
+ const data = await this.request(FIREFLIES_VIEWER_QUERY, {}, 64 * 1024);
196
+ const viewer = (data.viewer ?? {});
197
+ return { user_id: stringOrUndefined(viewer.user_id), email: stringOrUndefined(viewer.email) };
198
+ }
199
+ /** Bounded metadata listing: one time window, a page ceiling, no content fields requested. */
200
+ async listTranscripts(window) {
201
+ const transcripts = [];
202
+ let offset = 0;
203
+ let pages = 0;
204
+ for (;;) {
205
+ if (pages >= FIREFLIES_POLICY.max_list_pages)
206
+ return { transcripts, pages, truncated: true };
207
+ this.requests.list += 1;
208
+ const data = await this.request(FIREFLIES_LIST_QUERY, { from: window.from, to: window.to, limit: LIST_PAGE_SIZE, offset }, 4 * 1024 * 1024);
209
+ pages += 1;
210
+ const entries = Array.isArray(data.transcripts) ? data.transcripts : [];
211
+ for (const entry of entries) {
212
+ if (!entry || typeof entry.id !== "string")
213
+ continue;
214
+ const participants = Array.isArray(entry.participants) ? entry.participants : [];
215
+ transcripts.push({
216
+ id: entry.id,
217
+ title: stringOrUndefined(entry.title),
218
+ started_at: epochToIso(entry.date),
219
+ ended: epochToIso(entry.end_date),
220
+ status: stringOrUndefined(entry.status),
221
+ participants: participants
222
+ .filter((participant) => participant && (typeof participant.display_name === "string" || typeof participant.email === "string"))
223
+ .map((participant) => ({ display_name: stringOrUndefined(participant.display_name), email: stringOrUndefined(participant.email) })),
224
+ });
225
+ }
226
+ if (entries.length < LIST_PAGE_SIZE)
227
+ return { transcripts, pages, truncated: false };
228
+ offset += LIST_PAGE_SIZE;
229
+ }
230
+ }
231
+ /**
232
+ * Exactly one transcript's content (R-007). A fixture observes that the
233
+ * request carries a single well-formed identifier and nothing else.
234
+ */
235
+ async transcript(id) {
236
+ if (!id || /\s/.test(id))
237
+ throw new FirefliesRuntimeError("provider_failure", "a single well-formed transcript identifier is required");
238
+ this.requests.transcript += 1;
239
+ const data = await this.request(FIREFLIES_TRANSCRIPT_QUERY, { id });
240
+ const entry = (data.transcript ?? {});
241
+ if (!entry || typeof entry !== "object")
242
+ throw new FirefliesRuntimeError("access_denied", "Fireflies returned no transcript for the selected identifier");
243
+ const speakers = Array.isArray(entry.speakers) ? entry.speakers : [];
244
+ const sentences = Array.isArray(entry.sentences) ? entry.sentences : [];
245
+ return {
246
+ title: stringOrUndefined(entry.title),
247
+ speakers: speakers.map((speaker) => ({ name: stringOrUndefined(speaker.name) })),
248
+ sentences: sentences
249
+ .filter((sentence) => typeof sentence.text === "string")
250
+ .map((sentence) => ({
251
+ text: sentence.text,
252
+ start_date: stringOrUndefined(sentence.start_date),
253
+ end_date: stringOrUndefined(sentence.end_date),
254
+ speaker_id: stringOrUndefined(sentence.speaker_id),
255
+ })),
256
+ };
257
+ }
258
+ }
@@ -0,0 +1,10 @@
1
+ export type Tension = {
2
+ id: string;
3
+ factA: string;
4
+ factB: string;
5
+ ask: string;
6
+ title: string;
7
+ evidence: string[];
8
+ confidence: "high" | "medium";
9
+ };
10
+ export declare function detectTensions(root: string): Tension[];