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,344 @@
1
+ // Zendesk through Nango (zendesk-discovery-connector-v0, local worker mode).
2
+ //
3
+ // Nango is the credential broker only (Granola packet D-007, carried by this
4
+ // packet's D-010): productfoo asks Nango for the company's Zendesk credential and
5
+ // then talks to the Zendesk REST API directly, so comment-thread content
6
+ // never transits Nango. Everything here is content-free on every surface productfoo
7
+ // owns: credentials are held in process memory for one command, the Nango
8
+ // connection id is never printed (an opaque `connection_ref` stands in for
9
+ // it), and errors carry a typed code plus a bounded message that never
10
+ // embeds a provider response.
11
+ //
12
+ // Zendesk API shapes below are beliefs owned by the packet's feasibility task
13
+ // (T-001) and pinned by fixtures in test/discoveryZendeskRuntime.test.ts; the
14
+ // live dogfood run (T-008) is what promotes them from belief to verified.
15
+ import { createHash } from "node:crypto";
16
+ import { refuseSourceWrite } from "./sourceIngress.js";
17
+ export class ZendeskRuntimeError extends Error {
18
+ code;
19
+ constructor(code, message) {
20
+ super(message);
21
+ this.code = code;
22
+ this.name = "ZendeskRuntimeError";
23
+ }
24
+ }
25
+ // Versioned policy fields (Granola packet R-005): hard ceilings the worker
26
+ // enforces and reports, so a later change is explicit rather than silent.
27
+ export const ZENDESK_POLICY = {
28
+ policy_version: "zendesk-local-worker-0.1",
29
+ max_response_bytes: 8 * 1024 * 1024,
30
+ fetch_timeout_ms: 90_000,
31
+ max_model_input_tokens: 100_000,
32
+ max_list_pages: 5,
33
+ min_request_interval_ms: 350,
34
+ };
35
+ // Belief, owned by the packet's feasibility task (T-001): the OAuth scope
36
+ // that carries ticket reads (comment threads included). A token without it is
37
+ // observed as `missing` and the adapter fails closed (R-005).
38
+ const ZENDESK_COMMENT_SCOPE = "tickets:read";
39
+ const DEFAULT_NANGO_HOST = "https://api.nango.dev";
40
+ function nangoConfigured(env) {
41
+ return Boolean(env.NANGO_SECRET_KEY?.trim() && env.FOO_ZENDESK_NANGO_CONNECTION?.trim());
42
+ }
43
+ function directConfigured(env) {
44
+ return Boolean(env.FOO_ZENDESK_API_TOKEN?.trim() && env.FOO_ZENDESK_API_TOKEN_EMAIL?.trim());
45
+ }
46
+ export function zendeskConnectionConfigured(env) {
47
+ return nangoConfigured(env) || directConfigured(env);
48
+ }
49
+ export function zendeskCredentialBroker(env) {
50
+ if (nangoConfigured(env))
51
+ return "nango";
52
+ if (directConfigured(env))
53
+ return "direct";
54
+ return null;
55
+ }
56
+ // One DNS label: Zendesk subdomains are a single label under zendesk.com.
57
+ const SUBDOMAIN_SHAPE = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i;
58
+ function workspaceSubdomain(env) {
59
+ const subdomain = env.FOO_ZENDESK_SUBDOMAIN?.trim() ?? "";
60
+ if (!subdomain) {
61
+ throw new ZendeskRuntimeError("not_connected", "FOO_ZENDESK_SUBDOMAIN is not set: the workspace's Zendesk subdomain is required to reach the API host for every broker");
62
+ }
63
+ if (!SUBDOMAIN_SHAPE.test(subdomain)) {
64
+ throw new ZendeskRuntimeError("not_connected", "FOO_ZENDESK_SUBDOMAIN must be the workspace's single Zendesk subdomain label, not a URL");
65
+ }
66
+ return subdomain.toLowerCase();
67
+ }
68
+ function opaqueConnectionRef(integration, connectionId) {
69
+ return `zendesk:${createHash("sha256").update(`${integration}\n${connectionId}`).digest("hex").slice(0, 16)}`;
70
+ }
71
+ async function fetchWithTimeout(fetchImpl, url, init, timeoutMs) {
72
+ const controller = new AbortController();
73
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
74
+ try {
75
+ return await fetchImpl(url, { ...init, signal: controller.signal });
76
+ }
77
+ catch (error) {
78
+ if (controller.signal.aborted)
79
+ throw new ZendeskRuntimeError("provider_timeout", "the provider did not answer within the fetch ceiling");
80
+ throw new ZendeskRuntimeError("network", `network failure reaching ${new URL(url).hostname}`);
81
+ }
82
+ finally {
83
+ clearTimeout(timer);
84
+ }
85
+ }
86
+ // Reads a response body while counting toward the byte ceiling, so an
87
+ // oversized comment thread is dropped before it is ever materialized in full.
88
+ async function readBounded(response, maxBytes) {
89
+ const declared = Number(response.headers.get("content-length") ?? "0");
90
+ if (Number.isFinite(declared) && declared > maxBytes)
91
+ throw new ZendeskRuntimeError("transcript_too_large", "the provider response exceeds the byte ceiling");
92
+ if (!response.body) {
93
+ const buffer = await response.arrayBuffer();
94
+ if (buffer.byteLength > maxBytes)
95
+ throw new ZendeskRuntimeError("transcript_too_large", "the provider response exceeds the byte ceiling");
96
+ return new TextDecoder().decode(buffer);
97
+ }
98
+ const reader = response.body.getReader();
99
+ const chunks = [];
100
+ let total = 0;
101
+ for (;;) {
102
+ const { done, value } = await reader.read();
103
+ if (done)
104
+ break;
105
+ total += value.byteLength;
106
+ if (total > maxBytes) {
107
+ await reader.cancel().catch(() => undefined);
108
+ chunks.length = 0;
109
+ throw new ZendeskRuntimeError("transcript_too_large", "the provider response exceeds the byte ceiling");
110
+ }
111
+ chunks.push(value);
112
+ }
113
+ return new TextDecoder().decode(Buffer.concat(chunks));
114
+ }
115
+ function parseJson(text, label) {
116
+ try {
117
+ const parsed = JSON.parse(text);
118
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
119
+ throw new Error("not an object");
120
+ return parsed;
121
+ }
122
+ catch {
123
+ throw new ZendeskRuntimeError("provider_failure", `${label} returned a response productfoo could not read`);
124
+ }
125
+ }
126
+ /**
127
+ * Resolve the company's Zendesk credential. Nango is the primary broker: it
128
+ * holds the credential, refreshes it, and is where an administrator revokes
129
+ * it. When Nango is not configured, an administrator-issued API token and
130
+ * agent email set directly in this runtime's environment (FOO_ZENDESK_API_TOKEN
131
+ * / FOO_ZENDESK_API_TOKEN_EMAIL) is accepted as the direct fallback — the same
132
+ * company credential, minus the central refresh and revoke story. Either way
133
+ * productfoo receives it for one command and never persists or prints it. The
134
+ * workspace subdomain (FOO_ZENDESK_SUBDOMAIN) is required for both brokers.
135
+ */
136
+ export async function resolveZendeskConnection(input) {
137
+ const broker = zendeskCredentialBroker(input.env);
138
+ if (broker === null) {
139
+ throw new ZendeskRuntimeError("not_connected", "Zendesk is not connected: set NANGO_SECRET_KEY and FOO_ZENDESK_NANGO_CONNECTION for the company connection through Nango, or FOO_ZENDESK_API_TOKEN and FOO_ZENDESK_API_TOKEN_EMAIL for a direct administrator-issued API token");
140
+ }
141
+ const subdomain = workspaceSubdomain(input.env);
142
+ if (broker === "direct") {
143
+ const email = input.env.FOO_ZENDESK_API_TOKEN_EMAIL.trim();
144
+ const token = input.env.FOO_ZENDESK_API_TOKEN.trim();
145
+ return {
146
+ connection_ref: `zendesk:direct:${createHash("sha256").update(`${subdomain}\n${email}`).digest("hex").slice(0, 16)}`,
147
+ broker: "direct",
148
+ // Zendesk API-token auth: basic credentials whose username is the
149
+ // agent email with the /token suffix (belief, T-001-owned).
150
+ credential: { type: "basic", username: `${email}/token`, password: token },
151
+ credential_type: "basic",
152
+ comment_scope: "granted",
153
+ subdomain,
154
+ };
155
+ }
156
+ const secret = input.env.NANGO_SECRET_KEY.trim();
157
+ const connectionId = input.env.FOO_ZENDESK_NANGO_CONNECTION.trim();
158
+ const integration = input.env.FOO_ZENDESK_NANGO_INTEGRATION?.trim() || "zendesk";
159
+ const host = (input.env.NANGO_HOST?.trim() || DEFAULT_NANGO_HOST).replace(/\/+$/, "");
160
+ const url = `${host}/connection/${encodeURIComponent(connectionId)}?provider_config_key=${encodeURIComponent(integration)}`;
161
+ const response = await fetchWithTimeout(input.fetchImpl, url, { method: "GET", headers: { authorization: `Bearer ${secret}`, accept: "application/json" } }, ZENDESK_POLICY.fetch_timeout_ms);
162
+ if (response.status === 401 || response.status === 403)
163
+ throw new ZendeskRuntimeError("not_connected", "Nango refused the secret key; reconnect Zendesk");
164
+ if (response.status === 404)
165
+ throw new ZendeskRuntimeError("not_connected", "Nango has no Zendesk connection with that reference; connect Zendesk first");
166
+ if (!response.ok)
167
+ throw new ZendeskRuntimeError("provider_failure", `Nango answered ${response.status} while resolving the connection`);
168
+ const body = parseJson(await readBounded(response, 256 * 1024), "Nango");
169
+ const credentials = (body.credentials ?? {});
170
+ const type = String(credentials.type ?? "").toUpperCase();
171
+ const ref = opaqueConnectionRef(integration, connectionId);
172
+ if (type === "OAUTH2") {
173
+ const token = String(credentials.access_token ?? "");
174
+ if (!token)
175
+ throw new ZendeskRuntimeError("auth_expired", "the Nango connection carries no usable Zendesk access token; refresh or reconnect");
176
+ const raw = (credentials.raw ?? {});
177
+ const scopeValue = typeof raw.scope === "string" ? raw.scope : typeof credentials.scope === "string" ? credentials.scope : "";
178
+ const scopes = scopeValue.split(/[\s,]+/).filter(Boolean);
179
+ const commentScope = scopes.length === 0 ? "unknown" : scopes.includes(ZENDESK_COMMENT_SCOPE) ? "granted" : "missing";
180
+ return { connection_ref: ref, broker: "nango", credential: { type: "oauth2", access_token: token }, credential_type: "oauth2", comment_scope: commentScope, subdomain };
181
+ }
182
+ throw new ZendeskRuntimeError("not_connected", "the Nango connection uses a credential type productfoo does not support for Zendesk");
183
+ }
184
+ // One query clause per selector value, believed Zendesk search field syntax —
185
+ // T-001 owns verifying the operators against the live search surface; the
186
+ // fixtures pin productfoo's construction so any correction is a visible change.
187
+ function zendeskQueryParts(window, selectors) {
188
+ const day = (iso) => new Date(iso).toISOString().slice(0, 10);
189
+ const parts = [`type:ticket`, `status:solved,closed`, `created>=${day(window.from)}`, `created<=${day(window.to)}`];
190
+ const group = (label, values, wrap) => {
191
+ const trimmed = (values ?? []).map((value) => value.trim()).filter(Boolean);
192
+ if (!trimmed.length)
193
+ return undefined;
194
+ const clauses = trimmed.map((value) => `${label}:${wrap(value)}`);
195
+ return trimmed.length === 1 ? clauses[0] : `(${clauses.join(" OR ")})`;
196
+ };
197
+ // The listing is narrowed by the selectors where the search surface
198
+ // supports it; the worker additionally narrows by requester domain and
199
+ // solved time after the read — narrowing only, never widening (R-004).
200
+ parts.push(...[group("requester.email", selectors.external_domains, (value) => `*@${value}`), group("organization", selectors.organizations, (value) => `"${value.replaceAll('"', "")}"`), group("brand", selectors.brands, (value) => `"${value.replaceAll('"', "")}"`)].filter((part) => Boolean(part)));
201
+ return parts.join(" ");
202
+ }
203
+ const READ_ONLY_POSTS = new Set(["/api/v2/users/show_many"]);
204
+ /**
205
+ * Minimal read-only Zendesk REST client. Only documented read operations are
206
+ * reachable; any other method or path routes through the single write-refusal
207
+ * choke point (R-009) so the refusal is testable rather than scattered.
208
+ */
209
+ export class ZendeskClient {
210
+ credential;
211
+ subdomain;
212
+ options;
213
+ requests = { list: 0, users: 0, brands: 0, comments: 0 };
214
+ lastRequestAt = 0;
215
+ baseUrl;
216
+ sleep;
217
+ now;
218
+ fetchTimeoutMs;
219
+ constructor(credential, subdomain, options) {
220
+ this.credential = credential;
221
+ this.subdomain = subdomain;
222
+ this.options = options;
223
+ this.baseUrl = (options.baseUrl ?? `https://${subdomain}.zendesk.com`).replace(/\/+$/, "");
224
+ this.sleep = options.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
225
+ this.now = options.now ?? (() => Date.now());
226
+ this.fetchTimeoutMs = options.fetchTimeoutMs ?? ZENDESK_POLICY.fetch_timeout_ms;
227
+ }
228
+ authorization() {
229
+ if (this.credential.type === "basic")
230
+ return `Basic ${Buffer.from(`${this.credential.username}:${this.credential.password}`).toString("base64")}`;
231
+ return `Bearer ${this.credential.access_token}`;
232
+ }
233
+ async request(method, pathname, body, maxBytes = ZENDESK_POLICY.max_response_bytes) {
234
+ const readOnly = method === "GET" || (method === "POST" && READ_ONLY_POSTS.has(pathname.split("?")[0]));
235
+ if (!readOnly)
236
+ refuseSourceWrite(`zendesk ${method} ${pathname}`);
237
+ const wait = this.lastRequestAt + ZENDESK_POLICY.min_request_interval_ms - this.now();
238
+ if (wait > 0)
239
+ await this.sleep(wait);
240
+ this.lastRequestAt = this.now();
241
+ const response = await fetchWithTimeout(this.options.fetchImpl, `${this.baseUrl}${pathname}`, {
242
+ method,
243
+ headers: { authorization: this.authorization(), accept: "application/json", ...(body !== undefined ? { "content-type": "application/json" } : {}) },
244
+ ...(body !== undefined ? { body: JSON.stringify(body) } : {}),
245
+ }, this.fetchTimeoutMs);
246
+ if (response.status === 401)
247
+ throw new ZendeskRuntimeError("auth_expired", "Zendesk rejected the credential; refresh or reconnect");
248
+ if (response.status === 403)
249
+ throw new ZendeskRuntimeError("access_denied", "Zendesk denied this read; the credential lacks the required permission");
250
+ if (response.status === 429)
251
+ throw new ZendeskRuntimeError("budget_exhausted", "Zendesk rate limit reached; no retry was attempted");
252
+ if (response.status === 404)
253
+ throw new ZendeskRuntimeError("provider_failure", "Zendesk reported the requested record does not exist");
254
+ if (!response.ok)
255
+ throw new ZendeskRuntimeError("provider_failure", `Zendesk answered ${response.status}`);
256
+ return parseJson(await readBounded(response, maxBytes), "Zendesk");
257
+ }
258
+ /** Bounded metadata listing: one selector set, a page ceiling, no content. */
259
+ async listTickets(window, selectors = {}) {
260
+ const tickets = [];
261
+ let cursor;
262
+ let pages = 0;
263
+ for (;;) {
264
+ if (pages >= ZENDESK_POLICY.max_list_pages)
265
+ return { tickets, pages, truncated: true };
266
+ const params = new URLSearchParams({ query: zendeskQueryParts(window, selectors) });
267
+ if (cursor)
268
+ params.set("cursor", cursor);
269
+ this.requests.list += 1;
270
+ const body = await this.request("GET", `/api/v2/search/export.json?${params.toString()}`, undefined, 4 * 1024 * 1024);
271
+ pages += 1;
272
+ for (const entry of Array.isArray(body.results) ? body.results : []) {
273
+ if (!entry || typeof entry.id !== "number")
274
+ continue;
275
+ tickets.push({
276
+ id: String(entry.id),
277
+ subject: typeof entry.subject === "string" ? entry.subject : undefined,
278
+ status: typeof entry.status === "string" ? entry.status : undefined,
279
+ solved_at: typeof entry.solved_at === "string" ? entry.solved_at : undefined,
280
+ created_at: typeof entry.created_at === "string" ? entry.created_at : undefined,
281
+ updated_at: typeof entry.updated_at === "string" ? entry.updated_at : undefined,
282
+ requester_id: typeof entry.requester_id === "number" ? entry.requester_id : undefined,
283
+ assignee_id: typeof entry.assignee_id === "number" ? entry.assignee_id : undefined,
284
+ brand_id: typeof entry.brand_id === "number" ? entry.brand_id : undefined,
285
+ });
286
+ }
287
+ const meta = (body.meta ?? {});
288
+ cursor = typeof meta.after_cursor === "string" && meta.after_cursor ? meta.after_cursor : undefined;
289
+ const hasMore = typeof meta.has_more === "boolean" ? meta.has_more : Boolean(cursor);
290
+ if (!hasMore)
291
+ return { tickets, pages, truncated: false };
292
+ }
293
+ }
294
+ /** User metadata for the given ids (names, roles) — batched, no content fields. */
295
+ async users(ids) {
296
+ const out = new Map();
297
+ const unique = [...new Set(ids.filter((id) => Number.isFinite(id)))];
298
+ for (let index = 0; index < unique.length; index += 100) {
299
+ const batch = unique.slice(index, index + 100);
300
+ this.requests.users += 1;
301
+ const body = await this.request("POST", `/api/v2/users/show_many?ids=${batch.map((id) => String(id)).join(",")}`, undefined, 4 * 1024 * 1024);
302
+ for (const entry of Array.isArray(body.users) ? body.users : []) {
303
+ if (typeof entry.id !== "number")
304
+ continue;
305
+ out.set(entry.id, {
306
+ id: entry.id,
307
+ name: typeof entry.name === "string" ? entry.name : undefined,
308
+ email: typeof entry.email === "string" ? entry.email : undefined,
309
+ role: typeof entry.role === "string" ? entry.role : undefined,
310
+ });
311
+ }
312
+ }
313
+ return out;
314
+ }
315
+ /** Account brands, once per listing run, so brand_id maps to a name. */
316
+ async brands() {
317
+ this.requests.brands += 1;
318
+ const body = await this.request("GET", "/api/v2/brands.json", undefined, 1024 * 1024);
319
+ const out = new Map();
320
+ for (const entry of Array.isArray(body.brands) ? body.brands : []) {
321
+ if (typeof entry.id === "number" && typeof entry.name === "string")
322
+ out.set(entry.id, entry.name);
323
+ }
324
+ return out;
325
+ }
326
+ /**
327
+ * Exactly one ticket's comment thread (R-007). This method refuses to ask
328
+ * for more than one identifier and a fixture observes that no request ever
329
+ * carries more.
330
+ */
331
+ async comments(ticketId) {
332
+ if (!ticketId || /[\s?&/]/.test(ticketId))
333
+ throw new ZendeskRuntimeError("provider_failure", "a single well-formed ticket identifier is required");
334
+ this.requests.comments += 1;
335
+ const body = await this.request("GET", `/api/v2/tickets/${encodeURIComponent(ticketId)}/comments.json`);
336
+ return (Array.isArray(body.comments) ? body.comments : []).map((comment) => ({
337
+ id: typeof comment.id === "number" ? comment.id : undefined,
338
+ author_id: typeof comment.author_id === "number" ? comment.author_id : undefined,
339
+ body: typeof comment.body === "string" ? comment.body : undefined,
340
+ public: typeof comment.public === "boolean" ? comment.public : undefined,
341
+ created_at: typeof comment.created_at === "string" ? comment.created_at : undefined,
342
+ }));
343
+ }
344
+ }
@@ -0,0 +1,106 @@
1
+ import type { ZoomRecordingRecord } from "./discoveryProviders.js";
2
+ export type FetchLike = typeof globalThis.fetch;
3
+ export type ZoomRuntimeErrorCode = "not_connected" | "auth_expired" | "access_denied" | "provider_failure" | "network" | "provider_timeout" | "transcript_too_large" | "budget_exhausted";
4
+ export declare class ZoomRuntimeError extends Error {
5
+ readonly code: ZoomRuntimeErrorCode;
6
+ constructor(code: ZoomRuntimeErrorCode, message: string);
7
+ }
8
+ export type ZoomCredential = {
9
+ type: "oauth2";
10
+ access_token: string;
11
+ };
12
+ export type ZoomConnection = {
13
+ connection_ref: string;
14
+ broker: "nango" | "direct";
15
+ credential: ZoomCredential;
16
+ credential_type: "oauth2";
17
+ transcript_scope: "granted" | "missing" | "unknown";
18
+ };
19
+ export declare const ZOOM_POLICY: {
20
+ readonly policy_version: "zoom-local-worker-0.1";
21
+ readonly max_response_bytes: number;
22
+ readonly max_transcript_bytes: number;
23
+ readonly fetch_timeout_ms: 90000;
24
+ readonly max_model_input_tokens: 100000;
25
+ readonly max_list_pages: 5;
26
+ readonly max_page_size: 300;
27
+ readonly min_request_interval_ms: 350;
28
+ };
29
+ export type ZoomConnectionEnv = Record<string, string | undefined>;
30
+ export declare function zoomConnectionConfigured(env: ZoomConnectionEnv): boolean;
31
+ export declare function zoomCredentialBroker(env: ZoomConnectionEnv): "nango" | "direct" | null;
32
+ /**
33
+ * Resolve the company's Zoom credential. Nango is the primary broker: it holds
34
+ * the credential, refreshes it, and is where an administrator revokes it. When
35
+ * Nango is not configured, an administrator-issued server-to-server OAuth app
36
+ * (FOO_ZOOM_ACCOUNT_ID / FOO_ZOOM_CLIENT_ID / FOO_ZOOM_CLIENT_SECRET) is
37
+ * accepted as the direct fallback — the same company grant, minus the central
38
+ * refresh and revoke story. Either way productfoo receives it for one command and
39
+ * never persists or prints it.
40
+ */
41
+ export declare function resolveZoomConnection(input: {
42
+ env: ZoomConnectionEnv;
43
+ fetchImpl: FetchLike;
44
+ }): Promise<ZoomConnection>;
45
+ export type ZoomRecordingFile = {
46
+ file_type?: string;
47
+ download_url?: string;
48
+ play_url?: string;
49
+ status?: string;
50
+ };
51
+ export type ZoomListedRecording = ZoomRecordingRecord & {
52
+ recording_files?: ZoomRecordingFile[];
53
+ };
54
+ type ZoomClientOptions = {
55
+ fetchImpl: FetchLike;
56
+ baseUrl?: string;
57
+ sleep?: (ms: number) => Promise<void>;
58
+ now?: () => number;
59
+ fetchTimeoutMs?: number;
60
+ };
61
+ /**
62
+ * Minimal read-only Zoom REST client. Only documented read operations are
63
+ * reachable; any other method or path routes through the single write-refusal
64
+ * choke point (R-009) so the refusal is testable rather than scattered.
65
+ */
66
+ export declare class ZoomClient {
67
+ private readonly credential;
68
+ private readonly options;
69
+ readonly requests: {
70
+ list: number;
71
+ transcript: number;
72
+ };
73
+ private lastRequestAt;
74
+ private readonly baseUrl;
75
+ private readonly sleep;
76
+ private readonly now;
77
+ private readonly fetchTimeoutMs;
78
+ constructor(credential: ZoomCredential, options: ZoomClientOptions);
79
+ private authorization;
80
+ private request;
81
+ /**
82
+ * Bounded metadata listing: one time window, a page ceiling, no content. A
83
+ * recording's participant records carry no affiliation field — the mapping
84
+ * passes through only what is observed and leaves the rest undefined.
85
+ */
86
+ listSessions(userId: string, window: {
87
+ from: string;
88
+ to: string;
89
+ }): Promise<{
90
+ recordings: ZoomListedRecording[];
91
+ pages: number;
92
+ truncated: boolean;
93
+ }>;
94
+ private canonicalPageUrl;
95
+ /**
96
+ * Exactly one transcript download (R-007): the observed, downloadable
97
+ * transcript file of one recording. The URL is the one the listing observed
98
+ * for that recording; a tokenized link may be used in transit (Zoom's own
99
+ * access mechanism) and is never logged, persisted, or echoed — error
100
+ * messages carry the hostname only.
101
+ */
102
+ transcript(downloadUrl: string): Promise<{
103
+ vtt: string;
104
+ }>;
105
+ }
106
+ export {};