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,405 @@
1
+ import { existsSync, readFileSync, readdirSync } from "node:fs";
2
+ import path from "node:path";
3
+ import { parse } from "./vendorYaml.js";
4
+ export const LEARNING_ROUTING_POLICY = {
5
+ semantic_minimum: 0.45,
6
+ semantic_margin: 0.12,
7
+ catch_all_shared_max: 5,
8
+ synthesis_source_overlap_max: 0.82,
9
+ };
10
+ const STOPWORDS = new Set([
11
+ "about", "after", "again", "before", "being", "between", "could", "every",
12
+ "should", "their", "there", "these", "those", "through", "with", "without",
13
+ "would", "from", "into", "only", "that", "this", "when", "where", "which",
14
+ ]);
15
+ // These are common product-label words, not distinctive concepts. They can
16
+ // still contribute to paragraph evidence, but never establish title custody.
17
+ const GENERIC_TITLE_TOKENS = new Set([
18
+ "agent", "business", "company", "control", "enterprise", "management",
19
+ "plane", "platform", "product", "system", "workflow",
20
+ ]);
21
+ const CLUSTER_CONCEPTS = new Map([
22
+ ["access", "governance"], ["approval", "governance"], ["credential", "governance"],
23
+ ["gated", "governance"], ["govern", "governance"], ["guardrail", "governance"],
24
+ ["inspectable", "governance"], ["permission", "governance"], ["regulated", "governance"],
25
+ ["security", "governance"], ["backlog", "portfolio"], ["command", "portfolio"],
26
+ ["coordination", "portfolio"], ["portfolio", "portfolio"], ["prioritization", "portfolio"],
27
+ ["steering", "portfolio"], ["visibility", "portfolio"], ["adoption", "adoption"],
28
+ ["blocked", "adoption"], ["change", "adoption"], ["distribution", "adoption"],
29
+ ["onboarding", "adoption"], ["restriction", "adoption"], ["automation", "process"],
30
+ ["mining", "process"], ["process", "process"], ["recurring", "process"],
31
+ ["variation", "process"], ["workflow", "process"],
32
+ ]);
33
+ function normalizePath(root, file) {
34
+ return path.relative(root, file).split(path.sep).join("/");
35
+ }
36
+ function titleCase(value) {
37
+ return value
38
+ .replace(/\.md$/i, "")
39
+ .replace(/^\d{4}-\d{2}-\d{2}-/, "")
40
+ .replace(/-v\d+$/i, "")
41
+ .split(/[-_]+/)
42
+ .filter(Boolean)
43
+ .map((word) => `${word.charAt(0).toUpperCase()}${word.slice(1)}`)
44
+ .join(" ");
45
+ }
46
+ function frontmatter(text) {
47
+ if (!text.startsWith("---\n"))
48
+ return { meta: {}, body: text };
49
+ const closing = text.indexOf("\n---", 4);
50
+ if (closing === -1)
51
+ return { meta: {}, body: text };
52
+ const after = text.indexOf("\n", closing + 1);
53
+ let meta = {};
54
+ try {
55
+ const parsed = parse(text.slice(4, closing));
56
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed))
57
+ meta = parsed;
58
+ }
59
+ catch {
60
+ meta = {};
61
+ }
62
+ return { meta, body: after === -1 ? "" : text.slice(after + 1) };
63
+ }
64
+ function contentBlocks(body) {
65
+ const blocks = [];
66
+ for (const paragraph of body.split(/\n{2,}/)) {
67
+ const trimmed = paragraph.trim();
68
+ if (!trimmed)
69
+ continue;
70
+ if (trimmed.length > 1500) {
71
+ for (const line of trimmed.split("\n"))
72
+ if (line.trim())
73
+ blocks.push(line.trim());
74
+ }
75
+ else {
76
+ blocks.push(trimmed);
77
+ }
78
+ }
79
+ return blocks;
80
+ }
81
+ function markdownFiles(dir) {
82
+ if (!existsSync(dir))
83
+ return [];
84
+ const files = [];
85
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
86
+ const full = path.join(dir, entry.name);
87
+ if (entry.isDirectory())
88
+ files.push(...markdownFiles(full));
89
+ else if (entry.isFile() && entry.name.endsWith(".md"))
90
+ files.push(full);
91
+ }
92
+ return files;
93
+ }
94
+ function destinationFromFile(root, file, type, ref) {
95
+ const text = readFileSync(file, "utf8");
96
+ const parsed = frontmatter(text);
97
+ const metadataTitle = typeof parsed.meta.title === "string"
98
+ ? parsed.meta.title
99
+ : typeof parsed.meta.idea === "string"
100
+ ? parsed.meta.idea
101
+ : null;
102
+ const heading = /^#\s+(.+)$/m.exec(parsed.body)?.[1]?.trim() ?? null;
103
+ return {
104
+ type,
105
+ ref,
106
+ path: normalizePath(root, file),
107
+ title: metadataTitle?.trim() || heading || titleCase(path.basename(type === "backlog" ? path.dirname(file) : file)),
108
+ text: parsed.body,
109
+ blocks: contentBlocks(parsed.body),
110
+ };
111
+ }
112
+ function isArchivedPath(root, file) {
113
+ return normalizePath(root, file).split("/").some((segment) => segment.toLowerCase() === "archive");
114
+ }
115
+ function isActivePacket(file) {
116
+ const { meta } = frontmatter(readFileSync(file, "utf8"));
117
+ const lifecycle = typeof meta.lifecycle === "string" ? meta.lifecycle.trim().toLowerCase() : "";
118
+ return !new Set(["complete", "completed", "done", "killed", "parked", "retired", "stopped"]).has(lifecycle);
119
+ }
120
+ export function buildLearningDestinationCatalog(root) {
121
+ const destinations = [];
122
+ for (const file of markdownFiles(path.join(root, "ideas"))) {
123
+ if (isArchivedPath(root, file))
124
+ continue;
125
+ destinations.push(destinationFromFile(root, file, "idea", normalizePath(root, file)));
126
+ }
127
+ for (const file of markdownFiles(path.join(root, "research"))) {
128
+ if (isArchivedPath(root, file))
129
+ continue;
130
+ destinations.push(destinationFromFile(root, file, "research", normalizePath(root, file)));
131
+ }
132
+ const specsDir = path.join(root, "specs");
133
+ if (existsSync(specsDir)) {
134
+ for (const entry of readdirSync(specsDir, { withFileTypes: true })) {
135
+ if (!entry.isDirectory())
136
+ continue;
137
+ const file = path.join(specsDir, entry.name, "spec.md");
138
+ if (existsSync(file) && isActivePacket(file))
139
+ destinations.push(destinationFromFile(root, file, "backlog", entry.name));
140
+ }
141
+ }
142
+ return destinations.sort((left, right) => left.path.localeCompare(right.path));
143
+ }
144
+ function normalizedToken(token) {
145
+ if (/^evaluat|^evals?$/.test(token))
146
+ return "eval";
147
+ if (/^orchestrat/.test(token))
148
+ return "orchestr";
149
+ if (/^rout(?:e|ed|es|ing)?$/.test(token))
150
+ return "route";
151
+ if (token.length > 5 && token.endsWith("ies"))
152
+ return `${token.slice(0, -3)}y`;
153
+ if (token.length > 6 && token.endsWith("ing"))
154
+ return token.slice(0, -3);
155
+ if (token.length > 5 && token.endsWith("ed"))
156
+ return token.slice(0, -2);
157
+ if (token.length > 5 && token.endsWith("es"))
158
+ return token.slice(0, -2);
159
+ if (token.length > 4 && token.endsWith("s") && !token.endsWith("ss"))
160
+ return token.slice(0, -1);
161
+ return token;
162
+ }
163
+ function tokens(text) {
164
+ return new Set((text.toLowerCase().match(/[a-z0-9]+/g) ?? [])
165
+ .filter((token) => token.length >= 4 && !STOPWORDS.has(token))
166
+ .map(normalizedToken));
167
+ }
168
+ function normalizedText(text) {
169
+ return (text.toLowerCase().match(/[a-z0-9]+/g) ?? []).map(normalizedToken).join(" ");
170
+ }
171
+ function clusterTokens(finding) {
172
+ return tokens(`${finding.headline} ${finding.paraphrase}`);
173
+ }
174
+ function clusterConcepts(finding) {
175
+ const concepts = new Set();
176
+ for (const token of clusterTokens(finding)) {
177
+ const concept = CLUSTER_CONCEPTS.get(token);
178
+ if (concept)
179
+ concepts.add(concept);
180
+ }
181
+ return concepts;
182
+ }
183
+ function relatedClusterFindings(left, right) {
184
+ const leftConcepts = clusterConcepts(left);
185
+ const rightConcepts = clusterConcepts(right);
186
+ for (const concept of leftConcepts)
187
+ if (rightConcepts.has(concept))
188
+ return true;
189
+ const leftTokens = clusterTokens(left);
190
+ const rightTokens = clusterTokens(right);
191
+ let overlap = 0;
192
+ for (const token of leftTokens)
193
+ if (rightTokens.has(token))
194
+ overlap += 1;
195
+ return overlap >= 3;
196
+ }
197
+ function clusterKey(findings) {
198
+ const sharedConcepts = [...clusterConcepts(findings[0] ?? { finding_id: "", inbox_scope_id: "", headline: "", paraphrase: "" })]
199
+ .filter((concept) => findings.every((finding) => clusterConcepts(finding).has(concept)))
200
+ .sort();
201
+ return `cluster:${sharedConcepts[0] ?? "emerging"}:${findings[0]?.finding_id ?? "unknown"}`;
202
+ }
203
+ export function clusterUnmatchedLearnings(input) {
204
+ const findings = input
205
+ .filter((finding) => /^F-\d{3}$/.test(finding.finding_id) && finding.inbox_scope_id.trim() && (finding.headline.trim() || finding.paraphrase.trim()))
206
+ .map((finding) => ({ ...finding }))
207
+ .sort((left, right) => left.finding_id.localeCompare(right.finding_id));
208
+ const visited = new Set();
209
+ const clusters = [];
210
+ for (const seed of findings) {
211
+ if (visited.has(seed.finding_id))
212
+ continue;
213
+ const members = [];
214
+ const queue = [seed];
215
+ visited.add(seed.finding_id);
216
+ while (queue.length > 0) {
217
+ const current = queue.shift();
218
+ members.push(current);
219
+ for (const candidate of findings) {
220
+ if (visited.has(candidate.finding_id) || !relatedClusterFindings(current, candidate))
221
+ continue;
222
+ visited.add(candidate.finding_id);
223
+ queue.push(candidate);
224
+ }
225
+ }
226
+ members.sort((left, right) => left.finding_id.localeCompare(right.finding_id));
227
+ const sourceScopeIds = [...new Set(members.map((finding) => finding.inbox_scope_id))].sort();
228
+ clusters.push({
229
+ cluster_key: clusterKey(members),
230
+ status: sourceScopeIds.length >= 2 ? "eligible_for_synthesis" : "emerging",
231
+ source_finding_ids: members.map((finding) => finding.finding_id),
232
+ source_scope_ids: sourceScopeIds,
233
+ findings: members,
234
+ });
235
+ }
236
+ return clusters.sort((left, right) => left.cluster_key.localeCompare(right.cluster_key));
237
+ }
238
+ function tokenCoverage(left, right) {
239
+ const leftTokens = tokens(left);
240
+ const rightTokens = tokens(right);
241
+ if (leftTokens.size === 0 || rightTokens.size === 0)
242
+ return 0;
243
+ let overlap = 0;
244
+ for (const token of leftTokens)
245
+ if (rightTokens.has(token))
246
+ overlap += 1;
247
+ return overlap / Math.min(leftTokens.size, rightTokens.size);
248
+ }
249
+ export function validateHypothesisSynthesis(input) {
250
+ if (input.cluster.status !== "eligible_for_synthesis" || input.cluster.source_scope_ids.length < 2) {
251
+ return { ok: false, reason: "independent_calls_required" };
252
+ }
253
+ const actualSources = [...input.cluster.source_finding_ids].sort();
254
+ const requestedSources = [...new Set(input.synthesis.source_finding_ids)].sort();
255
+ if (requestedSources.length !== input.synthesis.source_finding_ids.length || requestedSources.join("\n") !== actualSources.join("\n")) {
256
+ return { ok: false, reason: "source_set_mismatch" };
257
+ }
258
+ for (const key of ["claim", "dissent", "falsifier", "next_evidence"]) {
259
+ const value = input.synthesis[key]?.trim();
260
+ if (!value || value.length > 1500)
261
+ return { ok: false, reason: `invalid_${key}` };
262
+ }
263
+ if (!new Set(["low", "medium"]).has(input.synthesis.starting_confidence)) {
264
+ return { ok: false, reason: "invalid_starting_confidence" };
265
+ }
266
+ const claim = input.synthesis.claim.trim();
267
+ const normalizedClaim = normalizedText(claim);
268
+ for (const finding of input.cluster.findings) {
269
+ for (const source of [finding.headline, finding.paraphrase, finding.proposal_text ?? ""]) {
270
+ const normalizedSource = normalizedText(source);
271
+ if (!normalizedSource)
272
+ continue;
273
+ const contained = normalizedClaim === normalizedSource
274
+ || (normalizedClaim.length >= 40 && normalizedSource.includes(normalizedClaim))
275
+ || (normalizedSource.length >= 40 && normalizedClaim.includes(normalizedSource));
276
+ if (contained || tokenCoverage(claim, source) >= LEARNING_ROUTING_POLICY.synthesis_source_overlap_max) {
277
+ return { ok: false, reason: "source_like_claim" };
278
+ }
279
+ }
280
+ }
281
+ return {
282
+ ok: true,
283
+ value: {
284
+ source_finding_ids: actualSources,
285
+ source_scope_ids: [...input.cluster.source_scope_ids],
286
+ claim,
287
+ dissent: input.synthesis.dissent.trim(),
288
+ falsifier: input.synthesis.falsifier.trim(),
289
+ next_evidence: input.synthesis.next_evidence.trim(),
290
+ starting_confidence: input.synthesis.starting_confidence,
291
+ },
292
+ };
293
+ }
294
+ function blockScore(findingTokens, block) {
295
+ if (findingTokens.size === 0)
296
+ return 0;
297
+ const blockTokens = tokens(block);
298
+ let overlap = 0;
299
+ for (const token of findingTokens)
300
+ if (blockTokens.has(token))
301
+ overlap += 1;
302
+ if (overlap < 3)
303
+ return 0;
304
+ const findingCoverage = overlap / Math.min(findingTokens.size, 12);
305
+ const blockPrecision = overlap / Math.min(blockTokens.size, 12);
306
+ return Math.min(1, (findingCoverage * 0.6) + (blockPrecision * 0.4));
307
+ }
308
+ function titleScore(findingTokens, destination) {
309
+ const coreTitle = destination.title.split(/[:—]/, 1)[0] ?? destination.title;
310
+ const titleTokens = new Set([...tokens(coreTitle)].filter((token) => !GENERIC_TITLE_TOKENS.has(token)));
311
+ let titleOverlap = 0;
312
+ for (const token of titleTokens)
313
+ if (findingTokens.has(token))
314
+ titleOverlap += 1;
315
+ if (titleOverlap < 2 || titleTokens.size === 0)
316
+ return 0;
317
+ // A title echo is a useful routing label only when the document body also
318
+ // supports the learning. This keeps a two-word coincidence from taking custody.
319
+ const bodySupported = destination.blocks.some((block) => {
320
+ const blockTokens = tokens(block);
321
+ let overlap = 0;
322
+ for (const token of findingTokens)
323
+ if (blockTokens.has(token))
324
+ overlap += 1;
325
+ return overlap >= 3;
326
+ });
327
+ if (!bodySupported)
328
+ return 0;
329
+ const titleCoverage = titleOverlap / titleTokens.size;
330
+ const pairCoverage = Math.min(1, titleOverlap / 2);
331
+ return Math.min(1, (titleCoverage * 0.75) + (pairCoverage * 0.25));
332
+ }
333
+ function semanticCandidates(findingText, destinations) {
334
+ const findingTokens = tokens(findingText);
335
+ return destinations
336
+ .map((destination) => ({
337
+ destination,
338
+ score: Math.max(titleScore(findingTokens, destination), destination.blocks.reduce((best, block) => Math.max(best, blockScore(findingTokens, block)), 0)),
339
+ }))
340
+ .filter((candidate) => candidate.score > 0)
341
+ .sort((left, right) => right.score - left.score || left.destination.path.localeCompare(right.destination.path));
342
+ }
343
+ function explicitRefs(finding) {
344
+ return Array.isArray(finding.explicit_refs)
345
+ ? finding.explicit_refs.filter((ref) => typeof ref === "string" && ref.trim().length > 0)
346
+ : [];
347
+ }
348
+ function includesExactRef(destination, ref) {
349
+ if (destination.ref === ref || destination.path === ref)
350
+ return true;
351
+ const escaped = ref.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
352
+ return new RegExp(`(^|[^A-Za-z0-9])${escaped}([^A-Za-z0-9]|$)`).test(destination.text);
353
+ }
354
+ function textField(record, key) {
355
+ const value = record?.[key];
356
+ return typeof value === "string" ? value.trim() : "";
357
+ }
358
+ export function routeLearning(input) {
359
+ for (const ref of explicitRefs(input.finding)) {
360
+ const exact = input.destinations.find((destination) => includesExactRef(destination, ref));
361
+ if (exact) {
362
+ return {
363
+ kind: "home",
364
+ destination: exact,
365
+ basis: "exact_ref",
366
+ placement_confidence: "high",
367
+ why: `The signal explicitly references ${ref} in ${exact.title}.`,
368
+ score: 1,
369
+ margin: 1,
370
+ };
371
+ }
372
+ }
373
+ const findingText = [textField(input.finding, "headline"), textField(input.finding, "paraphrase")]
374
+ .filter(Boolean)
375
+ .join(" ");
376
+ const candidates = semanticCandidates(findingText, input.destinations);
377
+ const eligible = candidates.filter((candidate) => (input.sharedTargetCounts?.get(candidate.destination.path) ?? 0) <= LEARNING_ROUTING_POLICY.catch_all_shared_max);
378
+ const best = eligible[0];
379
+ const runnerUp = eligible[1];
380
+ const margin = best ? best.score - (runnerUp?.score ?? 0) : 0;
381
+ if (best && best.score >= LEARNING_ROUTING_POLICY.semantic_minimum && margin >= LEARNING_ROUTING_POLICY.semantic_margin) {
382
+ return {
383
+ kind: "home",
384
+ destination: best.destination,
385
+ basis: "semantic",
386
+ placement_confidence: best.score >= 0.7 && margin >= 0.2 ? "high" : "medium",
387
+ why: `${best.destination.title} is the closest supported next-action match and clears the routing margin.`,
388
+ score: best.score,
389
+ margin,
390
+ };
391
+ }
392
+ if (best && best.score >= LEARNING_ROUTING_POLICY.semantic_minimum && runnerUp) {
393
+ return {
394
+ kind: "unverified",
395
+ reason: "conflict",
396
+ candidates: eligible.slice(0, 2),
397
+ why: "Two destinations are similarly supported, so the primary home needs human judgment.",
398
+ };
399
+ }
400
+ return {
401
+ kind: "unmatched",
402
+ candidates: (eligible.length ? eligible : candidates).slice(0, 2),
403
+ why: "No existing Idea, Research, or Backlog destination cleared admission; keep this signal emerging until an independent call corroborates it.",
404
+ };
405
+ }
@@ -0,0 +1,26 @@
1
+ import type { DiscoverySession } from "./discoverySources.js";
2
+ export type DiscoveryMatchTarget = {
3
+ provider: string;
4
+ expected_local_date: string | null;
5
+ timezone: string;
6
+ required_participants: string[];
7
+ required_title_tokens: string[];
8
+ };
9
+ export type DiscoveryCandidateRef = {
10
+ candidate_index: number;
11
+ source_fingerprint: string;
12
+ };
13
+ export type DiscoveryMatchResult = {
14
+ status: "none" | "unique" | "ambiguous";
15
+ matches: DiscoverySession[];
16
+ candidates: DiscoveryCandidateRef[];
17
+ };
18
+ export declare function sourceFingerprint(session: DiscoverySession): string;
19
+ export declare function matchDiscoverySessions(target: DiscoveryMatchTarget, sessions: DiscoverySession[]): DiscoveryMatchResult;
20
+ export type DiscoveryDuplicateProposal = {
21
+ left_fingerprint: string;
22
+ right_fingerprint: string;
23
+ confidence: "medium" | "high";
24
+ action: "review-canonical-source";
25
+ };
26
+ export declare function findProbableDiscoveryDuplicates(sessions: DiscoverySession[]): DiscoveryDuplicateProposal[];
@@ -0,0 +1,73 @@
1
+ import { createHash } from "node:crypto";
2
+ function normalize(value) {
3
+ return value.trim().toLowerCase().replace(/\s+/g, " ");
4
+ }
5
+ function localDate(iso, timeZone) {
6
+ const date = new Date(iso);
7
+ if (!Number.isFinite(date.getTime()))
8
+ return null;
9
+ try {
10
+ const parts = new Intl.DateTimeFormat("en-US", { timeZone, year: "numeric", month: "2-digit", day: "2-digit" }).formatToParts(date);
11
+ const map = Object.fromEntries(parts.map((part) => [part.type, part.value]));
12
+ return `${map.year}-${map.month}-${map.day}`;
13
+ }
14
+ catch {
15
+ return null;
16
+ }
17
+ }
18
+ function sessionMatches(target, session) {
19
+ if (session.completion_state !== "completed")
20
+ return false;
21
+ if (normalize(session.provider) !== normalize(target.provider))
22
+ return false;
23
+ if (target.expected_local_date && localDate(session.completed_at, target.timezone) !== target.expected_local_date)
24
+ return false;
25
+ const title = normalize(session.title);
26
+ if (!target.required_title_tokens.every((token) => title.includes(normalize(token))))
27
+ return false;
28
+ const participants = session.participants.map(normalize);
29
+ if (!target.required_participants.every((required) => participants.includes(normalize(required))))
30
+ return false;
31
+ return true;
32
+ }
33
+ export function sourceFingerprint(session) {
34
+ const identity = [
35
+ normalize(session.provider),
36
+ normalize(session.connection_alias),
37
+ session.runtime_handle,
38
+ new Date(session.completed_at).toISOString(),
39
+ normalize(session.title),
40
+ session.stable_url ?? "",
41
+ ].join("\n");
42
+ return `sha256:${createHash("sha256").update(identity).digest("hex")}`;
43
+ }
44
+ export function matchDiscoverySessions(target, sessions) {
45
+ const matches = sessions.filter((session) => sessionMatches(target, session));
46
+ const candidates = matches.map((session, index) => ({ candidate_index: index + 1, source_fingerprint: sourceFingerprint(session) }));
47
+ return { status: matches.length === 0 ? "none" : matches.length === 1 ? "unique" : "ambiguous", matches, candidates };
48
+ }
49
+ function participantOverlap(left, right) {
50
+ const rightNames = new Set(right.participants.map(normalize));
51
+ return left.participants.map(normalize).some((name) => rightNames.has(name));
52
+ }
53
+ export function findProbableDiscoveryDuplicates(sessions) {
54
+ const proposals = [];
55
+ for (let left = 0; left < sessions.length; left += 1) {
56
+ for (let right = left + 1; right < sessions.length; right += 1) {
57
+ const a = sessions[left];
58
+ const b = sessions[right];
59
+ if (normalize(a.provider) === normalize(b.provider))
60
+ continue;
61
+ const minutes = Math.abs(Date.parse(a.completed_at) - Date.parse(b.completed_at)) / 60_000;
62
+ if (minutes > 15 || normalize(a.title) !== normalize(b.title) || !participantOverlap(a, b))
63
+ continue;
64
+ proposals.push({
65
+ left_fingerprint: sourceFingerprint(a),
66
+ right_fingerprint: sourceFingerprint(b),
67
+ confidence: minutes <= 5 ? "high" : "medium",
68
+ action: "review-canonical-source",
69
+ });
70
+ }
71
+ }
72
+ return proposals;
73
+ }
@@ -0,0 +1,12 @@
1
+ import { type DiscoveryCommandOutcome } from "./discoveryCommand.js";
2
+ import { type SynthesisTransport } from "./discoverySynthesis.js";
3
+ import { type FetchLike } from "./outlookNango.js";
4
+ export type OutlookDiscoveryDeps = {
5
+ fetchImpl?: FetchLike;
6
+ env?: NodeJS.ProcessEnv;
7
+ now?: () => string;
8
+ sleep?: (ms: number) => Promise<void>;
9
+ transport?: SynthesisTransport;
10
+ fetchTimeoutMs?: number;
11
+ };
12
+ export declare function runOutlookDiscovery(root: string, args: string[], deps?: OutlookDiscoveryDeps): Promise<DiscoveryCommandOutcome>;