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,467 @@
1
+ import { appendFileSync, existsSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
2
+ import path from "node:path";
3
+ import { parse, stringify } from "./vendorYaml.js";
4
+ import { providerLinkForm, sanitizeDiscoveryStableUrl } from "./discoverySources.js";
5
+ export const DISCOVERY_SCHEMA_VERSION = "0.1";
6
+ const LIFECYCLES = new Set([
7
+ "draft",
8
+ "awaiting_interview",
9
+ "awaiting_match",
10
+ "ambiguous_match",
11
+ "needs_source_approval",
12
+ "needs_provider_access",
13
+ "needs_provider_connector",
14
+ "needs_research_proof",
15
+ "ready_to_synthesize",
16
+ "needs_review",
17
+ "complete",
18
+ "revoked",
19
+ ]);
20
+ const ALLOWED_TRANSITIONS = {
21
+ draft: ["awaiting_interview", "revoked"],
22
+ awaiting_interview: ["awaiting_match", "revoked"],
23
+ awaiting_match: ["ambiguous_match", "needs_source_approval", "needs_provider_access", "needs_provider_connector", "needs_research_proof", "ready_to_synthesize", "revoked"],
24
+ ambiguous_match: ["awaiting_match", "needs_source_approval", "needs_provider_access", "needs_provider_connector", "needs_research_proof", "ready_to_synthesize", "revoked"],
25
+ needs_source_approval: ["awaiting_match", "ambiguous_match", "needs_provider_access", "needs_provider_connector", "needs_research_proof", "ready_to_synthesize", "revoked"],
26
+ needs_provider_access: ["awaiting_match", "ambiguous_match", "needs_source_approval", "needs_provider_connector", "needs_research_proof", "ready_to_synthesize", "revoked"],
27
+ needs_provider_connector: ["awaiting_match", "ambiguous_match", "needs_source_approval", "needs_provider_access", "needs_research_proof", "ready_to_synthesize", "revoked"],
28
+ needs_research_proof: ["awaiting_match", "ambiguous_match", "needs_source_approval", "needs_provider_access", "needs_provider_connector", "ready_to_synthesize", "revoked"],
29
+ ready_to_synthesize: ["needs_review", "needs_provider_access", "needs_research_proof", "revoked"],
30
+ needs_review: ["complete", "awaiting_match", "revoked"],
31
+ complete: ["revoked"],
32
+ revoked: [],
33
+ };
34
+ const FORBIDDEN_PRIVATE_KEYS = new Set([
35
+ "runtime_handle",
36
+ "session_handle",
37
+ "meeting_id",
38
+ "connector_receipt",
39
+ "transcript",
40
+ "raw_transcript",
41
+ "raw_content",
42
+ "turns",
43
+ "utterances",
44
+ ]);
45
+ const PROVENANCE = new Set(["approved-context", "agent-inference", "legacy-untrusted"]);
46
+ const PROPOSAL_STATES = new Set(["draft", "needs_review", "promoted", "dismissed"]);
47
+ function readYaml(file) {
48
+ return parse(readFileSync(file, "utf8"));
49
+ }
50
+ function isRecord(value) {
51
+ return typeof value === "object" && value !== null && !Array.isArray(value);
52
+ }
53
+ function walkPrivateKeys(value, at, errors) {
54
+ if (Array.isArray(value)) {
55
+ value.forEach((entry, index) => walkPrivateKeys(entry, `${at}[${index}]`, errors));
56
+ return;
57
+ }
58
+ if (!isRecord(value))
59
+ return;
60
+ for (const [key, entry] of Object.entries(value)) {
61
+ if (FORBIDDEN_PRIVATE_KEYS.has(key.toLowerCase()))
62
+ errors.push(`${at}: forbidden private field ${key}`);
63
+ walkPrivateKeys(entry, `${at}.${key}`, errors);
64
+ }
65
+ }
66
+ function validateStableUrl(value, provider, at, errors) {
67
+ if (value === null || value === undefined || value === "")
68
+ return;
69
+ if (typeof value !== "string") {
70
+ errors.push(`${at}: stable_url must be a string or null`);
71
+ return;
72
+ }
73
+ // A provider with a declared canonical link form (gong-discovery-connector-v0
74
+ // R-006) is judged by that single form — the shared sanitizer is the only
75
+ // authority for it, so the two validators cannot drift for such providers.
76
+ if (providerLinkForm(provider)) {
77
+ try {
78
+ sanitizeDiscoveryStableUrl(provider, value);
79
+ }
80
+ catch (error) {
81
+ errors.push(`${at}: ${error instanceof Error ? error.message : "stable_url is invalid"}`);
82
+ }
83
+ return;
84
+ }
85
+ let parsed;
86
+ try {
87
+ parsed = new URL(value);
88
+ }
89
+ catch {
90
+ errors.push(`${at}: stable_url is invalid`);
91
+ return;
92
+ }
93
+ if (parsed.protocol !== "https:")
94
+ errors.push(`${at}: stable_url must use HTTPS`);
95
+ if (parsed.search)
96
+ errors.push(`${at}: stable_url must not contain a query string`);
97
+ if (parsed.hash)
98
+ errors.push(`${at}: stable_url must not contain a fragment`);
99
+ // Keep in lockstep with PROVIDER_HOSTS in discoverySources.ts (notes.granola.ai
100
+ // is Granola's share-link host — the divergence of these two lists refused an
101
+ // owner-approved ingestion once already; consolidation is a recorded follow-up).
102
+ const hosts = { granola: ["app.granola.ai", "granola.ai", "notes.granola.ai"] };
103
+ const approved = hosts[provider.toLowerCase()];
104
+ if (approved && !approved.includes(parsed.hostname.toLowerCase()))
105
+ errors.push(`${at}: stable_url host is not approved for ${provider}`);
106
+ }
107
+ export function loadDiscoveryRun(studyDir) {
108
+ const file = path.join(studyDir, "run.yaml");
109
+ if (!existsSync(file))
110
+ throw new Error(`missing discovery run: ${file}`);
111
+ return readYaml(file);
112
+ }
113
+ function validateRun(studyDir, errors) {
114
+ const required = ["run.yaml", "study.md", "findings.yaml", "proposals.yaml", "report.md", "events.jsonl"];
115
+ for (const name of required)
116
+ if (!existsSync(path.join(studyDir, name)))
117
+ errors.push(`${path.basename(studyDir)}: missing ${name}`);
118
+ if (!existsSync(path.join(studyDir, "run.yaml")))
119
+ return;
120
+ let run;
121
+ try {
122
+ run = readYaml(path.join(studyDir, "run.yaml"));
123
+ }
124
+ catch {
125
+ errors.push(`${path.basename(studyDir)}: run.yaml is not valid YAML`);
126
+ return;
127
+ }
128
+ walkPrivateKeys(run, `${path.basename(studyDir)}/run.yaml`, errors);
129
+ if (!isRecord(run)) {
130
+ errors.push(`${path.basename(studyDir)}: run.yaml must be an object`);
131
+ return;
132
+ }
133
+ if (run.schema_version !== DISCOVERY_SCHEMA_VERSION)
134
+ errors.push(`${path.basename(studyDir)}: schema_version must be 0.1`);
135
+ if (typeof run.study_id !== "string" || !/^study_[a-z0-9_]+$/.test(run.study_id))
136
+ errors.push(`${path.basename(studyDir)}: invalid study_id`);
137
+ if (!LIFECYCLES.has(run.state))
138
+ errors.push(`${path.basename(studyDir)}: invalid lifecycle state`);
139
+ if (run.lane !== "study_linked")
140
+ errors.push(`${path.basename(studyDir)}: study lane must be study_linked`);
141
+ if (!PROVENANCE.has(String(run.provenance)))
142
+ errors.push(`${path.basename(studyDir)}: invalid run provenance`);
143
+ const target = isRecord(run.target) ? run.target : {};
144
+ if (!PROVENANCE.has(String(target.provenance)))
145
+ errors.push(`${path.basename(studyDir)}: invalid target provenance`);
146
+ const source = isRecord(run.source) ? run.source : {};
147
+ const provider = typeof source.provider === "string" ? source.provider : "";
148
+ validateStableUrl(source.stable_url, provider, `${path.basename(studyDir)}/run.yaml`, errors);
149
+ validateDerivedArtifacts(studyDir, provider, errors);
150
+ }
151
+ function validateDerivedArtifacts(dir, provider, errors) {
152
+ const label = path.basename(dir);
153
+ const findingsPath = path.join(dir, "findings.yaml");
154
+ const proposalsPath = path.join(dir, "proposals.yaml");
155
+ const findingIds = new Set();
156
+ if (existsSync(findingsPath)) {
157
+ try {
158
+ const doc = readYaml(findingsPath);
159
+ walkPrivateKeys(doc, `${label}/findings.yaml`, errors);
160
+ if (!isRecord(doc) || doc.schema_version !== DISCOVERY_SCHEMA_VERSION || !Array.isArray(doc.findings)) {
161
+ errors.push(`${label}/findings.yaml must contain schema_version 0.1 and findings[]`);
162
+ }
163
+ else {
164
+ for (const [index, raw] of doc.findings.entries()) {
165
+ if (!isRecord(raw)) {
166
+ errors.push(`${label}/findings.yaml finding ${index + 1} must be an object`);
167
+ continue;
168
+ }
169
+ if (typeof raw.finding_id !== "string" || !raw.finding_id.trim())
170
+ errors.push(`${label}/findings.yaml finding ${index + 1}: finding_id is required`);
171
+ else if (findingIds.has(raw.finding_id))
172
+ errors.push(`${label}/findings.yaml finding ${index + 1}: duplicate finding_id ${raw.finding_id}`);
173
+ else
174
+ findingIds.add(raw.finding_id);
175
+ if (raw.lane !== undefined && raw.lane !== "study_linked" && raw.lane !== "unassigned_call_evidence")
176
+ errors.push(`${label}/findings.yaml finding ${index + 1}: invalid lane`);
177
+ if (raw.source_fingerprint !== undefined && (typeof raw.source_fingerprint !== "string" || !/^sha256:[a-f0-9]{64}$/i.test(raw.source_fingerprint)))
178
+ errors.push(`${label}/findings.yaml finding ${index + 1}: invalid source_fingerprint`);
179
+ const sourceProvider = typeof raw.source_provider === "string" ? raw.source_provider : provider;
180
+ validateStableUrl(raw.source_url, sourceProvider, `${label}/findings.yaml finding ${index + 1} source_url`, errors);
181
+ }
182
+ }
183
+ }
184
+ catch {
185
+ errors.push(`${label}/findings.yaml is not valid YAML`);
186
+ }
187
+ }
188
+ if (existsSync(proposalsPath)) {
189
+ try {
190
+ const doc = readYaml(proposalsPath);
191
+ walkPrivateKeys(doc, `${label}/proposals.yaml`, errors);
192
+ if (!isRecord(doc) || doc.schema_version !== DISCOVERY_SCHEMA_VERSION || !Array.isArray(doc.proposals)) {
193
+ errors.push(`${label}/proposals.yaml must contain schema_version 0.1 and proposals[]`);
194
+ }
195
+ else {
196
+ const proposalIds = new Set();
197
+ for (const [index, raw] of doc.proposals.entries()) {
198
+ if (!isRecord(raw)) {
199
+ errors.push(`${label}/proposals.yaml proposal ${index + 1} must be an object`);
200
+ continue;
201
+ }
202
+ if (typeof raw.proposal_id !== "string" || !raw.proposal_id.trim())
203
+ errors.push(`${label}/proposals.yaml proposal ${index + 1}: proposal_id is required`);
204
+ else if (proposalIds.has(raw.proposal_id))
205
+ errors.push(`${label}/proposals.yaml proposal ${index + 1}: duplicate proposal_id ${raw.proposal_id}`);
206
+ else
207
+ proposalIds.add(raw.proposal_id);
208
+ if (!PROPOSAL_STATES.has(String(raw.state)))
209
+ errors.push(`${label}/proposals.yaml proposal ${index + 1}: invalid state`);
210
+ const refs = Array.isArray(raw.source_finding_ids) ? raw.source_finding_ids : [];
211
+ for (const ref of refs)
212
+ if (typeof ref !== "string" || !findingIds.has(ref))
213
+ errors.push(`${label}/proposals.yaml proposal ${index + 1}: ${String(ref)} references an unknown finding`);
214
+ }
215
+ }
216
+ }
217
+ catch {
218
+ errors.push(`${label}/proposals.yaml is not valid YAML`);
219
+ }
220
+ }
221
+ const eventsPath = path.join(dir, "events.jsonl");
222
+ if (existsSync(eventsPath)) {
223
+ for (const [index, line] of readFileSync(eventsPath, "utf8").split("\n").entries()) {
224
+ if (!line.trim())
225
+ continue;
226
+ try {
227
+ walkPrivateKeys(JSON.parse(line), `${label}/events.jsonl line ${index + 1}`, errors);
228
+ }
229
+ catch {
230
+ errors.push(`${label}/events.jsonl line ${index + 1} is not valid JSON`);
231
+ }
232
+ }
233
+ }
234
+ }
235
+ function validateInbox(inboxDir, errors) {
236
+ for (const name of ["scope.yaml", "findings.yaml", "proposals.yaml", "events.jsonl"]) {
237
+ if (!existsSync(path.join(inboxDir, name)))
238
+ errors.push(`inbox: missing ${name}`);
239
+ }
240
+ const scopePath = path.join(inboxDir, "scope.yaml");
241
+ if (!existsSync(scopePath))
242
+ return;
243
+ let doc;
244
+ try {
245
+ doc = readYaml(scopePath);
246
+ }
247
+ catch {
248
+ errors.push("inbox/scope.yaml is not valid YAML");
249
+ return;
250
+ }
251
+ walkPrivateKeys(doc, "inbox/scope.yaml", errors);
252
+ if (!isRecord(doc) || doc.schema_version !== DISCOVERY_SCHEMA_VERSION || !Array.isArray(doc.scopes)) {
253
+ errors.push("inbox/scope.yaml must contain schema_version 0.1 and scopes[]");
254
+ return;
255
+ }
256
+ const scopeIds = new Set();
257
+ for (const [index, raw] of doc.scopes.entries()) {
258
+ if (!isRecord(raw)) {
259
+ errors.push(`inbox scope ${index + 1} must be an object`);
260
+ continue;
261
+ }
262
+ if (typeof raw.scope_id !== "string" || !/^[a-z0-9_]+$/.test(raw.scope_id))
263
+ errors.push(`inbox scope ${index + 1}: invalid scope_id`);
264
+ else if (scopeIds.has(raw.scope_id))
265
+ errors.push(`inbox scope ${index + 1}: duplicate scope_id ${raw.scope_id}`);
266
+ else
267
+ scopeIds.add(raw.scope_id);
268
+ if (raw.state !== "draft" && raw.state !== "approved" && raw.state !== "revoked")
269
+ errors.push(`inbox scope ${index + 1}: invalid state`);
270
+ if (raw.state === "approved" && (!raw.approved_by || !raw.approved_at))
271
+ errors.push(`inbox scope ${index + 1}: approved scope requires attribution`);
272
+ // At least one customer selector; call_owners is a gong kind
273
+ // (gong-discovery-connector-v0 R-004) and is empty/absent elsewhere.
274
+ const selectors = [raw.participant_allowlist, raw.domain_allowlist, raw.title_tokens, raw.call_owners];
275
+ if (!selectors.some((entry) => Array.isArray(entry) && entry.some((item) => typeof item === "string" && item.trim()))) {
276
+ errors.push(`inbox scope ${index + 1}: approved ingestion requires at least one customer selector`);
277
+ }
278
+ if (!isRecord(raw.time_window) || !raw.time_window.start || !raw.time_window.end)
279
+ errors.push(`inbox scope ${index + 1}: time_window requires start and end`);
280
+ else {
281
+ const start = Date.parse(String(raw.time_window.start));
282
+ const end = Date.parse(String(raw.time_window.end));
283
+ if (!Number.isFinite(start) || !Number.isFinite(end) || start > end)
284
+ errors.push(`inbox scope ${index + 1}: time_window must contain valid ordered timestamps`);
285
+ }
286
+ }
287
+ validateDerivedArtifacts(inboxDir, "", errors);
288
+ // Contact cards (discovery-insight-ties-v0 R-007): optional, human-corrected
289
+ // identity per scope. Absent is valid; present must be well-formed.
290
+ const contactsPath = path.join(inboxDir, "contacts.yaml");
291
+ if (existsSync(contactsPath)) {
292
+ let contactsDoc;
293
+ try {
294
+ contactsDoc = readYaml(contactsPath);
295
+ }
296
+ catch {
297
+ errors.push("inbox/contacts.yaml is not valid YAML");
298
+ return;
299
+ }
300
+ walkPrivateKeys(contactsDoc, "inbox/contacts.yaml", errors);
301
+ if (!isRecord(contactsDoc) || contactsDoc.schema_version !== DISCOVERY_SCHEMA_VERSION || !Array.isArray(contactsDoc.contacts)) {
302
+ errors.push("inbox/contacts.yaml must contain schema_version 0.1 and contacts[]");
303
+ return;
304
+ }
305
+ const contactScopeIds = new Set();
306
+ for (const [index, raw] of contactsDoc.contacts.entries()) {
307
+ if (!isRecord(raw)) {
308
+ errors.push(`inbox contact ${index + 1} must be an object`);
309
+ continue;
310
+ }
311
+ if (typeof raw.scope_id !== "string" || !scopeIds.has(raw.scope_id))
312
+ errors.push(`inbox contact ${index + 1}: scope_id must name a known inbox scope`);
313
+ else if (contactScopeIds.has(raw.scope_id))
314
+ errors.push(`inbox contact ${index + 1}: duplicate scope_id ${raw.scope_id}`);
315
+ else
316
+ contactScopeIds.add(raw.scope_id);
317
+ for (const field of ["full_name", "linkedin", "company", "title"]) {
318
+ if (raw[field] !== null && raw[field] !== undefined && typeof raw[field] !== "string")
319
+ errors.push(`inbox contact ${index + 1}: ${field} must be a string or null`);
320
+ }
321
+ if (typeof raw.linkedin === "string" && raw.linkedin && !isLinkedinUrl(raw.linkedin)) {
322
+ errors.push(`inbox contact ${index + 1}: linkedin must be an https linkedin.com URL`);
323
+ }
324
+ // Candidate layer (discovery-contact-capture-v0 R-002/R-004): inferred
325
+ // suggestions with provenance, beneath the human-confirmed fields. A
326
+ // candidate value carrying an email or phone number is a privacy leak,
327
+ // not a candidate — the company is derived from the domain at ingest and
328
+ // the raw address must never reach this committed file.
329
+ if (raw.candidates !== undefined) {
330
+ if (!Array.isArray(raw.candidates)) {
331
+ errors.push(`inbox contact ${index + 1}: candidates must be an array`);
332
+ continue;
333
+ }
334
+ for (const [candidateIndex, candidate] of raw.candidates.entries()) {
335
+ const label = `inbox contact ${index + 1} candidate ${candidateIndex + 1}`;
336
+ if (!isRecord(candidate)) {
337
+ errors.push(`${label} must be an object`);
338
+ continue;
339
+ }
340
+ for (const key of Object.keys(candidate)) {
341
+ if (!CONTACT_CANDIDATE_KEYS.has(key))
342
+ errors.push(`${label}: unknown field ${key}`);
343
+ }
344
+ if (candidate.field !== "full_name" && candidate.field !== "company" && candidate.field !== "title" && candidate.field !== "linkedin")
345
+ errors.push(`${label}: field must be full_name, company, title, or linkedin`);
346
+ if (candidate.inferred !== true)
347
+ errors.push(`${label}: candidates are always inferred: true — confirmed values live on the card fields`);
348
+ if (typeof candidate.source !== "string" || !candidate.source.trim())
349
+ errors.push(`${label}: source is required`);
350
+ if (typeof candidate.value !== "string" || !candidate.value.trim())
351
+ errors.push(`${label}: value is required`);
352
+ else {
353
+ if (CONTACT_EMAIL.test(candidate.value) || CONTACT_PHONE.test(candidate.value))
354
+ errors.push(`${label}: value must not contain an email address or phone number`);
355
+ if (candidate.field === "linkedin" && !isLinkedinUrl(candidate.value))
356
+ errors.push(`${label}: linkedin value must be an https linkedin.com URL`);
357
+ }
358
+ }
359
+ }
360
+ }
361
+ }
362
+ }
363
+ const CONTACT_CANDIDATE_KEYS = new Set(["field", "value", "inferred", "source"]);
364
+ const CONTACT_EMAIL = /[\w.+-]+@[\w-]+\.[\w.-]+/;
365
+ const CONTACT_PHONE = /\+?\d[\d\s().-]{7,}\d/;
366
+ function isLinkedinUrl(value) {
367
+ try {
368
+ const url = new URL(value);
369
+ return url.protocol === "https:" && (url.hostname === "linkedin.com" || url.hostname.endsWith(".linkedin.com"));
370
+ }
371
+ catch {
372
+ return false;
373
+ }
374
+ }
375
+ export function validateDiscoveryPath(root, target) {
376
+ const discoveryRoot = path.resolve(root, target ?? "discovery");
377
+ const errors = [];
378
+ if (!existsSync(discoveryRoot))
379
+ return { ok: false, errors: [`discovery path not found: ${discoveryRoot}`], studies: 0, inbox: false };
380
+ const directRun = existsSync(path.join(discoveryRoot, "run.yaml"));
381
+ const studyDirs = directRun
382
+ ? [discoveryRoot]
383
+ : readdirSync(discoveryRoot, { withFileTypes: true })
384
+ .filter((entry) => entry.isDirectory() && entry.name !== "inbox")
385
+ .map((entry) => path.join(discoveryRoot, entry.name));
386
+ const studyIds = new Set();
387
+ for (const studyDir of studyDirs) {
388
+ validateRun(studyDir, errors);
389
+ try {
390
+ const studyId = loadDiscoveryRun(studyDir).study_id;
391
+ if (studyIds.has(studyId))
392
+ errors.push(`${path.basename(studyDir)}: duplicate study_id ${studyId}`);
393
+ else
394
+ studyIds.add(studyId);
395
+ }
396
+ catch {
397
+ continue;
398
+ }
399
+ }
400
+ const inboxDir = directRun ? "" : path.join(discoveryRoot, "inbox");
401
+ const inbox = Boolean(inboxDir && existsSync(inboxDir));
402
+ if (inbox)
403
+ validateInbox(inboxDir, errors);
404
+ return { ok: errors.length === 0, errors, studies: studyDirs.length, inbox };
405
+ }
406
+ export function locateStudy(root, studyId) {
407
+ const discoveryRoot = path.join(root, "discovery");
408
+ if (!existsSync(discoveryRoot))
409
+ return null;
410
+ for (const entry of readdirSync(discoveryRoot, { withFileTypes: true })) {
411
+ if (!entry.isDirectory() || entry.name === "inbox")
412
+ continue;
413
+ const dir = path.join(discoveryRoot, entry.name);
414
+ try {
415
+ if (loadDiscoveryRun(dir).study_id === studyId)
416
+ return dir;
417
+ }
418
+ catch {
419
+ continue;
420
+ }
421
+ }
422
+ return null;
423
+ }
424
+ function repositoryRootForStudy(studyDir) {
425
+ return path.dirname(path.dirname(path.resolve(studyDir)));
426
+ }
427
+ export function transitionDiscoveryRun(studyDir, next, actor, now) {
428
+ if (!actor.id.trim())
429
+ throw new Error("discovery transition requires an attributed actor");
430
+ const run = loadDiscoveryRun(studyDir);
431
+ const prior = run.state;
432
+ if (!ALLOWED_TRANSITIONS[prior].includes(next))
433
+ throw new Error(`invalid discovery transition: ${prior} -> ${next}`);
434
+ if ((next === "complete" || next === "revoked") && actor.type !== "human")
435
+ throw new Error(`${next} is a human transition`);
436
+ run.state = next;
437
+ run.updated_at = now;
438
+ const runPath = path.join(studyDir, "run.yaml");
439
+ writeFileSync(runPath, stringify(run));
440
+ const event = {
441
+ specversion: "1.0",
442
+ id: `evt_discovery_${run.study_id}_${next}_${Date.parse(now)}`,
443
+ source: "agent://foo/discovery",
444
+ type: "com.adaptivespec.discovery.state_changed",
445
+ subject: `study:${run.study_id}`,
446
+ time: now,
447
+ actor,
448
+ data: { from: prior, to: next },
449
+ };
450
+ // The event intentionally carries only lifecycle provenance, never evidence.
451
+ appendFileSync(path.join(studyDir, "events.jsonl"), `${JSON.stringify(event)}\n`);
452
+ const root = repositoryRootForStudy(studyDir);
453
+ return [runPath, path.join(studyDir, "events.jsonl")].map((file) => ({ path: path.relative(root, file).split(path.sep).join("/"), action: "updated" }));
454
+ }
455
+ export function classifyDiscoveryCandidate(filePath, text) {
456
+ const normalizedPath = filePath.toLowerCase();
457
+ const normalizedText = text.toLowerCase();
458
+ if (normalizedPath.includes("/specs/") || normalizedPath.startsWith("specs/") || /product requirements|spec id/.test(normalizedText))
459
+ return "product-spec";
460
+ if (normalizedPath.includes("research/") || /research:|interview methods|method research/.test(normalizedText))
461
+ return "method-research";
462
+ if (/synthetic|rehearsal|mock interview/.test(normalizedText))
463
+ return "synthetic-rehearsal";
464
+ if (/customer interview|discovery call/.test(normalizedText) && /completed call|findings|evidence/.test(normalizedText))
465
+ return "real-study";
466
+ return "not-discovery";
467
+ }
@@ -0,0 +1,127 @@
1
+ import { type DiscoveryWrite } from "./discoveryArtifacts.js";
2
+ export declare const DISCOVERY_COMMAND_SCHEMA_VERSION: "0.1";
3
+ export type DiscoveryErrorCode = "E_DISCOVERY_SOURCE_APPROVAL" | "E_DISCOVERY_PROVIDER_ACCESS" | "E_DISCOVERY_PROVIDER_CONNECTOR" | "E_DISCOVERY_RESEARCH_PROOF" | "E_DISCOVERY_AMBIGUOUS_MATCH" | "E_DISCOVERY_INVALID_ENVELOPE" | "E_DISCOVERY_INVALID_TRANSITION" | "E_DISCOVERY_MANUAL_RESOLUTION" | "E_DISCOVERY_RECEIPT" | "E_DISCOVERY_VALIDATION";
4
+ export type DiscoveryCommandStatus = "ok" | "clean_no_op" | "awaiting_match" | "ambiguous_match" | "needs_source_approval" | "needs_provider_access" | "needs_provider_connector" | "needs_research_proof" | "needs_review" | "needs_service_verification" | "invalid" | "budget_exhausted";
5
+ export type DiscoveryCommandResult = {
6
+ schema_version: "0.1";
7
+ status: DiscoveryCommandStatus;
8
+ study_id?: string;
9
+ writes: DiscoveryWrite[];
10
+ errors: Array<{
11
+ code: DiscoveryErrorCode;
12
+ message: string;
13
+ }>;
14
+ handoff: string | null;
15
+ next_actions: string[];
16
+ coverage: Record<string, unknown>;
17
+ };
18
+ export type DiscoveryCommandOutcome = {
19
+ output: string;
20
+ exitCode: number;
21
+ result: DiscoveryCommandResult;
22
+ };
23
+ export declare function study(root: string, studyId: string): string;
24
+ export type InboxScope = {
25
+ scope_id: string;
26
+ provider: string;
27
+ connection_alias: string;
28
+ time_window: {
29
+ start: string;
30
+ end: string;
31
+ };
32
+ participant_allowlist: string[];
33
+ domain_allowlist: string[];
34
+ title_tokens: string[];
35
+ call_owners?: string[];
36
+ organizations?: string[];
37
+ brands?: string[];
38
+ include_internal_only?: boolean;
39
+ labels?: string[];
40
+ channel_ids?: string[];
41
+ thread_ts?: string[];
42
+ folders?: string[];
43
+ state: "draft" | "approved" | "revoked";
44
+ };
45
+ export declare function isInboxTarget(targetId: string): boolean;
46
+ export declare function inboxDir(root: string): string;
47
+ export declare function ensureInboxScaffold(root: string): void;
48
+ export declare function discoveryTargetDir(root: string, targetId: string): string;
49
+ export declare function localTargetName(targetId: string): string;
50
+ export declare function inboxScope(root: string, targetId: string): InboxScope;
51
+ export type GongScopeSelectors = {
52
+ window: {
53
+ start?: string;
54
+ end?: string;
55
+ };
56
+ named_external_participants?: string[];
57
+ external_companies_or_domains?: string[];
58
+ title_tokens?: string[];
59
+ call_owners?: string[];
60
+ };
61
+ export declare function gongScopeValidationError(scope: GongScopeSelectors): string | null;
62
+ export type ZendeskScopeSelectors = {
63
+ window: {
64
+ start?: string;
65
+ end?: string;
66
+ };
67
+ external_domains?: string[];
68
+ organizations?: string[];
69
+ brands?: string[];
70
+ include_internal_only?: boolean;
71
+ };
72
+ export declare function zendeskScopeValidationError(scope: ZendeskScopeSelectors): string | null;
73
+ export type GmailScopeSelectors = {
74
+ window: {
75
+ start?: string;
76
+ end?: string;
77
+ };
78
+ labels?: string[];
79
+ external_domains?: string[];
80
+ external_names?: string[];
81
+ include_internal_only?: boolean;
82
+ };
83
+ export declare function gmailScopeValidationError(scope: GmailScopeSelectors): string | null;
84
+ export type ZoomScopeSelectors = {
85
+ window: {
86
+ start?: string;
87
+ end?: string;
88
+ };
89
+ external_names?: string[];
90
+ external_domains?: string[];
91
+ title_tokens?: string[];
92
+ include_internal_only?: boolean;
93
+ };
94
+ export declare function zoomScopeValidationError(scope: ZoomScopeSelectors): string | null;
95
+ export type TeamsScopeSelectors = {
96
+ window: {
97
+ start?: string;
98
+ end?: string;
99
+ };
100
+ named_external_participants?: string[];
101
+ external_companies_or_domains?: string[];
102
+ organizers?: string[];
103
+ };
104
+ export declare function teamsScopeValidationError(scope: TeamsScopeSelectors): string | null;
105
+ export type OutlookScopeSelectors = {
106
+ window: {
107
+ start?: string;
108
+ end?: string;
109
+ };
110
+ folders?: string[];
111
+ external_domains?: string[];
112
+ external_names?: string[];
113
+ include_internal_only?: boolean;
114
+ };
115
+ export declare function outlookScopeValidationError(scope: OutlookScopeSelectors): string | null;
116
+ export declare function localRoot(root: string): string;
117
+ export declare function existingFingerprint(studyDir: string, fingerprint: string): boolean;
118
+ export type InsightTie = {
119
+ type: "bug" | "spec" | "research" | "idea" | "study";
120
+ ref: string;
121
+ url: string | null;
122
+ by: string;
123
+ actor: "agent" | "human";
124
+ at: string;
125
+ };
126
+ export { isValidLinkedinUrl } from "./discoverySources.js";
127
+ export declare function runDiscoveryCommand(root: string, args: string[], stdin?: string, now?: string): Promise<DiscoveryCommandOutcome>;