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,794 @@
|
|
|
1
|
+
// The spec-first front doors: spec start/from/nudge, shape, classify, roast,
|
|
2
|
+
// preview, learn, and the elicitation surface demo. These route work into
|
|
3
|
+
// skills and packets; the packet write itself lives in packetWrite.
|
|
4
|
+
import { readJson } from "../jsonFile.js";
|
|
5
|
+
import { GateBlock, UsageError } from "../errorTaxonomy.js";
|
|
6
|
+
import { existsSync } from "node:fs";
|
|
7
|
+
import path from "node:path";
|
|
8
|
+
import { appendEvent, initPacket } from "../packetWrite.js";
|
|
9
|
+
import { acceptPanelFinding, buildReconcileSpecAfterReport, canonizeSpecAfter, parseSpecFromArgs, runQaPanel, runSpecAfter, runSpecFrom, runSpecNudge, } from "../specAfter.js";
|
|
10
|
+
import { gitRunOrNull } from "../gitRun.js";
|
|
11
|
+
import { classifyWork, renderClassification } from "../riskClassify.js";
|
|
12
|
+
import { loadRoutingPolicy, resolveWorkflowLane, } from "../routingPolicy.js";
|
|
13
|
+
import { withGlyph } from "../statusGlyphs.js";
|
|
14
|
+
import { buildLinearCandidate, parseLinearSource } from "../sourceIngress.js";
|
|
15
|
+
import { findUnrepresentedUserCorrections, proposeSpecPatch, renderPatchProposal } from "../packetCorrections.js";
|
|
16
|
+
import { detectElicitationSurface } from "../elicitationSurface.js";
|
|
17
|
+
import { defineQuestion } from "../questionModel.js";
|
|
18
|
+
import { renderQuestion } from "../questionText.js";
|
|
19
|
+
import { flagValue, loadRegisteredSkills, registeredSkillPath, resolvePacketDir, ROOT } from "./shared.js";
|
|
20
|
+
import { costHeadline } from "./loop.js";
|
|
21
|
+
import { guardHumanSurface } from "../humanSurfaceEval.js";
|
|
22
|
+
import { researchRequestTopic } from "../researchGate.js";
|
|
23
|
+
import { SkillDeliveryError } from "../skillLocal.js";
|
|
24
|
+
function parseCompanionLens(value) {
|
|
25
|
+
if (!value)
|
|
26
|
+
throw new UsageError("--companion requires a value", "E_BAD_FLAG");
|
|
27
|
+
if (value !== "ponytail")
|
|
28
|
+
throw new UsageError(`unsupported companion: ${value}. Supported companions: ponytail`, "E_BAD_FLAG");
|
|
29
|
+
return value;
|
|
30
|
+
}
|
|
31
|
+
function renderCompanionLines(companions) {
|
|
32
|
+
if (!companions.includes("ponytail"))
|
|
33
|
+
return [];
|
|
34
|
+
return [
|
|
35
|
+
"Companion lens: Ponytail — if available, invoke it during implementation/review as advisory pressure for the smallest correct implementation; never let it override productfoo boundaries, validation, safety, accessibility, or clarity.",
|
|
36
|
+
];
|
|
37
|
+
}
|
|
38
|
+
function parseSpecStartArgs(args) {
|
|
39
|
+
const required = ["interview-me", "spec-swarm"];
|
|
40
|
+
const companions = new Set();
|
|
41
|
+
let request;
|
|
42
|
+
let packetName;
|
|
43
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
44
|
+
const arg = args[index];
|
|
45
|
+
if (arg === "--request") {
|
|
46
|
+
const value = args[index + 1];
|
|
47
|
+
if (!value)
|
|
48
|
+
throw new UsageError("--request requires a value", "E_BAD_FLAG");
|
|
49
|
+
request = value;
|
|
50
|
+
index += 1;
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
if (arg === "--packet") {
|
|
54
|
+
const value = args[index + 1];
|
|
55
|
+
if (!value)
|
|
56
|
+
throw new UsageError("--packet requires a value", "E_BAD_FLAG");
|
|
57
|
+
packetName = value;
|
|
58
|
+
index += 1;
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
if (arg === "--companion") {
|
|
62
|
+
companions.add(parseCompanionLens(args[index + 1]));
|
|
63
|
+
index += 1;
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
if (arg === "--ponytail") {
|
|
67
|
+
companions.add("ponytail");
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
if (arg !== "--skill")
|
|
71
|
+
throw new UsageError(`unknown spec start argument: ${arg}`, "E_BAD_FLAG");
|
|
72
|
+
const skill = args[index + 1];
|
|
73
|
+
if (!skill)
|
|
74
|
+
throw new UsageError("--skill requires a value", "E_BAD_FLAG");
|
|
75
|
+
required.push(skill);
|
|
76
|
+
index += 1;
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
requiredSkills: [...new Set(required)],
|
|
80
|
+
request,
|
|
81
|
+
packetName,
|
|
82
|
+
companions: [...companions],
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
function matchingTriggers(text, patterns) {
|
|
86
|
+
return patterns.flatMap(([label, pattern]) => (pattern.test(text) ? [label] : []));
|
|
87
|
+
}
|
|
88
|
+
function classifySpecStart(request) {
|
|
89
|
+
if (!request) {
|
|
90
|
+
return {
|
|
91
|
+
kind: "full-loop",
|
|
92
|
+
reason: "Default product/spec workflow.",
|
|
93
|
+
nextSkill: "interview-me",
|
|
94
|
+
triggers: [],
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
const rewriteTriggers = matchingTriggers(request, [
|
|
98
|
+
["reimagine", /\breimagin(e|es|ed|ing)\b/i],
|
|
99
|
+
["rewrite", /\brewrit(e|es|ing|ten)\b/i],
|
|
100
|
+
["pivot", /\bpivot(s|ed|ing)?\b/i],
|
|
101
|
+
["agentic", /\bagentic\b/i],
|
|
102
|
+
["EA", /\bEA\b/i],
|
|
103
|
+
["delegation", /\bdelegat(e|es|ed|ing|ion)\b/i],
|
|
104
|
+
["identity", /\bidentity\b/i],
|
|
105
|
+
["approval", /\bapproval\b/i],
|
|
106
|
+
["outbound communication", /\boutbound\b|\bcommunicat(e|es|ed|ing|ion)\b/i],
|
|
107
|
+
]);
|
|
108
|
+
const hasRewriteIntent = rewriteTriggers.some((trigger) => ["reimagine", "rewrite", "pivot"].includes(trigger));
|
|
109
|
+
const hasProductShapeTrigger = rewriteTriggers.some((trigger) => ["agentic", "EA", "delegation", "identity", "approval", "outbound communication"].includes(trigger));
|
|
110
|
+
if (hasRewriteIntent && hasProductShapeTrigger) {
|
|
111
|
+
return {
|
|
112
|
+
kind: "interview-required",
|
|
113
|
+
reason: "Product-shape rewrite detected.",
|
|
114
|
+
nextSkill: "interview-me",
|
|
115
|
+
triggers: rewriteTriggers,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
const artifactTriggers = matchingTriggers(request, [
|
|
119
|
+
["wired artifact", /\bwired artifact\b/i],
|
|
120
|
+
["artifact", /\bartifact\b/i],
|
|
121
|
+
["simulate", /\bsimulat(e|es|ed|ing)\b/i],
|
|
122
|
+
["end-user experience", /\bend[- ]user experience\b/i],
|
|
123
|
+
["scenario prototype", /\bscenario prototype\b/i],
|
|
124
|
+
["workbench", /\bworkbench\b/i],
|
|
125
|
+
]);
|
|
126
|
+
if (artifactTriggers.length > 0) {
|
|
127
|
+
return {
|
|
128
|
+
kind: "product-shape-interview-required",
|
|
129
|
+
reason: "Artifact generation needs a packet-local Shape Brief before HTML or UI output.",
|
|
130
|
+
nextSkill: "product-shape-interview",
|
|
131
|
+
triggers: artifactTriggers,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
return {
|
|
135
|
+
kind: "full-loop",
|
|
136
|
+
reason: "Default product/spec workflow.",
|
|
137
|
+
nextSkill: "interview-me",
|
|
138
|
+
triggers: [],
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
function renderTriggerLines(triggers) {
|
|
142
|
+
if (triggers.length === 0)
|
|
143
|
+
return [];
|
|
144
|
+
return ["", "Triggers:", ...triggers.map((trigger) => `- ${trigger}`)];
|
|
145
|
+
}
|
|
146
|
+
function renderSpecStart(workItem, options, registeredSkills) {
|
|
147
|
+
const route = classifySpecStart(options.request);
|
|
148
|
+
const requiredSkills = [...new Set([...options.requiredSkills, route.nextSkill])];
|
|
149
|
+
for (const skill of requiredSkills) {
|
|
150
|
+
registeredSkillPath(registeredSkills, skill);
|
|
151
|
+
}
|
|
152
|
+
const interviewPath = registeredSkillPath(registeredSkills, "interview-me");
|
|
153
|
+
const swarmPath = registeredSkillPath(registeredSkills, "spec-swarm");
|
|
154
|
+
if (route.kind === "interview-required") {
|
|
155
|
+
return [
|
|
156
|
+
`Product/spec work must pause for: ${workItem}`,
|
|
157
|
+
"",
|
|
158
|
+
`Routing: ${route.kind}`,
|
|
159
|
+
`Reason: ${route.reason}`,
|
|
160
|
+
...renderTriggerLines(route.triggers),
|
|
161
|
+
"",
|
|
162
|
+
`Next skill: ${route.nextSkill}`,
|
|
163
|
+
...renderCompanionLines(options.companions),
|
|
164
|
+
`Prompt: Use $${route.nextSkill} on this work item and request.${options.companions.length ? " Carry companion lenses forward only after productfoo captures the approved intake." : ""}`,
|
|
165
|
+
"Gate: Do not edit spec.md, tasks.yaml, or artifacts until the interview produces an approved intake summary.",
|
|
166
|
+
"",
|
|
167
|
+
].join("\n");
|
|
168
|
+
}
|
|
169
|
+
if (route.kind === "product-shape-interview-required") {
|
|
170
|
+
const shapePath = registeredSkillPath(registeredSkills, "product-shape-interview");
|
|
171
|
+
return [
|
|
172
|
+
`Product/spec work must shape the artifact first for: ${workItem}`,
|
|
173
|
+
"",
|
|
174
|
+
`Routing: ${route.kind}`,
|
|
175
|
+
`Reason: ${route.reason}`,
|
|
176
|
+
...renderTriggerLines(route.triggers),
|
|
177
|
+
"",
|
|
178
|
+
`Next skill: ${route.nextSkill} (${shapePath})`,
|
|
179
|
+
...renderCompanionLines(options.companions),
|
|
180
|
+
`Prompt: Use $product-shape-interview on the packet before generating the wired artifact.${options.companions.length ? " Carry companion lenses forward only after the Shape Brief." : ""}`,
|
|
181
|
+
"Boundary (B3): produce an approved Shape Brief before generating HTML, Build Previews, or scenario UI.",
|
|
182
|
+
"",
|
|
183
|
+
].join("\n");
|
|
184
|
+
}
|
|
185
|
+
return [
|
|
186
|
+
`Product/spec work must follow the full loop for: ${workItem}`,
|
|
187
|
+
"",
|
|
188
|
+
"Default caller: coding agent; users can state the work naturally and may run this manually when desired.",
|
|
189
|
+
"Signals: run `foo asp validate` after packet edits and `foo asp reconcile` after implementation-relevant changes; both surface findings into the ledger, they do not block.",
|
|
190
|
+
"",
|
|
191
|
+
`1. Interview: interview-me (${interviewPath})`,
|
|
192
|
+
" Prompt: Use $interview-me on this work item.",
|
|
193
|
+
" Boundary (B3): for irreversible, agentic, or outbound-facing work, do not draft or edit the spec before the interview produces an approved intake summary. For lighter work, `foo spec` is the faster reflex.",
|
|
194
|
+
"",
|
|
195
|
+
...renderCompanionLines(options.companions),
|
|
196
|
+
...(options.companions.length ? [""] : []),
|
|
197
|
+
`2. Expert swarm: spec-swarm (${swarmPath})`,
|
|
198
|
+
" Prompt: Use $spec-swarm on the approved intake summary or draft spec.",
|
|
199
|
+
" Signal: ask expert lenses and source artifacts before escalating questions to the user.",
|
|
200
|
+
"",
|
|
201
|
+
"3. Packet validation: foo asp validate <packet-dir>",
|
|
202
|
+
" Signal: spec.md, tasks.yaml, and events.jsonl structural validation; advisory. `foo self check` blocks only on B1 safety and B2 spec identity.",
|
|
203
|
+
"",
|
|
204
|
+
"4. Packet reconciliation: foo asp reconcile <packet-dir> --git-diff",
|
|
205
|
+
" Signal: changed work maps to agreed tasks or surfaces a human-visible finding.",
|
|
206
|
+
"",
|
|
207
|
+
options.companions.length
|
|
208
|
+
? "Next: run the interview now; carry the swarm packet forward before implementation, then invoke companion lenses only as advisory build/review pressure."
|
|
209
|
+
: "Next: run the interview now; carry the swarm packet forward before implementation.",
|
|
210
|
+
"",
|
|
211
|
+
].join("\n");
|
|
212
|
+
}
|
|
213
|
+
export function runSpecCommand(root, command, workItem, args) {
|
|
214
|
+
if (!command)
|
|
215
|
+
throw new UsageError("spec command missing", "E_COMMAND_MISSING");
|
|
216
|
+
if (command === "from") {
|
|
217
|
+
if (!workItem)
|
|
218
|
+
throw new UsageError("target missing — usage: foo spec from <what-you-built>", "E_SPEC_WORK_MISSING");
|
|
219
|
+
return runSpecFrom(root, workItem, args);
|
|
220
|
+
}
|
|
221
|
+
if (command === "nudge") {
|
|
222
|
+
return runSpecNudge(root);
|
|
223
|
+
}
|
|
224
|
+
// V0b (spec-after-capture T-007/T-008/T-009): review-only QA panel, attributed
|
|
225
|
+
// accept-as-known, and confirm-batch canonization into a reconcile-registered packet.
|
|
226
|
+
if (command === "panel" || command === "canonize") {
|
|
227
|
+
if (!workItem)
|
|
228
|
+
throw new UsageError(`target missing — usage: foo spec ${command} <what-you-built>`, "E_SPEC_WORK_MISSING");
|
|
229
|
+
// A revision beginning with "-" would be parsed by git as an option (audit
|
|
230
|
+
// F9) — `git diff --output=<path>` alone writes the diff to an arbitrary
|
|
231
|
+
// file. `--` cannot disambiguate here: inside `git diff` everything after
|
|
232
|
+
// `--` is a pathspec, so the guarded form silently yields an empty diff
|
|
233
|
+
// for every real revision. Refuse the shape instead.
|
|
234
|
+
if (workItem.startsWith("-"))
|
|
235
|
+
throw new UsageError(`revision must not begin with "-": ${workItem}`);
|
|
236
|
+
// Strip canonize-only flags before reusing the spec-from parser.
|
|
237
|
+
const passthrough = [];
|
|
238
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
239
|
+
if (args[i] === "--confirm-batch")
|
|
240
|
+
continue;
|
|
241
|
+
if (args[i] === "--packet" || args[i] === "--by") {
|
|
242
|
+
i += 1;
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
passthrough.push(args[i]);
|
|
246
|
+
}
|
|
247
|
+
const options = parseSpecFromArgs(passthrough);
|
|
248
|
+
const diff = gitRunOrNull(["-C", root, "diff", `${workItem}~1..${workItem}`]) ?? gitRunOrNull(["-C", root, "diff", workItem]) ?? "";
|
|
249
|
+
const report = runSpecAfter({ target: workItem, diff, consent: options.consent });
|
|
250
|
+
const panel = runQaPanel(report);
|
|
251
|
+
if (command === "panel") {
|
|
252
|
+
if (options.json)
|
|
253
|
+
return `${JSON.stringify(panel, null, 2)}\n`;
|
|
254
|
+
const lines = [`QA panel (review-only, fixed lens set: ${panel.lenses.join(", ")}):`];
|
|
255
|
+
for (const f of panel.findings)
|
|
256
|
+
lines.push(` ${f.id} [${f.lens}] ${f.severity === "hard-block" ? "HARD-BLOCK " : ""}${f.label}`);
|
|
257
|
+
if (!panel.findings.length)
|
|
258
|
+
lines.push(" (no findings)");
|
|
259
|
+
if (panel.security_blocked)
|
|
260
|
+
lines.push("Canonization is hard-blocked until a human accepts or resolves the security finding(s).");
|
|
261
|
+
return `${lines.join("\n")}\n`;
|
|
262
|
+
}
|
|
263
|
+
const packetName = flagValue(args, "--packet");
|
|
264
|
+
if (!packetName)
|
|
265
|
+
throw new UsageError("foo spec canonize needs --packet <name>", "E_BAD_FLAG");
|
|
266
|
+
const by = flagValue(args, "--by");
|
|
267
|
+
const result = canonizeSpecAfter(root, report, panel, {
|
|
268
|
+
packetName,
|
|
269
|
+
confirmBatch: args.includes("--confirm-batch"),
|
|
270
|
+
by,
|
|
271
|
+
at: new Date().toISOString(),
|
|
272
|
+
});
|
|
273
|
+
if (options.json)
|
|
274
|
+
return `${JSON.stringify({ schema_version: "0.1", ...result }, null, 2)}\n`;
|
|
275
|
+
if (!result.canonized) {
|
|
276
|
+
const lines = [`Not canonized: ${result.reason}`];
|
|
277
|
+
if (result.agree_batch.length) {
|
|
278
|
+
lines.push(`AGREE batch for human review (${result.agree_batch.length}):`);
|
|
279
|
+
for (const p of result.agree_batch)
|
|
280
|
+
lines.push(` ${p.intent_ref} ↔ ${p.behavior_ref}: ${p.label}`);
|
|
281
|
+
}
|
|
282
|
+
return `${lines.join("\n")}\n`;
|
|
283
|
+
}
|
|
284
|
+
return `Canonized ${result.agree_batch.length} confirmed AGREE pair(s) + ${report.drift.filter((d) => d.category !== "UNREVIEWED").length} carried drift item(s) into ${result.packetDir}.\nRegistered with the reconcile loop: foo asp reconcile ${packetName.includes("/") ? packetName : `specs/${packetName}`}\n`;
|
|
285
|
+
}
|
|
286
|
+
if (command === "patch") {
|
|
287
|
+
if (!workItem)
|
|
288
|
+
throw new UsageError("usage: foo spec patch <packet-dir> --correction <text> [--json]", "E_PACKET_DIR_MISSING");
|
|
289
|
+
const { packetDir } = resolvePacketDir(root, workItem);
|
|
290
|
+
const correction = flagValue(args, "--correction") ?? "";
|
|
291
|
+
const proposal = proposeSpecPatch(packetDir, correction);
|
|
292
|
+
if (args.includes("--json"))
|
|
293
|
+
return `${JSON.stringify(proposal, null, 2)}\n`;
|
|
294
|
+
return renderPatchProposal(proposal);
|
|
295
|
+
}
|
|
296
|
+
if (command === "accept") {
|
|
297
|
+
if (!workItem)
|
|
298
|
+
throw new UsageError("usage: foo spec accept <packet-dir> --finding <F-xxx> --lens <lens> --label <text> --by <who> --reason <why>", "E_PACKET_DIR_MISSING");
|
|
299
|
+
const { packetDir } = resolvePacketDir(root, workItem);
|
|
300
|
+
const finding = flagValue(args, "--finding");
|
|
301
|
+
const lens = flagValue(args, "--lens");
|
|
302
|
+
const label = flagValue(args, "--label") ?? "";
|
|
303
|
+
const by = flagValue(args, "--by") ?? "";
|
|
304
|
+
const reason = flagValue(args, "--reason") ?? "";
|
|
305
|
+
if (!finding || !lens)
|
|
306
|
+
throw new UsageError("foo spec accept needs --finding <F-xxx> and --lens <lens>", "E_BAD_FLAG");
|
|
307
|
+
acceptPanelFinding(packetDir, { finding_id: finding, lens, label, by, reason, at: new Date().toISOString() });
|
|
308
|
+
return `Accepted ${finding} as known (attributed to ${by}); recorded in the local event log at ${workItem}/events.jsonl.\n`;
|
|
309
|
+
}
|
|
310
|
+
if (command !== "start")
|
|
311
|
+
throw new UsageError(`unknown spec command: ${command}`, "E_BAD_FLAG");
|
|
312
|
+
if (!workItem)
|
|
313
|
+
throw new UsageError("work-item missing — usage: foo spec start <work-item> [--request <text>] [--packet <name>]", "E_SPEC_WORK_MISSING");
|
|
314
|
+
const options = parseSpecStartArgs(args);
|
|
315
|
+
const handoff = renderSpecStart(workItem, options, loadRegisteredSkills(root));
|
|
316
|
+
// Driver mode (asp-cli-lifecycle-v0 T-007): with --packet, spec start scaffolds
|
|
317
|
+
// the packet via the shared init path and records a work.started event, then
|
|
318
|
+
// prints the same routing handoff. The scaffold is an empty container — the
|
|
319
|
+
// interview still fills the spec, so the B3 gate in the handoff still holds.
|
|
320
|
+
if (!options.packetName)
|
|
321
|
+
return handoff;
|
|
322
|
+
const result = initPacket({ root, name: options.packetName });
|
|
323
|
+
const rel = path.relative(root, result.packetDir).split(path.sep).join("/");
|
|
324
|
+
const event = appendEvent({
|
|
325
|
+
packetDir: result.packetDir,
|
|
326
|
+
type: "com.adaptivespec.work.started",
|
|
327
|
+
subject: `packet:${result.specId}`,
|
|
328
|
+
data: { work_item: workItem, ...(options.request ? { request: options.request } : {}) },
|
|
329
|
+
});
|
|
330
|
+
return [
|
|
331
|
+
`Scaffolded packet: ${rel} (spec_id ${result.specId})`,
|
|
332
|
+
`Recorded work.started event: ${event.id}`,
|
|
333
|
+
"The scaffold is an empty container — the interview below fills the spec.",
|
|
334
|
+
"",
|
|
335
|
+
handoff,
|
|
336
|
+
].join("\n");
|
|
337
|
+
}
|
|
338
|
+
// reconcile-anywhere-v0 T-004: the `foo reconcile --adopt` write path. Composes
|
|
339
|
+
// the existing spec-after machinery — build a spec-after report from the
|
|
340
|
+
// recovered PR intent, run the review-only QA panel, then canonize into a packet
|
|
341
|
+
// that passes `foo asp validate`. This is the ONLY write path in the reconcile
|
|
342
|
+
// flow (D-002); the default run writes zero files. Adopt is the explicit human
|
|
343
|
+
// opt-in, so it confirms the batch on the human's behalf; a quarantined secret in
|
|
344
|
+
// the PR text still hard-blocks canonization until a human clears it.
|
|
345
|
+
export function adoptReconcileIntent(root, opts) {
|
|
346
|
+
const report = buildReconcileSpecAfterReport({
|
|
347
|
+
target: opts.target,
|
|
348
|
+
recovered: opts.recovered,
|
|
349
|
+
behavior: opts.behavior,
|
|
350
|
+
coverage: opts.coverage,
|
|
351
|
+
source: opts.target,
|
|
352
|
+
});
|
|
353
|
+
const panel = runQaPanel(report);
|
|
354
|
+
return canonizeSpecAfter(root, report, panel, {
|
|
355
|
+
packetName: opts.packetName,
|
|
356
|
+
confirmBatch: true,
|
|
357
|
+
by: opts.by,
|
|
358
|
+
at: new Date().toISOString(),
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
function parseRoastArgs(args) {
|
|
362
|
+
let mode = "auto";
|
|
363
|
+
const rest = [];
|
|
364
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
365
|
+
const arg = args[index];
|
|
366
|
+
if (arg === "--mode") {
|
|
367
|
+
const value = args[index + 1];
|
|
368
|
+
if (value !== "auto" && value !== "panel" && value !== "single") {
|
|
369
|
+
throw new UsageError("--mode must be auto, panel, or single", "E_BAD_FLAG");
|
|
370
|
+
}
|
|
371
|
+
mode = value;
|
|
372
|
+
index += 1;
|
|
373
|
+
continue;
|
|
374
|
+
}
|
|
375
|
+
if (arg === "--panel") {
|
|
376
|
+
mode = "panel";
|
|
377
|
+
continue;
|
|
378
|
+
}
|
|
379
|
+
if (arg === "--single") {
|
|
380
|
+
mode = "single";
|
|
381
|
+
continue;
|
|
382
|
+
}
|
|
383
|
+
rest.push(arg);
|
|
384
|
+
}
|
|
385
|
+
const artifact = rest.join(" ").trim();
|
|
386
|
+
if (!artifact)
|
|
387
|
+
throw new UsageError("artifact missing — usage: foo roast <artifact> [--mode auto|panel|single]", "E_BAD_FLAG");
|
|
388
|
+
return { artifact, mode };
|
|
389
|
+
}
|
|
390
|
+
const WORKFLOW_LANES = ["direct", "shape-fast", "review-targeted", "deep-explicit"];
|
|
391
|
+
function parseShapeArgs(args) {
|
|
392
|
+
let work;
|
|
393
|
+
let request;
|
|
394
|
+
let explicitLane;
|
|
395
|
+
const companions = new Set();
|
|
396
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
397
|
+
const arg = args[index];
|
|
398
|
+
if (arg === "--request") {
|
|
399
|
+
request = args[index + 1];
|
|
400
|
+
index += 1;
|
|
401
|
+
}
|
|
402
|
+
else if (arg === "--companion") {
|
|
403
|
+
companions.add(parseCompanionLens(args[index + 1]));
|
|
404
|
+
index += 1;
|
|
405
|
+
}
|
|
406
|
+
else if (arg === "--ponytail") {
|
|
407
|
+
companions.add("ponytail");
|
|
408
|
+
}
|
|
409
|
+
else if (arg === "--lane") {
|
|
410
|
+
const value = args[index + 1];
|
|
411
|
+
if (!value)
|
|
412
|
+
throw new UsageError("--lane requires a value", "E_BAD_FLAG");
|
|
413
|
+
if (!WORKFLOW_LANES.includes(value)) {
|
|
414
|
+
throw new UsageError("--lane must be direct, shape-fast, review-targeted, or deep-explicit", "E_BAD_FLAG");
|
|
415
|
+
}
|
|
416
|
+
if (explicitLane)
|
|
417
|
+
throw new UsageError("--lane may be provided only once", "E_BAD_FLAG");
|
|
418
|
+
explicitLane = value;
|
|
419
|
+
index += 1;
|
|
420
|
+
}
|
|
421
|
+
else if (arg === "--source" || arg === "--source-fixture") {
|
|
422
|
+
// Consumed by resolveLinearSeed; skip the flag and its value here.
|
|
423
|
+
index += 1;
|
|
424
|
+
}
|
|
425
|
+
else if (!work) {
|
|
426
|
+
work = arg;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
if (!work)
|
|
430
|
+
throw new UsageError("work missing — usage: foo spec <work> [--request <text>] [--companion ponytail]", "E_SPEC_WORK_MISSING");
|
|
431
|
+
return { work, request, companions: [...companions], explicitLane };
|
|
432
|
+
}
|
|
433
|
+
// foo spec (bare, no subcommand) is the frictionless spec-first reflex: a ~30-second shape brief
|
|
434
|
+
// that beats improvising. It routes to a fast interview (<=3 questions) and
|
|
435
|
+
// names the next handoff, so spec-first wins on speed, not on enforcement.
|
|
436
|
+
// Resolve an optional `--source linear:<url>` selector into a shape seed. V0 has
|
|
437
|
+
// no live MCP, so the issue/project payload is supplied via `--source-fixture
|
|
438
|
+
// <file>` (the runtime would hand it in the same way). Returns null when no
|
|
439
|
+
// --source is present; throws an actionable error when the payload is missing
|
|
440
|
+
// (errors-as-DX) rather than silently inventing a seed.
|
|
441
|
+
function resolveLinearSeed(root, args) {
|
|
442
|
+
const source = flagValue(args, "--source");
|
|
443
|
+
if (!source)
|
|
444
|
+
return null;
|
|
445
|
+
if (!source.startsWith("linear:")) {
|
|
446
|
+
throw new UsageError(`--source '${source}' is not supported; V0 admits only linear:<issue-or-project-url>`, "E_BAD_FLAG");
|
|
447
|
+
}
|
|
448
|
+
const selection = parseLinearSource(source);
|
|
449
|
+
const fixturePath = flagValue(args, "--source-fixture");
|
|
450
|
+
if (!fixturePath) {
|
|
451
|
+
// A missing fixture is the caller not supplying an input foo asked for. Guidance, not a bug.
|
|
452
|
+
throw new UsageError(`no Linear payload available for ${selection.url}. V0 has no live Linear MCP — supply the issue/project payload with --source-fixture <file.json>, then re-run.`, "E_BAD_FLAG");
|
|
453
|
+
}
|
|
454
|
+
let payload;
|
|
455
|
+
try {
|
|
456
|
+
payload = readJson(path.resolve(root, fixturePath));
|
|
457
|
+
}
|
|
458
|
+
catch {
|
|
459
|
+
throw new UsageError(`--source-fixture is not readable JSON: ${fixturePath}`, "E_BAD_FLAG");
|
|
460
|
+
}
|
|
461
|
+
const candidate = buildLinearCandidate(selection, payload);
|
|
462
|
+
return { requestLine: `From Linear ${selection.unit} ${selection.external_id}: ${candidate.intent}`, candidate };
|
|
463
|
+
}
|
|
464
|
+
async function resolveShapeSkillAdapter(root, name, options) {
|
|
465
|
+
const packageRoot = options.packageRoot ?? ROOT;
|
|
466
|
+
if (existsSync(path.join(packageRoot, "skills", "skill-registry.yaml"))) {
|
|
467
|
+
return registeredSkillPath(loadRegisteredSkills(root), name);
|
|
468
|
+
}
|
|
469
|
+
throw new SkillDeliveryError("unapproved-source", `Bundled skill registry is missing. Rebuild or reinstall productfoo before loading "${name}".`);
|
|
470
|
+
}
|
|
471
|
+
async function shapeRunContext(root, args, skillOptions) {
|
|
472
|
+
const { work, request, companions, explicitLane } = parseShapeArgs(args);
|
|
473
|
+
// Optional --source linear:<url> selector (linear_integration_v0 R-002): a
|
|
474
|
+
// Linear issue/project seeds the shape request. No new command, +1 concept.
|
|
475
|
+
const seed = resolveLinearSeed(root, args);
|
|
476
|
+
const effectiveRequest = seed ? (request ? `${request}\n\n${seed.requestLine}` : seed.requestLine) : request;
|
|
477
|
+
const classification = classifyWork(effectiveRequest ? `${work} ${effectiveRequest}` : work);
|
|
478
|
+
const routedWork = effectiveRequest ? `${work} ${effectiveRequest}` : work;
|
|
479
|
+
const workflow = resolveWorkflowLane(loadRoutingPolicy(ROOT), {
|
|
480
|
+
work: routedWork,
|
|
481
|
+
explicitLane,
|
|
482
|
+
risk: classification,
|
|
483
|
+
researchRequested: researchRequestTopic(routedWork) !== null,
|
|
484
|
+
});
|
|
485
|
+
const interviewPath = workflow.lane === "shape-fast" && workflow.required_capability !== "research"
|
|
486
|
+
? await resolveShapeSkillAdapter(root, "interview-me", skillOptions)
|
|
487
|
+
: null;
|
|
488
|
+
return { work, companions, interviewPath, seed, effectiveRequest, classification, workflow };
|
|
489
|
+
}
|
|
490
|
+
function renderShapeAgentContext(context, glyphsOn) {
|
|
491
|
+
const { work, companions, interviewPath, seed, effectiveRequest, classification, workflow } = context;
|
|
492
|
+
const common = [
|
|
493
|
+
"Use this run context. It is agent-only; do not relay it verbatim:",
|
|
494
|
+
`Work: ${work}`,
|
|
495
|
+
"",
|
|
496
|
+
"Capability: foo spec (frictionless spec-first reflex)",
|
|
497
|
+
`Workflow lane: ${workflow.lane}`,
|
|
498
|
+
`Recommended lane: ${workflow.recommended_lane}`,
|
|
499
|
+
`Route reason: ${workflow.reason}`,
|
|
500
|
+
`Route signals: ${workflow.signals.length > 0 ? workflow.signals.join(", ") : "none"}`,
|
|
501
|
+
`Route confidence: ${workflow.confidence}; deterministic routing model calls: ${workflow.routing_model_calls}`,
|
|
502
|
+
effectiveRequest ? `Request: ${effectiveRequest}` : "Request: (none provided)",
|
|
503
|
+
...renderCompanionLines(companions),
|
|
504
|
+
...(seed ? [`Source: Linear ${seed.candidate.source_id.external_id} (${seed.candidate.url}) — approved-private-context, verify against repo-truth before it becomes a requirement.`] : []),
|
|
505
|
+
withGlyph("classification", `Risk: ${classification.risky ? "risky" : "routine"} — ${classification.rationale}`, glyphsOn),
|
|
506
|
+
...(workflow.limitation ? [
|
|
507
|
+
`Limitation: ${workflow.limitation}.`,
|
|
508
|
+
"Do not silently substitute the historical six-lens fast swarm or a fixed first-N panel.",
|
|
509
|
+
] : []),
|
|
510
|
+
"",
|
|
511
|
+
];
|
|
512
|
+
if (workflow.required_capability === "research") {
|
|
513
|
+
return [
|
|
514
|
+
...common,
|
|
515
|
+
"Boundary (B5): explicit research runs through productfoo's governed research front door. Do not implement or interview.",
|
|
516
|
+
`Next: run \`foo research ${JSON.stringify(work)}\` and follow its trust and approval boundaries.`,
|
|
517
|
+
"",
|
|
518
|
+
].join("\n");
|
|
519
|
+
}
|
|
520
|
+
if (workflow.lane === "direct") {
|
|
521
|
+
return [
|
|
522
|
+
...common,
|
|
523
|
+
"Prompt: Continue in the current coding agent. Read the repository, implement the requested change, and verify it in proportion to risk.",
|
|
524
|
+
"Do not run an interview, swarm, panel, or routing-model call. Do not create a subagent merely to confirm this route.",
|
|
525
|
+
"Run the repository's tests and all applicable deterministic checks: safety scan/redaction, packet validation/reconciliation for packet-tied work, and productfoo self-checks when changing productfoo itself.",
|
|
526
|
+
"Preserve B1-B5, source approval, branch discipline, and explicit user control.",
|
|
527
|
+
"",
|
|
528
|
+
`Next: implement ${work} in the current agent, then report the result, evidence, dissent, and exact next action.`,
|
|
529
|
+
"",
|
|
530
|
+
].join("\n");
|
|
531
|
+
}
|
|
532
|
+
if (workflow.lane === "review-targeted") {
|
|
533
|
+
return [
|
|
534
|
+
...common,
|
|
535
|
+
`Limitation: ${workflow.limitation ?? "the bounded targeted adapter is unavailable"}.`,
|
|
536
|
+
"Do not silently substitute the historical six-lens fast swarm or a fixed first-N panel.",
|
|
537
|
+
`Next: pause this lane; use \`foo spec ${work} --lane shape-fast\` for bounded shaping, or choose deep-explicit deliberately.`,
|
|
538
|
+
"",
|
|
539
|
+
].join("\n");
|
|
540
|
+
}
|
|
541
|
+
if (workflow.lane === "deep-explicit") {
|
|
542
|
+
return [
|
|
543
|
+
...common,
|
|
544
|
+
"Prompt: Run the governed full spec loop explicitly. Preserve B1-B5, obtain any required autonomy budget, and keep exhaustive work opt-in.",
|
|
545
|
+
`Next: run \`foo spec start ${work}\` and follow its interview, targeted review, packet validation, and approval boundaries.`,
|
|
546
|
+
"",
|
|
547
|
+
].join("\n");
|
|
548
|
+
}
|
|
549
|
+
return [
|
|
550
|
+
...common,
|
|
551
|
+
`Skill adapter: interview-me (${interviewPath})`,
|
|
552
|
+
"Depth: fast interview — at most 3 stack-ranked questions.",
|
|
553
|
+
`Prompt: Use $interview-me in fast mode on ${work}; ask at most 3 stack-ranked questions, then emit a Shape Brief.${companions.length ? " Carry companion lenses forward as optional build/review pressure after the Shape Brief." : ""}`,
|
|
554
|
+
"",
|
|
555
|
+
"The Shape Brief must return:",
|
|
556
|
+
"1. The work in one line",
|
|
557
|
+
"2. The product bet and who it is for",
|
|
558
|
+
"3. Source and approval boundaries",
|
|
559
|
+
"4. MVP scope and the validation bar",
|
|
560
|
+
"5. Judgment ledger seed: belief, confidence, dissent, user-only decisions",
|
|
561
|
+
"",
|
|
562
|
+
"Packet handoff: a plain open question is a deferred note, never an urgent request. Use `State: needs-decision` only when active work cannot continue without a person, and copy the scaffold's complete decision block.",
|
|
563
|
+
"",
|
|
564
|
+
classification.spec_first_required
|
|
565
|
+
? withGlyph("needs_input", "Boundary (B3): this work is risky — escalate to `foo spec start` before build.", glyphsOn)
|
|
566
|
+
: "Signal: this work is routine — spec-first stays advisory; surface findings, do not block.",
|
|
567
|
+
`Next: carry the Shape Brief into build, or run \`foo spec start ${work}\` if the scope is deep.`,
|
|
568
|
+
"",
|
|
569
|
+
].join("\n");
|
|
570
|
+
}
|
|
571
|
+
function inlineCode(value) {
|
|
572
|
+
const oneLine = value.replace(/\s+/g, " ").trim();
|
|
573
|
+
const longestRun = Math.max(0, ...[...oneLine.matchAll(/`+/g)].map((match) => match[0].length));
|
|
574
|
+
const delimiter = "`".repeat(longestRun + 1);
|
|
575
|
+
const padding = oneLine.startsWith("`") || oneLine.endsWith("`") ? " " : "";
|
|
576
|
+
return `${delimiter}${padding}${oneLine}${padding}${delimiter}`;
|
|
577
|
+
}
|
|
578
|
+
export async function runShapeCommandWithHandoff(root, args, glyphsOn, skillOptions = {}) {
|
|
579
|
+
const context = await shapeRunContext(root, args, skillOptions);
|
|
580
|
+
const { work, classification, workflow } = context;
|
|
581
|
+
const output = workflow.required_capability === "research"
|
|
582
|
+
? [
|
|
583
|
+
`Research route prepared for: ${inlineCode(work)}`,
|
|
584
|
+
"",
|
|
585
|
+
`Lane: shape-fast — ${workflow.reason}`,
|
|
586
|
+
"B5 applies: research runs through productfoo's governed research path.",
|
|
587
|
+
"",
|
|
588
|
+
"Next: continue with governed research in your coding assistant.",
|
|
589
|
+
"",
|
|
590
|
+
].join("\n")
|
|
591
|
+
: workflow.lane === "direct"
|
|
592
|
+
? [
|
|
593
|
+
`Ready to build: ${inlineCode(work)}`,
|
|
594
|
+
"",
|
|
595
|
+
`Lane: direct — ${workflow.reason}`,
|
|
596
|
+
"This stays in your current coding agent; no extra model call is needed.",
|
|
597
|
+
"",
|
|
598
|
+
"Next: continue with the implementation in your coding assistant.",
|
|
599
|
+
"",
|
|
600
|
+
].join("\n")
|
|
601
|
+
: workflow.lane === "review-targeted"
|
|
602
|
+
? [
|
|
603
|
+
`Review route prepared for: ${inlineCode(work)}`,
|
|
604
|
+
"",
|
|
605
|
+
`Lane: review-targeted — ${workflow.reason}`,
|
|
606
|
+
`This route is not executable yet: ${workflow.limitation ?? "the bounded targeted adapter is unavailable"}.`,
|
|
607
|
+
"",
|
|
608
|
+
"Next: use shape-fast for bounded clarification, or choose deep-explicit deliberately.",
|
|
609
|
+
"",
|
|
610
|
+
].join("\n")
|
|
611
|
+
: workflow.lane === "deep-explicit"
|
|
612
|
+
? [
|
|
613
|
+
`Deep route prepared for: ${inlineCode(work)}`,
|
|
614
|
+
"",
|
|
615
|
+
`Lane: deep-explicit — ${workflow.reason}`,
|
|
616
|
+
"This runs only by explicit choice and keeps every safety and approval boundary.",
|
|
617
|
+
"",
|
|
618
|
+
"Next: continue with the governed full spec loop in your coding assistant.",
|
|
619
|
+
"",
|
|
620
|
+
].join("\n")
|
|
621
|
+
: [
|
|
622
|
+
`Ready to plan: ${inlineCode(work)}`,
|
|
623
|
+
"",
|
|
624
|
+
`Lane: shape-fast — ${workflow.reason}`,
|
|
625
|
+
...(workflow.limitation ? [`Targeted execution is unavailable: ${workflow.limitation}.`] : []),
|
|
626
|
+
"I’ll read the project first, then ask up to 3 questions only where the answer depends on you.",
|
|
627
|
+
classification.spec_first_required
|
|
628
|
+
? "This could be hard to reverse, act on its own, or affect people outside the project. Agree on the plan before building."
|
|
629
|
+
: "This looks safe to plan quickly.",
|
|
630
|
+
"",
|
|
631
|
+
"Next: continue with the first question in your coding assistant.",
|
|
632
|
+
"",
|
|
633
|
+
].join("\n");
|
|
634
|
+
return {
|
|
635
|
+
output: guardHumanSurface(output),
|
|
636
|
+
handoffSteps: [renderShapeAgentContext(context, glyphsOn)],
|
|
637
|
+
};
|
|
638
|
+
}
|
|
639
|
+
export async function runShapeCommand(root, args, glyphsOn) {
|
|
640
|
+
return (await runShapeCommandWithHandoff(root, args, glyphsOn)).output;
|
|
641
|
+
}
|
|
642
|
+
function parseClassifyArgs(args) {
|
|
643
|
+
let work;
|
|
644
|
+
let override;
|
|
645
|
+
let asJson = false;
|
|
646
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
647
|
+
const arg = args[index];
|
|
648
|
+
if (arg === "--json") {
|
|
649
|
+
asJson = true;
|
|
650
|
+
}
|
|
651
|
+
else if (arg === "--strict") {
|
|
652
|
+
// Consumed by the caller; named here so it is never mistaken for the work text.
|
|
653
|
+
}
|
|
654
|
+
else if (arg === "--override") {
|
|
655
|
+
override = args[index + 1];
|
|
656
|
+
index += 1;
|
|
657
|
+
}
|
|
658
|
+
else if (!work) {
|
|
659
|
+
work = arg;
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
if (!work)
|
|
663
|
+
throw new UsageError("work missing — usage: foo classify \"<work>\"", "E_BAD_FLAG");
|
|
664
|
+
return { work, override, asJson };
|
|
665
|
+
}
|
|
666
|
+
export function runClassifyCommand(args, glyphsOn) {
|
|
667
|
+
const { work, override, asJson } = parseClassifyArgs(args);
|
|
668
|
+
// --strict blocks on any keyword hit — the behaviour before the governing-frame
|
|
669
|
+
// downgrade existed. Kept so a caller who wants the blunt instrument can have it.
|
|
670
|
+
const strict = args.includes("--strict") || process.env.FOO_CLASSIFY_STRICT === "1";
|
|
671
|
+
return renderClassification(classifyWork(work, override, { strict }), asJson, glyphsOn);
|
|
672
|
+
}
|
|
673
|
+
export async function runRoastCommand(root, args) {
|
|
674
|
+
let roastPath;
|
|
675
|
+
if (existsSync(path.join(ROOT, "skills", "skill-registry.yaml"))) {
|
|
676
|
+
const registeredSkills = loadRegisteredSkills(root);
|
|
677
|
+
roastPath = registeredSkillPath(registeredSkills, "foo-roast");
|
|
678
|
+
}
|
|
679
|
+
else {
|
|
680
|
+
throw new SkillDeliveryError("unapproved-source", "Bundled skill registry is missing. Rebuild or reinstall productfoo before running roast.");
|
|
681
|
+
}
|
|
682
|
+
const { artifact, mode } = parseRoastArgs(args);
|
|
683
|
+
const panelLine = mode === "auto" ? "auto (panel for meaningful product work; single for tiny prompts)" : mode;
|
|
684
|
+
return [
|
|
685
|
+
`Product roast must run for: ${artifact}`,
|
|
686
|
+
"",
|
|
687
|
+
"Capability: foo roast",
|
|
688
|
+
`Skill adapter: foo-roast (${roastPath})`,
|
|
689
|
+
`Panel: ${panelLine}`,
|
|
690
|
+
"",
|
|
691
|
+
`Prompt: Use $foo-roast on ${artifact}`,
|
|
692
|
+
"",
|
|
693
|
+
"Five moves:",
|
|
694
|
+
"1. Core Job",
|
|
695
|
+
"2. Subtract",
|
|
696
|
+
"3. Consequences",
|
|
697
|
+
"4. Guardrails",
|
|
698
|
+
"5. Candidate evals",
|
|
699
|
+
"",
|
|
700
|
+
"The roast must return:",
|
|
701
|
+
"1. What this is trying to become",
|
|
702
|
+
"2. Take away",
|
|
703
|
+
"3. Preserve",
|
|
704
|
+
"4. Consequence map",
|
|
705
|
+
"5. Do not ask the coding agent to",
|
|
706
|
+
"6. Candidate evals",
|
|
707
|
+
"7. Panel dissent",
|
|
708
|
+
"8. Next prompt",
|
|
709
|
+
"",
|
|
710
|
+
"Signal: run this before the next generation so cuts, guardrails, and evals shape the next prompt.",
|
|
711
|
+
"Next: fold the cuts and guardrails into your next prompt, then `foo spec` the revised work.",
|
|
712
|
+
"",
|
|
713
|
+
].join("\n");
|
|
714
|
+
}
|
|
715
|
+
export async function runPreviewCommand(root, packetArg) {
|
|
716
|
+
const registeredSkills = loadRegisteredSkills(root);
|
|
717
|
+
const previewPath = registeredSkillPath(registeredSkills, "preview-swarm");
|
|
718
|
+
if (!packetArg)
|
|
719
|
+
throw new UsageError("packet-dir missing — usage: foo preview <packet-dir>", "E_PACKET_DIR_MISSING");
|
|
720
|
+
const packet = resolvePacketDir(root, packetArg);
|
|
721
|
+
const pending = findUnrepresentedUserCorrections(packet.packetDir);
|
|
722
|
+
if (pending.length > 0) {
|
|
723
|
+
const proposals = pending.map(({ summary }) => renderPatchProposal(proposeSpecPatch(packet.packetDir, summary)).trimEnd());
|
|
724
|
+
throw new GateBlock([
|
|
725
|
+
`drift — ${pending.length} accepted user correction${pending.length === 1 ? " is" : "s are"} missing from ${packet.packetArg}.`,
|
|
726
|
+
"Preview did not run. Review and apply the proposal before retrying.",
|
|
727
|
+
"",
|
|
728
|
+
...proposals.flatMap((proposal, index) => (index === 0 ? [proposal] : ["", proposal])),
|
|
729
|
+
"",
|
|
730
|
+
`Then run: foo asp validate ${packet.packetArg}`,
|
|
731
|
+
`Retry: foo preview ${packet.packetArg}`,
|
|
732
|
+
].join("\n"), "E_CONTRACT_DRIFT");
|
|
733
|
+
}
|
|
734
|
+
const artifactTarget = path.join(packet.packetArg, "artifacts", "previews", "<run-id>", "preview.html");
|
|
735
|
+
const cost = await costHeadline(root, packet.packetDir);
|
|
736
|
+
return [
|
|
737
|
+
`Build Preview must run for: ${packet.packetArg}`,
|
|
738
|
+
"",
|
|
739
|
+
"Capability: foo preview",
|
|
740
|
+
`Skill adapter: preview-swarm (${previewPath})`,
|
|
741
|
+
"",
|
|
742
|
+
`Prompt: Use $preview-swarm on ${packet.packetArg}`,
|
|
743
|
+
`Artifact target: ${artifactTarget}`,
|
|
744
|
+
"",
|
|
745
|
+
"Signal: run the Impeccable collaboration contract before marking the Build Preview complete; record a manual-review gap if Impeccable is unavailable.",
|
|
746
|
+
// Cost, where the decision actually is (spec-budget-v0 R-010). A preview is the
|
|
747
|
+
// "what am I about to pay for" moment, so the number belongs here rather than
|
|
748
|
+
// behind a verb nobody remembers to type. Structural only — never egresses —
|
|
749
|
+
// and silently absent if it cannot be computed honestly.
|
|
750
|
+
...(cost ? ["", `Cost: ${cost}`] : []),
|
|
751
|
+
"",
|
|
752
|
+
].join("\n");
|
|
753
|
+
}
|
|
754
|
+
// A small built-in question to demonstrate the canonical text rendering via
|
|
755
|
+
// `foo elicitation render`. Intentionally meta: the surface choice itself.
|
|
756
|
+
const EXAMPLE_QUESTION = {
|
|
757
|
+
header: "Surface",
|
|
758
|
+
prompt: "Which surface should productfoo use to ask this question?",
|
|
759
|
+
options: [
|
|
760
|
+
{ id: "widget", label: "Branded widget", description: "Full productfoo visual identity; needs a widget-capable TTY runtime." },
|
|
761
|
+
{ id: "text", label: "Numbered text", description: "The guaranteed fallback; every runtime and the agent reader can read it." },
|
|
762
|
+
],
|
|
763
|
+
recommendedOptionId: "text",
|
|
764
|
+
judgment: {
|
|
765
|
+
belief: "Text is the safe default; the widget is the earned exception.",
|
|
766
|
+
evidence: "R-004 — never render a widget into a piped or agent-read stream.",
|
|
767
|
+
confidence: "high",
|
|
768
|
+
},
|
|
769
|
+
};
|
|
770
|
+
// `foo elicitation surface` reports the resolved surface; `foo elicitation render` shows
|
|
771
|
+
// the canonical numbered-text rendering of an example question (T-001/T-003,
|
|
772
|
+
// specs/foo-branded-elicitation-v0). The default surface is text; the branded widget is
|
|
773
|
+
// the earned exception, and a piped/non-TTY context always reads as text.
|
|
774
|
+
export function runElicitationCommand(command, args) {
|
|
775
|
+
if (command === "surface") {
|
|
776
|
+
const decision = detectElicitationSurface();
|
|
777
|
+
if (args.includes("--json")) {
|
|
778
|
+
return `${JSON.stringify(decision, null, 2)}\n`;
|
|
779
|
+
}
|
|
780
|
+
return [
|
|
781
|
+
`Elicitation surface: ${decision.surface}`,
|
|
782
|
+
`Runtime: ${decision.runtime}`,
|
|
783
|
+
`Reason: ${decision.reason}`,
|
|
784
|
+
"",
|
|
785
|
+
].join("\n");
|
|
786
|
+
}
|
|
787
|
+
if (command === "render") {
|
|
788
|
+
return renderQuestion(defineQuestion(EXAMPLE_QUESTION)).text;
|
|
789
|
+
}
|
|
790
|
+
throw new UsageError(`unknown elicitation command: ${command ?? "(none)"}. Try: foo elicitation surface | render`, "E_BAD_FLAG");
|
|
791
|
+
}
|
|
792
|
+
// `foo learn`'s static screen was deleted when learn collapsed into `foo init`
|
|
793
|
+
// (cli-first-run-v0 D-011/R-013): one door, one first-run corpus. The alias
|
|
794
|
+
// dispatch lives in cli.ts; the orientation strings live in initCommand.ts.
|