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,209 @@
1
+ // Prompt Redaction Safety V0 — T-003 (R-004): the fail-closed commit gate.
2
+ // `foo self gate` scans staged content and hard-blocks high-confidence secrets
3
+ // before they can be committed (the irreversible egress, D-001). Calibrated
4
+ // (D-003): only HIGH confidence blocks; lower confidence is advisory and never
5
+ // gates. Bypass requires a human-set, recorded reason (R-007 human-only).
6
+ import { appendFileSync, mkdirSync } from "node:fs";
7
+ import path from "node:path";
8
+ import { TextDecoder } from "node:util";
9
+ import { gitRun, gitRunBuffer } from "./gitRun.js";
10
+ import { scanText } from "./redactEngine.js";
11
+ import { loadRepoAllowlist } from "./redactConfig.js";
12
+ // Pure decision: block iff a high-confidence secret is present and no override
13
+ // reason was supplied. Deterministic and side-effect-free for testability.
14
+ export function decideGate(staged, opts = {}) {
15
+ const high = [];
16
+ for (const f of staged) {
17
+ for (const finding of scanText(f.text, { allowlist: opts.allowlist }).findings) {
18
+ if (finding.confidence === "high")
19
+ high.push({ file: f.file, line: finding.line, column: finding.column, detector: finding.detector });
20
+ }
21
+ }
22
+ if (high.length === 0)
23
+ return { blocked: false, overridden: false, high: [] };
24
+ const reason = (opts.overrideReason ?? "").trim();
25
+ if (reason)
26
+ return { blocked: false, overridden: true, high, reason };
27
+ return { blocked: true, overridden: false, high };
28
+ }
29
+ const AUDIT_DIR = ".foo";
30
+ const AUDIT_FILE = "redaction-overrides.jsonl";
31
+ const MAX_STAGED_BYTES = 16 * 1024 * 1024;
32
+ const SCANNER_GIT_OPTIONS = { stdio: ["ignore", "pipe", "pipe"] };
33
+ const REGULAR_BLOB_MODES = new Set(["100644", "100755"]);
34
+ // With -z, raw diff records are:
35
+ // :<old-mode> <new-mode> <old-oid> <new-oid> <status>\0<path>\0
36
+ // Rename/copy records carry both old and new paths after the header. Reject the
37
+ // entire listing if Git returns anything incomplete or ambiguous: a partial
38
+ // index view cannot support a clean result.
39
+ function parseStagedIndex(raw) {
40
+ if (raw.length === 0)
41
+ return [];
42
+ if (!raw.endsWith("\0"))
43
+ return null;
44
+ const fields = raw.slice(0, -1).split("\0");
45
+ const entries = [];
46
+ const seen = new Set();
47
+ let cursor = 0;
48
+ while (cursor < fields.length) {
49
+ const header = fields[cursor++];
50
+ const match = /^:([0-7]{6}) ([0-7]{6}) ([0-9a-f]+) ([0-9a-f]+) ([A-Z])(\d*)$/.exec(header ?? "");
51
+ if (!match)
52
+ return null;
53
+ const sourcePath = fields[cursor++];
54
+ if (!sourcePath)
55
+ return null;
56
+ const status = match[5];
57
+ const file = status === "R" || status === "C" ? fields[cursor++] : sourcePath;
58
+ if (!file || seen.has(file))
59
+ return null;
60
+ seen.add(file);
61
+ entries.push({ file, mode: match[2] });
62
+ }
63
+ return entries;
64
+ }
65
+ function isProbablyText(buf) {
66
+ for (let i = 0; i < buf.length; i++) {
67
+ const byte = buf[i];
68
+ if (byte === 0 || (byte < 0x20 && byte !== 0x09 && byte !== 0x0a && byte !== 0x0d) || byte === 0x7f)
69
+ return false;
70
+ }
71
+ return true;
72
+ }
73
+ // Read the staged (index) content of files about to be committed. Every entry
74
+ // either becomes scannable UTF-8 text or a metadata-only refusal record.
75
+ export function readStaged(root, seams = {}) {
76
+ const run = seams.gitRun ?? gitRun;
77
+ const runBuffer = seams.gitRunBuffer ?? gitRunBuffer;
78
+ const listed = run(["diff", "--cached", "--raw", "--diff-filter=d", "-M", "-z"], { ...SCANNER_GIT_OPTIONS, cwd: root });
79
+ if (!listed.ok)
80
+ return { scanned: [], unscannable: [{ file: "[git-index]", reason: "git-index-unavailable" }] };
81
+ const entries = parseStagedIndex(listed.stdout);
82
+ if (!entries)
83
+ return { scanned: [], unscannable: [{ file: "[git-index]", reason: "git-index-unavailable" }] };
84
+ const scanned = [];
85
+ const unscannable = [];
86
+ for (const { file, mode } of entries) {
87
+ if (!REGULAR_BLOB_MODES.has(mode)) {
88
+ unscannable.push({ file, reason: "unsupported-file-type" });
89
+ continue;
90
+ }
91
+ // Ask git for size before reading bytes, so arbitrarily large blobs never
92
+ // enter this process merely to learn that they exceed the scanner bound.
93
+ const sized = run(["cat-file", "-s", `:${file}`], { ...SCANNER_GIT_OPTIONS, cwd: root });
94
+ const sizeText = sized.stdout.endsWith("\n") ? sized.stdout.slice(0, -1) : sized.stdout;
95
+ if (!sized.ok || !/^(?:0|[1-9]\d*)$/.test(sizeText)) {
96
+ unscannable.push({ file, reason: "blob-unreadable" });
97
+ continue;
98
+ }
99
+ const bytes = Number(sizeText);
100
+ if (!Number.isSafeInteger(bytes)) {
101
+ unscannable.push({ file, reason: "blob-unreadable" });
102
+ continue;
103
+ }
104
+ if (bytes > MAX_STAGED_BYTES) {
105
+ unscannable.push({ file, reason: "blob-too-large" });
106
+ continue;
107
+ }
108
+ const blob = runBuffer(["show", `:${file}`], { ...SCANNER_GIT_OPTIONS, cwd: root, maxBuffer: MAX_STAGED_BYTES + 1 });
109
+ if (!blob.ok) {
110
+ unscannable.push({ file, reason: "blob-unreadable" });
111
+ continue;
112
+ }
113
+ if (blob.stdout.length !== bytes) {
114
+ unscannable.push({ file, reason: "blob-unreadable" });
115
+ continue;
116
+ }
117
+ if (!isProbablyText(blob.stdout)) {
118
+ unscannable.push({ file, reason: "binary-or-nul" });
119
+ continue;
120
+ }
121
+ try {
122
+ scanned.push({ file, text: new TextDecoder("utf-8", { fatal: true }).decode(blob.stdout) });
123
+ }
124
+ catch {
125
+ unscannable.push({ file, reason: "decode-failed" });
126
+ }
127
+ }
128
+ return { scanned, unscannable };
129
+ }
130
+ function recordOverride(root, decision, at) {
131
+ mkdirSync(path.join(root, AUDIT_DIR), { recursive: true });
132
+ // Metadata-only audit record — reason + locations, never a secret value.
133
+ const byFile = new Map();
134
+ for (const f of decision.high) {
135
+ const list = byFile.get(f.file) ?? [];
136
+ list.push(f);
137
+ byFile.set(f.file, list);
138
+ }
139
+ const record = {
140
+ time: at,
141
+ reason: decision.reason,
142
+ total_high: decision.high.length,
143
+ files: [...byFile.entries()].map(([file, findings]) => ({
144
+ file,
145
+ findings: findings.map((x) => ({ line: x.line, column: x.column, detector: x.detector })),
146
+ })),
147
+ };
148
+ appendFileSync(path.join(root, AUDIT_DIR, AUDIT_FILE), `${JSON.stringify(record)}\n`);
149
+ }
150
+ export const UNSCANNABLE_REFUSAL = Object.freeze({
151
+ schema_version: "0.1",
152
+ status: "refused",
153
+ reason_code: "staged_file_unscannable",
154
+ message: "Staged scanning could not verify every staged file.",
155
+ safe_next_action: "Remove, replace, or convert each listed file to scannable UTF-8 text under 16 MiB, restage, and retry.",
156
+ });
157
+ function safeFilename(file) {
158
+ return safeJson(file);
159
+ }
160
+ function safeJson(value) {
161
+ return JSON.stringify(value).replace(/[\u007f-\u009f\u2028\u2029]/g, (char) => `\\u${char.codePointAt(0)?.toString(16).padStart(4, "0")}`);
162
+ }
163
+ function renderUnscannable(unscannable, machine) {
164
+ if (machine)
165
+ return safeJson({ ...UNSCANNABLE_REFUSAL, unscannable });
166
+ const files = unscannable.map(({ file, reason }) => `${safeFilename(file)} (${reason})`).join(", ");
167
+ return `blocked — ${UNSCANNABLE_REFUSAL.message} ${files}. ${UNSCANNABLE_REFUSAL.safe_next_action}`;
168
+ }
169
+ export function runRedactGate(root, opts = {}) {
170
+ const staged = readStaged(root, opts.seams);
171
+ if (staged.unscannable.length > 0) {
172
+ const machine = opts.machine ?? !process.stdout.isTTY;
173
+ return {
174
+ output: `${renderUnscannable(staged.unscannable, machine)}\n`,
175
+ exitCode: 1,
176
+ unscannable: true,
177
+ refusal: UNSCANNABLE_REFUSAL,
178
+ files: staged.unscannable,
179
+ };
180
+ }
181
+ const allowlist = loadRepoAllowlist(root);
182
+ const overrideReason = opts.overrideReason ?? process.env.FOO_REDACT_ALLOW;
183
+ const decision = decideGate(staged.scanned, { allowlist, overrideReason });
184
+ if (decision.blocked) {
185
+ const lines = [
186
+ "foo self gate — BLOCKED: high-confidence secret(s) in staged changes",
187
+ "",
188
+ ...decision.high.map((f) => ` ${f.file}:${f.line}:${f.column} [high] ${f.detector}`),
189
+ "",
190
+ "Fix: redact before committing — `foo redact <file> --write` (review the diff), or remove the secret.",
191
+ 'Override (human, audited): FOO_REDACT_ALLOW="why this is safe" git commit ...',
192
+ "Secret values are never shown or stored (R-007).",
193
+ "",
194
+ ];
195
+ return { output: lines.join("\n"), exitCode: 1, unscannable: false };
196
+ }
197
+ if (decision.overridden) {
198
+ recordOverride(root, decision, opts.at ?? new Date().toISOString());
199
+ const lines = [
200
+ `foo self gate — OVERRIDE: ${decision.high.length} high-confidence finding(s) bypassed`,
201
+ ` reason: ${decision.reason}`,
202
+ ` recorded to ${AUDIT_DIR}/${AUDIT_FILE} (metadata-only)`,
203
+ ...decision.high.map((f) => ` ${f.file}:${f.line} [high] ${f.detector}`),
204
+ "",
205
+ ];
206
+ return { output: lines.join("\n"), exitCode: 0, unscannable: false };
207
+ }
208
+ return { output: `foo self gate — ok: no high-confidence secrets in ${staged.scanned.length} staged file(s).\n`, exitCode: 0, unscannable: false };
209
+ }
@@ -0,0 +1,29 @@
1
+ import type { Tension } from "./firstMoveTensions.js";
2
+ export type RepoSignals = {
3
+ languages: string[];
4
+ hasTests: boolean;
5
+ hasCI: boolean;
6
+ readmeBytes: number;
7
+ bigFile: {
8
+ path: string;
9
+ lines: number;
10
+ } | null;
11
+ sourceFileCount: number;
12
+ };
13
+ export type Move = {
14
+ id: string;
15
+ title: string;
16
+ evidence: string[];
17
+ risk: number;
18
+ leverage: number;
19
+ effort: number;
20
+ tension?: Tension;
21
+ };
22
+ export declare function gatherRepoSignals(root: string): RepoSignals;
23
+ export declare function generateMoves(signals: RepoSignals): Move[];
24
+ export type RankedMoves = {
25
+ recommended: Move | null;
26
+ rest: Move[];
27
+ why: string | null;
28
+ };
29
+ export declare function rankMoves(moves: Move[]): RankedMoves;
@@ -0,0 +1,160 @@
1
+ import { gitRunOrNull } from "./gitRun.js";
2
+ import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
3
+ import path from "node:path";
4
+ function git(root, args) {
5
+ return gitRunOrNull(args, { cwd: root, stdio: ["ignore", "pipe", "ignore"] });
6
+ }
7
+ // Tracked files only — never walks untracked or ignored paths, so secrets and
8
+ // build output stay unread.
9
+ function trackedFiles(root) {
10
+ const out = git(root, ["ls-files"]);
11
+ if (out !== null)
12
+ return out.split(/\r?\n/).filter((l) => l.trim() !== "");
13
+ // Non-git fallback: a shallow read of the top level only.
14
+ try {
15
+ return readdirSync(root, { withFileTypes: true })
16
+ .filter((e) => e.isFile())
17
+ .map((e) => e.name);
18
+ }
19
+ catch {
20
+ return [];
21
+ }
22
+ }
23
+ const LANG_BY_EXT = {
24
+ ".ts": "TypeScript",
25
+ ".tsx": "TypeScript",
26
+ ".js": "JavaScript",
27
+ ".jsx": "JavaScript",
28
+ ".py": "Python",
29
+ ".go": "Go",
30
+ ".rs": "Rust",
31
+ ".rb": "Ruby",
32
+ ".java": "Java",
33
+ };
34
+ const SOURCE_EXTS = new Set(Object.keys(LANG_BY_EXT));
35
+ // Skip vendored, pinned, generated, or minified paths — they are not the
36
+ // developer's own code and would make the read point at noise (e.g. a pinned
37
+ // helper bundle or a 10k-line minified file).
38
+ function isVendored(file) {
39
+ if (file.startsWith("."))
40
+ return true; // .agents/, .github/, dotfiles
41
+ if (/(^|\/)(vendor|third_party|node_modules|dist|build|generated)(\/|$)/.test(file))
42
+ return true;
43
+ if (/\.min\.[a-z]+$/.test(file))
44
+ return true;
45
+ return false;
46
+ }
47
+ function isTestPath(file) {
48
+ return /(^|\/)(test|tests|__tests__|spec)(\/|$)/i.test(file) || /\.(test|spec)\.[a-z]+$/i.test(file);
49
+ }
50
+ function countLines(root, file) {
51
+ try {
52
+ return readFileSync(path.join(root, file), "utf8").split(/\r?\n/).length;
53
+ }
54
+ catch {
55
+ return 0;
56
+ }
57
+ }
58
+ export function gatherRepoSignals(root) {
59
+ const files = trackedFiles(root);
60
+ const langCounts = new Map();
61
+ let sourceFileCount = 0;
62
+ let hasTests = false;
63
+ let bigFile = null;
64
+ for (const file of files) {
65
+ if (isVendored(file))
66
+ continue;
67
+ const ext = path.extname(file);
68
+ if (SOURCE_EXTS.has(ext)) {
69
+ sourceFileCount += 1;
70
+ const lang = LANG_BY_EXT[ext];
71
+ langCounts.set(lang, (langCounts.get(lang) ?? 0) + 1);
72
+ if (isTestPath(file))
73
+ hasTests = true;
74
+ }
75
+ }
76
+ // Largest tracked source file (a documentation / decomposition candidate).
77
+ for (const file of files) {
78
+ if (isVendored(file) || !SOURCE_EXTS.has(path.extname(file)) || isTestPath(file))
79
+ continue;
80
+ const lines = countLines(root, file);
81
+ if (!bigFile || lines > bigFile.lines)
82
+ bigFile = { path: file, lines };
83
+ }
84
+ const readmePath = ["README.md", "README", "readme.md"].map((r) => path.join(root, r)).find(existsSync);
85
+ const readmeBytes = readmePath ? statSync(readmePath).size : 0;
86
+ const languages = [...langCounts.entries()].sort((a, b) => b[1] - a[1]).map(([lang]) => lang);
87
+ return {
88
+ languages,
89
+ hasTests,
90
+ hasCI: existsSync(path.join(root, ".github", "workflows")),
91
+ readmeBytes,
92
+ bigFile,
93
+ sourceFileCount,
94
+ };
95
+ }
96
+ // Generate candidate moves, each gated on a concrete fact. Order here is the
97
+ // pre-ranking; scoreMoves decides the recommendation.
98
+ export function generateMoves(signals) {
99
+ const moves = [];
100
+ if (signals.sourceFileCount > 0 && !signals.hasTests) {
101
+ moves.push({
102
+ id: "add-tests",
103
+ title: "Add a test safety net",
104
+ evidence: [`${signals.sourceFileCount} source file(s) and no tests found`],
105
+ risk: 3,
106
+ leverage: 3,
107
+ effort: 2,
108
+ });
109
+ }
110
+ if (!signals.hasCI && signals.sourceFileCount > 0) {
111
+ moves.push({
112
+ id: "add-ci",
113
+ title: "Set up CI so changes get checked automatically",
114
+ evidence: ["no .github/workflows — nothing runs on push"],
115
+ risk: 2,
116
+ leverage: 2,
117
+ effort: 1,
118
+ });
119
+ }
120
+ if (signals.readmeBytes < 400) {
121
+ moves.push({
122
+ id: "write-readme",
123
+ title: signals.readmeBytes === 0 ? "Write a README" : "Expand the thin README",
124
+ evidence: [signals.readmeBytes === 0 ? "no README found" : `README is only ${signals.readmeBytes} bytes`],
125
+ risk: 1,
126
+ leverage: 1,
127
+ effort: 1,
128
+ });
129
+ }
130
+ if (signals.bigFile && signals.bigFile.lines > 600) {
131
+ moves.push({
132
+ id: "tame-big-file",
133
+ title: `Break up ${signals.bigFile.path}`,
134
+ evidence: [`${signals.bigFile.path} is ${signals.bigFile.lines} lines — hard to change safely`],
135
+ risk: 2,
136
+ leverage: 2,
137
+ effort: 3,
138
+ });
139
+ }
140
+ return moves;
141
+ }
142
+ function score(move) {
143
+ // Favor high risk + high leverage, discount effort. Risk and leverage matter
144
+ // more than effort, so a risky-but-pricey fix can still win.
145
+ return move.risk * 2 + move.leverage * 2 - move.effort;
146
+ }
147
+ export function rankMoves(moves) {
148
+ const sorted = [...moves].sort((a, b) => score(b) - score(a) || a.id.localeCompare(b.id));
149
+ const recommended = sorted[0] ?? null;
150
+ const rest = sorted.slice(1);
151
+ // The why adds comparative reasoning — it does not restate the evidence line
152
+ // shown above it. Grounded in the ranking: top wins on leverage-per-effort.
153
+ let why = null;
154
+ if (recommended) {
155
+ why = rest.length
156
+ ? "it's the most leverage for the least effort of the options here, so the rest can wait"
157
+ : "it's the highest-leverage thing to settle before anything else";
158
+ }
159
+ return { recommended, rest, why };
160
+ }
@@ -0,0 +1,242 @@
1
+ import { type PricingTable } from "./loopBudget.js";
2
+ import type { FetchLike, SocialSource, YtDlp } from "./social/types.js";
3
+ export type SourceClass = "repo" | "web_free" | "web_firecrawl" | "social" | "connected";
4
+ export type SourceStatus = "available" | "degraded" | "excluded";
5
+ export type Depth = "fast" | "standard" | "deep";
6
+ export interface SourceReport {
7
+ class: SourceClass;
8
+ status: SourceStatus;
9
+ reason: string;
10
+ skill: string | null;
11
+ }
12
+ export interface ResearchEnv {
13
+ firecrawlKey?: string;
14
+ connectedRuntime?: boolean;
15
+ approvedSources?: string[];
16
+ }
17
+ export interface DetectOptions {
18
+ cwd?: string;
19
+ env?: ResearchEnv;
20
+ }
21
+ export declare function resolveEnv(processEnv?: NodeJS.ProcessEnv): ResearchEnv;
22
+ export type ClaimLabel = "primary" | "vendor" | "social" | "call";
23
+ export declare const CLAIM_LABELS: ClaimLabel[];
24
+ export type Confidence = "high" | "medium" | "low";
25
+ export declare const CONFIDENCE_LEVELS: Confidence[];
26
+ export interface Claim {
27
+ text: string;
28
+ source_class: ClaimLabel;
29
+ confidence: Confidence;
30
+ dissent: string | null;
31
+ source?: string;
32
+ }
33
+ export interface PanelFinding {
34
+ lens: string;
35
+ finding: string;
36
+ dissent: boolean;
37
+ }
38
+ export interface Theme {
39
+ title: string;
40
+ implication: string;
41
+ claims?: number[];
42
+ }
43
+ export interface Direction {
44
+ owner: string;
45
+ recommendation: string;
46
+ rationale: string;
47
+ falsifier?: string;
48
+ alternatives: string[];
49
+ status?: "proposed" | "decided";
50
+ decision?: string;
51
+ }
52
+ export interface ResearchPaper {
53
+ schema_version: "0.1";
54
+ topic: string;
55
+ date: string;
56
+ depth: Depth;
57
+ sources: SourceReport[];
58
+ claims: Claim[];
59
+ panel_findings: PanelFinding[];
60
+ open_questions: string[];
61
+ verdict?: string;
62
+ direction?: Direction;
63
+ themes?: Theme[];
64
+ recommendations?: string[];
65
+ self_application?: Claim;
66
+ }
67
+ export interface ParsedPaper {
68
+ topic: string;
69
+ date: string;
70
+ depth: Depth;
71
+ sources: Record<SourceClass, SourceStatus>;
72
+ claims: Claim[];
73
+ panel_findings: PanelFinding[];
74
+ open_questions: string[];
75
+ self_application?: Claim;
76
+ }
77
+ export declare function firecrawlUpsell(sources: SourceReport[]): string | null;
78
+ export declare function assertNoPrivateToFirecrawl(routedClasses: SourceClass[]): void;
79
+ export interface ConnectedSourceRef {
80
+ id: string;
81
+ approved: boolean;
82
+ }
83
+ export declare function admitApprovedSources(discovered: ConnectedSourceRef[]): string[];
84
+ export interface ConnectedEvidence {
85
+ source: string;
86
+ redacted: boolean;
87
+ summary: string;
88
+ link?: string;
89
+ raw?: string;
90
+ }
91
+ export declare function assertRedactedTranscript(evidence: ConnectedEvidence): void;
92
+ export declare function detectSources(root: string, options?: DetectOptions): SourceReport[];
93
+ export declare function hasZeroConfigValue(sources: SourceReport[]): boolean;
94
+ export declare const PANEL_ROLES: readonly ["domain-expert", "methodologist", "red-team-skeptic"];
95
+ export interface PanelSpec {
96
+ always: true;
97
+ blocking: false;
98
+ depth: Depth;
99
+ deep_swarm: boolean;
100
+ lenses: string[];
101
+ }
102
+ export declare function buildPanel(depth: Depth): PanelSpec;
103
+ export declare const ALLOWED_ACTIONS: readonly ["read_repo", "search_web", "fetch_web_untrusted", "read_approved_connected", "synthesize_paper", "write_scratch_paper"];
104
+ export declare const FORBIDDEN_ACTIONS: readonly ["send", "post", "commit_secret", "push", "mutate_source", "exfiltrate_private_data", "send_private_to_firecrawl", "ungated_outbound_inference"];
105
+ export interface SafetyPosture {
106
+ read_and_synthesize_only: true;
107
+ untrusted_web_isolated: true;
108
+ outbound_actions: string[];
109
+ allowed_actions: string[];
110
+ forbidden_actions: string[];
111
+ }
112
+ export declare function safetyPosture(): SafetyPosture;
113
+ export declare function assertReadAndSynthesizeOnly(plannedActions: string[]): void;
114
+ export interface ScreenResult {
115
+ inert_text: string;
116
+ stripped_directives: string[];
117
+ triggered: boolean;
118
+ }
119
+ export declare function screenUntrustedWeb(content: string): ScreenResult;
120
+ export interface DepthBounds {
121
+ depth: Depth;
122
+ sources_max: number;
123
+ pages_max: number;
124
+ panel_size: number;
125
+ }
126
+ export declare function depthBounds(depth: Depth): DepthBounds;
127
+ export interface DeepEstimate {
128
+ basis: "heuristic";
129
+ unit: "tokens";
130
+ expected_tokens: number;
131
+ ceiling_tokens: number;
132
+ /** Dollar range, null when the price table cannot price the worker model. */
133
+ expected_usd: number | null;
134
+ ceiling_usd: number | null;
135
+ priced_with: string;
136
+ confidence: Confidence;
137
+ disclosure: string;
138
+ /** What this number does NOT cover — stated, never implied. */
139
+ excludes: string[];
140
+ }
141
+ export declare function estimateDeep(bounds: DepthBounds, pricing?: PricingTable, worker?: string): DeepEstimate;
142
+ export declare function estimateForDepth(depth: Depth, pricing?: PricingTable, worker?: string): DeepEstimate;
143
+ export declare function estimatePitch(sections: number, panelSize: number, pricing?: PricingTable, worker?: string): DeepEstimate;
144
+ export interface RecencyWindow {
145
+ days: number;
146
+ end_date: string | null;
147
+ }
148
+ export declare const DEFAULT_RECENCY_DAYS = 30;
149
+ export interface ResearchArgs {
150
+ topic: string;
151
+ depth: Depth;
152
+ out: string | null;
153
+ toShape: boolean;
154
+ json: boolean;
155
+ recency: RecencyWindow;
156
+ }
157
+ export declare function slugifyTopic(topic: string): string;
158
+ export declare function defaultOutPath(topic: string, date: string): string;
159
+ export declare function parseResearchArgs(args: string[]): ResearchArgs;
160
+ export interface ResearchPlan {
161
+ schema_version: "0.1";
162
+ stage: "plan";
163
+ /** B5 proof: the id of the run this plan minted. A paper must carry it as
164
+ * `research_run:` or `seal`/`validate` refuse it. Null when nothing was minted. */
165
+ run_id: string | null;
166
+ topic: string;
167
+ depth: Depth;
168
+ recency: RecencyWindow;
169
+ out_path: string;
170
+ to_shape: boolean;
171
+ sources: SourceReport[];
172
+ zero_config_value: boolean;
173
+ upsell: string | null;
174
+ panel: PanelSpec;
175
+ /** Model execution is supplied by the active agent; no productfoo service is required. */
176
+ model_panel: ModelPanelPlan;
177
+ bounds: DepthBounds;
178
+ estimate: DeepEstimate;
179
+ safety: SafetyPosture;
180
+ }
181
+ export interface ModelPanelPlan {
182
+ mode: "multi-model" | "single-model";
183
+ reason: string;
184
+ /** The executor step the agent runs when the panel is on; null when single-model. */
185
+ run_hint: string | null;
186
+ }
187
+ export declare function modelPanelPlan(_depth: Depth, _env: ResearchEnv, _topic: string): ModelPanelPlan;
188
+ export interface BuildPlanOptions extends DetectOptions {
189
+ date?: string;
190
+ pricing?: PricingTable;
191
+ worker?: string;
192
+ /** The receipt minted for this run. Minting is a side effect, so it belongs to the
193
+ * command layer, not to this builder: a plan built directly (tests, callers that
194
+ * only want the shape) has no run behind it and says so by carrying null. */
195
+ runId?: string | null;
196
+ }
197
+ export declare function buildResearchPlan(root: string, args: ResearchArgs, options?: BuildPlanOptions): ResearchPlan;
198
+ export declare function renderResearchPlan(plan: ResearchPlan): string;
199
+ export declare function renderResearchJson(plan: ResearchPlan): string;
200
+ export interface ClaimValidation {
201
+ ok: boolean;
202
+ errors: string[];
203
+ }
204
+ export declare function validateClaims(claims: Claim[]): ClaimValidation;
205
+ export declare function assertClaimsLabeled(claims: Claim[]): void;
206
+ export declare function renderPaper(paper: ResearchPaper): string;
207
+ export declare function parsePaper(markdown: string): ParsedPaper;
208
+ export interface RealizedSummary {
209
+ schema_version: "0.1";
210
+ stage: "realized";
211
+ topic: string;
212
+ depth: Depth;
213
+ sources: Record<SourceClass, SourceStatus>;
214
+ claim_count: number;
215
+ panel: {
216
+ dissent_count: number;
217
+ };
218
+ open_questions: number;
219
+ }
220
+ export declare function summarizePaper(paper: ParsedPaper): RealizedSummary;
221
+ export interface ResearchResult {
222
+ output: string;
223
+ exitCode: number;
224
+ }
225
+ export declare function runResearchCommand(root: string, args: string[]): ResearchResult;
226
+ /** Public-query opt-in executes one bounded request. Planning without it stays
227
+ * local, with an explicit pending requirement that seal cannot skip. */
228
+ export declare function runResearchCommandAsync(root: string, args: string[]): Promise<ResearchResult>;
229
+ export interface GatherArgs {
230
+ topic: string;
231
+ recency: RecencyWindow;
232
+ sources: SocialSource[] | null;
233
+ limit: number | null;
234
+ json: boolean;
235
+ }
236
+ export declare function parseGatherArgs(args: string[]): GatherArgs;
237
+ export interface GatherRuntime {
238
+ fetchImpl?: FetchLike;
239
+ ytdlp?: YtDlp;
240
+ now?: Date;
241
+ }
242
+ export declare function runResearchGather(_root: string, args: string[], runtime?: GatherRuntime): Promise<ResearchResult>;