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,227 @@
|
|
|
1
|
+
import { createHash, randomBytes } from "node:crypto";
|
|
2
|
+
const MAX_STRING_LENGTH = 4_096;
|
|
3
|
+
const MAX_ARRAY_LENGTH = 100;
|
|
4
|
+
const UUID_V7 = /^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
|
|
5
|
+
const RFC_3339_UTC = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.\d+)?Z$/;
|
|
6
|
+
const SHA_256_DIGEST = /^sha256:[0-9a-f]{64}$/;
|
|
7
|
+
const ERROR_CLASSES = new Set(["none", "usage_error", "gate_block", "not_found", "io_error", "command_error"]);
|
|
8
|
+
const ERROR_CODES = new Set([
|
|
9
|
+
"E_COMMAND_MISSING", "E_PACKET_DIR_MISSING", "E_SWARM_TARGET_MISSING", "E_IDEATE_IDEA_MISSING", "E_SPEC_WORK_MISSING", "E_UNKNOWN_DOMAIN", "E_BAD_FLAG", "E_NOT_A_RESEARCH_PAPER",
|
|
10
|
+
"E_PACKET_NOT_FOUND", "E_SPEC_NOT_FOUND", "E_SKILL_NOT_FOUND",
|
|
11
|
+
"E_GATE_B1_SECRET", "E_GATE_B2_SPEC_ID", "E_GATE_B4_BUDGET", "E_GATE_B5_UNGOVERNED", "E_GATE_B5_CLAIM_UNLABELED", "E_GATE_BLOCKED", "E_GATE_INTERVIEW", "E_CONTRACT_DRIFT",
|
|
12
|
+
"E_IO", "E_UNKNOWN",
|
|
13
|
+
]);
|
|
14
|
+
function jcs(value) {
|
|
15
|
+
if (value === null || typeof value === "boolean" || typeof value === "string")
|
|
16
|
+
return JSON.stringify(value);
|
|
17
|
+
if (typeof value === "number") {
|
|
18
|
+
if (!Number.isFinite(value))
|
|
19
|
+
throw new Error("canonical JSON refuses non-finite numbers");
|
|
20
|
+
return JSON.stringify(value);
|
|
21
|
+
}
|
|
22
|
+
if (Array.isArray(value))
|
|
23
|
+
return `[${value.map(jcs).join(",")}]`;
|
|
24
|
+
if (typeof value === "object") {
|
|
25
|
+
const source = value;
|
|
26
|
+
return `{${Object.keys(source).sort().map((key) => `${JSON.stringify(key)}:${jcs(source[key])}`).join(",")}}`;
|
|
27
|
+
}
|
|
28
|
+
throw new Error(`canonical JSON refuses ${typeof value}`);
|
|
29
|
+
}
|
|
30
|
+
export function canonicalBytes(capsule) {
|
|
31
|
+
return Buffer.from(jcs(capsule), "utf8");
|
|
32
|
+
}
|
|
33
|
+
export function payloadDigest(capsule) {
|
|
34
|
+
return `sha256:${createHash("sha256").update(canonicalBytes(capsule)).digest("hex")}`;
|
|
35
|
+
}
|
|
36
|
+
export function uuidV7(nowMs = Date.now(), entropy = randomBytes(10)) {
|
|
37
|
+
if (!Number.isSafeInteger(nowMs) || nowMs < 0 || nowMs > 0xffff_ffff_ffff)
|
|
38
|
+
throw new Error("UUIDv7 timestamp must fit in 48 bits");
|
|
39
|
+
if (entropy.length !== 10)
|
|
40
|
+
throw new Error("UUIDv7 entropy must be 10 bytes");
|
|
41
|
+
const bytes = Buffer.alloc(16);
|
|
42
|
+
let timestamp = BigInt(nowMs);
|
|
43
|
+
for (let index = 5; index >= 0; index -= 1) {
|
|
44
|
+
bytes[index] = Number(timestamp & 0xffn);
|
|
45
|
+
timestamp >>= 8n;
|
|
46
|
+
}
|
|
47
|
+
entropy.copy(bytes, 6);
|
|
48
|
+
bytes[6] = 0x70 | (bytes[6] & 0x0f);
|
|
49
|
+
bytes[8] = 0x80 | (bytes[8] & 0x3f);
|
|
50
|
+
const hex = bytes.toString("hex");
|
|
51
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
52
|
+
}
|
|
53
|
+
function object(value, label) {
|
|
54
|
+
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
55
|
+
throw new Error(`${label} must be an object`);
|
|
56
|
+
return value;
|
|
57
|
+
}
|
|
58
|
+
function closedObject(value, label, allowed, required = allowed) {
|
|
59
|
+
const source = object(value, label);
|
|
60
|
+
for (const key of Object.keys(source)) {
|
|
61
|
+
if (!allowed.includes(key))
|
|
62
|
+
throw new Error(`unknown ${label} field: ${key}`);
|
|
63
|
+
}
|
|
64
|
+
for (const key of required) {
|
|
65
|
+
if (!(key in source))
|
|
66
|
+
throw new Error(`${label} field is required: ${key}`);
|
|
67
|
+
}
|
|
68
|
+
return source;
|
|
69
|
+
}
|
|
70
|
+
function boundedString(value, label) {
|
|
71
|
+
if (typeof value !== "string")
|
|
72
|
+
throw new Error(`${label} must be a string`);
|
|
73
|
+
if (value.length > MAX_STRING_LENGTH)
|
|
74
|
+
throw new Error(`${label} must be at most ${MAX_STRING_LENGTH} characters`);
|
|
75
|
+
return value;
|
|
76
|
+
}
|
|
77
|
+
function boundedArray(value, label) {
|
|
78
|
+
if (!Array.isArray(value))
|
|
79
|
+
throw new Error(`${label} must be an array`);
|
|
80
|
+
if (value.length > MAX_ARRAY_LENGTH)
|
|
81
|
+
throw new Error(`${label} must contain at most ${MAX_ARRAY_LENGTH} entries`);
|
|
82
|
+
return value;
|
|
83
|
+
}
|
|
84
|
+
function uuid(value, label) {
|
|
85
|
+
const parsed = boundedString(value, label);
|
|
86
|
+
if (!UUID_V7.test(parsed))
|
|
87
|
+
throw new Error(`${label} must be a UUIDv7`);
|
|
88
|
+
return parsed;
|
|
89
|
+
}
|
|
90
|
+
function rfc3339(value, label) {
|
|
91
|
+
const parsed = boundedString(value, label);
|
|
92
|
+
const match = RFC_3339_UTC.exec(parsed);
|
|
93
|
+
const date = new Date(parsed);
|
|
94
|
+
if (match === null ||
|
|
95
|
+
Number.isNaN(date.valueOf()) ||
|
|
96
|
+
date.getUTCFullYear() !== Number(match[1]) ||
|
|
97
|
+
date.getUTCMonth() + 1 !== Number(match[2]) ||
|
|
98
|
+
date.getUTCDate() !== Number(match[3]) ||
|
|
99
|
+
date.getUTCHours() !== Number(match[4]) ||
|
|
100
|
+
date.getUTCMinutes() !== Number(match[5]) ||
|
|
101
|
+
date.getUTCSeconds() !== Number(match[6])) {
|
|
102
|
+
throw new Error(`${label} must be RFC 3339 UTC`);
|
|
103
|
+
}
|
|
104
|
+
return parsed;
|
|
105
|
+
}
|
|
106
|
+
function fieldValue(value, label) {
|
|
107
|
+
const source = object(value, label);
|
|
108
|
+
const state = source.state;
|
|
109
|
+
if (state === "collected") {
|
|
110
|
+
if (!("value" in source))
|
|
111
|
+
throw new Error("collected field requires value");
|
|
112
|
+
const collected = closedObject(source, label, ["state", "value"]);
|
|
113
|
+
return { state, value: boundedString(collected.value, `${label}.value`) };
|
|
114
|
+
}
|
|
115
|
+
if (state === "not_collected" || state === "withheld" || state === "unavailable") {
|
|
116
|
+
if ("value" in source)
|
|
117
|
+
throw new Error("non-collected field cannot contain value");
|
|
118
|
+
const absent = closedObject(source, label, ["state", "reason"]);
|
|
119
|
+
return { state, reason: boundedString(absent.reason, `${label}.reason`) };
|
|
120
|
+
}
|
|
121
|
+
throw new Error(`${label}.state is invalid`);
|
|
122
|
+
}
|
|
123
|
+
function requiredStringFields(value, label, fields) {
|
|
124
|
+
const source = closedObject(value, label, fields);
|
|
125
|
+
for (const field of fields)
|
|
126
|
+
boundedString(source[field], `${label}.${field}`);
|
|
127
|
+
}
|
|
128
|
+
export function parseBugCapsule(value) {
|
|
129
|
+
const capsule = closedObject(value, "BugCapsule", [
|
|
130
|
+
"schema_version", "capsule_id", "occurred_at", "producer", "product", "invocation", "failure", "report", "evidence", "similarity", "links", "extensions",
|
|
131
|
+
]);
|
|
132
|
+
if (capsule.schema_version !== "0.1")
|
|
133
|
+
throw new Error("BugCapsule.schema_version must be 0.1");
|
|
134
|
+
uuid(capsule.capsule_id, "BugCapsule.capsule_id");
|
|
135
|
+
rfc3339(capsule.occurred_at, "BugCapsule.occurred_at");
|
|
136
|
+
requiredStringFields(capsule.producer, "BugCapsule.producer", ["name", "version"]);
|
|
137
|
+
requiredStringFields(capsule.product, "BugCapsule.product", ["name", "component", "version"]);
|
|
138
|
+
const invocation = closedObject(capsule.invocation, "BugCapsule.invocation", ["command", "runtime"]);
|
|
139
|
+
boundedString(invocation.command, "BugCapsule.invocation.command");
|
|
140
|
+
requiredStringFields(invocation.runtime, "BugCapsule.invocation.runtime", ["node", "platform", "arch"]);
|
|
141
|
+
const failure = closedObject(capsule.failure, "BugCapsule.failure", ["class", "code", "classifier_version", "classification", "message", "stack"]);
|
|
142
|
+
if (!ERROR_CLASSES.has(failure.class))
|
|
143
|
+
throw new Error("BugCapsule.failure.class is invalid");
|
|
144
|
+
if (!ERROR_CODES.has(failure.code))
|
|
145
|
+
throw new Error("BugCapsule.failure.code is invalid");
|
|
146
|
+
if (failure.classifier_version !== "0.1")
|
|
147
|
+
throw new Error("BugCapsule.failure.classifier_version must be 0.1");
|
|
148
|
+
if (failure.classification !== "known" && failure.classification !== "fallback")
|
|
149
|
+
throw new Error("BugCapsule.failure.classification is invalid");
|
|
150
|
+
fieldValue(failure.message, "BugCapsule.failure.message");
|
|
151
|
+
fieldValue(failure.stack, "BugCapsule.failure.stack");
|
|
152
|
+
const report = closedObject(capsule.report, "BugCapsule.report", ["expected", "actual", "reproduction"]);
|
|
153
|
+
fieldValue(report.expected, "BugCapsule.report.expected");
|
|
154
|
+
fieldValue(report.actual, "BugCapsule.report.actual");
|
|
155
|
+
fieldValue(report.reproduction, "BugCapsule.report.reproduction");
|
|
156
|
+
for (const [index, entry] of boundedArray(capsule.evidence, "BugCapsule.evidence").entries()) {
|
|
157
|
+
const evidence = closedObject(entry, `BugCapsule.evidence[${index}]`, ["kind", "state", "content_type"]);
|
|
158
|
+
if (evidence.kind !== "diagnostic" && evidence.kind !== "user_report")
|
|
159
|
+
throw new Error(`BugCapsule.evidence[${index}].kind is invalid`);
|
|
160
|
+
if (!["collected", "not_collected", "withheld", "unavailable"].includes(String(evidence.state)))
|
|
161
|
+
throw new Error(`BugCapsule.evidence[${index}].state is invalid`);
|
|
162
|
+
boundedString(evidence.content_type, `BugCapsule.evidence[${index}].content_type`);
|
|
163
|
+
}
|
|
164
|
+
const similarity = closedObject(capsule.similarity, "BugCapsule.similarity", ["version", "signals"]);
|
|
165
|
+
if (similarity.version !== "0.1")
|
|
166
|
+
throw new Error("BugCapsule.similarity.version must be 0.1");
|
|
167
|
+
for (const [index, signal] of boundedArray(similarity.signals, "BugCapsule.similarity.signals").entries()) {
|
|
168
|
+
const parsed = closedObject(signal, `BugCapsule.similarity.signals[${index}]`, ["kind", "value"]);
|
|
169
|
+
if (parsed.kind !== "error_fingerprint")
|
|
170
|
+
throw new Error(`BugCapsule.similarity.signals[${index}].kind is invalid`);
|
|
171
|
+
boundedString(parsed.value, `BugCapsule.similarity.signals[${index}].value`);
|
|
172
|
+
}
|
|
173
|
+
for (const [index, link] of boundedArray(capsule.links, "BugCapsule.links").entries()) {
|
|
174
|
+
const parsed = closedObject(link, `BugCapsule.links[${index}]`, ["relation", "provider", "external_id", "provenance", "authority"]);
|
|
175
|
+
boundedString(parsed.relation, `BugCapsule.links[${index}].relation`);
|
|
176
|
+
boundedString(parsed.provider, `BugCapsule.links[${index}].provider`);
|
|
177
|
+
boundedString(parsed.external_id, `BugCapsule.links[${index}].external_id`);
|
|
178
|
+
if (parsed.provenance !== "reporter_observed")
|
|
179
|
+
throw new Error(`BugCapsule.links[${index}].provenance is invalid`);
|
|
180
|
+
if (parsed.authority !== "reference")
|
|
181
|
+
throw new Error(`BugCapsule.links[${index}].authority is invalid`);
|
|
182
|
+
}
|
|
183
|
+
const extensions = object(capsule.extensions, "BugCapsule.extensions");
|
|
184
|
+
if (extensions.foo !== undefined) {
|
|
185
|
+
const foo = closedObject(extensions.foo, "BugCapsule.extensions.foo", ["spec_context"], []);
|
|
186
|
+
if (foo.spec_context !== undefined) {
|
|
187
|
+
const context = closedObject(foo.spec_context, "BugCapsule.extensions.foo.spec_context", ["spec_id", "packet_path", "revision", "requirement_ids", "task_ids", "provenance"], ["spec_id", "packet_path", "requirement_ids", "task_ids", "provenance"]);
|
|
188
|
+
boundedString(context.spec_id, "BugCapsule.extensions.foo.spec_context.spec_id");
|
|
189
|
+
boundedString(context.packet_path, "BugCapsule.extensions.foo.spec_context.packet_path");
|
|
190
|
+
if (context.revision !== undefined)
|
|
191
|
+
boundedString(context.revision, "BugCapsule.extensions.foo.spec_context.revision");
|
|
192
|
+
for (const [index, requirement] of boundedArray(context.requirement_ids, "BugCapsule.extensions.foo.spec_context.requirement_ids").entries())
|
|
193
|
+
boundedString(requirement, `BugCapsule.extensions.foo.spec_context.requirement_ids[${index}]`);
|
|
194
|
+
for (const [index, task] of boundedArray(context.task_ids, "BugCapsule.extensions.foo.spec_context.task_ids").entries())
|
|
195
|
+
boundedString(task, `BugCapsule.extensions.foo.spec_context.task_ids[${index}]`);
|
|
196
|
+
if (context.provenance !== "reporter_observed")
|
|
197
|
+
throw new Error("BugCapsule.extensions.foo.spec_context.provenance is invalid");
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return capsule;
|
|
201
|
+
}
|
|
202
|
+
export function parseDeliveryReceipt(value) {
|
|
203
|
+
const receipt = closedObject(value, "DeliveryReceipt", ["schema_version", "receipt_id", "capsule_id", "payload_digest", "accepted_at", "destination", "status", "error"]);
|
|
204
|
+
if (receipt.schema_version !== "0.1")
|
|
205
|
+
throw new Error("DeliveryReceipt.schema_version must be 0.1");
|
|
206
|
+
uuid(receipt.receipt_id, "DeliveryReceipt.receipt_id");
|
|
207
|
+
uuid(receipt.capsule_id, "DeliveryReceipt.capsule_id");
|
|
208
|
+
const digest = boundedString(receipt.payload_digest, "DeliveryReceipt.payload_digest");
|
|
209
|
+
if (!SHA_256_DIGEST.test(digest))
|
|
210
|
+
throw new Error("DeliveryReceipt.payload_digest must be a lowercase SHA-256 digest");
|
|
211
|
+
rfc3339(receipt.accepted_at, "DeliveryReceipt.accepted_at");
|
|
212
|
+
boundedString(receipt.destination, "DeliveryReceipt.destination");
|
|
213
|
+
if (receipt.status !== "accepted" && receipt.status !== "rejected" && receipt.status !== "retryable")
|
|
214
|
+
throw new Error("DeliveryReceipt.status is invalid");
|
|
215
|
+
if (receipt.status === "accepted") {
|
|
216
|
+
if (receipt.error !== null)
|
|
217
|
+
throw new Error("accepted receipt requires error to be null");
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
const error = closedObject(receipt.error, "DeliveryReceipt.error", ["code", "message", "retry_after"], ["code", "message"]);
|
|
221
|
+
boundedString(error.code, "DeliveryReceipt.error.code");
|
|
222
|
+
boundedString(error.message, "DeliveryReceipt.error.message");
|
|
223
|
+
if (error.retry_after !== undefined)
|
|
224
|
+
rfc3339(error.retry_after, "DeliveryReceipt.error.retry_after");
|
|
225
|
+
}
|
|
226
|
+
return receipt;
|
|
227
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type FieldValue } from "./bugCapsule.js";
|
|
2
|
+
import { type LocalBugRecord } from "./bugReportStore.js";
|
|
3
|
+
import type { BugSpecContext } from "./bugSpecContext.js";
|
|
4
|
+
import { type FailureMark } from "./errorTaxonomy.js";
|
|
5
|
+
export type FailureCaptureInput = {
|
|
6
|
+
failure: FailureMark;
|
|
7
|
+
command: string;
|
|
8
|
+
version: string;
|
|
9
|
+
specContext?: BugSpecContext;
|
|
10
|
+
isTest?: boolean;
|
|
11
|
+
};
|
|
12
|
+
export type ManualCaptureInput = {
|
|
13
|
+
expected?: string;
|
|
14
|
+
actual?: string;
|
|
15
|
+
reproduction?: string;
|
|
16
|
+
command?: string;
|
|
17
|
+
version: string;
|
|
18
|
+
specContext?: BugSpecContext;
|
|
19
|
+
};
|
|
20
|
+
/** Secret-redact and path-scrub one diagnostic without ever returning raw text on failure. */
|
|
21
|
+
export declare function scrubDiagnostic(text: string, root: string): FieldValue;
|
|
22
|
+
export declare function captureFailureCapsule(root: string, input: FailureCaptureInput, now?: Date): LocalBugRecord | undefined;
|
|
23
|
+
export type FailureCapsuleCapture = (root: string, input: FailureCaptureInput, now?: Date) => LocalBugRecord | undefined;
|
|
24
|
+
/** Create the once-only capture boundary owned by one main() invocation. */
|
|
25
|
+
export declare function createFailureCapsuleCapture(): FailureCapsuleCapture;
|
|
26
|
+
export declare function captureManualCapsule(root: string, input: ManualCaptureInput, now?: Date): LocalBugRecord;
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import { parseBugCapsule, uuidV7 } from "./bugCapsule.js";
|
|
2
|
+
import { savePending } from "./bugReportStore.js";
|
|
3
|
+
import { errorFingerprint, pages, UsageError } from "./errorTaxonomy.js";
|
|
4
|
+
import { redactText } from "./redactEngine.js";
|
|
5
|
+
const MAX_STRING_LENGTH = 4_096;
|
|
6
|
+
const MAX_PATH_TOKEN_LENGTH = 16_384;
|
|
7
|
+
function bounded(value) {
|
|
8
|
+
return value.slice(0, MAX_STRING_LENGTH);
|
|
9
|
+
}
|
|
10
|
+
function absolutePathKind(text, index) {
|
|
11
|
+
const first = text[index];
|
|
12
|
+
if (/[A-Za-z]/.test(first ?? "") && text[index + 1] === ":" && /[\\/]/.test(text[index + 2] ?? ""))
|
|
13
|
+
return "windows";
|
|
14
|
+
if (first === "\\" && text[index + 1] === "\\")
|
|
15
|
+
return "windows";
|
|
16
|
+
if (first === "/" && (index === 0 || !/[\p{L}\p{N}._@+-]/u.test(text[index - 1])))
|
|
17
|
+
return "posix";
|
|
18
|
+
return undefined;
|
|
19
|
+
}
|
|
20
|
+
function safePathBasename(raw) {
|
|
21
|
+
const withoutLocation = raw.replace(/:\d+(?::\d+)?$/, "").replace(/[.,;!?]+$/, "");
|
|
22
|
+
const basename = withoutLocation.split(/[\\/]/).at(-1);
|
|
23
|
+
return basename && /^[A-Za-z0-9._@+-]{1,255}$/.test(basename) && basename !== "." && basename !== ".."
|
|
24
|
+
? basename
|
|
25
|
+
: undefined;
|
|
26
|
+
}
|
|
27
|
+
function nextSpaceChunkHasSeparator(text, index, closing) {
|
|
28
|
+
let start = index;
|
|
29
|
+
while (text[start] === " ")
|
|
30
|
+
start += 1;
|
|
31
|
+
let end = start;
|
|
32
|
+
while (end < text.length && !/\s/.test(text[end]) && (!closing || text[end] !== closing))
|
|
33
|
+
end += 1;
|
|
34
|
+
return /[\\/]/.test(text.slice(start, end));
|
|
35
|
+
}
|
|
36
|
+
function basenameLooksComplete(raw) {
|
|
37
|
+
const basename = safePathBasename(raw);
|
|
38
|
+
return Boolean(basename && /\.[A-Za-z0-9]{1,16}$/.test(basename));
|
|
39
|
+
}
|
|
40
|
+
function remainderCouldContinueAbsolutePath(text, index) {
|
|
41
|
+
// The chunk straight after the punctuation may still be this path's next
|
|
42
|
+
// segment ("customer) records/private/file.txt"), so any separator there
|
|
43
|
+
// keeps the boundary unproven.
|
|
44
|
+
if (nextSpaceChunkHasSeparator(text, index, undefined))
|
|
45
|
+
return true;
|
|
46
|
+
// Beyond that chunk, only an absolute-looking start (/x, C:\x, \\share)
|
|
47
|
+
// keeps the boundary unproven. Repo-relative tokens such as src/x.ts,
|
|
48
|
+
// bin/foo, or discovery/inbox are the vocabulary of a bug report about foo
|
|
49
|
+
// itself: they say nothing about the reporter's machine and must never
|
|
50
|
+
// poison an otherwise provable boundary into withholding the field.
|
|
51
|
+
for (let scan = index; scan < text.length; scan += 1) {
|
|
52
|
+
if (absolutePathKind(text, scan))
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
function punctuationBoundaryIsProven(text, index) {
|
|
58
|
+
if (index + 1 === text.length)
|
|
59
|
+
return true;
|
|
60
|
+
if (!/\s/.test(text[index + 1]))
|
|
61
|
+
return false;
|
|
62
|
+
return !remainderCouldContinueAbsolutePath(text, index + 1);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Linear path tokenizer. Only absolute/home/drive/UNC starts are treated as
|
|
66
|
+
* paths; repo-relative tokens (src/x.ts, bin/foo) pass through untouched. An
|
|
67
|
+
* unprovable boundary on an absolute path withholds the whole field.
|
|
68
|
+
*/
|
|
69
|
+
function scrubAbsolutePaths(text) {
|
|
70
|
+
const wrappers = { '"': '"', "'": "'", "`": "`", "(": ")", "[": "]", "{": "}" };
|
|
71
|
+
let result = "";
|
|
72
|
+
let index = 0;
|
|
73
|
+
while (index < text.length) {
|
|
74
|
+
const kind = absolutePathKind(text, index);
|
|
75
|
+
if (!kind) {
|
|
76
|
+
result += text[index];
|
|
77
|
+
index += 1;
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
const closing = wrappers[text[index - 1] ?? ""];
|
|
81
|
+
let end = index;
|
|
82
|
+
while (end < text.length) {
|
|
83
|
+
const char = text[end];
|
|
84
|
+
if (char === "\n" || char === "\r" || char === "\t")
|
|
85
|
+
break;
|
|
86
|
+
if (closing && char === closing) {
|
|
87
|
+
if (punctuationBoundaryIsProven(text, end))
|
|
88
|
+
break;
|
|
89
|
+
return undefined;
|
|
90
|
+
}
|
|
91
|
+
if (!closing && char === " ") {
|
|
92
|
+
if (nextSpaceChunkHasSeparator(text, end, closing)) {
|
|
93
|
+
end += 1;
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
if (!basenameLooksComplete(text.slice(index, end)))
|
|
97
|
+
return undefined;
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
if (!closing && /[\])}'"`]/.test(char)) {
|
|
101
|
+
if (punctuationBoundaryIsProven(text, end))
|
|
102
|
+
break;
|
|
103
|
+
return undefined;
|
|
104
|
+
}
|
|
105
|
+
if (!closing && /[,;!?]/.test(char) && (end + 1 === text.length || /\s/.test(text[end + 1])))
|
|
106
|
+
break;
|
|
107
|
+
end += 1;
|
|
108
|
+
if (end - index >= MAX_PATH_TOKEN_LENGTH) {
|
|
109
|
+
while (end < text.length && !/[\n\r\t]/.test(text[end]))
|
|
110
|
+
end += 1;
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
const basename = safePathBasename(text.slice(index, end));
|
|
115
|
+
result += basename ? `<path>/${basename}` : "<path>";
|
|
116
|
+
index = Math.max(end, index + 1);
|
|
117
|
+
}
|
|
118
|
+
return result;
|
|
119
|
+
}
|
|
120
|
+
/** Secret-redact and path-scrub one diagnostic without ever returning raw text on failure. */
|
|
121
|
+
export function scrubDiagnostic(text, root) {
|
|
122
|
+
try {
|
|
123
|
+
void root;
|
|
124
|
+
// Order matters: remove complete URLs and credentials before their slashes or
|
|
125
|
+
// punctuation can be mistaken for filesystem tokens. Each matcher is linear,
|
|
126
|
+
// whitespace-bounded, and refuses to span prose or surrounding punctuation.
|
|
127
|
+
let scrubbed = text.replace(/\bhttps?:\/\/[^\s<>"'`]+/gi, "[URL_REDACTED]");
|
|
128
|
+
scrubbed = scrubbed.replace(/\bBearer[ \t]+[^\s,;'"<>()\[\]{}]+/gi, "Bearer [REDACTED]");
|
|
129
|
+
const pathScrubbed = scrubAbsolutePaths(scrubbed);
|
|
130
|
+
if (pathScrubbed === undefined)
|
|
131
|
+
return { state: "withheld", reason: "ambiguous_path_boundary" };
|
|
132
|
+
scrubbed = pathScrubbed;
|
|
133
|
+
return { state: "collected", value: redactText(scrubbed).redactedText };
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
return { state: "withheld", reason: "scrubbing_failed" };
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
function boundedField(field) {
|
|
140
|
+
return field.state === "collected" ? { state: "collected", value: bounded(field.value) } : field;
|
|
141
|
+
}
|
|
142
|
+
function absent(reason) {
|
|
143
|
+
return { state: "not_collected", reason };
|
|
144
|
+
}
|
|
145
|
+
function diagnostic(value, root, reason) {
|
|
146
|
+
return value === undefined ? absent(reason) : boundedField(scrubDiagnostic(value, root));
|
|
147
|
+
}
|
|
148
|
+
function evidenceState(fields) {
|
|
149
|
+
if (fields.some((field) => field.state === "withheld"))
|
|
150
|
+
return "withheld";
|
|
151
|
+
if (fields.some((field) => field.state === "collected"))
|
|
152
|
+
return "collected";
|
|
153
|
+
if (fields.some((field) => field.state === "unavailable"))
|
|
154
|
+
return "unavailable";
|
|
155
|
+
return "not_collected";
|
|
156
|
+
}
|
|
157
|
+
function invocationCommand(command) {
|
|
158
|
+
return bounded(command.startsWith("foo ") ? command : `foo ${command}`);
|
|
159
|
+
}
|
|
160
|
+
function capsuleBase(version, command, occurredAt, specContext) {
|
|
161
|
+
const boundedVersion = bounded(version);
|
|
162
|
+
return {
|
|
163
|
+
schema_version: "0.1",
|
|
164
|
+
capsule_id: uuidV7(occurredAt.getTime()),
|
|
165
|
+
occurred_at: occurredAt.toISOString(),
|
|
166
|
+
producer: { name: "foo", version: boundedVersion },
|
|
167
|
+
product: { name: "productfoo", component: "cli", version: boundedVersion },
|
|
168
|
+
invocation: {
|
|
169
|
+
command: invocationCommand(command),
|
|
170
|
+
runtime: {
|
|
171
|
+
node: bounded(process.version.replace(/^v/, "")),
|
|
172
|
+
platform: bounded(process.platform),
|
|
173
|
+
arch: bounded(process.arch),
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
links: [],
|
|
177
|
+
extensions: specContext ? { foo: { spec_context: specContext } } : {},
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
export function captureFailureCapsule(root, input, now = new Date()) {
|
|
181
|
+
if (input.isTest || !pages(input.failure.errorClass))
|
|
182
|
+
return undefined;
|
|
183
|
+
try {
|
|
184
|
+
const message = diagnostic(input.failure.message, root, "failure did not provide a message");
|
|
185
|
+
const stack = diagnostic(input.failure.stack, root, "failure did not provide a stack");
|
|
186
|
+
const fingerprint = errorFingerprint(input.failure.errorCode, input.failure.stack);
|
|
187
|
+
const capsule = parseBugCapsule({
|
|
188
|
+
...capsuleBase(input.version, input.command, now, input.specContext),
|
|
189
|
+
failure: {
|
|
190
|
+
class: input.failure.errorClass,
|
|
191
|
+
code: input.failure.errorCode,
|
|
192
|
+
classifier_version: "0.1",
|
|
193
|
+
classification: input.failure.errorCode === "E_UNKNOWN" ? "fallback" : "known",
|
|
194
|
+
message,
|
|
195
|
+
stack,
|
|
196
|
+
},
|
|
197
|
+
report: {
|
|
198
|
+
expected: absent("automatic failure capture"),
|
|
199
|
+
actual: absent("automatic failure capture"),
|
|
200
|
+
reproduction: absent("automatic failure capture"),
|
|
201
|
+
},
|
|
202
|
+
evidence: [{ kind: "diagnostic", state: evidenceState([message, stack]), content_type: "text/plain" }],
|
|
203
|
+
similarity: {
|
|
204
|
+
version: "0.1",
|
|
205
|
+
signals: fingerprint ? [{ kind: "error_fingerprint", value: fingerprint }] : [],
|
|
206
|
+
},
|
|
207
|
+
});
|
|
208
|
+
return savePending(root, capsule);
|
|
209
|
+
}
|
|
210
|
+
catch {
|
|
211
|
+
return undefined;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
/** Create the once-only capture boundary owned by one main() invocation. */
|
|
215
|
+
export function createFailureCapsuleCapture() {
|
|
216
|
+
let captured = false;
|
|
217
|
+
return (root, input, now = new Date()) => {
|
|
218
|
+
if (captured)
|
|
219
|
+
return undefined;
|
|
220
|
+
const record = captureFailureCapsule(root, input, now);
|
|
221
|
+
if (record)
|
|
222
|
+
captured = true;
|
|
223
|
+
return record;
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
export function captureManualCapsule(root, input, now = new Date()) {
|
|
227
|
+
if (!input.expected?.trim())
|
|
228
|
+
throw new UsageError("expected behavior is required", "E_BAD_FLAG");
|
|
229
|
+
if (!input.actual?.trim())
|
|
230
|
+
throw new UsageError("actual behavior is required", "E_BAD_FLAG");
|
|
231
|
+
const expected = boundedField(scrubDiagnostic(input.expected, root));
|
|
232
|
+
const actual = boundedField(scrubDiagnostic(input.actual, root));
|
|
233
|
+
const reproduction = input.reproduction?.trim()
|
|
234
|
+
? boundedField(scrubDiagnostic(input.reproduction, root))
|
|
235
|
+
: absent("not provided");
|
|
236
|
+
const capsule = parseBugCapsule({
|
|
237
|
+
...capsuleBase(input.version, input.command ?? "report add", now, input.specContext),
|
|
238
|
+
failure: {
|
|
239
|
+
class: "command_error",
|
|
240
|
+
code: "E_UNKNOWN",
|
|
241
|
+
classifier_version: "0.1",
|
|
242
|
+
classification: "fallback",
|
|
243
|
+
message: absent("manual report"),
|
|
244
|
+
stack: absent("manual report"),
|
|
245
|
+
},
|
|
246
|
+
report: { expected, actual, reproduction },
|
|
247
|
+
evidence: [{ kind: "user_report", state: evidenceState([expected, actual, reproduction]), content_type: "text/plain" }],
|
|
248
|
+
similarity: { version: "0.1", signals: [] },
|
|
249
|
+
});
|
|
250
|
+
return savePending(root, capsule);
|
|
251
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
export type GhCall = {
|
|
2
|
+
args: string[];
|
|
3
|
+
};
|
|
4
|
+
export type GhExecResult = {
|
|
5
|
+
ok: boolean;
|
|
6
|
+
stdout: string;
|
|
7
|
+
stderr: string;
|
|
8
|
+
};
|
|
9
|
+
export type GhExec = (args: string[]) => GhExecResult;
|
|
10
|
+
export declare const defaultGhExec: GhExec;
|
|
11
|
+
export type BugLogIntake = {
|
|
12
|
+
/** Candidate issue title (pre-scrub). */
|
|
13
|
+
title: string;
|
|
14
|
+
/** Full markdown issue body (pre-scrub). */
|
|
15
|
+
body: string;
|
|
16
|
+
/** Text evaluated for dedupe matching. */
|
|
17
|
+
search_text: string;
|
|
18
|
+
/** Companion issue refs, e.g. ["#528", "#529"]. */
|
|
19
|
+
refs: string[];
|
|
20
|
+
};
|
|
21
|
+
export type BugLogMatch = {
|
|
22
|
+
issue_number: number;
|
|
23
|
+
issue_url: string;
|
|
24
|
+
issue_title: string;
|
|
25
|
+
issue_state: string;
|
|
26
|
+
score: number;
|
|
27
|
+
matched_terms: string[];
|
|
28
|
+
};
|
|
29
|
+
export type BugLogStatus = "reproduced" | "filed" | "refused" | "retryable";
|
|
30
|
+
export type BugLogResult = {
|
|
31
|
+
schema_version: "0.1";
|
|
32
|
+
status: BugLogStatus;
|
|
33
|
+
repo: string | null;
|
|
34
|
+
issue_number: number | null;
|
|
35
|
+
issue_url: string | null;
|
|
36
|
+
match: BugLogMatch | null;
|
|
37
|
+
withheld: string | null;
|
|
38
|
+
errors: Array<{
|
|
39
|
+
code: string;
|
|
40
|
+
message: string;
|
|
41
|
+
}>;
|
|
42
|
+
next_actions: string[];
|
|
43
|
+
};
|
|
44
|
+
/** Per-run bounded-autonomy state (R-006): creation ceiling + title-hash guard. */
|
|
45
|
+
export type BugLogSession = {
|
|
46
|
+
created: number;
|
|
47
|
+
max_creates: number;
|
|
48
|
+
title_hashes: Set<string>;
|
|
49
|
+
};
|
|
50
|
+
/** Recent auto-creations for the configured owner repo, within the rolling window. */
|
|
51
|
+
export declare function recentBugCreateCount(root: string, env: NodeJS.ProcessEnv, now?: number): number;
|
|
52
|
+
/** Records one auto-creation so the next invocation's ceiling counts it (R-006/RISK-002). */
|
|
53
|
+
export declare function recordBugCreate(root: string, env: NodeJS.ProcessEnv, repo: string, now?: number): void;
|
|
54
|
+
export declare function newBugLogSession(env: NodeJS.ProcessEnv, root?: string): BugLogSession;
|
|
55
|
+
type OwnerIssue = {
|
|
56
|
+
number: number;
|
|
57
|
+
title: string;
|
|
58
|
+
state: string;
|
|
59
|
+
url: string;
|
|
60
|
+
body: string;
|
|
61
|
+
};
|
|
62
|
+
export type DedupeVerdict = CommentVerdict | CreateVerdict;
|
|
63
|
+
export type CommentVerdict = {
|
|
64
|
+
decision: "comment";
|
|
65
|
+
match: BugLogMatch;
|
|
66
|
+
};
|
|
67
|
+
/** Only `evaluateBugDedupe` constructs this; `createOwnerIssue` requires it. */
|
|
68
|
+
export type CreateVerdict = {
|
|
69
|
+
decision: "create";
|
|
70
|
+
evaluated_issues: number;
|
|
71
|
+
proof: "dedupe_evaluated";
|
|
72
|
+
};
|
|
73
|
+
export declare function evaluateBugDedupe(intake: BugLogIntake, issues: OwnerIssue[]): DedupeVerdict;
|
|
74
|
+
export declare function buildBugLogIntake(fields: {
|
|
75
|
+
expected: string;
|
|
76
|
+
actual: string;
|
|
77
|
+
reproduction?: string;
|
|
78
|
+
suggested?: string;
|
|
79
|
+
refs?: string[];
|
|
80
|
+
}): BugLogIntake;
|
|
81
|
+
/** Seeds the engine from a discovery inbox signal: headline → title candidate,
|
|
82
|
+
* paraphrase → evidence body with provenance. Signals are already sanitized
|
|
83
|
+
* paraphrases; provenance names the finding, call date, and attribution basis. */
|
|
84
|
+
export declare function buildSignalBugIntake(record: Record<string, unknown>): BugLogIntake;
|
|
85
|
+
export declare function bugLogRefusal(code: string, message: string, nextActions: string[], repo?: string | null, withheld?: string | null): BugLogResult;
|
|
86
|
+
export declare function runBugLog(options: {
|
|
87
|
+
env: NodeJS.ProcessEnv;
|
|
88
|
+
gh: GhExec;
|
|
89
|
+
session: BugLogSession;
|
|
90
|
+
intake: BugLogIntake;
|
|
91
|
+
root: string;
|
|
92
|
+
}): BugLogResult;
|
|
93
|
+
export {};
|