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,93 @@
|
|
|
1
|
+
import { gitRunOrNull } from "./gitRun.js";
|
|
2
|
+
const IGNORED_TOP = new Set(["node_modules", "dist", "build", "out", "vendor", "coverage", ".git", "docs", ".github", "examples", "specs"]);
|
|
3
|
+
const TEST_RE = /(^|\/)(tests?|__tests__|spec|specs|e2e)(\/|$)|\.(test|spec)\.[a-z]+$|_test\.[a-z]+$/i;
|
|
4
|
+
const SOURCE_RE = /\.(ts|tsx|js|jsx|py|go|rb|rs|java|kt|swift|php|cs|scala|c|cc|cpp|h|hpp|m|mm)$/i;
|
|
5
|
+
function git(root, args) {
|
|
6
|
+
return gitRunOrNull(args, { cwd: root, stdio: ["ignore", "pipe", "ignore"] });
|
|
7
|
+
}
|
|
8
|
+
// A generic top-level container (src/, lib/, app/) isn't a meaningful "area" —
|
|
9
|
+
// everything's under it. Descend one level so the tension names the real room
|
|
10
|
+
// (src/payments) rather than the whole house (src).
|
|
11
|
+
const CONTAINER = new Set(["src", "lib", "app", "pkg", "packages", "internal", "cmd", "source", "sources", "components", "modules"]);
|
|
12
|
+
function topDir(file) {
|
|
13
|
+
const parts = file.split("/");
|
|
14
|
+
if (parts.length < 2)
|
|
15
|
+
return null; // a root-level file has no owning dir
|
|
16
|
+
if (CONTAINER.has(parts[0]) && parts.length >= 3)
|
|
17
|
+
return `${parts[0]}/${parts[1]}`;
|
|
18
|
+
return parts[0];
|
|
19
|
+
}
|
|
20
|
+
// Churn × test-gap: the area you change most, held against whether anything
|
|
21
|
+
// tests it. Two facts the repo holds; the tension is that the busiest code is
|
|
22
|
+
// the least-covered. Universal (git only), cheap, low false-positive.
|
|
23
|
+
function churnVsTests(root) {
|
|
24
|
+
// Last 100 non-merge commits — robust for low-velocity repos where a date
|
|
25
|
+
// window would be nearly empty.
|
|
26
|
+
const raw = git(root, ["log", "-n", "100", "--no-merges", "--name-only", "--format=%x00%H"]);
|
|
27
|
+
if (raw === null)
|
|
28
|
+
return null;
|
|
29
|
+
const commits = raw.split("\0").filter((c) => c.trim() !== "");
|
|
30
|
+
const M = commits.length;
|
|
31
|
+
if (M < 12)
|
|
32
|
+
return null; // too little history to claim a pattern (anti-slop floor)
|
|
33
|
+
const commitsTouchingDir = new Map();
|
|
34
|
+
for (const block of commits) {
|
|
35
|
+
const files = block.split(/\r?\n/).slice(1).filter(Boolean);
|
|
36
|
+
const dirs = new Set();
|
|
37
|
+
for (const f of files) {
|
|
38
|
+
if (!SOURCE_RE.test(f) || TEST_RE.test(f))
|
|
39
|
+
continue;
|
|
40
|
+
const d = topDir(f);
|
|
41
|
+
if (d && !IGNORED_TOP.has(d))
|
|
42
|
+
dirs.add(d);
|
|
43
|
+
}
|
|
44
|
+
for (const d of dirs)
|
|
45
|
+
commitsTouchingDir.set(d, (commitsTouchingDir.get(d) ?? 0) + 1);
|
|
46
|
+
}
|
|
47
|
+
if (commitsTouchingDir.size === 0)
|
|
48
|
+
return null;
|
|
49
|
+
const [busiest, count] = [...commitsTouchingDir.entries()].sort((a, b) => b[1] - a[1])[0];
|
|
50
|
+
// Must be genuinely dominant, not just "an area that got touched".
|
|
51
|
+
if (count < 5 || count < M * 0.2)
|
|
52
|
+
return null;
|
|
53
|
+
// Does any test reference the busiest dir? A test file under it, or one whose
|
|
54
|
+
// path names it. (Path heuristic — never a coverage claim, just evidence.)
|
|
55
|
+
const tracked = (git(root, ["ls-files"]) ?? "").split(/\r?\n/).filter(Boolean);
|
|
56
|
+
const testFiles = tracked.filter((f) => TEST_RE.test(f));
|
|
57
|
+
// The area may be "src/payments"; a test that covers it is one UNDER it, or one
|
|
58
|
+
// whose path/name references the leaf ("payments") — match the leaf, not the path.
|
|
59
|
+
const leaf = busiest.split("/").pop() ?? busiest;
|
|
60
|
+
const covered = testFiles.some((t) => t.startsWith(`${busiest}/`) || t.toLowerCase().includes(leaf.toLowerCase()));
|
|
61
|
+
if (covered)
|
|
62
|
+
return null; // the busiest area IS tested — no tension here
|
|
63
|
+
const noTestsAnywhere = testFiles.length === 0;
|
|
64
|
+
return {
|
|
65
|
+
id: "churn-vs-tests",
|
|
66
|
+
factA: `You've changed ${busiest}/ in ${count} of your last ${M} commits — it's the busiest room in the house.`,
|
|
67
|
+
factB: noTestsAnywhere ? `There isn't a test anywhere in the project.` : `Nothing in your test suite references ${busiest}/.`,
|
|
68
|
+
ask: `Which of those two are you not comfortable with?`,
|
|
69
|
+
title: `A safety net for ${busiest}/ — the code you change most, with no test under it`,
|
|
70
|
+
evidence: [`${busiest}/ touched in ${count}/${M} recent commits`, noTestsAnywhere ? "no test files found in the repo" : `${testFiles.length} test file(s), none referencing ${busiest}/`],
|
|
71
|
+
confidence: count >= M * 0.35 ? "high" : "medium",
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
// Ordered by grounding strength. First non-null wins as the headline tension;
|
|
75
|
+
// the rest stay available as "also saw" (future). Only add detectors that are
|
|
76
|
+
// cheap, grounded, and low-false-positive — a wrong first-run insight is worse
|
|
77
|
+
// than a boring one.
|
|
78
|
+
const DETECTORS = [churnVsTests];
|
|
79
|
+
export function detectTensions(root) {
|
|
80
|
+
const found = [];
|
|
81
|
+
for (const detect of DETECTORS) {
|
|
82
|
+
try {
|
|
83
|
+
const t = detect(root);
|
|
84
|
+
if (t)
|
|
85
|
+
found.push(t);
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
// a detector that throws must never break the first read — skip it.
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// High-confidence first; a tension foo isn't sure of never leads.
|
|
92
|
+
return found.sort((a, b) => (a.confidence === b.confidence ? 0 : a.confidence === "high" ? -1 : 1));
|
|
93
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
type GitStdio = Array<"ignore" | "pipe" | "inherit">;
|
|
2
|
+
export type GitRunOptions = {
|
|
3
|
+
cwd?: string;
|
|
4
|
+
maxBuffer?: number;
|
|
5
|
+
stdio?: GitStdio;
|
|
6
|
+
timeout?: number;
|
|
7
|
+
env?: NodeJS.ProcessEnv;
|
|
8
|
+
};
|
|
9
|
+
export type GitRunResult = {
|
|
10
|
+
ok: boolean;
|
|
11
|
+
stdout: string;
|
|
12
|
+
stderr: string;
|
|
13
|
+
message: string;
|
|
14
|
+
};
|
|
15
|
+
export declare function gitRun(args: string[], opts?: GitRunOptions): GitRunResult;
|
|
16
|
+
export declare function gitRunOrNull(args: string[], opts?: GitRunOptions): string | null;
|
|
17
|
+
export declare function gitRunBuffer(args: string[], opts?: GitRunOptions): {
|
|
18
|
+
ok: boolean;
|
|
19
|
+
stdout: Buffer;
|
|
20
|
+
};
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// One shared wrapper for productfoo's git invocations. It reports outcome; the caller
|
|
2
|
+
// owns what a failure means — some sites fail open (null/[] and continue),
|
|
3
|
+
// others fail closed. Implemented over execFileSync so each site's existing
|
|
4
|
+
// stdio/maxBuffer/stderr-echo semantics survive: execFileSync's default echoes
|
|
5
|
+
// the child's stderr to the parent process, and a site that historically
|
|
6
|
+
// silenced git must keep doing so by passing `stdio` explicitly.
|
|
7
|
+
import { execFileSync } from "node:child_process";
|
|
8
|
+
// Only forward options a caller actually set, so execFileSync's defaults
|
|
9
|
+
// (cwd = process.cwd(), maxBuffer = 1 MiB, stderr echoed to the parent) hold
|
|
10
|
+
// exactly where they held before.
|
|
11
|
+
function execOptions(opts) {
|
|
12
|
+
return {
|
|
13
|
+
...(opts.cwd !== undefined ? { cwd: opts.cwd } : {}),
|
|
14
|
+
...(opts.maxBuffer !== undefined ? { maxBuffer: opts.maxBuffer } : {}),
|
|
15
|
+
...(opts.stdio !== undefined ? { stdio: opts.stdio } : {}),
|
|
16
|
+
...(opts.timeout !== undefined ? { timeout: opts.timeout } : {}),
|
|
17
|
+
...(opts.env !== undefined ? { env: opts.env } : {}),
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export function gitRun(args, opts = {}) {
|
|
21
|
+
try {
|
|
22
|
+
const stdout = execFileSync("git", args, { encoding: "utf8", ...execOptions(opts) });
|
|
23
|
+
return { ok: true, stdout: stdout ?? "", stderr: "", message: "" };
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
const failure = error;
|
|
27
|
+
return {
|
|
28
|
+
ok: false,
|
|
29
|
+
stdout: typeof failure.stdout === "string" ? failure.stdout : "",
|
|
30
|
+
stderr: typeof failure.stderr === "string" ? failure.stderr : "",
|
|
31
|
+
message: error instanceof Error ? error.message : String(error),
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
// Convenience for the common fail-open sites: stdout on success, null on any
|
|
36
|
+
// git failure (including git not being installed).
|
|
37
|
+
export function gitRunOrNull(args, opts = {}) {
|
|
38
|
+
const result = gitRun(args, opts);
|
|
39
|
+
return result.ok ? result.stdout : null;
|
|
40
|
+
}
|
|
41
|
+
// Raw-bytes variant for reading blobs (e.g. staged file content) where the
|
|
42
|
+
// binary guard must inspect real bytes, not a utf8 re-encoding.
|
|
43
|
+
export function gitRunBuffer(args, opts = {}) {
|
|
44
|
+
try {
|
|
45
|
+
return { ok: true, stdout: execFileSync("git", args, execOptions(opts)) };
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return { ok: false, stdout: Buffer.alloc(0) };
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { type GithubFixture, type SourceId } from "./sourceIngress.js";
|
|
2
|
+
export type GithubCheck = {
|
|
3
|
+
name?: string;
|
|
4
|
+
conclusion?: string;
|
|
5
|
+
};
|
|
6
|
+
export type GithubEvidence = {
|
|
7
|
+
merged?: boolean;
|
|
8
|
+
state?: string;
|
|
9
|
+
checks?: GithubCheck[];
|
|
10
|
+
commits?: Array<{
|
|
11
|
+
message?: string;
|
|
12
|
+
files?: string[];
|
|
13
|
+
}>;
|
|
14
|
+
files_changed?: string[];
|
|
15
|
+
};
|
|
16
|
+
export type CriterionCheck = {
|
|
17
|
+
kind: "pr_merged";
|
|
18
|
+
} | {
|
|
19
|
+
kind: "checks_pass";
|
|
20
|
+
} | {
|
|
21
|
+
kind: "path_changed";
|
|
22
|
+
path: string;
|
|
23
|
+
};
|
|
24
|
+
export type DoneWhenCriterion = {
|
|
25
|
+
id: string;
|
|
26
|
+
text?: string;
|
|
27
|
+
check?: CriterionCheck;
|
|
28
|
+
};
|
|
29
|
+
export type NotVerifiedReason = "no-linkage" | "signal-absent" | "out-of-reach";
|
|
30
|
+
export type CriterionStatus = "corroborated" | "contradicted" | "unresolvable";
|
|
31
|
+
export type Verdict = "satisfied" | "drifted" | "not-verified";
|
|
32
|
+
export type CriterionVerdict = {
|
|
33
|
+
criterion_id: string;
|
|
34
|
+
status: CriterionStatus;
|
|
35
|
+
reason?: NotVerifiedReason;
|
|
36
|
+
basis: string;
|
|
37
|
+
teach?: string;
|
|
38
|
+
};
|
|
39
|
+
export declare function verifyCriterion(criterion: DoneWhenCriterion, ev: GithubEvidence, linked: boolean): CriterionVerdict;
|
|
40
|
+
export type ReconcileResult = {
|
|
41
|
+
verdict: Verdict;
|
|
42
|
+
criteria: CriterionVerdict[];
|
|
43
|
+
counts: {
|
|
44
|
+
corroborated: number;
|
|
45
|
+
contradicted: number;
|
|
46
|
+
unresolvable: number;
|
|
47
|
+
};
|
|
48
|
+
observed_at?: string;
|
|
49
|
+
};
|
|
50
|
+
export declare function aggregateVerdict(criteria: CriterionVerdict[]): Verdict;
|
|
51
|
+
export declare function reconcileDoneWhen(opts: {
|
|
52
|
+
criteria: DoneWhenCriterion[];
|
|
53
|
+
evidence: GithubEvidence;
|
|
54
|
+
linked: boolean;
|
|
55
|
+
observedAt?: string;
|
|
56
|
+
}): ReconcileResult;
|
|
57
|
+
export declare const DEFAULT_VERDICT_MAX_AGE_SECONDS = 86400;
|
|
58
|
+
export declare function isStale(observedAt: string, now: string, maxAgeSeconds?: number): boolean;
|
|
59
|
+
export declare function recordGithubConflicts(packetDir: string, sourceId: SourceId, result: ReconcileResult, at: string): number;
|
|
60
|
+
export type GithubReceipt = {
|
|
61
|
+
schema_version: "0.1";
|
|
62
|
+
packet: string;
|
|
63
|
+
source_id: SourceId;
|
|
64
|
+
verdict: Verdict;
|
|
65
|
+
observed_at?: string;
|
|
66
|
+
counts: ReconcileResult["counts"];
|
|
67
|
+
criteria: Array<{
|
|
68
|
+
criterion_id: string;
|
|
69
|
+
verdict: Verdict;
|
|
70
|
+
reason?: NotVerifiedReason;
|
|
71
|
+
basis: string;
|
|
72
|
+
}>;
|
|
73
|
+
};
|
|
74
|
+
export declare function evidenceFromFixture(fixture: GithubFixture): GithubEvidence;
|
|
75
|
+
export type PrProof = {
|
|
76
|
+
evidence: GithubEvidence;
|
|
77
|
+
result: ReconcileResult;
|
|
78
|
+
receipt: GithubReceipt;
|
|
79
|
+
linked: boolean;
|
|
80
|
+
};
|
|
81
|
+
export declare function reconcilePrProof(opts: {
|
|
82
|
+
packet: string;
|
|
83
|
+
sourceId: SourceId;
|
|
84
|
+
fixture: GithubFixture;
|
|
85
|
+
specId: string;
|
|
86
|
+
criteria: DoneWhenCriterion[];
|
|
87
|
+
observedAt?: string;
|
|
88
|
+
}): PrProof;
|
|
89
|
+
export declare function buildGithubReceipt(opts: {
|
|
90
|
+
packet: string;
|
|
91
|
+
sourceId: SourceId;
|
|
92
|
+
result: ReconcileResult;
|
|
93
|
+
}): GithubReceipt;
|
|
94
|
+
export declare function renderGithubReceipt(receipt: GithubReceipt): string;
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
// GitHub done_when verdict engine (github-integration-v0 T-003/T-004). Reconciles
|
|
2
|
+
// a packet's done_when criteria against the typed GitHub facts of an approved PR
|
|
3
|
+
// into a fail-closed tri-state verdict. Pure + offline: the runtime/CLI supplies
|
|
4
|
+
// the evidence, this module decides. It consumes sourceIngress for the source
|
|
5
|
+
// identity and the payload-free conflict-event shape; it re-implements no
|
|
6
|
+
// substrate behavior (R-005). This is the PROOF axis (criterion ↔ evidence) —
|
|
7
|
+
// orthogonal to and composing with packetReconcile's COVERAGE axis (changed-file
|
|
8
|
+
// ↔ task); the two are named as one drift model with two axes, never merged
|
|
9
|
+
// (D-011). `no-linkage` here is the proof-axis analog of the coverage axis's
|
|
10
|
+
// `unmapped`.
|
|
11
|
+
import { appendSourceConflictEvent, githubLinkageForSpec } from "./sourceIngress.js";
|
|
12
|
+
// null = no diff information at all (signal-absent); [] = diff known but empty.
|
|
13
|
+
function changedFiles(ev) {
|
|
14
|
+
const hasInfo = ev.files_changed !== undefined || (ev.commits ?? []).some((c) => c.files !== undefined);
|
|
15
|
+
if (!hasInfo)
|
|
16
|
+
return null;
|
|
17
|
+
return [...(ev.files_changed ?? []), ...(ev.commits ?? []).flatMap((c) => c.files ?? [])];
|
|
18
|
+
}
|
|
19
|
+
// Errors that teach (R-006): each not-verified reason names the concept, the fix,
|
|
20
|
+
// and the next command — the Rust-compiler bar, not a bare assertion.
|
|
21
|
+
const teachFor = {
|
|
22
|
+
"no-linkage": (c) => `not-verified (no-linkage): no PR/commit is bound to ${c.id} → add a Foo-Spec trailer to the implementing commit (or pass --source github:<pr-url>), then re-run foo asp reconcile`,
|
|
23
|
+
"signal-absent": (c) => `not-verified (signal-absent): ${c.id} needs a GitHub signal that is not present yet (e.g. no required checks, or the PR is still open) → re-run once the signal exists`,
|
|
24
|
+
"out-of-reach": (c) => `not-verified (out-of-reach): ${c.id} asserts something read-only GitHub signal cannot confirm → verify by test/review, or declare a check predicate (pr_merged | checks_pass | path_changed)`,
|
|
25
|
+
};
|
|
26
|
+
// Verify ONE criterion against the typed evidence (R-006). Corroboration is read
|
|
27
|
+
// only from typed fields; free text never corroborates. Precedence inside a
|
|
28
|
+
// criterion is fail-closed: an explicit contradiction beats a missing signal.
|
|
29
|
+
export function verifyCriterion(criterion, ev, linked) {
|
|
30
|
+
const nv = (reason, basis) => ({
|
|
31
|
+
criterion_id: criterion.id,
|
|
32
|
+
status: "unresolvable",
|
|
33
|
+
reason,
|
|
34
|
+
basis,
|
|
35
|
+
teach: teachFor[reason](criterion),
|
|
36
|
+
});
|
|
37
|
+
// (1) no-linkage: nothing binds this PR to the criterion's packet (D-009).
|
|
38
|
+
if (!linked)
|
|
39
|
+
return nv("no-linkage", "no PR/commit is bound to this criterion's task via the Foo-Spec trailer");
|
|
40
|
+
// (3) out-of-reach: no typed predicate, so GitHub signal cannot speak to it.
|
|
41
|
+
const check = criterion.check;
|
|
42
|
+
if (!check)
|
|
43
|
+
return nv("out-of-reach", "no GitHub-checkable predicate; the criterion is outside read-only GitHub signal");
|
|
44
|
+
if (check.kind === "pr_merged") {
|
|
45
|
+
if (ev.merged === true)
|
|
46
|
+
return { criterion_id: criterion.id, status: "corroborated", basis: "PR is merged" };
|
|
47
|
+
if (ev.merged === false)
|
|
48
|
+
return { criterion_id: criterion.id, status: "contradicted", basis: `PR is not merged (state: ${ev.state ?? "open"})` };
|
|
49
|
+
return nv("signal-absent", "PR merge state is not present in the evidence");
|
|
50
|
+
}
|
|
51
|
+
if (check.kind === "checks_pass") {
|
|
52
|
+
const checks = ev.checks ?? [];
|
|
53
|
+
if (checks.length === 0)
|
|
54
|
+
return nv("signal-absent", "no required checks are present");
|
|
55
|
+
const failed = checks.find((c) => c.conclusion === "failure");
|
|
56
|
+
if (failed)
|
|
57
|
+
return { criterion_id: criterion.id, status: "contradicted", basis: `a required check = failure` };
|
|
58
|
+
if (checks.every((c) => c.conclusion === "success")) {
|
|
59
|
+
return { criterion_id: criterion.id, status: "corroborated", basis: `${checks.length}/${checks.length} required checks green` };
|
|
60
|
+
}
|
|
61
|
+
// pending/neutral/unknown conclusions present and none failed: cannot confirm green.
|
|
62
|
+
return nv("signal-absent", "not all required checks have a success conclusion yet");
|
|
63
|
+
}
|
|
64
|
+
// path_changed
|
|
65
|
+
const files = changedFiles(ev);
|
|
66
|
+
if (files === null)
|
|
67
|
+
return nv("signal-absent", "no diff/file information is present in the evidence");
|
|
68
|
+
const hit = files.some((f) => f === check.path || f.startsWith(check.path) || f.includes(check.path));
|
|
69
|
+
return hit
|
|
70
|
+
? { criterion_id: criterion.id, status: "corroborated", basis: `a commit changed ${check.path}` }
|
|
71
|
+
: { criterion_id: criterion.id, status: "contradicted", basis: `no commit changed ${check.path}` };
|
|
72
|
+
}
|
|
73
|
+
// Aggregate per-criterion statuses into the fail-closed verdict (R-005): any
|
|
74
|
+
// contradicted → drifted; else any unresolvable → not-verified; else satisfied.
|
|
75
|
+
// `satisfied` therefore requires positive corroboration on EVERY criterion —
|
|
76
|
+
// silence is never a pass. An empty criteria set is not-verified, not satisfied.
|
|
77
|
+
export function aggregateVerdict(criteria) {
|
|
78
|
+
if (criteria.length === 0)
|
|
79
|
+
return "not-verified";
|
|
80
|
+
if (criteria.some((c) => c.status === "contradicted"))
|
|
81
|
+
return "drifted";
|
|
82
|
+
if (criteria.some((c) => c.status === "unresolvable"))
|
|
83
|
+
return "not-verified";
|
|
84
|
+
return "satisfied";
|
|
85
|
+
}
|
|
86
|
+
export function reconcileDoneWhen(opts) {
|
|
87
|
+
const criteria = opts.criteria.map((c) => verifyCriterion(c, opts.evidence, opts.linked));
|
|
88
|
+
return {
|
|
89
|
+
verdict: aggregateVerdict(criteria),
|
|
90
|
+
criteria,
|
|
91
|
+
counts: {
|
|
92
|
+
corroborated: criteria.filter((c) => c.status === "corroborated").length,
|
|
93
|
+
contradicted: criteria.filter((c) => c.status === "contradicted").length,
|
|
94
|
+
unresolvable: criteria.filter((c) => c.status === "unresolvable").length,
|
|
95
|
+
},
|
|
96
|
+
observed_at: opts.observedAt,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
// Freshness (R-005 / OQ-2 carried default): a typed-fact verdict is stamped with
|
|
100
|
+
// observed_at and goes stale past the window, so a re-run is prompted rather than
|
|
101
|
+
// a cached `satisfied` trusted. Fail-closed: an unparseable timestamp is stale.
|
|
102
|
+
export const DEFAULT_VERDICT_MAX_AGE_SECONDS = 86400;
|
|
103
|
+
export function isStale(observedAt, now, maxAgeSeconds = DEFAULT_VERDICT_MAX_AGE_SECONDS) {
|
|
104
|
+
const obs = Date.parse(observedAt);
|
|
105
|
+
const cur = Date.parse(now);
|
|
106
|
+
if (Number.isNaN(obs) || Number.isNaN(cur))
|
|
107
|
+
return true;
|
|
108
|
+
return (cur - obs) / 1000 > maxAgeSeconds;
|
|
109
|
+
}
|
|
110
|
+
// Record a payload-free conflict event for each contradicted criterion (C-006),
|
|
111
|
+
// reusing the substrate writer. Returns the number of conflicts recorded. The
|
|
112
|
+
// event carries only criterion ids/status — no raw GitHub payload (B1).
|
|
113
|
+
export function recordGithubConflicts(packetDir, sourceId, result, at) {
|
|
114
|
+
const contradicted = result.criteria.filter((c) => c.status === "contradicted");
|
|
115
|
+
if (contradicted.length === 0)
|
|
116
|
+
return 0;
|
|
117
|
+
appendSourceConflictEvent(packetDir, {
|
|
118
|
+
source_id: sourceId,
|
|
119
|
+
conflicts: contradicted.map((c) => ({ criterion_id: c.criterion_id, status: c.status })),
|
|
120
|
+
note: "GitHub evidence contradicts a done_when criterion; not promoted (github-integration-v0 R-004/R-005).",
|
|
121
|
+
}, at);
|
|
122
|
+
return contradicted.length;
|
|
123
|
+
}
|
|
124
|
+
// --- Dual-reader proof receipt (github-integration-v0 T-006/R-008) ----------
|
|
125
|
+
// The per-criterion status maps to the criterion-level verdict vocabulary.
|
|
126
|
+
const CRITERION_VERDICT = {
|
|
127
|
+
corroborated: "satisfied",
|
|
128
|
+
contradicted: "drifted",
|
|
129
|
+
unresolvable: "not-verified",
|
|
130
|
+
};
|
|
131
|
+
// --- Shared PR-reconcile engine (reconcile-anywhere-v0 T-001) ----------------
|
|
132
|
+
// The PROOF-axis core both entry points share (D-001): `asp reconcile --source
|
|
133
|
+
// github:` (packet path — criteria from tasks.yaml) and the top-level packet-free
|
|
134
|
+
// `foo reconcile`. Free text still never corroborates; only typed fields feed the
|
|
135
|
+
// verdict. Keeping this one function is the anti-drift mitigation the D-001
|
|
136
|
+
// dissent named: two entry points, one engine.
|
|
137
|
+
// Lift the typed GithubEvidence out of an offline fixture (or a runtime-supplied
|
|
138
|
+
// PR payload of the same shape). Only typed fields cross; bodies/titles stay out.
|
|
139
|
+
export function evidenceFromFixture(fixture) {
|
|
140
|
+
return {
|
|
141
|
+
merged: fixture.merged,
|
|
142
|
+
state: fixture.state,
|
|
143
|
+
checks: fixture.checks,
|
|
144
|
+
commits: fixture.commits,
|
|
145
|
+
files_changed: fixture.files_changed,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
// Given a PR fixture + a packet's done_when criteria, produce the typed-fact
|
|
149
|
+
// verdict and dual-reader receipt. `asp reconcile` delegates here (behavior
|
|
150
|
+
// preserved); the packet-free command reuses `evidenceFromFixture` and this same
|
|
151
|
+
// verdict once a packet has been adopted.
|
|
152
|
+
export function reconcilePrProof(opts) {
|
|
153
|
+
const evidence = evidenceFromFixture(opts.fixture);
|
|
154
|
+
const linked = githubLinkageForSpec({
|
|
155
|
+
specId: opts.specId,
|
|
156
|
+
commitMessages: (opts.fixture.commits ?? []).map((c) => c.message ?? ""),
|
|
157
|
+
branch: opts.fixture.branch,
|
|
158
|
+
prBody: opts.fixture.body,
|
|
159
|
+
}).linked;
|
|
160
|
+
const result = reconcileDoneWhen({ criteria: opts.criteria, evidence, linked, observedAt: opts.observedAt });
|
|
161
|
+
const receipt = buildGithubReceipt({ packet: opts.packet, sourceId: opts.sourceId, result });
|
|
162
|
+
return { evidence, result, receipt, linked };
|
|
163
|
+
}
|
|
164
|
+
export function buildGithubReceipt(opts) {
|
|
165
|
+
return {
|
|
166
|
+
schema_version: "0.1",
|
|
167
|
+
packet: opts.packet,
|
|
168
|
+
source_id: opts.sourceId,
|
|
169
|
+
verdict: opts.result.verdict,
|
|
170
|
+
observed_at: opts.result.observed_at,
|
|
171
|
+
counts: opts.result.counts,
|
|
172
|
+
criteria: opts.result.criteria.map((c) => ({
|
|
173
|
+
criterion_id: c.criterion_id,
|
|
174
|
+
verdict: CRITERION_VERDICT[c.status],
|
|
175
|
+
reason: c.reason,
|
|
176
|
+
basis: c.basis,
|
|
177
|
+
})),
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
// Render the receipt as a copy-pasteable PR comment the DEVELOPER posts (foo posts
|
|
181
|
+
// nothing, R-008/R-007). Dual-reader: human-scannable markdown lines PLUS a
|
|
182
|
+
// machine block in an HTML comment (invisible in rendered markdown) so an agent
|
|
183
|
+
// re-reading the PR reconstructs the verdict without re-running. Payload-free.
|
|
184
|
+
export function renderGithubReceipt(receipt) {
|
|
185
|
+
const lines = receipt.criteria.map((c) => `- ${c.criterion_id}: ${c.verdict}${c.reason ? ` (${c.reason})` : ""} — ${c.basis}`);
|
|
186
|
+
const machine = JSON.stringify({
|
|
187
|
+
foo_verdict: {
|
|
188
|
+
schema_version: receipt.schema_version,
|
|
189
|
+
packet: receipt.packet,
|
|
190
|
+
source_id: receipt.source_id,
|
|
191
|
+
verdict: receipt.verdict,
|
|
192
|
+
observed_at: receipt.observed_at,
|
|
193
|
+
criteria: receipt.criteria.map((c) => ({ criterion_id: c.criterion_id, verdict: c.verdict, reason: c.reason })),
|
|
194
|
+
},
|
|
195
|
+
});
|
|
196
|
+
return [
|
|
197
|
+
`**foo proof receipt** — \`${receipt.packet}\` · verdict: **${receipt.verdict}**`,
|
|
198
|
+
`source: ${receipt.source_id.provider}:${receipt.source_id.connection_id} (${receipt.source_id.external_id ?? "repo"}) · ${receipt.counts.corroborated} satisfied / ${receipt.counts.contradicted} drifted / ${receipt.counts.unresolvable} not-verified`,
|
|
199
|
+
"",
|
|
200
|
+
...(lines.length ? lines : ["- (no criteria evaluated)"]),
|
|
201
|
+
"",
|
|
202
|
+
`<!-- foo:verdict ${machine} -->`,
|
|
203
|
+
"",
|
|
204
|
+
].join("\n");
|
|
205
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
export type FetchLike = typeof globalThis.fetch;
|
|
2
|
+
export type GmailRuntimeErrorCode = "not_connected" | "auth_expired" | "access_denied" | "provider_failure" | "network" | "provider_timeout" | "thread_too_large" | "budget_exhausted";
|
|
3
|
+
export declare class GmailRuntimeError extends Error {
|
|
4
|
+
readonly code: GmailRuntimeErrorCode;
|
|
5
|
+
constructor(code: GmailRuntimeErrorCode, message: string);
|
|
6
|
+
}
|
|
7
|
+
export type GmailConnection = {
|
|
8
|
+
connection_ref: string;
|
|
9
|
+
broker: "nango";
|
|
10
|
+
credential: {
|
|
11
|
+
type: "oauth2";
|
|
12
|
+
access_token: string;
|
|
13
|
+
};
|
|
14
|
+
credential_type: "oauth2";
|
|
15
|
+
body_scope: "granted" | "missing" | "unknown";
|
|
16
|
+
};
|
|
17
|
+
export declare const GMAIL_POLICY: {
|
|
18
|
+
readonly policy_version: "gmail-local-worker-0.1";
|
|
19
|
+
readonly max_response_bytes: number;
|
|
20
|
+
readonly fetch_timeout_ms: 90000;
|
|
21
|
+
readonly max_model_input_tokens: 100000;
|
|
22
|
+
readonly max_list_pages: 5;
|
|
23
|
+
readonly min_request_interval_ms: 350;
|
|
24
|
+
readonly quiet_period_hours: 48;
|
|
25
|
+
};
|
|
26
|
+
export type GmailConnectionEnv = Record<string, string | undefined>;
|
|
27
|
+
export declare function gmailConnectionConfigured(env: GmailConnectionEnv): boolean;
|
|
28
|
+
export declare function gmailCredentialBroker(_env: GmailConnectionEnv): "nango" | null;
|
|
29
|
+
/**
|
|
30
|
+
* Resolve the verified user's Gmail credential through Nango. There is no
|
|
31
|
+
* direct fallback (D-002): the mailbox belongs to one person, so the OAuth
|
|
32
|
+
* grant is always brokered, refreshable, and revocable centrally. productfoo receives
|
|
33
|
+
* the token for one command and never persists or prints it.
|
|
34
|
+
*/
|
|
35
|
+
export declare function resolveGmailConnection(input: {
|
|
36
|
+
env: GmailConnectionEnv;
|
|
37
|
+
fetchImpl: FetchLike;
|
|
38
|
+
}): Promise<GmailConnection>;
|
|
39
|
+
export type GmailThreadRef = {
|
|
40
|
+
id: string;
|
|
41
|
+
snippet?: string;
|
|
42
|
+
};
|
|
43
|
+
export type GmailMessageHeader = {
|
|
44
|
+
name?: string;
|
|
45
|
+
value?: string;
|
|
46
|
+
};
|
|
47
|
+
export type GmailThreadMessage = {
|
|
48
|
+
id: string;
|
|
49
|
+
internal_date?: string;
|
|
50
|
+
labels?: string[];
|
|
51
|
+
from?: {
|
|
52
|
+
display_name?: string;
|
|
53
|
+
email?: string;
|
|
54
|
+
};
|
|
55
|
+
to?: Array<{
|
|
56
|
+
display_name?: string;
|
|
57
|
+
email?: string;
|
|
58
|
+
}>;
|
|
59
|
+
subject?: string;
|
|
60
|
+
body_text?: string;
|
|
61
|
+
};
|
|
62
|
+
export type GmailThread = {
|
|
63
|
+
id: string;
|
|
64
|
+
messages: GmailThreadMessage[];
|
|
65
|
+
};
|
|
66
|
+
type GmailClientOptions = {
|
|
67
|
+
fetchImpl: FetchLike;
|
|
68
|
+
baseUrl?: string;
|
|
69
|
+
sleep?: (ms: number) => Promise<void>;
|
|
70
|
+
now?: () => number;
|
|
71
|
+
fetchTimeoutMs?: number;
|
|
72
|
+
};
|
|
73
|
+
/**
|
|
74
|
+
* Minimal read-only Gmail REST client. Only documented read operations are
|
|
75
|
+
* reachable — every request method is GET and anything else routes through
|
|
76
|
+
* the single write-refusal choke point (R-009), so the refusal is testable
|
|
77
|
+
* rather than scattered. There is no attachment fetch method at all (D-003).
|
|
78
|
+
*/
|
|
79
|
+
export declare class GmailClient {
|
|
80
|
+
private readonly credential;
|
|
81
|
+
private readonly options;
|
|
82
|
+
readonly requests: {
|
|
83
|
+
profile: number;
|
|
84
|
+
list: number;
|
|
85
|
+
metadata: number;
|
|
86
|
+
thread: number;
|
|
87
|
+
};
|
|
88
|
+
private lastRequestAt;
|
|
89
|
+
private readonly baseUrl;
|
|
90
|
+
private readonly fetchTimeoutMs;
|
|
91
|
+
private readonly sleep;
|
|
92
|
+
private readonly now;
|
|
93
|
+
constructor(credential: {
|
|
94
|
+
type: "oauth2";
|
|
95
|
+
access_token: string;
|
|
96
|
+
}, options: GmailClientOptions);
|
|
97
|
+
private request;
|
|
98
|
+
/** The mailbox owner's address (metadata only) — defines "internal" for a per-user mailbox (R-004). */
|
|
99
|
+
profile(): Promise<{
|
|
100
|
+
email?: string;
|
|
101
|
+
}>;
|
|
102
|
+
/**
|
|
103
|
+
* Bounded metadata listing (R-004): explicit labels, a time window expressed
|
|
104
|
+
* as Gmail's after/before query operators, a page ceiling, no message
|
|
105
|
+
* bodies. A listing that exceeds the ceiling returns `truncated` and the
|
|
106
|
+
* run stops — it never widens.
|
|
107
|
+
*/
|
|
108
|
+
listThreads(scope: {
|
|
109
|
+
label_ids: string[];
|
|
110
|
+
from: string;
|
|
111
|
+
to: string;
|
|
112
|
+
}): Promise<{
|
|
113
|
+
threads: GmailThreadRef[];
|
|
114
|
+
pages: number;
|
|
115
|
+
truncated: boolean;
|
|
116
|
+
}>;
|
|
117
|
+
/**
|
|
118
|
+
* One thread's headers only (format=metadata) — the bounded listing read
|
|
119
|
+
* (R-004): participants and dates without any message body. Bodies are
|
|
120
|
+
* fetched solely by `thread()` under the minted proof (R-007).
|
|
121
|
+
*/
|
|
122
|
+
threadMetadata(threadId: string): Promise<GmailThread>;
|
|
123
|
+
/**
|
|
124
|
+
* Exactly one thread's messages (R-007). This method refuses to ask for
|
|
125
|
+
* more than one identifier — a fixture observes that no request ever
|
|
126
|
+
* carries one. Attachment parts are skipped, never fetched (D-003).
|
|
127
|
+
*/
|
|
128
|
+
thread(threadId: string): Promise<GmailThread>;
|
|
129
|
+
private parseMessage;
|
|
130
|
+
}
|
|
131
|
+
export {};
|