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,292 @@
1
+ // Top-level packet-free `foo reconcile` (reconcile-anywhere-v0 T-003/T-004).
2
+ //
3
+ // The adoption wedge: a stranger in a repo that has never heard of packets runs
4
+ // `foo reconcile --source github:<pr-url>` and gets value in one command — no
5
+ // specs/ dir, no init, no config. It recovers the PR's intent, diffs what the
6
+ // change actually does against that recovered intent, and reports drift, silent
7
+ // scope, and unproven claims.
8
+ //
9
+ // Two hard rules from the packet Decisions:
10
+ // D-001 — this is a NEW top-level command, but it shares ONE engine with
11
+ // `asp reconcile` (githubReconcile.reconcilePrProof / packetReconcile
12
+ // .classifyChangedFiles), so the two entry points can never drift.
13
+ // D-002 — zero side effects by default. Read-only. `--adopt` is the ONLY write
14
+ // path (T-004), and it goes through the spec-after machinery in specCmd.
15
+ //
16
+ // Report ORDER is load-bearing (R-003, the anti-"PR linter" defense): it LEADS
17
+ // with recovered intent, not lint findings. Intent is the reference point.
18
+ import { readJson } from "../jsonFile.js";
19
+ import path from "node:path";
20
+ import { extractBehaviorStories } from "../codeCatalog.js";
21
+ import { parseGithubSource } from "../sourceIngress.js";
22
+ import { evidenceFromFixture } from "../githubReconcile.js";
23
+ import { recoverPrIntent, suggestDrift, } from "../specAfter.js";
24
+ import { adoptReconcileIntent } from "./specCmd.js";
25
+ import { STATUS_GLYPHS, withGlyph } from "../statusGlyphs.js";
26
+ import { flagValue } from "./shared.js";
27
+ import { classifyThrown, markFailure } from "../errorTaxonomy.js";
28
+ // A malformed reconcile invocation returns exit 1 with a usage line rather than
29
+ // throwing, so it must mark itself usage_error — otherwise a codeless nonzero
30
+ // exit files as a command_error crash and pages for a typo.
31
+ function reconcileUsageFail(output) {
32
+ markFailure({ errorClass: "usage_error", errorCode: "E_BAD_FLAG", message: output.trim() });
33
+ return { output, exitCode: 1 };
34
+ }
35
+ // Collect changed file paths from whichever field the fixture carries.
36
+ function changedFilePaths(fixture) {
37
+ if (fixture.files && fixture.files.length)
38
+ return fixture.files;
39
+ const paths = new Set();
40
+ for (const f of fixture.files_changed ?? [])
41
+ paths.add(f);
42
+ for (const c of fixture.commits ?? [])
43
+ for (const f of c.files ?? [])
44
+ paths.add(f);
45
+ return [...paths].map((p) => ({ path: p }));
46
+ }
47
+ function storyFromFile(file, seq) {
48
+ const added = file.additions ?? 0;
49
+ const removed = file.deletions ?? 0;
50
+ const delta = added || removed ? ` (+${added}/-${removed})` : "";
51
+ return {
52
+ id: `bs-${String(seq + 1).padStart(3, "0")}`,
53
+ file: file.path,
54
+ change_kind: "modified",
55
+ title: `changes ${file.path}`,
56
+ expected_behavior: `Changes \`${file.path}\`${delta}.`,
57
+ evidence: [],
58
+ added_symbols: [],
59
+ removed_symbols: [],
60
+ added_lines: added,
61
+ removed_lines: removed,
62
+ // File-list-derived from the PR's own changed files — repo truth, not a
63
+ // guess about symbols.
64
+ provenance: "repo-truth",
65
+ self_reported: true,
66
+ };
67
+ }
68
+ // What the change does. A full diff yields symbol-level behavior stories; a plain
69
+ // file list yields one story per changed file.
70
+ function behaviorFromFixture(fixture) {
71
+ if (fixture.diff && fixture.diff.trim()) {
72
+ const { stories, coverage } = extractBehaviorStories(fixture.diff);
73
+ return { stories, coverage };
74
+ }
75
+ const files = changedFilePaths(fixture);
76
+ const stories = files.map((f, i) => storyFromFile(f, i));
77
+ return {
78
+ stories,
79
+ coverage: {
80
+ scanned_files: files.length,
81
+ story_files: stories.length,
82
+ stories: stories.length,
83
+ basis: "PR changed-file list (no unified diff supplied); one behavior story per changed file. Code-derived, self-reported.",
84
+ skipped: [],
85
+ },
86
+ };
87
+ }
88
+ function summarizeChecks(fixture) {
89
+ const checks = fixture.checks ?? [];
90
+ if (checks.length === 0)
91
+ return "absent";
92
+ if (checks.some((c) => c.conclusion === "failure"))
93
+ return "fail";
94
+ if (checks.every((c) => c.conclusion === "success"))
95
+ return "pass";
96
+ return "mixed";
97
+ }
98
+ export function buildReconcileReport(source, fixture) {
99
+ const recovered = recoverPrIntent({ title: fixture.title, body: fixture.body, linked_issue: fixture.linked_issue });
100
+ const { stories, coverage } = behaviorFromFixture(fixture);
101
+ const drift = suggestDrift(recovered.items.map((item, index) => ({ id: item.id, text: item.text, source: "prompt", raw_index: index })), stories);
102
+ const evidence = evidenceFromFixture(fixture);
103
+ const checks = summarizeChecks(fixture);
104
+ const proven = [];
105
+ const contradicted = [];
106
+ if (evidence.merged === true)
107
+ proven.push("PR is merged (typed fact)");
108
+ if (evidence.merged === false)
109
+ contradicted.push(`PR is not merged (state: ${evidence.state ?? "open"})`);
110
+ if (checks === "pass")
111
+ proven.push(`required checks green (${(fixture.checks ?? []).length}/${(fixture.checks ?? []).length})`);
112
+ if (checks === "fail")
113
+ contradicted.push("a required check reports failure");
114
+ return {
115
+ schema_version: "0.1",
116
+ source,
117
+ packet_free: true,
118
+ recovered_intent: recovered,
119
+ behavior: stories,
120
+ coverage,
121
+ drift,
122
+ proof: {
123
+ merged: evidence.merged ?? null,
124
+ checks,
125
+ declared_packet: recovered.declares_packet,
126
+ // Recovered intent is a claim, never proven by a title/body — only typed
127
+ // facts corroborate (🟡 claimed vs ✅ proven).
128
+ claimed: recovered.items.map((i) => i.text),
129
+ proven,
130
+ contradicted,
131
+ },
132
+ };
133
+ }
134
+ const JUDGMENT_GLOSS = {
135
+ "repo-evidence": "repo evidence",
136
+ "approved-context": "approved context",
137
+ "role-expertise": "role expertise",
138
+ "agent-inference": "agent inference",
139
+ "user-judgment": "user judgment",
140
+ };
141
+ const SOURCE_GLOSS = {
142
+ "pr-title": "PR title",
143
+ "pr-body": "PR body",
144
+ "linked-issue": "linked issue",
145
+ };
146
+ export function renderReconcileReport(report, glyphsOn) {
147
+ const lines = [];
148
+ lines.push(`foo reconcile — packet-free drift-against-intent for ${report.source}`);
149
+ lines.push("");
150
+ // (1) Recovered intent — LEADS the report (R-003). Intent is the reference
151
+ // point, not findings volume.
152
+ lines.push(withGlyph("classification", "Recovered intent (provisional — recovered from the PR, not agreed):", glyphsOn));
153
+ if (report.recovered_intent.recovered) {
154
+ for (const item of report.recovered_intent.items) {
155
+ lines.push(` ${item.id} [${JUDGMENT_GLOSS[item.judgment]} · ${SOURCE_GLOSS[item.source]}] ${item.text}`);
156
+ }
157
+ }
158
+ else {
159
+ lines.push(withGlyph("needs_input", ` ${report.recovered_intent.reason}`, glyphsOn));
160
+ }
161
+ if (report.recovered_intent.declares_packet) {
162
+ lines.push(` (the PR declares Foo-Spec: ${report.recovered_intent.declares_packet})`);
163
+ }
164
+ if (report.recovered_intent.screening.triggered) {
165
+ lines.push(` ${report.recovered_intent.screening.stripped.length} injected directive(s) in the PR text were neutralized as inert data.`);
166
+ }
167
+ if (report.recovered_intent.redaction.quarantined) {
168
+ lines.push(" a secret-shaped token in the PR text was quarantined — a human must clear it before --adopt.");
169
+ }
170
+ lines.push("");
171
+ // (2) What the diff actually does.
172
+ lines.push("What the change does:");
173
+ if (report.behavior.length) {
174
+ for (const story of report.behavior)
175
+ lines.push(` ${story.id}: ${story.expected_behavior}`);
176
+ }
177
+ else {
178
+ lines.push(" (no changed files in the supplied evidence)");
179
+ }
180
+ lines.push("");
181
+ // (3) Drift / silent scope.
182
+ lines.push("Drift & silent scope:");
183
+ const intentOnly = report.drift.filter((d) => d.category === "INTENT_ONLY");
184
+ const codeOnly = report.drift.filter((d) => d.category === "CODE_ONLY");
185
+ if (!intentOnly.length && !codeOnly.length) {
186
+ lines.push(" (recovered intent and the change line up — nothing unmatched)");
187
+ }
188
+ for (const d of intentOnly)
189
+ lines.push(withGlyph("drift", ` [asked, not built] ${d.label}`, glyphsOn));
190
+ for (const d of codeOnly)
191
+ lines.push(withGlyph("drift", ` [silent scope — built, not stated] ${d.label}`, glyphsOn));
192
+ lines.push(" note: deterministic keyword-overlap suggestions over recovered (not agreed) intent — you reconcile.");
193
+ lines.push("");
194
+ // (4) Unproven claims — the internal `claimed` state gets an actionable
195
+ // human label while the report/JSON contract remains unchanged.
196
+ lines.push(`Proof — ${STATUS_GLYPHS.claimed.label} vs proven:`);
197
+ lines.push(withGlyph("claimed", ` ${STATUS_GLYPHS.claimed.label}: ${report.proof.claimed.length} recovered intent item(s) — the PR asserts them; typed facts have not proven them.`, glyphsOn));
198
+ for (const p of report.proof.proven)
199
+ lines.push(withGlyph("proven", ` proven: ${p}`, glyphsOn));
200
+ for (const c of report.proof.contradicted)
201
+ lines.push(withGlyph("drift", ` contradicted: ${c}`, glyphsOn));
202
+ if (report.proof.checks === "absent")
203
+ lines.push(" no required checks present — merge/verify state cannot be proven from typed facts.");
204
+ lines.push("");
205
+ lines.push("Next: `foo reconcile --source github:<pr-url> --adopt --packet <name>` writes the recovered intent as a spec-after packet you can keep honest with `foo asp reconcile`.");
206
+ return lines.join("\n");
207
+ }
208
+ function reconcileUsageHandoff() {
209
+ return [
210
+ "usage: foo reconcile --source github:<pr-url> [--source-fixture <file.json>] [--json] [--adopt --packet <name> [--by <who>]]",
211
+ " Packet-free: recovers a PR's intent, diffs the change against it, reports drift and unproven claims.",
212
+ " Read-only by default; --adopt is the only write path.",
213
+ ].join("\n");
214
+ }
215
+ export function runReconcileCommand(root, args, glyphsOn) {
216
+ const json = args.includes("--json");
217
+ const source = flagValue(args, "--source");
218
+ if (!source)
219
+ return reconcileUsageFail(`${reconcileUsageHandoff()}\n`);
220
+ if (!source.startsWith("github:")) {
221
+ return reconcileUsageFail(`--source '${source}' is not supported; V0 admits only github:<pr-url>\n`);
222
+ }
223
+ let selection;
224
+ try {
225
+ selection = parseGithubSource(source);
226
+ }
227
+ catch (error) {
228
+ return { exitCode: 1, output: `${error instanceof Error ? error.message : String(error)}\n` };
229
+ }
230
+ if (selection.unit !== "pr") {
231
+ return {
232
+ exitCode: 1,
233
+ output: `point foo reconcile at a specific pull request (…/pull/<n>); a whole-repo URL is out of scope for the packet-free wedge: ${selection.url}\n`,
234
+ };
235
+ }
236
+ const fixturePath = flagValue(args, "--source-fixture");
237
+ if (!fixturePath) {
238
+ return {
239
+ exitCode: 1,
240
+ output: `no GitHub evidence for ${selection.url}. productfoo's CLI has no live GitHub MCP — supply the PR payload with --source-fixture <file.json>, then re-run:\n` +
241
+ ` foo reconcile --source ${source} --source-fixture <file.json>\n`,
242
+ };
243
+ }
244
+ let fixture;
245
+ try {
246
+ fixture = readJson(path.resolve(root, fixturePath));
247
+ }
248
+ catch {
249
+ return { exitCode: 1, output: `--source-fixture is not readable JSON: ${fixturePath}\n` };
250
+ }
251
+ const report = buildReconcileReport(source, fixture);
252
+ // --adopt (T-004): the ONLY write path (D-002). Graduates the one-shot run into
253
+ // a spec-after packet via the spec-after machinery (specCmd). Refuses when
254
+ // there is no recoverable intent — never writes a hallucinated contract.
255
+ if (args.includes("--adopt")) {
256
+ if (!report.recovered_intent.recovered) {
257
+ return { exitCode: 1, output: `nothing to adopt: ${report.recovered_intent.reason}\n` };
258
+ }
259
+ const packetName = flagValue(args, "--packet");
260
+ if (!packetName)
261
+ return reconcileUsageFail("foo reconcile --adopt needs --packet <name>\n");
262
+ const by = flagValue(args, "--by") ?? "reconcile-adopt";
263
+ try {
264
+ const result = adoptReconcileIntent(root, {
265
+ target: selection.url,
266
+ recovered: report.recovered_intent,
267
+ behavior: report.behavior,
268
+ coverage: report.coverage,
269
+ packetName,
270
+ by,
271
+ });
272
+ if (json)
273
+ return { exitCode: result.canonized ? 0 : 1, output: `${JSON.stringify({ schema_version: "0.1", report, adopt: result }, null, 2)}\n` };
274
+ if (!result.canonized)
275
+ return { exitCode: 1, output: `Not adopted: ${result.reason}\n` };
276
+ const rel = packetName.includes("/") ? packetName : `specs/${packetName}`;
277
+ return {
278
+ exitCode: 0,
279
+ output: `${renderReconcileReport(report, glyphsOn)}\n\n` +
280
+ `Adopted recovered intent into ${rel} (spec-after draft — provisional, agent-inference).\n` +
281
+ `Validate it: foo asp validate ${rel}\n`,
282
+ };
283
+ }
284
+ catch (error) {
285
+ markFailure(classifyThrown(error));
286
+ return { exitCode: 1, output: `${error instanceof Error ? error.message : String(error)}\n` };
287
+ }
288
+ }
289
+ if (json)
290
+ return { exitCode: 0, output: `${JSON.stringify(report, null, 2)}\n` };
291
+ return { exitCode: 0, output: `${renderReconcileReport(report, glyphsOn)}\n` };
292
+ }
@@ -0,0 +1 @@
1
+ export declare function runRuntimeCommand(args: string[], glyphs: boolean): string;
@@ -0,0 +1,36 @@
1
+ // `foo runtime` reports the active harness AND, when the harness is routed to a
2
+ // non-native model endpoint (e.g. Claude Code pointed at z.ai to run GLM 5.2), the
3
+ // backing-model signal. This is provenance for the judgment ledger: productfoo's runtime
4
+ // identity is the harness, but the model actually answering may be swapped under it.
5
+ // Signal, not boundary — it never blocks and never changes branch prefix or the
6
+ // elicitation surface. The 🏷️ classification glyph is human-surface-only (gated off
7
+ // for --json/piped output by `glyphs`).
8
+ import { detectRuntimeId } from "../elicitationSurface.js";
9
+ import { describeActiveModel, resolveActiveModel } from "../activeModel.js";
10
+ import { withGlyph } from "../statusGlyphs.js";
11
+ export function runRuntimeCommand(args, glyphs) {
12
+ const runtime = detectRuntimeId();
13
+ const active = resolveActiveModel();
14
+ if (args.includes("--json")) {
15
+ return `${JSON.stringify({ runtime, active }, null, 2)}\n`;
16
+ }
17
+ const lines = [`Runtime (harness): ${runtime}`];
18
+ const note = describeActiveModel(active);
19
+ if (note) {
20
+ // ⚠️ when the model is only assumed (inferred from a base URL); 🏷️ when a routed
21
+ // model is explicitly confirmed. Glyphs are human-surface-only (gated off for --json).
22
+ const state = active.confidence === "assumed" ? "drift" : "classification";
23
+ lines.push(withGlyph(state, `Active model: ${note}`, glyphs));
24
+ lines.push(" Runtime identity and branch prefix are unchanged — the harness is still " + runtime + ".");
25
+ }
26
+ else {
27
+ lines.push(`Active model: native (${runtime} running its own model)`);
28
+ }
29
+ // Roster/unknown-model findings (model-roster-data-v0 R-003): always worded;
30
+ // the ⚠️ drift glyph is human-surface-only (gated off for --json above).
31
+ for (const finding of active.findings) {
32
+ lines.push(withGlyph("drift", ` finding: ${finding}`, glyphs));
33
+ }
34
+ lines.push("");
35
+ return lines.join("\n");
36
+ }
@@ -0,0 +1,8 @@
1
+ export declare function runScanCommand(args: string[]): {
2
+ output: string;
3
+ exitCode: number;
4
+ };
5
+ export declare function runRedactCommand(args: string[]): {
6
+ output: string;
7
+ exitCode: number;
8
+ };
@@ -0,0 +1,266 @@
1
+ import { existsSync, lstatSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
2
+ import path from "node:path";
3
+ import { parseAllowlist, redactText, scanText } from "../redactEngine.js";
4
+ // Argument validation throws UsageError, never a bare Error: a mistyped flag is a
5
+ // typo, and a bare Error classifies as command_error — which pages and files a Bug
6
+ // Capsule. See src/errorTaxonomy.ts.
7
+ import { UsageError } from "../errorTaxonomy.js";
8
+ // --- foo scan (prompt_redaction_safety_v0 T-001) -----------------------------
9
+ // Thin IO wrapper over the pure redactEngine: walk files/dirs/stdin, scan each,
10
+ // print metadata-only findings. The engine never returns secret values (R-007).
11
+ const SCAN_SKIP_DIRS = new Set([".git", "node_modules", "dist", ".worktrees"]);
12
+ // Crude binary guard: a NUL byte in the first chunk means skip (not text).
13
+ function isProbablyText(buf) {
14
+ const n = Math.min(buf.length, 4096);
15
+ for (let i = 0; i < n; i++)
16
+ if (buf[i] === 0)
17
+ return false;
18
+ return true;
19
+ }
20
+ // A path the walk declines to scan is surfaced, never silently dropped.
21
+ function skipScanTarget(target, skipped, reason) {
22
+ skipped.push({ file: path.relative(process.cwd(), target) || target, reason });
23
+ }
24
+ function collectScanTargets(target, acc, skipped) {
25
+ const stat = lstatSync(target);
26
+ // lstat sees a symlink as neither file nor directory, which is how #777
27
+ // silently dropped linked files — a secret-detection blindspot. Resolve one
28
+ // hop with statSync so the real file gets scanned; an unresolvable link
29
+ // (dangling, looped) surfaces as a broken-symlink skip. Links to directories
30
+ // are not followed (a cycle would not terminate) and special files (fifo,
31
+ // socket) cannot be read as text — both surface as skips so the contract at
32
+ // the skipped list below holds for every path the walk visits.
33
+ if (stat.isSymbolicLink()) {
34
+ let resolved;
35
+ try {
36
+ resolved = statSync(target);
37
+ }
38
+ catch {
39
+ skipScanTarget(target, skipped, "broken-symlink");
40
+ return;
41
+ }
42
+ if (resolved.isFile())
43
+ acc.push(target);
44
+ else
45
+ skipScanTarget(target, skipped, resolved.isDirectory() ? "symlinked-directory" : "symlinked-special");
46
+ return;
47
+ }
48
+ if (stat.isDirectory()) {
49
+ if (SCAN_SKIP_DIRS.has(path.basename(target)))
50
+ return;
51
+ for (const entry of readdirSync(target).sort())
52
+ collectScanTargets(path.join(target, entry), acc, skipped);
53
+ }
54
+ else if (stat.isFile()) {
55
+ acc.push(target);
56
+ }
57
+ }
58
+ export function runScanCommand(args) {
59
+ const json = args.includes("--json");
60
+ const exitOnFindings = args.includes("--exit-code");
61
+ let minEntropyLen = 20;
62
+ let profiles;
63
+ const allowlist = [];
64
+ const positionals = [];
65
+ for (let i = 0; i < args.length; i++) {
66
+ const arg = args[i];
67
+ if (arg === "--json" || arg === "--exit-code")
68
+ continue;
69
+ if (arg === "--profile") {
70
+ const value = args[++i];
71
+ if (value)
72
+ profiles = value.split(",").map((s) => s.trim()).filter(Boolean);
73
+ continue;
74
+ }
75
+ if (arg === "--allow") {
76
+ const file = args[++i];
77
+ if (!file)
78
+ throw new UsageError("--allow needs a file path", "E_BAD_FLAG");
79
+ allowlist.push(...parseAllowlist(readFileSync(path.resolve(process.cwd(), file), "utf8")));
80
+ continue;
81
+ }
82
+ if (arg === "--min-entropy-len") {
83
+ const n = Number(args[++i]);
84
+ if (Number.isFinite(n) && n > 0)
85
+ minEntropyLen = n;
86
+ continue;
87
+ }
88
+ if (arg.startsWith("--"))
89
+ throw new UsageError(`unknown scan flag: ${arg}`, "E_BAD_FLAG");
90
+ positionals.push(arg);
91
+ }
92
+ const opts = { allowlist, minEntropyLen, profiles };
93
+ const results = [];
94
+ const targets = positionals.filter((p) => p !== "-");
95
+ const wantStdin = positionals.includes("-") || (positionals.length === 0 && !process.stdin.isTTY);
96
+ if (positionals.length === 0 && process.stdin.isTTY) {
97
+ throw new UsageError("scan target missing: pass a file, a directory, or - for stdin", "E_BAD_FLAG");
98
+ }
99
+ if (wantStdin)
100
+ results.push({ file: "<stdin>", result: scanText(readFileSync(0, "utf8"), opts) });
101
+ const files = [];
102
+ const skipped = [];
103
+ for (const p of targets) {
104
+ const resolved = path.resolve(process.cwd(), p);
105
+ if (!existsSync(resolved))
106
+ throw new Error(`scan target not found: ${p}`);
107
+ collectScanTargets(resolved, files, skipped);
108
+ }
109
+ // A skipped file is surfaced, never silently dropped: an unscanned path is a
110
+ // coverage gap the caller must be able to see (blindspot: NUL-early binaries).
111
+ for (const file of files.sort()) {
112
+ const rel = path.relative(process.cwd(), file) || file;
113
+ let buf;
114
+ try {
115
+ buf = readFileSync(file);
116
+ }
117
+ catch {
118
+ skipped.push({ file: rel, reason: "unreadable" });
119
+ continue;
120
+ }
121
+ if (!isProbablyText(buf)) {
122
+ skipped.push({ file: rel, reason: "binary" });
123
+ continue;
124
+ }
125
+ results.push({ file: rel, result: scanText(buf.toString("utf8"), opts) });
126
+ }
127
+ const totals = { high: 0, medium: 0, low: 0, total: 0 };
128
+ for (const r of results) {
129
+ totals.high += r.result.counts.high;
130
+ totals.medium += r.result.counts.medium;
131
+ totals.low += r.result.counts.low;
132
+ totals.total += r.result.counts.total;
133
+ }
134
+ // Pure reporting by default (exit 0). --exit-code makes high-confidence
135
+ // findings non-zero for scripting; the blocking gate proper is T-003.
136
+ const exitCode = exitOnFindings && totals.high > 0 ? 2 : 0;
137
+ if (json) {
138
+ const payload = { schema_version: "0.1", scanned: results.length, skipped, totals, results };
139
+ return { output: `${JSON.stringify(payload, null, 2)}\n`, exitCode };
140
+ }
141
+ const lines = ["foo scan", ""];
142
+ const withFindings = results.filter((r) => r.result.findings.length > 0);
143
+ if (withFindings.length === 0) {
144
+ lines.push(` no secrets detected across ${results.length} file(s).`);
145
+ }
146
+ else {
147
+ for (const r of withFindings) {
148
+ lines.push(r.file);
149
+ for (const f of r.result.findings) {
150
+ const ent = f.entropy !== undefined ? ` entropy=${f.entropy}` : "";
151
+ lines.push(` ${f.line}:${f.column} [${f.confidence}] ${f.detector} (len ${f.length})${ent}`);
152
+ }
153
+ lines.push("");
154
+ }
155
+ }
156
+ lines.push(`Totals: ${totals.high} high · ${totals.medium} medium · ${totals.low} low (${totals.total} findings, ${results.length} file(s))`);
157
+ if (skipped.length > 0) {
158
+ lines.push(`Skipped (not scanned): ${skipped.length} file(s)`);
159
+ for (const s of skipped)
160
+ lines.push(` ${s.file} — ${s.reason}`);
161
+ }
162
+ lines.push("Note: scan reports; the fail-closed commit gate (T-003) decides what blocks. Secret values are never shown (R-007).");
163
+ lines.push("");
164
+ return { output: lines.join("\n"), exitCode };
165
+ }
166
+ // --- foo redact (prompt_redaction_safety_v0 T-002) ---------------------------
167
+ // Replace detected secrets with consistent, irreversible placeholders and emit
168
+ // a metadata-only receipt (R-002, R-003). Default prints redacted output to
169
+ // stdout (non-mutating); --write overwrites the file (explicit), --dry-run
170
+ // previews the receipt and changed lines without writing.
171
+ function renderRedactionReceipt(receipt) {
172
+ const lines = [
173
+ `Redactions: ${receipt.redactions} (${receipt.by_confidence.high} high · ${receipt.by_confidence.medium} medium · ${receipt.by_confidence.low} low)`,
174
+ ];
175
+ const types = Object.keys(receipt.by_type).sort();
176
+ if (types.length)
177
+ lines.push(` by type: ${types.map((t) => `${t}=${receipt.by_type[t]}`).join(", ")}`);
178
+ if (receipt.placeholders.length)
179
+ lines.push(` placeholders: ${receipt.placeholders.join(", ")}`);
180
+ if (receipt.kept.length) {
181
+ lines.push(` kept for review (below threshold): ${receipt.kept.length}`);
182
+ for (const k of receipt.kept)
183
+ lines.push(` ${k.line}:${k.column} ${k.detector} [${k.confidence}] — ${k.reason}`);
184
+ }
185
+ return lines;
186
+ }
187
+ export function runRedactCommand(args) {
188
+ const json = args.includes("--json");
189
+ const dryRun = args.includes("--dry-run");
190
+ const write = args.includes("--write");
191
+ let threshold = "medium";
192
+ if (args.includes("--high-only"))
193
+ threshold = "high";
194
+ if (args.includes("--include-low"))
195
+ threshold = "low";
196
+ let minEntropyLen = 20;
197
+ let profiles;
198
+ const allowlist = [];
199
+ const positionals = [];
200
+ const flags = new Set(["--json", "--dry-run", "--write", "--high-only", "--include-low"]);
201
+ for (let i = 0; i < args.length; i++) {
202
+ const arg = args[i];
203
+ if (flags.has(arg))
204
+ continue;
205
+ if (arg === "--profile") {
206
+ const value = args[++i];
207
+ if (value)
208
+ profiles = value.split(",").map((s) => s.trim()).filter(Boolean);
209
+ continue;
210
+ }
211
+ if (arg === "--allow") {
212
+ const file = args[++i];
213
+ if (!file)
214
+ throw new UsageError("--allow needs a file path", "E_BAD_FLAG");
215
+ allowlist.push(...parseAllowlist(readFileSync(path.resolve(process.cwd(), file), "utf8")));
216
+ continue;
217
+ }
218
+ if (arg === "--min-entropy-len") {
219
+ const n = Number(args[++i]);
220
+ if (Number.isFinite(n) && n > 0)
221
+ minEntropyLen = n;
222
+ continue;
223
+ }
224
+ if (arg.startsWith("--"))
225
+ throw new UsageError(`unknown redact flag: ${arg}`, "E_BAD_FLAG");
226
+ positionals.push(arg);
227
+ }
228
+ if (positionals.length > 1)
229
+ throw new UsageError("redact accepts one file or - for stdin", "E_BAD_FLAG");
230
+ const target = positionals[0];
231
+ const fromStdin = !target || target === "-";
232
+ if (write && fromStdin)
233
+ throw new UsageError("--write needs a file target (not stdin)", "E_BAD_FLAG");
234
+ if (!target && process.stdin.isTTY)
235
+ throw new UsageError("redact target missing: pass a file or - for stdin", "E_BAD_FLAG");
236
+ const inputPath = fromStdin ? null : path.resolve(process.cwd(), target);
237
+ if (inputPath && !existsSync(inputPath))
238
+ throw new Error(`redact target not found: ${target}`);
239
+ const text = fromStdin ? readFileSync(0, "utf8") : readFileSync(inputPath, "utf8");
240
+ const { redactedText, receipt } = redactText(text, { allowlist, minEntropyLen, threshold, profiles });
241
+ if (json) {
242
+ return { output: `${JSON.stringify({ schema_version: "0.1", receipt, redactedText }, null, 2)}\n`, exitCode: 0 };
243
+ }
244
+ if (dryRun) {
245
+ const origLines = text.split("\n");
246
+ const redLines = redactedText.split("\n");
247
+ const changed = [];
248
+ for (let i = 0; i < redLines.length; i++) {
249
+ if (origLines[i] !== redLines[i])
250
+ changed.push(` ${i + 1}: ${redLines[i]}`);
251
+ }
252
+ const lines = ["foo redact --dry-run", "", ...renderRedactionReceipt(receipt), ""];
253
+ if (changed.length)
254
+ lines.push("Preview (redacted lines — secret values already removed):", ...changed, "");
255
+ lines.push("(--dry-run: no output emitted, no file written. Drop --dry-run to emit; add --write to overwrite the file.)");
256
+ lines.push("");
257
+ return { output: lines.join("\n"), exitCode: 0 };
258
+ }
259
+ if (write && inputPath) {
260
+ writeFileSync(inputPath, redactedText);
261
+ const rel = path.relative(process.cwd(), inputPath) || target;
262
+ return { output: [`foo redact — wrote ${rel}`, "", ...renderRedactionReceipt(receipt), ""].join("\n"), exitCode: 0 };
263
+ }
264
+ // Default: emit redacted content to stdout (non-mutating).
265
+ return { output: redactedText, exitCode: 0 };
266
+ }
@@ -0,0 +1,28 @@
1
+ import { type ChannelFreshness } from "../channelFreshness.js";
2
+ type HooksWiringState = "wired" | "unset-safe" | "conflict" | "no-dir";
3
+ export declare function hooksWiringPlan(input: {
4
+ dirPresent: boolean;
5
+ currentHooksPath: string | null;
6
+ }): {
7
+ state: HooksWiringState;
8
+ wired: boolean;
9
+ };
10
+ export declare function wireHooks(): string;
11
+ type BuildFreshnessState = "no-src" | "no-build" | "fresh" | "stale";
12
+ export declare function buildFreshnessPlan(input: {
13
+ newestSrcMtimeMs: number | null;
14
+ distMtimeMs: number | null;
15
+ }): {
16
+ state: BuildFreshnessState;
17
+ stale: boolean;
18
+ };
19
+ export type ResearchGateWiring = {
20
+ label: string;
21
+ format: string;
22
+ wired: boolean;
23
+ };
24
+ export declare function researchGateWiring(root: string): ResearchGateWiring[];
25
+ export declare function currentHarnessLabel(env?: NodeJS.ProcessEnv): string | null;
26
+ export declare function researchGateDoctorLine(wiring: ResearchGateWiring[], currentLabel: string | null): string;
27
+ export declare function renderDoctor(root: string, format: "text" | "json", selfRoot?: string, freshness?: ChannelFreshness, homeRoot?: string, now?: () => string): string;
28
+ export {};