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,398 @@
1
+ // `foo doctor` and its --fix: install readiness, skills-bundle adapter checks,
2
+ // and the .githooks wiring status. Setup/repair of harness command files lives
3
+ // in the agent module (foo agent setup).
4
+ import { existsSync, lstatSync, readdirSync, readFileSync } from "node:fs";
5
+ import { homedir } from "node:os";
6
+ import path from "node:path";
7
+ import { gitRun, gitRunOrNull } from "../gitRun.js";
8
+ import { readPackageVersion, ROOT } from "./shared.js";
9
+ import { HARNESS_GATES } from "../harnessGates.js";
10
+ import { AGENT_DEFINITIONS, agentCommandState, codexGlobalAdapterStatus } from "./agent.js";
11
+ import { channelFreshness, distributionPackageName, } from "../channelFreshness.js";
12
+ import { UPDATE_COMMAND, noticeAudience } from "../updateNotice.js";
13
+ import { firecrawlKeyStatus } from "./login.js";
14
+ import { resolveHarnessCommandTarget } from "../agentAdapters.js";
15
+ import { bundledSkillTreeVerified, inspectDevelopmentSkillTrust } from "../skillLocal.js";
16
+ import { BUNDLED_SKILL_TREE } from "../skillClientPolicy.js";
17
+ // Top-level `foo doctor` reports whether productfoo's skills-bundle adapter is present
18
+ // for each agent; the command/plugin layer is handled by `foo agent` instead.
19
+ function adapterStatus(root, homeRoot, agent) {
20
+ const project = resolveHarnessCommandTarget(agent, "project");
21
+ const global = resolveHarnessCommandTarget(agent, "global");
22
+ const scope = project.supported ? "project" : global.supported ? "global" : "unsupported";
23
+ if (scope === "unsupported") {
24
+ const projectReason = project.supported ? null : project.reason;
25
+ const globalReason = global.supported ? null : global.reason;
26
+ return { scope, resolvedPath: `unsupported: ${projectReason ?? globalReason ?? "no supported command scope"}`, status: "unsupported" };
27
+ }
28
+ if (agent.id === "codex") {
29
+ const codex = codexGlobalAdapterStatus(homeRoot);
30
+ return { scope: "global", resolvedPath: codex.command_path, status: codex.status };
31
+ }
32
+ const base = scope === "global" ? homeRoot : root;
33
+ const resolvedPath = path.join(base, agent.projectPath);
34
+ if (existsSync(resolvedPath))
35
+ return { scope, resolvedPath, status: "ready" };
36
+ // #930: first-run setup (#913) installs productfoo's commands in GLOBAL scope, in
37
+ // the user's home, for every project. A project without its own copy is
38
+ // still set up when productfoo's command files are installed globally, so report
39
+ // that rather than "missing". The check looks for productfoo's own launchers,
40
+ // never just a directory the user may use for their own commands.
41
+ if (scope === "project" && global.supported && agentCommandState(homeRoot, agent, "global").installed.length > 0) {
42
+ return { scope: "global", resolvedPath: path.join(homeRoot, global.dir), status: "ready" };
43
+ }
44
+ return { scope, resolvedPath, status: "missing" };
45
+ }
46
+ // Pure decision: given whether .githooks exists and the current core.hooksPath,
47
+ // what should `foo doctor` do? Side-effect-free so it is unit-testable.
48
+ export function hooksWiringPlan(input) {
49
+ if (!input.dirPresent)
50
+ return { state: "no-dir", wired: false };
51
+ const value = input.currentHooksPath;
52
+ if (value === null || value === "")
53
+ return { state: "unset-safe", wired: false };
54
+ const normalized = value.replace(/^\.\//, "").replace(/\/+$/, "");
55
+ if (normalized === ".githooks")
56
+ return { state: "wired", wired: true };
57
+ return { state: "conflict", wired: false };
58
+ }
59
+ // Hooks operate on the repo the user is in (cwd), not productfoo's install dir (root).
60
+ function repoRootFromCwd() {
61
+ const out = gitRunOrNull(["rev-parse", "--show-toplevel"]);
62
+ return out === null ? null : out.trim() || null;
63
+ }
64
+ function hooksStatus() {
65
+ const repo = repoRootFromCwd();
66
+ if (!repo)
67
+ return { dirPresent: false, currentHooksPath: null, ...hooksWiringPlan({ dirPresent: false, currentHooksPath: null }) };
68
+ const dirPresent = existsSync(path.join(repo, ".githooks"));
69
+ const configOut = gitRunOrNull(["-C", repo, "config", "--local", "core.hooksPath"]);
70
+ const currentHooksPath = configOut === null ? null : configOut.trim() || null;
71
+ return { dirPresent, currentHooksPath, ...hooksWiringPlan({ dirPresent, currentHooksPath }) };
72
+ }
73
+ export function wireHooks() {
74
+ const repo = repoRootFromCwd();
75
+ if (!repo)
76
+ return "foo doctor --fix: not inside a git repository.\n";
77
+ const status = hooksStatus();
78
+ if (status.state === "no-dir")
79
+ return "foo doctor --fix: no .githooks/ directory to wire.\n";
80
+ if (status.state === "wired")
81
+ return "foo doctor --fix: commit hooks already active (core.hooksPath -> .githooks).\n";
82
+ if (status.state === "conflict") {
83
+ return `foo doctor --fix: core.hooksPath is set to "${status.currentHooksPath}", not .githooks. ` +
84
+ "Refusing to clobber a custom hooks path; set it yourself if intended: git config core.hooksPath .githooks\n";
85
+ }
86
+ const set = gitRun(["-C", repo, "config", "--local", "core.hooksPath", ".githooks"]);
87
+ if (!set.ok) {
88
+ return `foo doctor --fix: could not set core.hooksPath (${set.message}).\n`;
89
+ }
90
+ return "foo doctor --fix: wired core.hooksPath -> .githooks. productfoo's commit hooks (branch guard + spec-after keep-it nudge) are now active.\n";
91
+ }
92
+ function hooksDoctorLine(status) {
93
+ switch (status.state) {
94
+ case "wired":
95
+ return "Commit hooks: active (.githooks)";
96
+ case "unset-safe":
97
+ return "Commit hooks: present but not wired — run `foo doctor --fix`";
98
+ case "conflict":
99
+ return `Commit hooks: core.hooksPath set elsewhere (${status.currentHooksPath}) — wire .githooks manually if intended`;
100
+ case "no-dir":
101
+ return "Commit hooks: no .githooks/ directory";
102
+ }
103
+ }
104
+ // Pure decision: given the newest source mtime and the compiled CLI's mtime,
105
+ // is the build the CLI is running from stale? Side-effect-free so it is
106
+ // unit-testable. `null` means the tree is absent — an npm install ships
107
+ // dist/ without src/, so "no-src" is the healthy installed state.
108
+ export function buildFreshnessPlan(input) {
109
+ if (input.newestSrcMtimeMs === null)
110
+ return { state: "no-src", stale: false };
111
+ if (input.distMtimeMs === null)
112
+ return { state: "no-build", stale: true };
113
+ if (input.newestSrcMtimeMs > input.distMtimeMs)
114
+ return { state: "stale", stale: true };
115
+ return { state: "fresh", stale: false };
116
+ }
117
+ function newestSourceMtimeMs(dir) {
118
+ if (!existsSync(dir))
119
+ return null;
120
+ let newest = null;
121
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
122
+ const full = path.join(dir, entry.name);
123
+ let candidate = null;
124
+ if (entry.isDirectory())
125
+ candidate = newestSourceMtimeMs(full);
126
+ else if (entry.isFile() && entry.name.endsWith(".ts"))
127
+ candidate = lstatSync(full).mtimeMs;
128
+ if (candidate !== null && (newest === null || candidate > newest))
129
+ newest = candidate;
130
+ }
131
+ return newest;
132
+ }
133
+ // Compares productfoo's OWN src/ and dist/ (module-relative ROOT), never the cwd: a
134
+ // tester running doctor inside THEIR project (which has a src/ but no foo
135
+ // build) was told "run `npm run build`" about code that wasn't productfoo's.
136
+ function buildFreshnessStatus(selfRoot) {
137
+ const distCli = path.join(selfRoot, "dist", "src", "cli.js");
138
+ return buildFreshnessPlan({
139
+ newestSrcMtimeMs: newestSourceMtimeMs(path.join(selfRoot, "src")),
140
+ distMtimeMs: existsSync(distCli) ? lstatSync(distCli).mtimeMs : null,
141
+ });
142
+ }
143
+ // Advisory signal, never a block: a stale build means `bin/foo` is silently
144
+ // running old code. Omitted entirely for npm installs (no src/ to compare).
145
+ function buildDoctorLine(status) {
146
+ switch (status.state) {
147
+ case "no-src":
148
+ return null;
149
+ case "no-build":
150
+ return "Build: src/ present but no compiled dist/src/cli.js — run `npm run build`";
151
+ case "stale":
152
+ return "Build: stale — src/ is newer than dist/, so the CLI is running old code. Run `npm run build`";
153
+ case "fresh":
154
+ return "Build: dist/ up to date with src/";
155
+ }
156
+ }
157
+ // Advisory signal, never a block. Every install gets an answer: a tester on a
158
+ // stale build asked doctor what was wrong and doctor said nothing, because this
159
+ // line used to be gated on having a channel install — which only the owner has.
160
+ // "Nothing to update" is the one silent state, and only for a repo checkout with
161
+ // no channel beside it.
162
+ //
163
+ // The wording follows the install: an owner running the repo build is being told
164
+ // about a channel they know they have; a tester is being told about the client
165
+ // they are running. Neither should have to learn the other's vocabulary.
166
+ function channelDoctorLine(freshness) {
167
+ // An installed client updates itself now — one word, and `foo update` installs
168
+ // into whichever prefix it is actually running from (global npm, or the channel
169
+ // dir the PATH shim execs). The exception is a REPO run: it is telling you about
170
+ // a channel install that `bin/foo update` deliberately will not touch, so that
171
+ // one still names the npm line that would fix it — pinned to the version the
172
+ // check just read, in the tilde form the docs print. This is a display line,
173
+ // not an argv; the executable form lives in commands/update.ts, which builds
174
+ // it from the same contract (the package name is never re-hardcoded here).
175
+ const channelRefreshDisplay = () => {
176
+ if (!freshness.latest)
177
+ return null; // only the "behind" state reaches this; keep the type honest
178
+ return `npm install --prefix ~/.foo/versions/dist ${distributionPackageName()}@${freshness.latest}`;
179
+ };
180
+ const refresh = freshness.kind === "repo" ? channelRefreshDisplay() : UPDATE_COMMAND;
181
+ if (freshness.kind === "repo") {
182
+ switch (freshness.state) {
183
+ case "no-channel":
184
+ return null;
185
+ case "current":
186
+ return `Client: dist channel ${freshness.installed} — the newest published release`;
187
+ case "unknown":
188
+ return `Client: dist channel ${freshness.installed} — could not check npm for a newer release, so one may exist`;
189
+ case "behind":
190
+ return refresh
191
+ ? `Client: dist channel ${freshness.installed} is behind the published ${freshness.latest} — bare \`foo\` is serving the old client. Refresh it: ${refresh}`
192
+ : null;
193
+ }
194
+ }
195
+ switch (freshness.state) {
196
+ case "no-channel":
197
+ return null;
198
+ case "current":
199
+ return `Client: ${freshness.installed} — the newest published release`;
200
+ case "unknown":
201
+ return `Client: ${freshness.installed} — could not check for a newer release, so one may exist`;
202
+ case "behind":
203
+ return `Client: ${freshness.installed} — ${freshness.latest} is available. Update: ${refresh}`;
204
+ }
205
+ }
206
+ export function researchGateWiring(root) {
207
+ return HARNESS_GATES.map((gate) => {
208
+ const file = path.join(root, gate.configPath);
209
+ let wired = false;
210
+ try {
211
+ wired = existsSync(file) && /guard-research|foo-research-gate/i.test(readFileSync(file, "utf8"));
212
+ }
213
+ catch {
214
+ wired = false; // unreadable config is not verifiable wiring — never claim it
215
+ }
216
+ return { label: gate.label, format: gate.format, wired };
217
+ });
218
+ }
219
+ // Which coding agent this shell belongs to, by the markers harnesses set for
220
+ // their tool shells (same source of truth as the handoff detector).
221
+ const HARNESS_MARKER_LABELS = [
222
+ ["CLAUDECODE", "Claude Code"],
223
+ ["CLAUDE_CODE", "Claude Code"],
224
+ ["CODEX_SANDBOX", "Codex"],
225
+ ["CURSOR_AGENT", "Cursor"],
226
+ ["OPENCODE", "OpenCode"],
227
+ ];
228
+ export function currentHarnessLabel(env = process.env) {
229
+ for (const [marker, label] of HARNESS_MARKER_LABELS)
230
+ if (env[marker])
231
+ return label;
232
+ return null;
233
+ }
234
+ export function researchGateDoctorLine(wiring, currentLabel) {
235
+ const wiredLabels = wiring.filter((entry) => entry.wired).map((entry) => entry.label);
236
+ const notWired = wiring.filter((entry) => !entry.wired).map((entry) => entry.label);
237
+ const summary = `${wiredLabels.length ? `Wired: ${wiredLabels.join(", ")}` : "Wired: none"}${notWired.length ? ` · not wired: ${notWired.join(", ")} — \`foo research install-gate\`` : ""}`;
238
+ const paperRefusal = "an ungoverned paper is still refused as evidence — a paper naming no `foo research` run does not count.";
239
+ if (currentLabel === null) {
240
+ return `Research gate: no coding agent detected in this shell — enforcement lives in the agent's tool hooks. ${summary}. Everywhere else, ${paperRefusal}`;
241
+ }
242
+ const here = wiring.find((entry) => entry.label === currentLabel);
243
+ if (!here) {
244
+ // An unknown harness has no verified gate adapter.
245
+ return `Research gate: ${currentLabel} cannot enforce tool hooks — here, ${paperRefusal} ${summary}.`;
246
+ }
247
+ return here.wired
248
+ ? `Research gate: enforced here in ${currentLabel} (web refused until \`foo research\` runs). ${summary}.`
249
+ : `Research gate: not wired in ${currentLabel} yet — \`foo research install-gate\`. Until then, ${paperRefusal} ${summary}.`;
250
+ }
251
+ export function renderDoctor(root, format, selfRoot = ROOT, freshness = channelFreshness(), homeRoot = homedir(), now = () => new Date().toISOString()) {
252
+ const version = readPackageVersion(root);
253
+ // Only the running package can supply trusted skills. A caller repository may
254
+ // contain a same-shaped registry, but it cannot change delivery mode or make
255
+ // an incomplete install report itself as bundled.
256
+ const skillsPresent = existsSync(path.join(selfRoot, "skills", "skill-registry.yaml"));
257
+ const developmentTrust = skillsPresent
258
+ ? inspectDevelopmentSkillTrust(selfRoot, path.join(homeRoot, ".foo", "trust", "development-skill-source.json"), now())
259
+ : null;
260
+ const firecrawl = firecrawlKeyStatus();
261
+ // #897: bundled skills that match this release's anchor load with no
262
+ // approval step (skillLocal readBundledCanonicalSkill), so doctor must not
263
+ // send that install to `foo skill trust`. Only an edited or unanchored tree
264
+ // genuinely needs the development approval.
265
+ const bundledVerified = skillsPresent && developmentTrust?.status !== "ready" && bundledSkillTreeVerified(selfRoot);
266
+ const skillsMode = skillsPresent
267
+ ? developmentTrust?.status === "ready" ? "verified" : bundledVerified ? "bundled" : "needs_approval"
268
+ : "unavailable";
269
+ const adapters = AGENT_DEFINITIONS.map((agent) => {
270
+ const resolved = adapterStatus(root, homeRoot, agent);
271
+ return {
272
+ id: agent.id,
273
+ label: agent.label,
274
+ project_path: agent.projectPath,
275
+ scope: resolved.scope,
276
+ resolved_path: resolved.resolvedPath,
277
+ status: resolved.status,
278
+ };
279
+ });
280
+ const anyAdapterReady = adapters.some((adapter) => adapter.status === "ready");
281
+ const hooks = hooksStatus();
282
+ const gateWiring = researchGateWiring(root);
283
+ const harnessLabel = currentHarnessLabel();
284
+ const gateHere = gateWiring.find((entry) => entry.label === harnessLabel);
285
+ const build = buildFreshnessStatus(selfRoot);
286
+ // Installed = foo resolves its own package (version known). Skills are a
287
+ // separate axis: bundled (repo/full install) or unavailable (no trusted
288
+ // local package content). A token never turns a missing skill remote.
289
+ const installed = version !== "unknown";
290
+ const setUp = anyAdapterReady;
291
+ // doctor is the readiness check; `foo init` is the hero first-run. Once
292
+ // companions are set up, doctor hands off to `foo init`. Until then it keeps
293
+ // the setup hand-off (preserving the installer's machine-readable signal,
294
+ // npm-installer-v0 R-005).
295
+ const nextCommand = !installed
296
+ ? "reinstall foo: the CLI cannot resolve its own package"
297
+ : skillsMode === "needs_approval"
298
+ ? "foo skill trust"
299
+ : skillsMode === "unavailable"
300
+ ? "reinstall productfoo with its bundled skills, then run `foo doctor`"
301
+ : setUp
302
+ ? "foo init"
303
+ : "foo agent setup --agent all --scope project --dry-run";
304
+ const payload = {
305
+ schema_version: "0.1",
306
+ foo: {
307
+ installed,
308
+ version,
309
+ bundled_skills: skillsPresent,
310
+ skills_mode: skillsMode,
311
+ development_trust: developmentTrust,
312
+ firecrawl_key: firecrawl.present,
313
+ firecrawl_key_source: firecrawl.source,
314
+ },
315
+ companions: {
316
+ set_up: setUp,
317
+ adapters,
318
+ },
319
+ hooks: {
320
+ dir_present: hooks.dirPresent,
321
+ hooks_path: hooks.currentHooksPath,
322
+ wired: hooks.wired,
323
+ state: hooks.state,
324
+ },
325
+ research_gate: {
326
+ current_harness: harnessLabel,
327
+ enforced_here: harnessLabel === null ? null : Boolean(gateHere?.wired),
328
+ harnesses: gateWiring.map(({ label, wired }) => ({ label, wired })),
329
+ },
330
+ build: {
331
+ state: build.state,
332
+ stale: build.stale,
333
+ },
334
+ client: {
335
+ channel_state: freshness.state,
336
+ kind: freshness.kind,
337
+ installed: freshness.installed,
338
+ latest_published: freshness.latest,
339
+ },
340
+ update_relay: noticeAudience(process.env, false) === "agent" ? "active" : "terminal_only",
341
+ next_command: nextCommand,
342
+ };
343
+ if (format === "json")
344
+ return `${JSON.stringify(payload, null, 2)}\n`;
345
+ // Where does B5 actually bind? Two different answers, and conflating them is how a
346
+ // boundary becomes a comforting lie.
347
+ //
348
+ // Tool-hook coverage depends on the selected harness and its wiring. The registry
349
+ // reports those limits; an unwired or partially covered host cannot refuse every
350
+ // research action. Evidence validation must therefore remain independent of hooks.
351
+ //
352
+ // There, productfoo refuses the RESULT instead: a paper that cannot name a run `foo research`
353
+ // actually minted is not evidence, and that check is productfoo's own CLI, so it holds everywhere.
354
+ // The reading is not stopped. It just does not count.
355
+ // Which surface the update offer can actually reach here — the same honesty rule
356
+ // as the research gate: never claim a reach productfoo does not have. `relay active`
357
+ // means a harness is detected, so a person who only ever drives foo through an
358
+ // agent still gets offered updates. `terminal-only` means no marker, so the offer
359
+ // reaches only an attended terminal. (agent-relay R-005)
360
+ function updateRelayDoctorLine(env = process.env) {
361
+ // Force the non-TTY view: the question is "would an agent-only run be reached",
362
+ // not "is a human at the terminal right now".
363
+ const relayActive = noticeAudience(env, false) === "agent";
364
+ return relayActive
365
+ ? "Update relay: active — an agent running productfoo will be offered new builds to pass on to you, even with no terminal."
366
+ : "Update relay: terminal-only — the update offer reaches only an attended terminal; an agent-only run cannot be told (no harness detected).";
367
+ }
368
+ return [
369
+ "foo doctor",
370
+ "",
371
+ `productfoo installed: ${installed ? "yes" : "no"} (version ${version})`,
372
+ skillsMode === "verified" && developmentTrust?.status === "ready"
373
+ ? `Skills: verified development tree ${developmentTrust.skills_sha256.slice(0, 12)} (valid until ${developmentTrust.expires_at})`
374
+ : skillsMode === "bundled"
375
+ ? `Skills: ${BUNDLED_SKILL_TREE.skill_count} bundled skills, verified against this release — no approval step needed`
376
+ : skillsMode === "needs_approval"
377
+ ? "Skills: on disk but not approved — run `foo skill trust`"
378
+ : "Skills: unavailable in this build — reinstall productfoo with its bundled skills",
379
+ `Firecrawl: ${firecrawl.detail}`,
380
+ `Companion stack set up: ${setUp ? "yes" : "no"}`,
381
+ // Say plainly WHERE the research boundary actually binds. productfoo can refuse a web read
382
+ // only in a harness that gives it a tool-call hook; everywhere else the reading
383
+ // happens and productfoo refuses the RESULT instead. Reporting "enforced" in a harness where
384
+ // it isn't would be the worst outcome — a boundary people trust and don't have.
385
+ researchGateDoctorLine(gateWiring, harnessLabel),
386
+ updateRelayDoctorLine(),
387
+ hooksDoctorLine(hooks),
388
+ buildDoctorLine(build) ?? "",
389
+ channelDoctorLine(freshness) ?? "",
390
+ "",
391
+ ...adapters.map((adapter) => `${adapter.label}: ${adapter.status} (${adapter.scope}: ${adapter.resolved_path})`),
392
+ "",
393
+ "Install puts foo on the machine; setup makes the companion stack real.",
394
+ `Next: ${nextCommand}`,
395
+ installed && setUp ? "Start here: foo init reads your repo and suggests a first move." : "",
396
+ "",
397
+ ].filter((line, index, all) => !(line === "" && all[index - 1] === "")).join("\n");
398
+ }
@@ -0,0 +1,17 @@
1
+ import { type FailureMark } from "../errorTaxonomy.js";
2
+ export declare const ROOT: string;
3
+ export declare function failWith(message: string, mark?: Partial<FailureMark>): number;
4
+ /**
5
+ * A command threw. Classify it honestly (io_error for an errno, command_error otherwise),
6
+ * keep the message and stack for the local log, and print the message as before.
7
+ */
8
+ export declare function failSkillDelivery(error: unknown): number | null;
9
+ export declare function failThrown(error: unknown, args?: string[]): number;
10
+ export declare function loadRegisteredSkills(root: string): Map<string, string>;
11
+ export declare function registeredSkillPath(registeredSkills: Map<string, string>, skill: string): string;
12
+ export declare function resolvePacketDir(root: string, packetArg: string | undefined): {
13
+ packetDir: string;
14
+ packetArg: string;
15
+ };
16
+ export { hasFlag, flagValue } from "../cliArgs.js";
17
+ export declare function readPackageVersion(root: string): string;
@@ -0,0 +1,147 @@
1
+ // Small cross-domain CLI utilities shared by the command modules under
2
+ // src/commands/. Kept here (not in cli.ts) so domain modules never import the
3
+ // entry point — no circular imports.
4
+ import { existsSync, readFileSync, realpathSync, statSync } from "node:fs";
5
+ import path from "node:path";
6
+ import { fileURLToPath } from "node:url";
7
+ import { classifyThrown, markFailure, NotFoundError, UsageError } from "../errorTaxonomy.js";
8
+ import { parse as parseYaml } from "../vendorYaml.js";
9
+ import { readJson } from "../jsonFile.js";
10
+ import { SkillDeliveryError, markSkillFailure } from "../skillLocal.js";
11
+ const moduleDir = path.dirname(fileURLToPath(import.meta.url));
12
+ // productfoo's own install dir, for loading productfoo's bundled assets (commands/), NOT for
13
+ // resolving the user's packets. Resolved relative to this module's compiled
14
+ // location (dist/src/commands/) — three levels up to the package root.
15
+ export const ROOT = path.resolve(moduleDir, "..", "..", "..");
16
+ // error-instrumentation-v0 T-001. Two ways to fail, and they are NOT the same thing:
17
+ //
18
+ // failWith(literal) — "you invoked this wrong". A missing arg, an unknown domain.
19
+ // foo prints usage. It is a typo. It must never page anyone.
20
+ // failThrown(error) — something threw. Nobody predicted it. It IS a defect.
21
+ // It pages, and it carries its message and stack to the LOCAL log.
22
+ //
23
+ // They are separate functions on purpose. When both were spelled `failWith`, a genuine
24
+ // crash caught in a dispatch catch-block was indistinguishable from a typo — and marking
25
+ // those 39 catch-alls as usage errors would have SILENCED every real bug in foo. A false
26
+ // "typo" hides a defect; a false "defect" merely pages you. So the shapes must differ,
27
+ // and the honest default is to page.
28
+ export function failWith(message, mark) {
29
+ markFailure({
30
+ errorClass: mark?.errorClass ?? "usage_error",
31
+ errorCode: mark?.errorCode ?? "E_BAD_FLAG",
32
+ message: mark?.message ?? message,
33
+ ...(mark?.stack ? { stack: mark.stack } : {}),
34
+ });
35
+ process.stderr.write(`${message}\n`);
36
+ process.stderr.write("Run `foo --help` to see all commands.\n");
37
+ return 1;
38
+ }
39
+ /**
40
+ * A command threw. Classify it honestly (io_error for an errno, command_error otherwise),
41
+ * keep the message and stack for the local log, and print the message as before.
42
+ */
43
+ export function failSkillDelivery(error) {
44
+ if (!(error instanceof SkillDeliveryError))
45
+ return null;
46
+ markSkillFailure(error.kind, error.message);
47
+ process.stderr.write(`${error.message}\n`);
48
+ return 1;
49
+ }
50
+ export function failThrown(error, args = process.argv.slice(2)) {
51
+ const skill = failSkillDelivery(error);
52
+ if (skill !== null)
53
+ return skill;
54
+ const mark = classifyThrown(error);
55
+ markFailure(mark);
56
+ process.stderr.write(`${mark.message}\n`);
57
+ process.stderr.write("Run `foo --help` to see all commands.\n");
58
+ return 1;
59
+ }
60
+ export function loadRegisteredSkills(root) {
61
+ void root;
62
+ // Every branch below is an integrity check on productfoo's own bundled tree: the
63
+ // registry is missing, malformed, or names a path that escapes skills/.
64
+ // That is a broken or tampered install, and saying so beats reporting an
65
+ // outage the reader can neither wait out nor fix.
66
+ const unreadable = () => {
67
+ throw new SkillDeliveryError("unapproved-source", "productfoo's bundled skill registry could not be read safely — it is missing, malformed, or points outside skills/. Reinstall or update productfoo.");
68
+ };
69
+ try {
70
+ const lexicalSkillsRoot = path.join(ROOT, "skills");
71
+ const realSkillsRoot = realpathSync(lexicalSkillsRoot);
72
+ const registryPath = path.join(realSkillsRoot, "skill-registry.yaml");
73
+ if (!statSync(registryPath).isFile())
74
+ return unreadable();
75
+ const registry = parseYaml(readFileSync(registryPath, "utf8"));
76
+ if (!Array.isArray(registry.skills))
77
+ return unreadable();
78
+ const resolved = new Map();
79
+ for (const skill of registry.skills) {
80
+ if (typeof skill.id !== "string" || typeof skill.path !== "string" || path.isAbsolute(skill.path))
81
+ return unreadable();
82
+ const candidate = path.resolve(ROOT, skill.path);
83
+ const lexicalRelative = path.relative(lexicalSkillsRoot, candidate);
84
+ if (!lexicalRelative || lexicalRelative.startsWith(`..${path.sep}`) || lexicalRelative === ".." || path.isAbsolute(lexicalRelative))
85
+ return unreadable();
86
+ if (!existsSync(candidate) || !statSync(candidate).isFile())
87
+ return unreadable();
88
+ const realCandidate = realpathSync(candidate);
89
+ const realRelative = path.relative(realSkillsRoot, realCandidate);
90
+ if (!realRelative || realRelative.startsWith(`..${path.sep}`) || realRelative === ".." || path.isAbsolute(realRelative))
91
+ return unreadable();
92
+ if (resolved.has(skill.id))
93
+ return unreadable();
94
+ resolved.set(skill.id, realCandidate);
95
+ }
96
+ return resolved;
97
+ }
98
+ catch (error) {
99
+ if (error instanceof SkillDeliveryError)
100
+ throw error;
101
+ return unreadable();
102
+ }
103
+ }
104
+ export function registeredSkillPath(registeredSkills, skill) {
105
+ const skillPath = registeredSkills.get(skill);
106
+ if (!skillPath)
107
+ throw new SkillDeliveryError("not-found", `"${skill}" is not a registered productfoo skill.`);
108
+ return skillPath;
109
+ }
110
+ export function resolvePacketDir(root, packetArg) {
111
+ // A missing packet arg is a typo (usage_error); a named-but-absent packet is a not_found.
112
+ // Neither is a defect, and neither may page — but as bare Errors both classified as
113
+ // command_error and paged, because nearly every packet command funnels through here.
114
+ if (!packetArg)
115
+ throw new UsageError("packet-dir missing", "E_PACKET_DIR_MISSING");
116
+ const packetDir = path.resolve(root, packetArg);
117
+ if (!existsSync(packetDir))
118
+ throw new NotFoundError(`packet directory not found: ${packetArg}`, "E_PACKET_NOT_FOUND");
119
+ return { packetDir, packetArg };
120
+ }
121
+ // Re-exported from the shared argv helpers so existing `./shared.js` importers
122
+ // keep working; new call sites can import from ../cliArgs.js directly.
123
+ export { hasFlag, flagValue } from "../cliArgs.js";
124
+ // productfoo's OWN version — resolved module-relative (this file compiles to
125
+ // dist/src/commands/shared.js, so ../../../package.json is productfoo's package root
126
+ // in every layout: repo checkout, bare clone, and npm-installed thin client).
127
+ // The old cwd-based read was wrong twice over: "unknown" from a clean install,
128
+ // and — worse — a tester running foo inside THEIR project reported THEIR app's
129
+ // version into telemetry. cwd stays only as a last-resort fallback, and only
130
+ // when its package.json actually declares the `foo` bin.
131
+ function versionFrom(pkgPath, requireFooBin) {
132
+ if (!existsSync(pkgPath))
133
+ return null;
134
+ try {
135
+ const pkg = readJson(pkgPath);
136
+ if (requireFooBin && !(pkg.bin && typeof pkg.bin === "object" && "foo" in pkg.bin))
137
+ return null;
138
+ return typeof pkg.version === "string" ? pkg.version : null;
139
+ }
140
+ catch {
141
+ return null;
142
+ }
143
+ }
144
+ export function readPackageVersion(root) {
145
+ const selfPkg = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "..", "..", "package.json");
146
+ return versionFrom(selfPkg, true) ?? versionFrom(path.join(root, "package.json"), true) ?? "unknown";
147
+ }
@@ -0,0 +1 @@
1
+ export declare function runSourceCommand(root: string, command: string | undefined, args: string[]): Promise<string>;