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.
- package/LICENSE +201 -0
- package/README.md +338 -2
- package/bin/foo +3 -0
- package/bin/foo.mjs +42 -0
- package/commands/bug.md +31 -0
- package/commands/discovery.md +28 -0
- package/commands/ideate.md +27 -0
- package/commands/init.md +28 -0
- package/commands/pitch.md +27 -0
- package/commands/preview.md +25 -0
- package/commands/research.md +31 -0
- package/commands/roast.md +27 -0
- package/commands/spec.md +30 -0
- package/config/pricing.yaml +198 -0
- package/config/routing-policy.yaml +171 -0
- package/dist-public/src/activeModel.d.ts +83 -0
- package/dist-public/src/activeModel.js +331 -0
- package/dist-public/src/agentAdapters.d.ts +122 -0
- package/dist-public/src/agentAdapters.js +178 -0
- package/dist-public/src/agentState.d.ts +43 -0
- package/dist-public/src/agentState.js +177 -0
- package/dist-public/src/bugCapsule.d.ts +94 -0
- package/dist-public/src/bugCapsule.js +227 -0
- package/dist-public/src/bugCapture.d.ts +26 -0
- package/dist-public/src/bugCapture.js +251 -0
- package/dist-public/src/bugOwnerLog.d.ts +93 -0
- package/dist-public/src/bugOwnerLog.js +304 -0
- package/dist-public/src/bugReportStore.d.ts +48 -0
- package/dist-public/src/bugReportStore.js +860 -0
- package/dist-public/src/bugSpecContext.d.ts +7 -0
- package/dist-public/src/bugSpecContext.js +129 -0
- package/dist-public/src/channelFreshness.d.ts +25 -0
- package/dist-public/src/channelFreshness.js +194 -0
- package/dist-public/src/cli.d.ts +30 -0
- package/dist-public/src/cli.js +1667 -0
- package/dist-public/src/cliArgs.d.ts +7 -0
- package/dist-public/src/cliArgs.js +44 -0
- package/dist-public/src/codeCatalog.d.ts +41 -0
- package/dist-public/src/codeCatalog.js +197 -0
- package/dist-public/src/commandContract.d.ts +84 -0
- package/dist-public/src/commandContract.js +390 -0
- package/dist-public/src/commandUsage.d.ts +3 -0
- package/dist-public/src/commandUsage.js +30 -0
- package/dist-public/src/commands/agent.d.ts +60 -0
- package/dist-public/src/commands/agent.js +1353 -0
- package/dist-public/src/commands/asp.d.ts +8 -0
- package/dist-public/src/commands/asp.js +669 -0
- package/dist-public/src/commands/evalCmd.d.ts +4 -0
- package/dist-public/src/commands/evalCmd.js +405 -0
- package/dist-public/src/commands/login.d.ts +25 -0
- package/dist-public/src/commands/login.js +94 -0
- package/dist-public/src/commands/loop.d.ts +16 -0
- package/dist-public/src/commands/loop.js +619 -0
- package/dist-public/src/commands/reconcile.d.ts +41 -0
- package/dist-public/src/commands/reconcile.js +292 -0
- package/dist-public/src/commands/runtime.d.ts +1 -0
- package/dist-public/src/commands/runtime.js +36 -0
- package/dist-public/src/commands/scanRedact.d.ts +8 -0
- package/dist-public/src/commands/scanRedact.js +266 -0
- package/dist-public/src/commands/setup.d.ts +28 -0
- package/dist-public/src/commands/setup.js +398 -0
- package/dist-public/src/commands/shared.d.ts +17 -0
- package/dist-public/src/commands/shared.js +147 -0
- package/dist-public/src/commands/source.d.ts +1 -0
- package/dist-public/src/commands/source.js +134 -0
- package/dist-public/src/commands/specCmd.d.ts +24 -0
- package/dist-public/src/commands/specCmd.js +794 -0
- package/dist-public/src/commands/update.d.ts +61 -0
- package/dist-public/src/commands/update.js +244 -0
- package/dist-public/src/comprehensionSignal.d.ts +20 -0
- package/dist-public/src/comprehensionSignal.js +166 -0
- package/dist-public/src/conductor/diversity.d.ts +48 -0
- package/dist-public/src/conductor/diversity.js +423 -0
- package/dist-public/src/conductor/engine.d.ts +7 -0
- package/dist-public/src/conductor/engine.js +295 -0
- package/dist-public/src/conductor/families/ideate.d.ts +2 -0
- package/dist-public/src/conductor/families/ideate.js +255 -0
- package/dist-public/src/conductor/families/interview.d.ts +2 -0
- package/dist-public/src/conductor/families/interview.js +39 -0
- package/dist-public/src/conductor/families/specSwarm.d.ts +2 -0
- package/dist-public/src/conductor/families/specSwarm.js +146 -0
- package/dist-public/src/conductor/familyDelivery.d.ts +6 -0
- package/dist-public/src/conductor/familyDelivery.js +37 -0
- package/dist-public/src/conductor/familyPackArtifact.d.ts +4 -0
- package/dist-public/src/conductor/familyPackArtifact.js +260 -0
- package/dist-public/src/conductor/ideateDecision.d.ts +6 -0
- package/dist-public/src/conductor/ideateDecision.js +237 -0
- package/dist-public/src/conductor/pack.d.ts +26 -0
- package/dist-public/src/conductor/pack.js +75 -0
- package/dist-public/src/conductor/types.d.ts +111 -0
- package/dist-public/src/conductor/types.js +7 -0
- package/dist-public/src/configPath.d.ts +2 -0
- package/dist-public/src/configPath.js +7 -0
- package/dist-public/src/discoveryArtifacts.d.ts +54 -0
- package/dist-public/src/discoveryArtifacts.js +467 -0
- package/dist-public/src/discoveryCommand.d.ts +127 -0
- package/dist-public/src/discoveryCommand.js +2148 -0
- package/dist-public/src/discoveryConnections.d.ts +339 -0
- package/dist-public/src/discoveryConnections.js +613 -0
- package/dist-public/src/discoveryDocs.d.ts +129 -0
- package/dist-public/src/discoveryDocs.js +577 -0
- package/dist-public/src/discoveryEvidence.d.ts +59 -0
- package/dist-public/src/discoveryEvidence.js +198 -0
- package/dist-public/src/discoveryFireflies.d.ts +25 -0
- package/dist-public/src/discoveryFireflies.js +551 -0
- package/dist-public/src/discoveryGmail.d.ts +12 -0
- package/dist-public/src/discoveryGmail.js +466 -0
- package/dist-public/src/discoveryGong.d.ts +12 -0
- package/dist-public/src/discoveryGong.js +491 -0
- package/dist-public/src/discoveryLearningRouting.d.ts +90 -0
- package/dist-public/src/discoveryLearningRouting.js +405 -0
- package/dist-public/src/discoveryMatching.d.ts +26 -0
- package/dist-public/src/discoveryMatching.js +73 -0
- package/dist-public/src/discoveryOutlook.d.ts +12 -0
- package/dist-public/src/discoveryOutlook.js +492 -0
- package/dist-public/src/discoveryProcess.d.ts +221 -0
- package/dist-public/src/discoveryProcess.js +703 -0
- package/dist-public/src/discoveryProof.d.ts +143 -0
- package/dist-public/src/discoveryProof.js +529 -0
- package/dist-public/src/discoveryProviders.d.ts +152 -0
- package/dist-public/src/discoveryProviders.js +756 -0
- package/dist-public/src/discoveryReadiness.d.ts +219 -0
- package/dist-public/src/discoveryReadiness.js +672 -0
- package/dist-public/src/discoveryReconcile.d.ts +57 -0
- package/dist-public/src/discoveryReconcile.js +424 -0
- package/dist-public/src/discoverySlack.d.ts +12 -0
- package/dist-public/src/discoverySlack.js +452 -0
- package/dist-public/src/discoverySources.d.ts +56 -0
- package/dist-public/src/discoverySources.js +322 -0
- package/dist-public/src/discoverySync.d.ts +52 -0
- package/dist-public/src/discoverySync.js +151 -0
- package/dist-public/src/discoverySynthesis.d.ts +57 -0
- package/dist-public/src/discoverySynthesis.js +215 -0
- package/dist-public/src/discoveryTeams.d.ts +12 -0
- package/dist-public/src/discoveryTeams.js +516 -0
- package/dist-public/src/discoveryZoom.d.ts +12 -0
- package/dist-public/src/discoveryZoom.js +523 -0
- package/dist-public/src/elicitationSurface.d.ts +13 -0
- package/dist-public/src/elicitationSurface.js +77 -0
- package/dist-public/src/errorReport.d.ts +99 -0
- package/dist-public/src/errorReport.js +443 -0
- package/dist-public/src/errorTaxonomy.d.ts +84 -0
- package/dist-public/src/errorTaxonomy.js +189 -0
- package/dist-public/src/evalCalibration.d.ts +82 -0
- package/dist-public/src/evalCalibration.js +169 -0
- package/dist-public/src/evalChecks.d.ts +21 -0
- package/dist-public/src/evalChecks.js +295 -0
- package/dist-public/src/evalCompile.d.ts +56 -0
- package/dist-public/src/evalCompile.js +58 -0
- package/dist-public/src/evalImprove.d.ts +60 -0
- package/dist-public/src/evalImprove.js +175 -0
- package/dist-public/src/evalJudge.d.ts +47 -0
- package/dist-public/src/evalJudge.js +143 -0
- package/dist-public/src/evalLabels.d.ts +100 -0
- package/dist-public/src/evalLabels.js +287 -0
- package/dist-public/src/evalRecord.d.ts +68 -0
- package/dist-public/src/evalRecord.js +165 -0
- package/dist-public/src/evalRoast.d.ts +88 -0
- package/dist-public/src/evalRoast.js +249 -0
- package/dist-public/src/evidenceIntake.d.ts +66 -0
- package/dist-public/src/evidenceIntake.js +356 -0
- package/dist-public/src/feedback.d.ts +78 -0
- package/dist-public/src/feedback.js +294 -0
- package/dist-public/src/firefliesClient.d.ts +106 -0
- package/dist-public/src/firefliesClient.js +258 -0
- package/dist-public/src/firstMoveTensions.d.ts +10 -0
- package/dist-public/src/firstMoveTensions.js +93 -0
- package/dist-public/src/gitRun.d.ts +21 -0
- package/dist-public/src/gitRun.js +50 -0
- package/dist-public/src/githubReconcile.d.ts +94 -0
- package/dist-public/src/githubReconcile.js +205 -0
- package/dist-public/src/gmailNango.d.ts +131 -0
- package/dist-public/src/gmailNango.js +329 -0
- package/dist-public/src/gongNango.d.ts +118 -0
- package/dist-public/src/gongNango.js +308 -0
- package/dist-public/src/grammarGate.d.ts +13 -0
- package/dist-public/src/grammarGate.js +72 -0
- package/dist-public/src/harnessGates.d.ts +65 -0
- package/dist-public/src/harnessGates.js +168 -0
- package/dist-public/src/humanSurfaceEval.d.ts +19 -0
- package/dist-public/src/humanSurfaceEval.js +156 -0
- package/dist-public/src/ideate.d.ts +43 -0
- package/dist-public/src/ideate.js +255 -0
- package/dist-public/src/ideateContext.d.ts +11 -0
- package/dist-public/src/ideateContext.js +83 -0
- package/dist-public/src/index.d.ts +2 -0
- package/dist-public/src/index.js +4 -0
- package/dist-public/src/initCommand.d.ts +25 -0
- package/dist-public/src/initCommand.js +558 -0
- package/dist-public/src/interviewGate.d.ts +25 -0
- package/dist-public/src/interviewGate.js +126 -0
- package/dist-public/src/jsonFile.d.ts +2 -0
- package/dist-public/src/jsonFile.js +22 -0
- package/dist-public/src/loopBudget.d.ts +182 -0
- package/dist-public/src/loopBudget.js +494 -0
- package/dist-public/src/loopContracts.d.ts +35 -0
- package/dist-public/src/loopContracts.js +364 -0
- package/dist-public/src/machineState.d.ts +1 -0
- package/dist-public/src/machineState.js +9 -0
- package/dist-public/src/notionNango.d.ts +93 -0
- package/dist-public/src/notionNango.js +279 -0
- package/dist-public/src/orchestrationResult.d.ts +11 -0
- package/dist-public/src/orchestrationResult.js +73 -0
- package/dist-public/src/outlookNango.d.ts +124 -0
- package/dist-public/src/outlookNango.js +327 -0
- package/dist-public/src/packetCorrections.d.ts +40 -0
- package/dist-public/src/packetCorrections.js +172 -0
- package/dist-public/src/packetGlossary.d.ts +6 -0
- package/dist-public/src/packetGlossary.js +42 -0
- package/dist-public/src/packetIndex.d.ts +54 -0
- package/dist-public/src/packetIndex.js +744 -0
- package/dist-public/src/packetIndexEntry.d.ts +3 -0
- package/dist-public/src/packetIndexEntry.js +128 -0
- package/dist-public/src/packetIndexServe.d.ts +13 -0
- package/dist-public/src/packetIndexServe.js +113 -0
- package/dist-public/src/packetIndexWorker.d.ts +7 -0
- package/dist-public/src/packetIndexWorker.js +45 -0
- package/dist-public/src/packetLifecycle.d.ts +30 -0
- package/dist-public/src/packetLifecycle.js +127 -0
- package/dist-public/src/packetReconcile.d.ts +73 -0
- package/dist-public/src/packetReconcile.js +386 -0
- package/dist-public/src/packetStatus.d.ts +125 -0
- package/dist-public/src/packetStatus.js +770 -0
- package/dist-public/src/packetValidation.d.ts +17 -0
- package/dist-public/src/packetValidation.js +333 -0
- package/dist-public/src/packetVerify.d.ts +73 -0
- package/dist-public/src/packetVerify.js +303 -0
- package/dist-public/src/packetWrite.d.ts +52 -0
- package/dist-public/src/packetWrite.js +448 -0
- package/dist-public/src/pitch.d.ts +38 -0
- package/dist-public/src/pitch.js +154 -0
- package/dist-public/src/processMemo.d.ts +8 -0
- package/dist-public/src/processMemo.js +23 -0
- package/dist-public/src/productDetect.d.ts +30 -0
- package/dist-public/src/productDetect.js +376 -0
- package/dist-public/src/profile.d.ts +62 -0
- package/dist-public/src/profile.js +334 -0
- package/dist-public/src/questionModel.d.ts +46 -0
- package/dist-public/src/questionModel.js +74 -0
- package/dist-public/src/questionText.d.ts +7 -0
- package/dist-public/src/questionText.js +38 -0
- package/dist-public/src/redactConfig.d.ts +2 -0
- package/dist-public/src/redactConfig.js +11 -0
- package/dist-public/src/redactEngine.d.ts +59 -0
- package/dist-public/src/redactEngine.js +509 -0
- package/dist-public/src/redactGate.d.ts +63 -0
- package/dist-public/src/redactGate.js +209 -0
- package/dist-public/src/repoRead.d.ts +29 -0
- package/dist-public/src/repoRead.js +160 -0
- package/dist-public/src/research.d.ts +242 -0
- package/dist-public/src/research.js +1314 -0
- package/dist-public/src/researchCompletion.d.ts +34 -0
- package/dist-public/src/researchCompletion.js +123 -0
- package/dist-public/src/researchExecution.d.ts +47 -0
- package/dist-public/src/researchExecution.js +309 -0
- package/dist-public/src/researchFormat.d.ts +21 -0
- package/dist-public/src/researchFormat.js +77 -0
- package/dist-public/src/researchGate.d.ts +86 -0
- package/dist-public/src/researchGate.js +1036 -0
- package/dist-public/src/researchReceipt.d.ts +76 -0
- package/dist-public/src/researchReceipt.js +148 -0
- package/dist-public/src/researchRender.d.ts +2 -0
- package/dist-public/src/researchRender.js +267 -0
- package/dist-public/src/researchSigningKey.d.ts +19 -0
- package/dist-public/src/researchSigningKey.js +95 -0
- package/dist-public/src/riskClassify.d.ts +42 -0
- package/dist-public/src/riskClassify.js +149 -0
- package/dist-public/src/routines.d.ts +42 -0
- package/dist-public/src/routines.js +269 -0
- package/dist-public/src/routingPolicy.d.ts +172 -0
- package/dist-public/src/routingPolicy.js +646 -0
- package/dist-public/src/secretInput.d.ts +8 -0
- package/dist-public/src/secretInput.js +89 -0
- package/dist-public/src/selfCheck.d.ts +7 -0
- package/dist-public/src/selfCheck.js +473 -0
- package/dist-public/src/selfCheckCache.d.ts +29 -0
- package/dist-public/src/selfCheckCache.js +147 -0
- package/dist-public/src/severityClass.d.ts +15 -0
- package/dist-public/src/severityClass.js +22 -0
- package/dist-public/src/skillClientPolicy.d.ts +8 -0
- package/dist-public/src/skillClientPolicy.js +16 -0
- package/dist-public/src/skillLocal.d.ts +98 -0
- package/dist-public/src/skillLocal.js +463 -0
- package/dist-public/src/skillTreeDigest.d.ts +9 -0
- package/dist-public/src/skillTreeDigest.js +64 -0
- package/dist-public/src/slackNango.d.ts +62 -0
- package/dist-public/src/slackNango.js +208 -0
- package/dist-public/src/social/arxiv.d.ts +19 -0
- package/dist-public/src/social/arxiv.js +96 -0
- package/dist-public/src/social/github.d.ts +2 -0
- package/dist-public/src/social/github.js +78 -0
- package/dist-public/src/social/hackernews.d.ts +2 -0
- package/dist-public/src/social/hackernews.js +67 -0
- package/dist-public/src/social/index.d.ts +10 -0
- package/dist-public/src/social/index.js +79 -0
- package/dist-public/src/social/reddit.d.ts +2 -0
- package/dist-public/src/social/reddit.js +125 -0
- package/dist-public/src/social/types.d.ts +73 -0
- package/dist-public/src/social/types.js +61 -0
- package/dist-public/src/social/xml.d.ts +10 -0
- package/dist-public/src/social/xml.js +49 -0
- package/dist-public/src/social/youtube.d.ts +7 -0
- package/dist-public/src/social/youtube.js +217 -0
- package/dist-public/src/sourceIngress.d.ts +488 -0
- package/dist-public/src/sourceIngress.js +1651 -0
- package/dist-public/src/specAfter.d.ts +187 -0
- package/dist-public/src/specAfter.js +814 -0
- package/dist-public/src/specBudget.d.ts +124 -0
- package/dist-public/src/specBudget.js +424 -0
- package/dist-public/src/specDecisionSignals.d.ts +38 -0
- package/dist-public/src/specDecisionSignals.js +121 -0
- package/dist-public/src/specLinkedCommits.d.ts +7 -0
- package/dist-public/src/specLinkedCommits.js +107 -0
- package/dist-public/src/specSections.d.ts +105 -0
- package/dist-public/src/specSections.js +718 -0
- package/dist-public/src/statusGlyphs.d.ts +18 -0
- package/dist-public/src/statusGlyphs.js +75 -0
- package/dist-public/src/swarmCommand.d.ts +10 -0
- package/dist-public/src/swarmCommand.js +96 -0
- package/dist-public/src/teamsNango.d.ts +114 -0
- package/dist-public/src/teamsNango.js +301 -0
- package/dist-public/src/tokenStore.d.ts +10 -0
- package/dist-public/src/tokenStore.js +77 -0
- package/dist-public/src/trustEnvelope.d.ts +78 -0
- package/dist-public/src/trustEnvelope.js +392 -0
- package/dist-public/src/untrustedText.d.ts +6 -0
- package/dist-public/src/untrustedText.js +20 -0
- package/dist-public/src/updateNotice.d.ts +41 -0
- package/dist-public/src/updateNotice.js +290 -0
- package/dist-public/src/vendorYaml.d.ts +1 -0
- package/dist-public/src/vendorYaml.js +7374 -0
- package/dist-public/src/workflowRunActuals.d.ts +67 -0
- package/dist-public/src/workflowRunActuals.js +184 -0
- package/dist-public/src/zendeskDiscovery.d.ts +12 -0
- package/dist-public/src/zendeskDiscovery.js +513 -0
- package/dist-public/src/zendeskNango.d.ts +131 -0
- package/dist-public/src/zendeskNango.js +344 -0
- package/dist-public/src/zoomNango.d.ts +106 -0
- package/dist-public/src/zoomNango.js +351 -0
- package/docs/CHANGELOG.md +32 -0
- package/docs/THIRD_PARTY_NOTICES.md +36 -0
- package/package.json +71 -4
- package/schemas/bug-capsule-receipt.schema.json +54 -0
- package/schemas/bug-capsule.schema.json +189 -0
- package/schemas/discovery-evidence-envelope.schema.json +79 -0
- package/schemas/discovery-processing-receipt.schema.json +71 -0
- package/schemas/discovery-service-contract.schema.json +189 -0
- package/skills/AGENTS.md +32 -0
- package/skills/README.md +287 -0
- package/skills/bug/SKILL.md +49 -0
- package/skills/build-preview-spec/SKILL.md +103 -0
- package/skills/capture-external-artifact/SKILL.md +23 -0
- package/skills/capture-external-artifact/agents/openai.yaml +4 -0
- package/skills/capture-external-artifact/references/extractor-libraries.md +27 -0
- package/skills/check-spec-health/SKILL.md +45 -0
- package/skills/check-spec-health/agents/openai.yaml +4 -0
- package/skills/competitive-positioning/SKILL.md +86 -0
- package/skills/competitive-positioning/agents/openai.yaml +4 -0
- package/skills/cpo-lens/SKILL.md +398 -0
- package/skills/cpo-lens/agents/openai.yaml +4 -0
- package/skills/create-prd/SKILL.md +26 -0
- package/skills/create-prd/agents/openai.yaml +4 -0
- package/skills/customer-discovery/SKILL.md +192 -0
- package/skills/design-system/SKILL.md +49 -0
- package/skills/design-system/agents/openai.yaml +4 -0
- package/skills/discussion-guide/SKILL.md +75 -0
- package/skills/discussion-guide/agents/openai.yaml +4 -0
- package/skills/firecrawl-research-papers/SKILL.md +96 -0
- package/skills/firecrawl-research-papers/agents/openai.yaml +4 -0
- package/skills/foo-roast/SKILL.md +325 -0
- package/skills/generate-gtm-brief/SKILL.md +41 -0
- package/skills/generate-gtm-brief/agents/openai.yaml +4 -0
- package/skills/generate-gtm-brief/references/gtm-brief-template.md +56 -0
- package/skills/gong-quotes/SKILL.md +43 -0
- package/skills/gong-quotes/agents/openai.yaml +4 -0
- package/skills/grill-me/SKILL.md +27 -0
- package/skills/grill-me/agents/openai.yaml +4 -0
- package/skills/ideate/SKILL.md +180 -0
- package/skills/ideate/references/family-packs.md +5 -0
- package/skills/initiative-tracker/SKILL.md +23 -0
- package/skills/initiative-tracker/agents/openai.yaml +4 -0
- package/skills/interop-review/SKILL.md +25 -0
- package/skills/interop-review/agents/openai.yaml +4 -0
- package/skills/interview-me/SKILL.md +404 -0
- package/skills/interview-me/agents/openai.yaml +4 -0
- package/skills/loop-library-audit/SKILL.md +123 -0
- package/skills/pitch/SKILL.md +110 -0
- package/skills/pitch/references/opportunity-assessment.md +136 -0
- package/skills/pitch/references/prfaq-template.md +54 -0
- package/skills/pmm-release-briefing/SKILL.md +27 -0
- package/skills/pmm-release-briefing/agents/openai.yaml +4 -0
- package/skills/pmm-release-briefing/references/variant-generalized.md +16 -0
- package/skills/positioning-messaging/SKILL.md +70 -0
- package/skills/positioning-messaging/agents/openai.yaml +4 -0
- package/skills/positioning-messaging/references/guest-insights.md +1400 -0
- package/skills/preview-swarm/SKILL.md +418 -0
- package/skills/preview-swarm/agents/openai.yaml +4 -0
- package/skills/preview-swarm/references/html-effectiveness-build-previews.md +168 -0
- package/skills/product-copywriting/SKILL.md +127 -0
- package/skills/product-copywriting/agents/openai.yaml +4 -0
- package/skills/product-copywriting/references/foo-voice.md +26 -0
- package/skills/product-shape-interview/SKILL.md +219 -0
- package/skills/product-shape-interview/agents/openai.yaml +4 -0
- package/skills/ready-for-release/SKILL.md +39 -0
- package/skills/ready-for-release/agents/openai.yaml +4 -0
- package/skills/redact-transcripts/SKILL.md +23 -0
- package/skills/redact-transcripts/agents/openai.yaml +4 -0
- package/skills/research-brief/SKILL.md +48 -0
- package/skills/research-brief/agents/openai.yaml +4 -0
- package/skills/research-refresh/SKILL.md +63 -0
- package/skills/research-refresh/references/worked-cases.md +44 -0
- package/skills/review-loop/SKILL.md +200 -0
- package/skills/review-spec/SKILL.md +32 -0
- package/skills/review-spec/agents/openai.yaml +4 -0
- package/skills/rfc-from-research/SKILL.md +42 -0
- package/skills/rfc-from-research/agents/openai.yaml +4 -0
- package/skills/rfc-from-research/references/rfc-pattern.md +69 -0
- package/skills/skill-registry.yaml +810 -0
- package/skills/spec-cleanup/SKILL.md +103 -0
- package/skills/spec-cleanup/agents/openai.yaml +4 -0
- package/skills/spec-swarm/SKILL.md +87 -0
- package/skills/spec-swarm/agents/openai.yaml +4 -0
- package/skills/spec-swarm/template/SKILL.template.md +94 -0
- package/skills/spec-swarm/template/personas/accessibility-inclusion.md +40 -0
- package/skills/spec-swarm/template/personas/ai-technical-pm.md +69 -0
- package/skills/spec-swarm/template/personas/analytics-engineering.md +39 -0
- package/skills/spec-swarm/template/personas/applied-ai-eval.md +64 -0
- package/skills/spec-swarm/template/personas/business-gm-pm.md +67 -0
- package/skills/spec-swarm/template/personas/consumer-craft-pm.md +68 -0
- package/skills/spec-swarm/template/personas/content-design.md +40 -0
- package/skills/spec-swarm/template/personas/cpo.md +42 -0
- package/skills/spec-swarm/template/personas/data-science.md +42 -0
- package/skills/spec-swarm/template/personas/developer-experience.md +65 -0
- package/skills/spec-swarm/template/personas/dx-product.md +70 -0
- package/skills/spec-swarm/template/personas/field.md +43 -0
- package/skills/spec-swarm/template/personas/finance-cfo.md +40 -0
- package/skills/spec-swarm/template/personas/growth-pm.md +67 -0
- package/skills/spec-swarm/template/personas/platform-pm.md +67 -0
- package/skills/spec-swarm/template/personas/pmm.md +43 -0
- package/skills/spec-swarm/template/personas/principal-product-designer.md +42 -0
- package/skills/spec-swarm/template/personas/product-ops-program.md +41 -0
- package/skills/spec-swarm/template/personas/qa-release.md +41 -0
- package/skills/spec-swarm/template/personas/responsible-ai-safety.md +64 -0
- package/skills/spec-swarm/template/personas/security-privacy-legal.md +40 -0
- package/skills/spec-swarm/template/personas/strategy-competitive.md +41 -0
- package/skills/spec-swarm/template/personas/technical-architect.md +42 -0
- package/skills/spec-swarm/template/personas/technical-lead.md +43 -0
- package/skills/spec-swarm/template/personas/user-research.md +41 -0
- package/skills/spec-swarm-accessibility-inclusion/SKILL.md +95 -0
- package/skills/spec-swarm-accessibility-inclusion/agents/openai.yaml +4 -0
- package/skills/spec-swarm-ai-technical-pm/SKILL.md +124 -0
- package/skills/spec-swarm-analytics-engineering/SKILL.md +94 -0
- package/skills/spec-swarm-analytics-engineering/agents/openai.yaml +4 -0
- package/skills/spec-swarm-applied-ai-eval/SKILL.md +120 -0
- package/skills/spec-swarm-business-gm-pm/SKILL.md +122 -0
- package/skills/spec-swarm-consumer-craft-pm/SKILL.md +122 -0
- package/skills/spec-swarm-content-design/SKILL.md +95 -0
- package/skills/spec-swarm-content-design/agents/openai.yaml +4 -0
- package/skills/spec-swarm-cpo/SKILL.md +94 -0
- package/skills/spec-swarm-cpo/agents/openai.yaml +4 -0
- package/skills/spec-swarm-data-science/SKILL.md +95 -0
- package/skills/spec-swarm-data-science/agents/openai.yaml +4 -0
- package/skills/spec-swarm-developer-experience/SKILL.md +121 -0
- package/skills/spec-swarm-dx-product/SKILL.md +126 -0
- package/skills/spec-swarm-field/SKILL.md +96 -0
- package/skills/spec-swarm-field/agents/openai.yaml +4 -0
- package/skills/spec-swarm-finance-cfo/SKILL.md +95 -0
- package/skills/spec-swarm-finance-cfo/agents/openai.yaml +4 -0
- package/skills/spec-swarm-growth-pm/SKILL.md +122 -0
- package/skills/spec-swarm-platform-pm/SKILL.md +122 -0
- package/skills/spec-swarm-pmm/SKILL.md +96 -0
- package/skills/spec-swarm-pmm/agents/openai.yaml +4 -0
- package/skills/spec-swarm-principal-product-designer/SKILL.md +95 -0
- package/skills/spec-swarm-principal-product-designer/agents/openai.yaml +4 -0
- package/skills/spec-swarm-product-ops-program/SKILL.md +96 -0
- package/skills/spec-swarm-product-ops-program/agents/openai.yaml +4 -0
- package/skills/spec-swarm-qa-release/SKILL.md +96 -0
- package/skills/spec-swarm-qa-release/agents/openai.yaml +4 -0
- package/skills/spec-swarm-responsible-ai-safety/SKILL.md +120 -0
- package/skills/spec-swarm-security-privacy-legal/SKILL.md +95 -0
- package/skills/spec-swarm-security-privacy-legal/agents/openai.yaml +4 -0
- package/skills/spec-swarm-strategy-competitive/SKILL.md +96 -0
- package/skills/spec-swarm-strategy-competitive/agents/openai.yaml +4 -0
- package/skills/spec-swarm-technical-architect/SKILL.md +95 -0
- package/skills/spec-swarm-technical-architect/agents/openai.yaml +4 -0
- package/skills/spec-swarm-technical-lead/SKILL.md +96 -0
- package/skills/spec-swarm-technical-lead/agents/openai.yaml +4 -0
- package/skills/spec-swarm-user-research/SKILL.md +95 -0
- package/skills/spec-swarm-user-research/agents/openai.yaml +4 -0
- package/skills/strategy-check/SKILL.md +170 -0
- package/skills/strategy-check/agents/openai.yaml +4 -0
- package/skills/study-digest/SKILL.md +41 -0
- package/skills/synthetic-customer/SKILL.md +68 -0
- package/skills/update-cli-spec/SKILL.md +69 -0
- package/skills/update-cli-spec/agents/openai.yaml +4 -0
- package/skills/voc-researcher/SKILL.md +45 -0
- package/skills/voc-researcher/agents/openai.yaml +4 -0
- package/skills-lock.json +35 -0
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
// Zoom through Nango (zoom-discovery-connector-v0, local worker mode).
|
|
2
|
+
//
|
|
3
|
+
// Nango is the credential broker only (gong-discovery-connector-v0 D-003,
|
|
4
|
+
// carried by this packet's D-001): productfoo asks Nango for the company's Zoom
|
|
5
|
+
// credential and then talks to Zoom's REST API directly, so transcript bytes
|
|
6
|
+
// never transit 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 embeds
|
|
10
|
+
// a provider response or a tokenized download URL.
|
|
11
|
+
//
|
|
12
|
+
// Zoom API shapes below are beliefs owned by the packet's feasibility task
|
|
13
|
+
// (T-001) and pinned by fixtures in test/discoveryZoomRuntime.test.ts; the
|
|
14
|
+
// live dogfood run (T-010) is what promotes them from belief to verified.
|
|
15
|
+
import { createHash } from "node:crypto";
|
|
16
|
+
import { refuseSourceWrite } from "./sourceIngress.js";
|
|
17
|
+
export class ZoomRuntimeError extends Error {
|
|
18
|
+
code;
|
|
19
|
+
constructor(code, message) {
|
|
20
|
+
super(message);
|
|
21
|
+
this.code = code;
|
|
22
|
+
this.name = "ZoomRuntimeError";
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
// Versioned policy fields (Granola packet R-005, carried by D-001): hard
|
|
26
|
+
// ceilings the worker enforces and reports, so a later change is explicit
|
|
27
|
+
// rather than silent.
|
|
28
|
+
export const ZOOM_POLICY = {
|
|
29
|
+
policy_version: "zoom-local-worker-0.1",
|
|
30
|
+
max_response_bytes: 8 * 1024 * 1024,
|
|
31
|
+
max_transcript_bytes: 4 * 1024 * 1024,
|
|
32
|
+
fetch_timeout_ms: 90_000,
|
|
33
|
+
max_model_input_tokens: 100_000,
|
|
34
|
+
max_list_pages: 5,
|
|
35
|
+
max_page_size: 300,
|
|
36
|
+
min_request_interval_ms: 350,
|
|
37
|
+
};
|
|
38
|
+
// The recording read grant that also covers cloud-recording downloads
|
|
39
|
+
// (belief owned by T-001; the feasibility report pins the exact scope string).
|
|
40
|
+
const ZOOM_RECORDING_SCOPES = ["recording:read", "recording:read:admin"];
|
|
41
|
+
const DEFAULT_NANGO_HOST = "https://api.nango.dev";
|
|
42
|
+
const DEFAULT_ZOOM_BASE = "https://api.zoom.us";
|
|
43
|
+
const DEFAULT_ZOOM_TOKEN_BASE = "https://zoom.us";
|
|
44
|
+
function nangoConfigured(env) {
|
|
45
|
+
return Boolean(env.NANGO_SECRET_KEY?.trim() && env.FOO_ZOOM_NANGO_CONNECTION?.trim());
|
|
46
|
+
}
|
|
47
|
+
function directConfigured(env) {
|
|
48
|
+
return Boolean(env.FOO_ZOOM_ACCOUNT_ID?.trim() && env.FOO_ZOOM_CLIENT_ID?.trim() && env.FOO_ZOOM_CLIENT_SECRET?.trim());
|
|
49
|
+
}
|
|
50
|
+
export function zoomConnectionConfigured(env) {
|
|
51
|
+
return nangoConfigured(env) || directConfigured(env);
|
|
52
|
+
}
|
|
53
|
+
export function zoomCredentialBroker(env) {
|
|
54
|
+
if (nangoConfigured(env))
|
|
55
|
+
return "nango";
|
|
56
|
+
if (directConfigured(env))
|
|
57
|
+
return "direct";
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
function opaqueConnectionRef(integration, connectionId) {
|
|
61
|
+
return `zoom:${createHash("sha256").update(`${integration}\n${connectionId}`).digest("hex").slice(0, 16)}`;
|
|
62
|
+
}
|
|
63
|
+
async function fetchWithTimeout(fetchImpl, url, init, timeoutMs) {
|
|
64
|
+
const controller = new AbortController();
|
|
65
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
66
|
+
try {
|
|
67
|
+
return await fetchImpl(url, { ...init, signal: controller.signal });
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
if (controller.signal.aborted)
|
|
71
|
+
throw new ZoomRuntimeError("provider_timeout", "the provider did not answer within the fetch ceiling");
|
|
72
|
+
throw new ZoomRuntimeError("network", `network failure reaching ${new URL(url).hostname}`);
|
|
73
|
+
}
|
|
74
|
+
finally {
|
|
75
|
+
clearTimeout(timer);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
// Reads a response body while counting toward the byte ceiling, so an
|
|
79
|
+
// oversized transcript is dropped before it is ever materialized in full.
|
|
80
|
+
async function readBounded(response, maxBytes) {
|
|
81
|
+
const declared = Number(response.headers.get("content-length") ?? "0");
|
|
82
|
+
if (Number.isFinite(declared) && declared > maxBytes)
|
|
83
|
+
throw new ZoomRuntimeError("transcript_too_large", "the provider response exceeds the byte ceiling");
|
|
84
|
+
if (!response.body) {
|
|
85
|
+
const buffer = await response.arrayBuffer();
|
|
86
|
+
if (buffer.byteLength > maxBytes)
|
|
87
|
+
throw new ZoomRuntimeError("transcript_too_large", "the provider response exceeds the byte ceiling");
|
|
88
|
+
return new TextDecoder().decode(buffer);
|
|
89
|
+
}
|
|
90
|
+
const reader = response.body.getReader();
|
|
91
|
+
const chunks = [];
|
|
92
|
+
let total = 0;
|
|
93
|
+
for (;;) {
|
|
94
|
+
const { done, value } = await reader.read();
|
|
95
|
+
if (done)
|
|
96
|
+
break;
|
|
97
|
+
total += value.byteLength;
|
|
98
|
+
if (total > maxBytes) {
|
|
99
|
+
await reader.cancel().catch(() => undefined);
|
|
100
|
+
chunks.length = 0;
|
|
101
|
+
throw new ZoomRuntimeError("transcript_too_large", "the provider response exceeds the byte ceiling");
|
|
102
|
+
}
|
|
103
|
+
chunks.push(value);
|
|
104
|
+
}
|
|
105
|
+
return new TextDecoder().decode(Buffer.concat(chunks));
|
|
106
|
+
}
|
|
107
|
+
function parseJson(text, label) {
|
|
108
|
+
try {
|
|
109
|
+
const parsed = JSON.parse(text);
|
|
110
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
111
|
+
throw new Error("not an object");
|
|
112
|
+
return parsed;
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
throw new ZoomRuntimeError("provider_failure", `${label} returned a response productfoo could not read`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
function recordingScopeFromScopes(scopes) {
|
|
119
|
+
if (scopes.length === 0)
|
|
120
|
+
return "unknown";
|
|
121
|
+
return scopes.some((scope) => ZOOM_RECORDING_SCOPES.includes(scope)) ? "granted" : "missing";
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Resolve the company's Zoom credential. Nango is the primary broker: it holds
|
|
125
|
+
* the credential, refreshes it, and is where an administrator revokes it. When
|
|
126
|
+
* Nango is not configured, an administrator-issued server-to-server OAuth app
|
|
127
|
+
* (FOO_ZOOM_ACCOUNT_ID / FOO_ZOOM_CLIENT_ID / FOO_ZOOM_CLIENT_SECRET) is
|
|
128
|
+
* accepted as the direct fallback — the same company grant, minus the central
|
|
129
|
+
* refresh and revoke story. Either way productfoo receives it for one command and
|
|
130
|
+
* never persists or prints it.
|
|
131
|
+
*/
|
|
132
|
+
export async function resolveZoomConnection(input) {
|
|
133
|
+
const broker = zoomCredentialBroker(input.env);
|
|
134
|
+
if (broker === null) {
|
|
135
|
+
throw new ZoomRuntimeError("not_connected", "Zoom is not connected: set NANGO_SECRET_KEY and FOO_ZOOM_NANGO_CONNECTION for the company connection through Nango, or FOO_ZOOM_ACCOUNT_ID, FOO_ZOOM_CLIENT_ID, and FOO_ZOOM_CLIENT_SECRET for a direct administrator-issued server-to-server app");
|
|
136
|
+
}
|
|
137
|
+
if (broker === "direct") {
|
|
138
|
+
const accountId = input.env.FOO_ZOOM_ACCOUNT_ID.trim();
|
|
139
|
+
const clientId = input.env.FOO_ZOOM_CLIENT_ID.trim();
|
|
140
|
+
const clientSecret = input.env.FOO_ZOOM_CLIENT_SECRET.trim();
|
|
141
|
+
// Documented server-to-server token exchange — an auth operation, not a
|
|
142
|
+
// source read; it happens once per command against zoom.us. The response
|
|
143
|
+
// token lives in process memory for the command and is never logged.
|
|
144
|
+
const response = await fetchWithTimeout(input.fetchImpl, `${DEFAULT_ZOOM_TOKEN_BASE}/oauth/token`, {
|
|
145
|
+
method: "POST",
|
|
146
|
+
headers: { authorization: `Basic ${Buffer.from(`${clientId}:${clientSecret}`).toString("base64")}`, "content-type": "application/x-www-form-urlencoded" },
|
|
147
|
+
body: new URLSearchParams({ grant_type: "account_credentials", account_id: accountId }).toString(),
|
|
148
|
+
}, ZOOM_POLICY.fetch_timeout_ms);
|
|
149
|
+
if (response.status === 400 || response.status === 401 || response.status === 403)
|
|
150
|
+
throw new ZoomRuntimeError("auth_expired", "Zoom refused the server-to-server credential; check the account id, client id, and secret");
|
|
151
|
+
if (!response.ok)
|
|
152
|
+
throw new ZoomRuntimeError("provider_failure", `Zoom answered ${response.status} while exchanging the server-to-server credential`);
|
|
153
|
+
const body = parseJson(await readBounded(response, 64 * 1024), "Zoom");
|
|
154
|
+
const token = String(body.access_token ?? "");
|
|
155
|
+
if (!token)
|
|
156
|
+
throw new ZoomRuntimeError("auth_expired", "Zoom returned no access token for the server-to-server credential");
|
|
157
|
+
return { connection_ref: `zoom:direct:${createHash("sha256").update(clientId).digest("hex").slice(0, 16)}`, broker: "direct", credential: { type: "oauth2", access_token: token }, credential_type: "oauth2", transcript_scope: "granted" };
|
|
158
|
+
}
|
|
159
|
+
const secret = input.env.NANGO_SECRET_KEY.trim();
|
|
160
|
+
const connectionId = input.env.FOO_ZOOM_NANGO_CONNECTION.trim();
|
|
161
|
+
const integration = input.env.FOO_ZOOM_NANGO_INTEGRATION?.trim() || "zoom";
|
|
162
|
+
const host = (input.env.NANGO_HOST?.trim() || DEFAULT_NANGO_HOST).replace(/\/+$/, "");
|
|
163
|
+
const url = `${host}/connection/${encodeURIComponent(connectionId)}?provider_config_key=${encodeURIComponent(integration)}`;
|
|
164
|
+
const response = await fetchWithTimeout(input.fetchImpl, url, { method: "GET", headers: { authorization: `Bearer ${secret}`, accept: "application/json" } }, ZOOM_POLICY.fetch_timeout_ms);
|
|
165
|
+
if (response.status === 401 || response.status === 403)
|
|
166
|
+
throw new ZoomRuntimeError("not_connected", "Nango refused the secret key; reconnect Zoom");
|
|
167
|
+
if (response.status === 404)
|
|
168
|
+
throw new ZoomRuntimeError("not_connected", "Nango has no Zoom connection with that reference; connect Zoom first");
|
|
169
|
+
if (!response.ok)
|
|
170
|
+
throw new ZoomRuntimeError("provider_failure", `Nango answered ${response.status} while resolving the connection`);
|
|
171
|
+
const body = parseJson(await readBounded(response, 256 * 1024), "Nango");
|
|
172
|
+
const credentials = (body.credentials ?? {});
|
|
173
|
+
const type = String(credentials.type ?? "").toUpperCase();
|
|
174
|
+
const ref = opaqueConnectionRef(integration, connectionId);
|
|
175
|
+
if (type === "OAUTH2") {
|
|
176
|
+
const token = String(credentials.access_token ?? "");
|
|
177
|
+
if (!token)
|
|
178
|
+
throw new ZoomRuntimeError("auth_expired", "the Nango connection carries no usable Zoom access token; refresh or reconnect");
|
|
179
|
+
const raw = (credentials.raw ?? {});
|
|
180
|
+
const scopeValue = typeof raw.scope === "string" ? raw.scope : typeof credentials.scope === "string" ? credentials.scope : "";
|
|
181
|
+
const scopes = scopeValue.split(/[\s,]+/).filter(Boolean);
|
|
182
|
+
return { connection_ref: ref, broker: "nango", credential: { type: "oauth2", access_token: token }, credential_type: "oauth2", transcript_scope: recordingScopeFromScopes(scopes) };
|
|
183
|
+
}
|
|
184
|
+
throw new ZoomRuntimeError("not_connected", "the Nango connection uses a credential type productfoo does not support for Zoom");
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Minimal read-only Zoom REST client. Only documented read operations are
|
|
188
|
+
* reachable; any other method or path routes through the single write-refusal
|
|
189
|
+
* choke point (R-009) so the refusal is testable rather than scattered.
|
|
190
|
+
*/
|
|
191
|
+
export class ZoomClient {
|
|
192
|
+
credential;
|
|
193
|
+
options;
|
|
194
|
+
requests = { list: 0, transcript: 0 };
|
|
195
|
+
lastRequestAt = 0;
|
|
196
|
+
baseUrl;
|
|
197
|
+
sleep;
|
|
198
|
+
now;
|
|
199
|
+
fetchTimeoutMs;
|
|
200
|
+
constructor(credential, options) {
|
|
201
|
+
this.credential = credential;
|
|
202
|
+
this.options = options;
|
|
203
|
+
this.baseUrl = (options.baseUrl ?? DEFAULT_ZOOM_BASE).replace(/\/+$/, "");
|
|
204
|
+
this.sleep = options.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
|
|
205
|
+
this.now = options.now ?? (() => Date.now());
|
|
206
|
+
this.fetchTimeoutMs = options.fetchTimeoutMs ?? ZOOM_POLICY.fetch_timeout_ms;
|
|
207
|
+
}
|
|
208
|
+
authorization() {
|
|
209
|
+
return `Bearer ${this.credential.access_token}`;
|
|
210
|
+
}
|
|
211
|
+
async request(pathname, maxBytes) {
|
|
212
|
+
if (!pathname.startsWith("/"))
|
|
213
|
+
refuseSourceWrite(`zoom ${pathname}`);
|
|
214
|
+
const wait = this.lastRequestAt + ZOOM_POLICY.min_request_interval_ms - this.now();
|
|
215
|
+
if (wait > 0)
|
|
216
|
+
await this.sleep(wait);
|
|
217
|
+
this.lastRequestAt = this.now();
|
|
218
|
+
const response = await fetchWithTimeout(this.options.fetchImpl, `${this.baseUrl}${pathname}`, { method: "GET", headers: { authorization: this.authorization(), accept: "application/json" } }, this.fetchTimeoutMs);
|
|
219
|
+
if (response.status === 401)
|
|
220
|
+
throw new ZoomRuntimeError("auth_expired", "Zoom rejected the credential; refresh or reconnect");
|
|
221
|
+
if (response.status === 403)
|
|
222
|
+
throw new ZoomRuntimeError("access_denied", "Zoom denied this read; the credential lacks the required permission");
|
|
223
|
+
if (response.status === 429)
|
|
224
|
+
throw new ZoomRuntimeError("budget_exhausted", "Zoom rate limit reached; no retry was attempted");
|
|
225
|
+
if (response.status === 404)
|
|
226
|
+
throw new ZoomRuntimeError("provider_failure", "Zoom reported the requested record does not exist");
|
|
227
|
+
if (!response.ok)
|
|
228
|
+
throw new ZoomRuntimeError("provider_failure", `Zoom answered ${response.status}`);
|
|
229
|
+
return parseJson(await readBounded(response, maxBytes), "Zoom");
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Bounded metadata listing: one time window, a page ceiling, no content. A
|
|
233
|
+
* recording's participant records carry no affiliation field — the mapping
|
|
234
|
+
* passes through only what is observed and leaves the rest undefined.
|
|
235
|
+
*/
|
|
236
|
+
async listSessions(userId, window) {
|
|
237
|
+
const recordings = [];
|
|
238
|
+
let nextPageToken;
|
|
239
|
+
let pages = 0;
|
|
240
|
+
for (;;) {
|
|
241
|
+
if (pages >= ZOOM_POLICY.max_list_pages)
|
|
242
|
+
return { recordings, pages, truncated: true };
|
|
243
|
+
const params = new URLSearchParams({ from: window.from, to: window.to, page_size: String(ZOOM_POLICY.max_page_size) });
|
|
244
|
+
if (nextPageToken)
|
|
245
|
+
params.set("next_page_token", nextPageToken);
|
|
246
|
+
this.requests.list += 1;
|
|
247
|
+
const body = await this.request(`/users/${encodeURIComponent(userId)}/recordings?${params.toString()}`, 4 * 1024 * 1024);
|
|
248
|
+
pages += 1;
|
|
249
|
+
for (const entry of Array.isArray(body.recordings) ? body.recordings : []) {
|
|
250
|
+
// Entries without the contract's required identity fields cannot be
|
|
251
|
+
// normalized and are skipped, exactly as Gong's listing skips calls
|
|
252
|
+
// without an id.
|
|
253
|
+
if (!entry || typeof entry.uuid !== "string" || typeof entry.topic !== "string" || typeof entry.start_time !== "string")
|
|
254
|
+
continue;
|
|
255
|
+
const files = (Array.isArray(entry.recording_files) ? entry.recording_files : []).map((file) => ({
|
|
256
|
+
file_type: typeof file.file_type === "string" ? file.file_type : undefined,
|
|
257
|
+
download_url: typeof file.download_url === "string" ? file.download_url : undefined,
|
|
258
|
+
play_url: typeof file.play_url === "string" ? file.play_url : undefined,
|
|
259
|
+
status: typeof file.status === "string" ? file.status : undefined,
|
|
260
|
+
}));
|
|
261
|
+
// A transcript file counts as available only when it is actually
|
|
262
|
+
// downloadable — the observed state of THIS recording, never assumed
|
|
263
|
+
// from the topic or the account (R-005).
|
|
264
|
+
const transcriptFile = files.find((file) => file.file_type === "TRANSCRIPTION" && file.download_url && file.status === "completed");
|
|
265
|
+
const participants = (Array.isArray(entry.participants) ? entry.participants : [])
|
|
266
|
+
.map((participant) => ({
|
|
267
|
+
display_name: typeof participant.display_name === "string" ? participant.display_name : undefined,
|
|
268
|
+
email: typeof participant.email === "string" ? participant.email : undefined,
|
|
269
|
+
}))
|
|
270
|
+
.filter((participant) => participant.display_name || participant.email);
|
|
271
|
+
recordings.push({
|
|
272
|
+
meeting_uuid: entry.uuid,
|
|
273
|
+
topic: entry.topic,
|
|
274
|
+
start_time: entry.start_time,
|
|
275
|
+
end_time: typeof entry.end_time === "string" ? entry.end_time : undefined,
|
|
276
|
+
state: typeof entry.state === "string" ? entry.state : undefined,
|
|
277
|
+
host_display_name: typeof entry.host_display_name === "string" ? entry.host_display_name : undefined,
|
|
278
|
+
participants,
|
|
279
|
+
// Omitted, never cleaned: a tokenized or non-canonical page URL is
|
|
280
|
+
// dropped here and the adapter additionally refuses non-canonical
|
|
281
|
+
// forms as defense in depth (R-006).
|
|
282
|
+
url: this.canonicalPageUrl(typeof entry.play_url === "string" ? entry.play_url : undefined),
|
|
283
|
+
transcript_available: Boolean(transcriptFile),
|
|
284
|
+
recording_files: files,
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
nextPageToken = typeof body.next_page_token === "string" && body.next_page_token ? body.next_page_token : undefined;
|
|
288
|
+
if (!nextPageToken)
|
|
289
|
+
return { recordings, pages, truncated: false };
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
// Accepts only the canonical recording page form the sanitizer in
|
|
293
|
+
// src/discoverySources.ts accepts (one account subdomain, /recording/<id>,
|
|
294
|
+
// no query, no fragment); anything else — including tokenized share links —
|
|
295
|
+
// is omitted, never cleaned (R-006).
|
|
296
|
+
canonicalPageUrl(url) {
|
|
297
|
+
if (!url)
|
|
298
|
+
return undefined;
|
|
299
|
+
try {
|
|
300
|
+
const parsed = new URL(url);
|
|
301
|
+
if (parsed.protocol !== "https:" || parsed.search || parsed.hash)
|
|
302
|
+
return undefined;
|
|
303
|
+
const host = parsed.hostname.toLowerCase();
|
|
304
|
+
const suffix = ".zoom.us";
|
|
305
|
+
if (!host.endsWith(suffix))
|
|
306
|
+
return undefined;
|
|
307
|
+
const label = host.slice(0, -suffix.length);
|
|
308
|
+
if (!label || !/^[a-z0-9-]+$/.test(label))
|
|
309
|
+
return undefined;
|
|
310
|
+
if (!/^\/recording\/[A-Za-z0-9_-]{16,128}$/.test(parsed.pathname))
|
|
311
|
+
return undefined;
|
|
312
|
+
return `https://${host}${parsed.pathname}`;
|
|
313
|
+
}
|
|
314
|
+
catch {
|
|
315
|
+
return undefined;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Exactly one transcript download (R-007): the observed, downloadable
|
|
320
|
+
* transcript file of one recording. The URL is the one the listing observed
|
|
321
|
+
* for that recording; a tokenized link may be used in transit (Zoom's own
|
|
322
|
+
* access mechanism) and is never logged, persisted, or echoed — error
|
|
323
|
+
* messages carry the hostname only.
|
|
324
|
+
*/
|
|
325
|
+
async transcript(downloadUrl) {
|
|
326
|
+
let hostname = "";
|
|
327
|
+
try {
|
|
328
|
+
const parsed = new URL(downloadUrl);
|
|
329
|
+
hostname = parsed.hostname;
|
|
330
|
+
if (parsed.protocol !== "https:" || !(parsed.hostname === "zoom.us" || parsed.hostname.endsWith(".zoom.us"))) {
|
|
331
|
+
throw new Error("not a zoom host");
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
catch {
|
|
335
|
+
throw new ZoomRuntimeError("provider_failure", "a single well-formed Zoom transcript download URL is required");
|
|
336
|
+
}
|
|
337
|
+
this.requests.transcript += 1;
|
|
338
|
+
const response = await fetchWithTimeout(this.options.fetchImpl, downloadUrl, { method: "GET", headers: { authorization: this.authorization(), accept: "text/vtt, text/plain, */*" } }, this.fetchTimeoutMs);
|
|
339
|
+
if (response.status === 401)
|
|
340
|
+
throw new ZoomRuntimeError("auth_expired", `Zoom rejected the credential for the transcript download from ${hostname}`);
|
|
341
|
+
if (response.status === 403)
|
|
342
|
+
throw new ZoomRuntimeError("access_denied", `Zoom denied the transcript download from ${hostname}`);
|
|
343
|
+
if (response.status === 429)
|
|
344
|
+
throw new ZoomRuntimeError("budget_exhausted", "Zoom rate limit reached; no retry was attempted");
|
|
345
|
+
if (response.status === 404)
|
|
346
|
+
throw new ZoomRuntimeError("provider_failure", `Zoom reported the transcript on ${hostname} does not exist`);
|
|
347
|
+
if (!response.ok)
|
|
348
|
+
throw new ZoomRuntimeError("provider_failure", `Zoom answered ${response.status} for the transcript download`);
|
|
349
|
+
return { vtt: await readBounded(response, ZOOM_POLICY.max_transcript_bytes) };
|
|
350
|
+
}
|
|
351
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
This changelog covers the public productfoo distribution. Pre-public development
|
|
4
|
+
records are not part of the public release history.
|
|
5
|
+
|
|
6
|
+
## 1.0.1 — October 17, 2026
|
|
7
|
+
|
|
8
|
+
Patch release from the fresh public repository. Includes updated README setup
|
|
9
|
+
guidance and section order, plus current installation documentation. CLI commands,
|
|
10
|
+
library exports, bundled skills, packet formats, and runtime requirements are
|
|
11
|
+
unchanged from 1.0.0.
|
|
12
|
+
|
|
13
|
+
## 1.0.0 — October 17, 2026
|
|
14
|
+
|
|
15
|
+
The initial release candidate includes the local CLI, bundled product-management
|
|
16
|
+
skills, spec workflows, research and discovery helpers, validation, reconciliation,
|
|
17
|
+
and scanning tools under Apache-2.0. The terminal command is `foo`.
|
|
18
|
+
|
|
19
|
+
The experimental sales-development subsystem (`foo sdr`) and its PostgreSQL
|
|
20
|
+
dependency were removed before release. Core spec, research, discovery, skill,
|
|
21
|
+
and reporting workflows need no database server.
|
|
22
|
+
|
|
23
|
+
The local workflows require no productfoo account or hosted service. Optional
|
|
24
|
+
model and connector workflows may use external services and incur charges.
|
|
25
|
+
|
|
26
|
+
productfoo is a personal open-source project with best-effort maintenance and
|
|
27
|
+
support. Agent behavior depends on the selected model, runtime, and permissions;
|
|
28
|
+
checks cannot guarantee correctness or safety. Read
|
|
29
|
+
[project status and responsible use](https://github.com/rwo572/productfoo#project-status-and-responsible-use)
|
|
30
|
+
before getting started.
|
|
31
|
+
|
|
32
|
+
Each published release is verified against its exact source and package bytes.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Third-party notices
|
|
2
|
+
|
|
3
|
+
This file lists productfoo's direct runtime dependencies and their licenses.
|
|
4
|
+
It is generated from the package's declared dependencies by
|
|
5
|
+
`scripts/gen-third-party-notices.mjs` — do not edit it by hand. To
|
|
6
|
+
regenerate after adding or upgrading a runtime dependency, run:
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
node scripts/gen-third-party-notices.mjs
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Scope note: runtime dependencies may be bundled into the build or installed
|
|
13
|
+
alongside the package by npm. Development and build-time tooling is not
|
|
14
|
+
distributed with the package and is not listed here. productfoo itself is
|
|
15
|
+
licensed under the [Apache License 2.0](https://github.com/rwo572/productfoo/blob/main/LICENSE).
|
|
16
|
+
|
|
17
|
+
## yaml 2.9.0
|
|
18
|
+
|
|
19
|
+
- License: ISC
|
|
20
|
+
- Homepage: https://eemeli.org/yaml/
|
|
21
|
+
|
|
22
|
+
```text
|
|
23
|
+
Copyright Eemeli Aro <eemeli@gmail.com>
|
|
24
|
+
|
|
25
|
+
Permission to use, copy, modify, and/or distribute this software for any purpose
|
|
26
|
+
with or without fee is hereby granted, provided that the above copyright notice
|
|
27
|
+
and this permission notice appear in all copies.
|
|
28
|
+
|
|
29
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
30
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
31
|
+
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
32
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
|
33
|
+
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
|
34
|
+
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
|
35
|
+
THIS SOFTWARE.
|
|
36
|
+
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,73 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "productfoo",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "Product-management workflows, specs, and verification for coding agents.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"cli",
|
|
7
|
+
"product-management",
|
|
8
|
+
"specifications",
|
|
9
|
+
"coding-agents",
|
|
10
|
+
"ai-agents"
|
|
11
|
+
],
|
|
12
|
+
"license": "Apache-2.0",
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/rwo572/productfoo.git"
|
|
16
|
+
},
|
|
17
|
+
"bugs": {
|
|
18
|
+
"url": "https://github.com/rwo572/productfoo/issues"
|
|
19
|
+
},
|
|
20
|
+
"homepage": "https://github.com/rwo572/productfoo#readme",
|
|
21
|
+
"type": "module",
|
|
22
|
+
"bin": {
|
|
23
|
+
"foo": "bin/foo.mjs"
|
|
24
|
+
},
|
|
25
|
+
"exports": {
|
|
26
|
+
".": {
|
|
27
|
+
"types": "./dist-public/src/index.d.ts",
|
|
28
|
+
"default": "./dist-public/src/index.js"
|
|
29
|
+
},
|
|
30
|
+
"./cli": {
|
|
31
|
+
"types": "./dist-public/src/cli.d.ts",
|
|
32
|
+
"default": "./dist-public/src/cli.js"
|
|
33
|
+
},
|
|
34
|
+
"./package.json": "./package.json"
|
|
35
|
+
},
|
|
36
|
+
"foo": {
|
|
37
|
+
"brandUrl": "https://github.com/rwo572/productfoo"
|
|
38
|
+
},
|
|
39
|
+
"files": [
|
|
40
|
+
"bin",
|
|
41
|
+
"docs/CHANGELOG.md",
|
|
42
|
+
"commands",
|
|
43
|
+
"dist-public/src",
|
|
44
|
+
"config/pricing.yaml",
|
|
45
|
+
"config/routing-policy.yaml",
|
|
46
|
+
"schemas",
|
|
47
|
+
"skills",
|
|
48
|
+
"skills-lock.json",
|
|
49
|
+
"docs/THIRD_PARTY_NOTICES.md"
|
|
50
|
+
],
|
|
51
|
+
"engines": {
|
|
52
|
+
"node": ">=18"
|
|
53
|
+
},
|
|
54
|
+
"scripts": {
|
|
55
|
+
"build": "tsc && node scripts/bundle-vendor.mjs",
|
|
56
|
+
"build:public": "node scripts/build-public.mjs",
|
|
57
|
+
"verify:public": "npm run build && npm run check:generated && npm run build:public && node scripts/verify-public-package.mjs && node scripts/verify-public-git-manifest.mjs && node scripts/smoke-public-package.mjs",
|
|
58
|
+
"prepack": "npm run build:public",
|
|
59
|
+
"prepublishOnly": "npm run build:public",
|
|
60
|
+
"test": "rm -rf dist && npm run build && find dist -name '*.test.js' -print0 | xargs -0 env NODE_ENV=test node --test",
|
|
61
|
+
"test:packetindex": "npm run build && env NODE_ENV=test node --test dist/test/packetIndexGolden.test.js dist/test/packetIndex.test.js",
|
|
62
|
+
"generate": "npm run build && node scripts/build-swarm-skills.mjs && node scripts/skill-tree-anchor.mjs && node scripts/build-anthropic-plugin.mjs && node scripts/gen-cli-reference.mjs && node scripts/gen-third-party-notices.mjs && node scripts/gen-cheatsheet.mjs",
|
|
63
|
+
"check:generated": "node scripts/build-swarm-skills.mjs --verify && node scripts/skill-tree-anchor.mjs --check && node scripts/build-anthropic-plugin.mjs --check && node scripts/gen-cli-reference.mjs --check && node scripts/gen-third-party-notices.mjs --check && node scripts/gen-cheatsheet.mjs --check"
|
|
64
|
+
},
|
|
65
|
+
"dependencies": {
|
|
66
|
+
"yaml": "^2.8.1"
|
|
67
|
+
},
|
|
68
|
+
"devDependencies": {
|
|
69
|
+
"@types/node": "^26.3.0",
|
|
70
|
+
"esbuild": "^0.28.2",
|
|
71
|
+
"typescript": "^7.0.2"
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://foo.example/schemas/bug-capsule-receipt.schema.json",
|
|
4
|
+
"title": "DeliveryReceipt 0.1",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"required": ["schema_version", "receipt_id", "capsule_id", "payload_digest", "accepted_at", "destination", "status", "error"],
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"properties": {
|
|
9
|
+
"schema_version": { "const": "0.1" },
|
|
10
|
+
"receipt_id": { "$ref": "#/$defs/uuidV7" },
|
|
11
|
+
"capsule_id": { "$ref": "#/$defs/uuidV7" },
|
|
12
|
+
"payload_digest": {
|
|
13
|
+
"type": "string",
|
|
14
|
+
"maxLength": 4096,
|
|
15
|
+
"pattern": "^sha256:[0-9a-f]{64}$"
|
|
16
|
+
},
|
|
17
|
+
"accepted_at": { "$ref": "#/$defs/rfc3339Utc" },
|
|
18
|
+
"destination": { "$ref": "#/$defs/string" },
|
|
19
|
+
"status": { "enum": ["accepted", "rejected", "retryable"] },
|
|
20
|
+
"error": { "type": ["null", "object"] }
|
|
21
|
+
},
|
|
22
|
+
"allOf": [
|
|
23
|
+
{
|
|
24
|
+
"if": { "properties": { "status": { "const": "accepted" } }, "required": ["status"] },
|
|
25
|
+
"then": { "properties": { "error": { "const": null } } },
|
|
26
|
+
"else": { "properties": { "error": { "$ref": "#/$defs/error" } } }
|
|
27
|
+
}
|
|
28
|
+
],
|
|
29
|
+
"$defs": {
|
|
30
|
+
"string": { "type": "string", "maxLength": 4096 },
|
|
31
|
+
"uuidV7": {
|
|
32
|
+
"type": "string",
|
|
33
|
+
"maxLength": 4096,
|
|
34
|
+
"format": "uuid",
|
|
35
|
+
"pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"
|
|
36
|
+
},
|
|
37
|
+
"rfc3339Utc": {
|
|
38
|
+
"type": "string",
|
|
39
|
+
"maxLength": 4096,
|
|
40
|
+
"format": "date-time",
|
|
41
|
+
"pattern": "^(?:\\d{4})-(?:\\d{2})-(?:\\d{2})T(?:\\d{2}):(?:\\d{2}):(?:\\d{2})(?:\\.\\d+)?Z$"
|
|
42
|
+
},
|
|
43
|
+
"error": {
|
|
44
|
+
"type": "object",
|
|
45
|
+
"required": ["code", "message"],
|
|
46
|
+
"additionalProperties": false,
|
|
47
|
+
"properties": {
|
|
48
|
+
"code": { "$ref": "#/$defs/string" },
|
|
49
|
+
"message": { "$ref": "#/$defs/string" },
|
|
50
|
+
"retry_after": { "$ref": "#/$defs/rfc3339Utc" }
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|