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,558 @@
|
|
|
1
|
+
import { mkdirSync, writeFileSync, existsSync } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { gatherRepoSignals, generateMoves, rankMoves } from "./repoRead.js";
|
|
4
|
+
import { detectTensions } from "./firstMoveTensions.js";
|
|
5
|
+
import { updateTask } from "./packetWrite.js";
|
|
6
|
+
import { gitRunOrNull } from "./gitRun.js";
|
|
7
|
+
import { readFileSync, readdirSync } from "node:fs";
|
|
8
|
+
import { loadProfile, PRODUCT_VIEW_ROLES, profileHarnesses, runFirstRunSurvey, saveProfile, reportProfile } from "./profile.js";
|
|
9
|
+
import { readPackageVersion } from "./commands/shared.js";
|
|
10
|
+
import { decisionRequestAuthoringComment } from "./specSections.js";
|
|
11
|
+
// foo init — the language-free first read. It reads what the developer already
|
|
12
|
+
// has, hands back a recommended first move plus options in plain English (a
|
|
13
|
+
// number or prose both work), and teaches productfoo's words in context as it goes.
|
|
14
|
+
// Picking a move scaffolds a real spec packet underneath — the user never has
|
|
15
|
+
// to type a foo verb to get the contract.
|
|
16
|
+
//
|
|
17
|
+
// It is also productfoo's orientation surface (cli-first-run-v0 R-013/D-011): the
|
|
18
|
+
// first-ever run in a repo opens with two plain lines, then goes quiet forever;
|
|
19
|
+
// a run outside a repo tells the short story instead of erroring. `foo learn`
|
|
20
|
+
// is a hidden alias for this command (dispatched in cli.ts).
|
|
21
|
+
// The first-run strings, exported as the eval corpus (R-007a): the language
|
|
22
|
+
// tests scan exactly these constants, so a wording change can't dodge the eval.
|
|
23
|
+
// T-006's render chokepoint should absorb these when it lands.
|
|
24
|
+
export const FIRST_RUN_OPENER = [
|
|
25
|
+
"productfoo helps you agree on work before building, and prove it when it's done.",
|
|
26
|
+
"It starts by reading what's already in your project.",
|
|
27
|
+
];
|
|
28
|
+
export const NO_REPO_STORY = [
|
|
29
|
+
"productfoo — agree on work before building, prove it when it's done.",
|
|
30
|
+
"",
|
|
31
|
+
"The loop is short: say what you want to build, productfoo turns it into an",
|
|
32
|
+
"agreed plan in writing, and when the work ships you attach proof so",
|
|
33
|
+
"anyone can see it's really done — not just claimed done.",
|
|
34
|
+
"",
|
|
35
|
+
"This folder isn't a project yet, so there's nothing to read here.",
|
|
36
|
+
"",
|
|
37
|
+
"Next: cd into a project and run `foo init` again.",
|
|
38
|
+
];
|
|
39
|
+
function isGitRepo(root) {
|
|
40
|
+
return gitRunOrNull(["rev-parse", "--is-inside-work-tree"], { cwd: root, stdio: ["ignore", "pipe", "ignore"] }) !== null;
|
|
41
|
+
}
|
|
42
|
+
// The once-ever marker lives in gitignored local state (.foo/), so the opener
|
|
43
|
+
// never renders twice on the same checkout and never ships in a commit.
|
|
44
|
+
function firstRunMarkerPath(root) {
|
|
45
|
+
return path.join(root, ".foo", "first-run");
|
|
46
|
+
}
|
|
47
|
+
function hasSeenFirstRun(root) {
|
|
48
|
+
return existsSync(firstRunMarkerPath(root));
|
|
49
|
+
}
|
|
50
|
+
function markFirstRunSeen(root) {
|
|
51
|
+
const marker = firstRunMarkerPath(root);
|
|
52
|
+
mkdirSync(path.dirname(marker), { recursive: true });
|
|
53
|
+
writeFileSync(marker, `${new Date().toISOString()}\n`);
|
|
54
|
+
}
|
|
55
|
+
function plainRead(signals) {
|
|
56
|
+
const parts = [];
|
|
57
|
+
parts.push(signals.languages.length ? `a ${signals.languages.slice(0, 2).join("/")} project` : "a project");
|
|
58
|
+
parts.push(`${signals.sourceFileCount} source file${signals.sourceFileCount === 1 ? "" : "s"}`);
|
|
59
|
+
parts.push(signals.hasTests ? "tests present" : "no tests");
|
|
60
|
+
parts.push(signals.hasCI ? "CI set up" : "no CI");
|
|
61
|
+
if (signals.readmeBytes === 0)
|
|
62
|
+
parts.push("no README");
|
|
63
|
+
else if (signals.readmeBytes < 400)
|
|
64
|
+
parts.push("a thin README");
|
|
65
|
+
return parts.join(", ");
|
|
66
|
+
}
|
|
67
|
+
function slugify(text) {
|
|
68
|
+
return text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40) || "first-move";
|
|
69
|
+
}
|
|
70
|
+
// Scaffold a minimal, structurally valid spec packet from a chosen move. This is
|
|
71
|
+
// the "packet created invisibly" — the durable foo contract appears without the
|
|
72
|
+
// user naming it.
|
|
73
|
+
export function scaffoldPacket(root, title, evidence, intent) {
|
|
74
|
+
const slug = slugify(title);
|
|
75
|
+
const specId = `${slug.replace(/-/g, "_")}_v0`;
|
|
76
|
+
const packetDir = path.join(root, "specs", `${slug}-v0`);
|
|
77
|
+
mkdirSync(packetDir, { recursive: true });
|
|
78
|
+
const now = new Date().toISOString();
|
|
79
|
+
const ev = evidence.length ? evidence.join("; ") : "captured from foo init";
|
|
80
|
+
const spec = [
|
|
81
|
+
"---",
|
|
82
|
+
`spec_id: ${specId}`,
|
|
83
|
+
`title: ${JSON.stringify(title)}`,
|
|
84
|
+
"mode: capability",
|
|
85
|
+
"lifecycle: draft",
|
|
86
|
+
"stage: shaping",
|
|
87
|
+
"owner: product",
|
|
88
|
+
"autonomy: human-in-loop",
|
|
89
|
+
`updated: ${now}`,
|
|
90
|
+
"---",
|
|
91
|
+
"",
|
|
92
|
+
`# ${title}`,
|
|
93
|
+
"",
|
|
94
|
+
"## Intent",
|
|
95
|
+
"",
|
|
96
|
+
`${title}. ${intent}`.trim(),
|
|
97
|
+
"",
|
|
98
|
+
"## Current Understanding",
|
|
99
|
+
"",
|
|
100
|
+
`Started by foo init from a repo read. Evidence: ${ev}.`,
|
|
101
|
+
"",
|
|
102
|
+
"## Requirements",
|
|
103
|
+
"",
|
|
104
|
+
`- R-001 (must): ${title}.`,
|
|
105
|
+
"",
|
|
106
|
+
"## Decisions",
|
|
107
|
+
"",
|
|
108
|
+
"- Started from the foo init recommendation; scope to be confirmed in shaping.",
|
|
109
|
+
"",
|
|
110
|
+
"## Risks",
|
|
111
|
+
"",
|
|
112
|
+
"- Scope is unconfirmed — shape before building.",
|
|
113
|
+
"",
|
|
114
|
+
"## Validation",
|
|
115
|
+
"",
|
|
116
|
+
"- inspection: the plan reads back cleanly once shaped.",
|
|
117
|
+
"",
|
|
118
|
+
"## Evidence",
|
|
119
|
+
"",
|
|
120
|
+
`- foo init repo read: ${ev}.`,
|
|
121
|
+
"",
|
|
122
|
+
"## Open Questions",
|
|
123
|
+
"",
|
|
124
|
+
decisionRequestAuthoringComment(),
|
|
125
|
+
"",
|
|
126
|
+
].join("\n");
|
|
127
|
+
const tasks = [
|
|
128
|
+
'schema_version: "0.1"',
|
|
129
|
+
`spec_id: ${specId}`,
|
|
130
|
+
`spec_ref: specs/${slug}-v0/spec.md`,
|
|
131
|
+
`updated: "${now}"`,
|
|
132
|
+
"",
|
|
133
|
+
"defaults:",
|
|
134
|
+
" autonomy: human-in-loop",
|
|
135
|
+
" stale_after_days:",
|
|
136
|
+
" suggested: 7",
|
|
137
|
+
" discovered: 7",
|
|
138
|
+
"",
|
|
139
|
+
"ledger:",
|
|
140
|
+
" segment_order:",
|
|
141
|
+
" - events.jsonl",
|
|
142
|
+
"",
|
|
143
|
+
"tasks:",
|
|
144
|
+
" - id: T-001",
|
|
145
|
+
` title: Shape ${title}`,
|
|
146
|
+
" status: todo",
|
|
147
|
+
" agreement: agreed",
|
|
148
|
+
" stage: shaping",
|
|
149
|
+
" refs: [R-001]",
|
|
150
|
+
" depends_on: []",
|
|
151
|
+
" owner: agent:any",
|
|
152
|
+
" autonomy: human-in-loop",
|
|
153
|
+
" do:",
|
|
154
|
+
` - Interview to confirm scope for: ${title}.`,
|
|
155
|
+
" done_when:",
|
|
156
|
+
" - id: C-001",
|
|
157
|
+
" text: Scope is confirmed and the smallest useful slice is named.",
|
|
158
|
+
" done: false",
|
|
159
|
+
' proof: ""',
|
|
160
|
+
" completed: null",
|
|
161
|
+
" blocked: null",
|
|
162
|
+
" review:",
|
|
163
|
+
" owner: product",
|
|
164
|
+
" due: null",
|
|
165
|
+
" stale_after_days: null",
|
|
166
|
+
" extensions: {}",
|
|
167
|
+
"",
|
|
168
|
+
].join("\n");
|
|
169
|
+
const event = JSON.stringify({
|
|
170
|
+
specversion: "0.1",
|
|
171
|
+
id: "evt_init_001",
|
|
172
|
+
source: "agent://foo/init",
|
|
173
|
+
type: "com.adaptivespec.spec.created",
|
|
174
|
+
subject: `spec:${specId}`,
|
|
175
|
+
time: now,
|
|
176
|
+
actor: { type: "agent", id: "foo-init", mode: "human-in-loop" },
|
|
177
|
+
data: { mode: "capability", stage: "shaping", summary: `Created by foo init from a repo read: ${title}.` },
|
|
178
|
+
extensions: {},
|
|
179
|
+
}) + "\n";
|
|
180
|
+
writeFileSync(path.join(packetDir, "spec.md"), spec);
|
|
181
|
+
writeFileSync(path.join(packetDir, "tasks.yaml"), tasks);
|
|
182
|
+
writeFileSync(path.join(packetDir, "events.jsonl"), event);
|
|
183
|
+
return packetDir;
|
|
184
|
+
}
|
|
185
|
+
// The structured surface a coding-agent harness fills with sharper
|
|
186
|
+
// judgment. The deterministic moves are the floor; this contract is the ceiling.
|
|
187
|
+
function agentContract(signals, moves) {
|
|
188
|
+
return {
|
|
189
|
+
instructions: "Compose a recommended first move plus 2-3 options for this repo. Lead with the recommendation, number the options, and give each a one-line reason grounded in the signals below. Say why the top option beats the runner-up. Use the developer's own words; when you use a foo term (shaping, spec, boundary), define it inline on first use in <=6 words. Never show an option without a concrete repo fact.",
|
|
190
|
+
grammar: ["recommendation-first", "numbered options", "comparative why", "plain language", "define foo terms inline"],
|
|
191
|
+
signals,
|
|
192
|
+
deterministic_moves: moves,
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
export function parseInitArgs(args) {
|
|
196
|
+
const options = { json: false, pick: null, intent: null, pm: false, attachProof: null };
|
|
197
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
198
|
+
const arg = args[i];
|
|
199
|
+
if (arg === "--json")
|
|
200
|
+
options.json = true;
|
|
201
|
+
else if (arg === "--pick") {
|
|
202
|
+
const value = args[i + 1];
|
|
203
|
+
if (!value || !/^[0-9]+$/.test(value))
|
|
204
|
+
throw new Error("--pick requires a number");
|
|
205
|
+
options.pick = Number(value);
|
|
206
|
+
i += 1;
|
|
207
|
+
}
|
|
208
|
+
else if (arg === "--intent") {
|
|
209
|
+
const value = args[i + 1];
|
|
210
|
+
if (!value)
|
|
211
|
+
throw new Error("--intent requires text");
|
|
212
|
+
options.intent = value;
|
|
213
|
+
i += 1;
|
|
214
|
+
}
|
|
215
|
+
else if (arg === "--pm")
|
|
216
|
+
options.pm = true;
|
|
217
|
+
else if (arg === "--attach-proof") {
|
|
218
|
+
const value = args[i + 1];
|
|
219
|
+
if (!value)
|
|
220
|
+
throw new Error("--attach-proof requires text (what shows it's done)");
|
|
221
|
+
options.attachProof = value;
|
|
222
|
+
i += 1;
|
|
223
|
+
}
|
|
224
|
+
else
|
|
225
|
+
throw new Error(`unknown init argument: ${arg}`);
|
|
226
|
+
}
|
|
227
|
+
return options;
|
|
228
|
+
}
|
|
229
|
+
// The most recent init-scaffolded spec: where --attach-proof lands. Found by
|
|
230
|
+
// the foo-init creation event, newest first, so the PM never names a path.
|
|
231
|
+
function latestInitSpec(root) {
|
|
232
|
+
const specsDir = path.join(root, "specs");
|
|
233
|
+
if (!existsSync(specsDir))
|
|
234
|
+
return null;
|
|
235
|
+
const candidates = readdirSync(specsDir)
|
|
236
|
+
.map((name) => path.join(specsDir, name))
|
|
237
|
+
.filter((dir) => {
|
|
238
|
+
const events = path.join(dir, "events.jsonl");
|
|
239
|
+
return existsSync(events) && readFileSync(events, "utf8").includes("agent://foo/init");
|
|
240
|
+
})
|
|
241
|
+
.sort((a, b) => (readFileSync(path.join(b, "events.jsonl"), "utf8") > readFileSync(path.join(a, "events.jsonl"), "utf8") ? 1 : -1));
|
|
242
|
+
return candidates[0] ?? null;
|
|
243
|
+
}
|
|
244
|
+
// foo-pm-surface-v0 R-004 guard: these internal words must never render on the
|
|
245
|
+
// PM surface; the raw layer keeps them exactly. The canonical list lives with
|
|
246
|
+
// the linter (productDetect JARGON_TERMS) so the PM guard and the shipped-prose
|
|
247
|
+
// jargon signal can never drift apart. Re-exported for the regression tests.
|
|
248
|
+
// `export ... from` re-exports without binding the name locally, and
|
|
249
|
+
// pmSurfaceLeaks below needs it in scope — so import, then re-export.
|
|
250
|
+
import { JARGON_TERMS } from "./productDetect.js";
|
|
251
|
+
export { JARGON_TERMS as PM_SURFACE_FORBIDDEN };
|
|
252
|
+
// comprehension-loop-v0 T-002: the one membership check, lowercased on BOTH
|
|
253
|
+
// sides — "Packet ASP Done_When Reconcile" used to walk straight past a
|
|
254
|
+
// case-sensitive includes(). Every surface eval goes through this helper so
|
|
255
|
+
// the Shift key never beats the list again.
|
|
256
|
+
export function pmSurfaceLeaks(text) {
|
|
257
|
+
const lower = text.toLowerCase();
|
|
258
|
+
return JARGON_TERMS.filter((word) => lower.includes(word.toLowerCase()));
|
|
259
|
+
}
|
|
260
|
+
function firstCheckText(packetDir) {
|
|
261
|
+
const tasks = readFileSync(path.join(packetDir, "tasks.yaml"), "utf8");
|
|
262
|
+
const m = tasks.match(/^\s+text: (.+)$/m);
|
|
263
|
+
return m ? m[1].trim() : "Scope is confirmed and the smallest useful slice is named.";
|
|
264
|
+
}
|
|
265
|
+
// T-003: the jargon-free scaffold message — the spec, what it believes, what
|
|
266
|
+
// counts as done, and the proof move. Raw-layer filenames never appear.
|
|
267
|
+
// The line that replaced a broken promise. init used to say "Next I'd ask a
|
|
268
|
+
// few quick questions to lock the scope" — and nothing anywhere asked; the
|
|
269
|
+
// asking lives with the coding agent (the init handoff instructs it) or in
|
|
270
|
+
// `foo spec`. Name the real next step instead of promising one that never comes.
|
|
271
|
+
function scopeNextStep(title) {
|
|
272
|
+
return `Scope is unconfirmed until a short interview locks it — your coding agent runs that next, or start it yourself: foo spec "${title}"`;
|
|
273
|
+
}
|
|
274
|
+
function pmScaffoldMessage(root, dir, title) {
|
|
275
|
+
const specName = path.basename(dir);
|
|
276
|
+
return [
|
|
277
|
+
`Started the spec for "${title}".`,
|
|
278
|
+
` Where it lives: specs/${specName} (the spec is a short written agreement; productfoo keeps the full history underneath)`,
|
|
279
|
+
` What it believes so far: ${scopeNextStep(title)}`,
|
|
280
|
+
` What counts as done: ${firstCheckText(dir)}`,
|
|
281
|
+
"When the work is done, attach proof:",
|
|
282
|
+
' foo init --pm --attach-proof "what shows it\'s done"',
|
|
283
|
+
"Any time after that, check for drift — foo compares the spec against what actually got built.",
|
|
284
|
+
"",
|
|
285
|
+
].join("\n");
|
|
286
|
+
}
|
|
287
|
+
export function runInit(root, args) {
|
|
288
|
+
const options = parseInitArgs(args);
|
|
289
|
+
// init-onboarding-survey-v0 R-003: the profile personalizes the surface.
|
|
290
|
+
// Product-view roles (product, founder, executive) make the PM surface the
|
|
291
|
+
// default — no more typing --pm. Explicit flags still win, and --json never
|
|
292
|
+
// changes shape (the PM render branch already excludes it).
|
|
293
|
+
if (!options.pm && loadProfile(root)?.roles?.some((role) => PRODUCT_VIEW_ROLES.includes(role)))
|
|
294
|
+
options.pm = true;
|
|
295
|
+
// R-013: a bare read with no repo underneath tells the short story and ends
|
|
296
|
+
// on the one next step — the empty state is the orientation, never an error.
|
|
297
|
+
// Explicit actions (--pick/--intent/--attach-proof) and --json keep their
|
|
298
|
+
// existing behavior everywhere.
|
|
299
|
+
const bareRead = !options.json && options.pick === null && !options.intent && !options.attachProof;
|
|
300
|
+
if (bareRead && !isGitRepo(root))
|
|
301
|
+
return `${NO_REPO_STORY.join("\n")}\n`;
|
|
302
|
+
// R-013: the first-ever read in a repo opens with two plain lines, then goes
|
|
303
|
+
// quiet forever. Human read paths only — never --json (agents read that), and
|
|
304
|
+
// an explicit action flag means they have already met foo.
|
|
305
|
+
let opener = "";
|
|
306
|
+
if (bareRead && !hasSeenFirstRun(root)) {
|
|
307
|
+
opener = `${FIRST_RUN_OPENER.join("\n")}\n\n`;
|
|
308
|
+
markFirstRunSeen(root);
|
|
309
|
+
}
|
|
310
|
+
// PM surface: attach proof to the newest init-started spec (T-003 — the
|
|
311
|
+
// proof moment in plain language; the raw contract is updated underneath).
|
|
312
|
+
if (options.pm && options.attachProof) {
|
|
313
|
+
const dir = latestInitSpec(root);
|
|
314
|
+
if (!dir)
|
|
315
|
+
return "No spec started by foo init yet — start one first: foo init --pm\n";
|
|
316
|
+
updateTask({ packetDir: dir, taskId: "T-001", status: "done", proof: options.attachProof, summary: "First done_when proven via foo init --pm." });
|
|
317
|
+
return [
|
|
318
|
+
"Proof attached — the first check is now proven.",
|
|
319
|
+
` What counted as done: ${firstCheckText(dir)}`,
|
|
320
|
+
` Your proof: ${options.attachProof}`,
|
|
321
|
+
"Next: check for drift any time — productfoo will compare the spec against what actually got built.",
|
|
322
|
+
"",
|
|
323
|
+
].join("\n");
|
|
324
|
+
}
|
|
325
|
+
const signals = gatherRepoSignals(root);
|
|
326
|
+
const moves = generateMoves(signals);
|
|
327
|
+
const ranked = rankMoves(moves);
|
|
328
|
+
const ordered = ranked.recommended ? [ranked.recommended, ...ranked.rest] : [];
|
|
329
|
+
// first-move-two-facts: a real, grounded tension (two facts the repo already
|
|
330
|
+
// holds, in conflict) outranks every hygiene chore as the headline first move.
|
|
331
|
+
// Human read paths only (agents read --json's raw moves); only fires when the
|
|
332
|
+
// signal genuinely supports it, so a boring hygiene move or the honest floor
|
|
333
|
+
// still leads when there's no real tension to surface.
|
|
334
|
+
if (!options.json) {
|
|
335
|
+
const topTension = detectTensions(root)[0] ?? null;
|
|
336
|
+
if (topTension) {
|
|
337
|
+
ordered.unshift({ id: `tension:${topTension.id}`, title: topTension.title, evidence: topTension.evidence, risk: 3, leverage: 3, effort: 2, tension: topTension });
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
// Act on an explicit pick or a free-text intent: scaffold the packet.
|
|
341
|
+
if (options.intent) {
|
|
342
|
+
const dir = scaffoldPacket(root, options.intent, [], "Stated directly to foo init.");
|
|
343
|
+
if (options.pm)
|
|
344
|
+
return pmScaffoldMessage(root, dir, options.intent);
|
|
345
|
+
return [
|
|
346
|
+
`Got it — we'll shape "${options.intent}".`,
|
|
347
|
+
`I started a plan (a spec) for it at ${path.relative(root, dir) || dir}.`,
|
|
348
|
+
scopeNextStep(options.intent),
|
|
349
|
+
"",
|
|
350
|
+
].join("\n");
|
|
351
|
+
}
|
|
352
|
+
if (options.pick !== null) {
|
|
353
|
+
const move = ordered[options.pick - 1];
|
|
354
|
+
if (!move)
|
|
355
|
+
throw new Error(`no option ${options.pick}; run foo init to see the options`);
|
|
356
|
+
const dir = scaffoldPacket(root, move.title, move.evidence, "Picked from the foo init read.");
|
|
357
|
+
if (options.pm)
|
|
358
|
+
return pmScaffoldMessage(root, dir, move.title);
|
|
359
|
+
return [
|
|
360
|
+
`Got it — we'll shape "${move.title}".`,
|
|
361
|
+
`I started a plan (a spec) for it at ${path.relative(root, dir) || dir}.`,
|
|
362
|
+
scopeNextStep(move.title),
|
|
363
|
+
"",
|
|
364
|
+
].join("\n");
|
|
365
|
+
}
|
|
366
|
+
// T-002: the persona-shaped PM first move — same repo facts, the signed-off
|
|
367
|
+
// vocabulary (vocabulary-map.md): "the spec", "expert review", "what counts
|
|
368
|
+
// as done", "proof attached", "check for drift". Never a raw-layer word.
|
|
369
|
+
if (options.pm && !options.json) {
|
|
370
|
+
if (ordered.length === 0) {
|
|
371
|
+
return opener + [
|
|
372
|
+
"foo — a first read of your project",
|
|
373
|
+
"",
|
|
374
|
+
`Read: ${plainRead(signals)}. Not enough here yet to point at one thing.`,
|
|
375
|
+
"",
|
|
376
|
+
"Tell me what you want to ship and we'll shape it into an agreed spec:",
|
|
377
|
+
' foo init --pm --intent "…"',
|
|
378
|
+
"",
|
|
379
|
+
].join("\n");
|
|
380
|
+
}
|
|
381
|
+
const lines = [
|
|
382
|
+
"foo — a first read of your project",
|
|
383
|
+
"",
|
|
384
|
+
`Read: ${plainRead(signals)}.`,
|
|
385
|
+
"",
|
|
386
|
+
"Pick one and foo shapes it with you: a short agreed spec — what we're",
|
|
387
|
+
"building, what it believes and why, and what counts as done. An expert",
|
|
388
|
+
"review (product, design, engineering, data, GTM) is available on anything risky.",
|
|
389
|
+
"",
|
|
390
|
+
];
|
|
391
|
+
ordered.forEach((m, i) => {
|
|
392
|
+
if (i === 0 && m.tension) {
|
|
393
|
+
// Two facts, one friction: stack them so the tension sits in the gap.
|
|
394
|
+
lines.push("→ 1 (recommended) — the thing hiding in plain sight:");
|
|
395
|
+
lines.push(` ${m.tension.factA}`);
|
|
396
|
+
lines.push(` ${m.tension.factB}`);
|
|
397
|
+
lines.push(` ${m.tension.ask}`);
|
|
398
|
+
}
|
|
399
|
+
else if (i === 0) {
|
|
400
|
+
lines.push(`→ 1 (recommended) ${m.title}`);
|
|
401
|
+
lines.push(` seen in your project: ${m.evidence.join("; ")}`);
|
|
402
|
+
if (ranked.why)
|
|
403
|
+
lines.push(` Why this first: ${ranked.why}.`.replace("..", "."));
|
|
404
|
+
}
|
|
405
|
+
else {
|
|
406
|
+
lines.push(` ${i + 1} ${m.title} — ${m.evidence[0]}`);
|
|
407
|
+
}
|
|
408
|
+
});
|
|
409
|
+
lines.push("");
|
|
410
|
+
lines.push("Reply with a number, or say it in your own words:");
|
|
411
|
+
lines.push(" foo init --pm --pick 1");
|
|
412
|
+
lines.push(' foo init --pm --intent "…"');
|
|
413
|
+
lines.push("Once the work is done, attach proof:");
|
|
414
|
+
lines.push(' foo init --pm --attach-proof "what shows it\'s done"');
|
|
415
|
+
lines.push("");
|
|
416
|
+
return opener + lines.join("\n");
|
|
417
|
+
}
|
|
418
|
+
if (options.json) {
|
|
419
|
+
return (JSON.stringify({
|
|
420
|
+
schema_version: "0.1",
|
|
421
|
+
read: plainRead(signals),
|
|
422
|
+
options: ordered.map((m, i) => ({
|
|
423
|
+
n: i + 1,
|
|
424
|
+
id: m.id,
|
|
425
|
+
title: m.title,
|
|
426
|
+
evidence: m.evidence,
|
|
427
|
+
recommended: i === 0,
|
|
428
|
+
why: i === 0 ? ranked.why : null,
|
|
429
|
+
})),
|
|
430
|
+
agent_contract: agentContract(signals, moves),
|
|
431
|
+
}, null, 2) + "\n");
|
|
432
|
+
}
|
|
433
|
+
// Thin-repo fallback: never invent options. Ask what they came to build.
|
|
434
|
+
if (ordered.length === 0) {
|
|
435
|
+
return opener + [
|
|
436
|
+
"foo init — a first read of your repo",
|
|
437
|
+
"",
|
|
438
|
+
`Read: ${plainRead(signals)}. Not enough here yet for me to point at one thing.`,
|
|
439
|
+
"",
|
|
440
|
+
"Tell me what you came to build and we'll shape it:",
|
|
441
|
+
' foo init --intent "…"',
|
|
442
|
+
"",
|
|
443
|
+
].join("\n");
|
|
444
|
+
}
|
|
445
|
+
const lines = [
|
|
446
|
+
"foo init — a first read of your repo",
|
|
447
|
+
"",
|
|
448
|
+
`Read: ${plainRead(signals)}.`,
|
|
449
|
+
"",
|
|
450
|
+
"Here's what I'd pick up first. Choosing one starts shaping it — in foo,",
|
|
451
|
+
"shaping just means turning a rough idea into an agreed spec (a short written",
|
|
452
|
+
"plan) before any code gets written.",
|
|
453
|
+
"",
|
|
454
|
+
];
|
|
455
|
+
ordered.forEach((m, i) => {
|
|
456
|
+
if (i === 0) {
|
|
457
|
+
lines.push(`→ 1 (recommended) ${m.title}`);
|
|
458
|
+
lines.push(` ${m.evidence.join("; ")}`);
|
|
459
|
+
if (ranked.why)
|
|
460
|
+
lines.push(` Why this first: ${ranked.why}.`.replace("..", "."));
|
|
461
|
+
}
|
|
462
|
+
else {
|
|
463
|
+
lines.push(` ${i + 1} ${m.title} — ${m.evidence[0]}`);
|
|
464
|
+
}
|
|
465
|
+
});
|
|
466
|
+
lines.push("");
|
|
467
|
+
lines.push("Reply with a number to start, or say it in your own words:");
|
|
468
|
+
lines.push(" foo init --pick 1");
|
|
469
|
+
lines.push(' foo init --intent "…"');
|
|
470
|
+
lines.push("");
|
|
471
|
+
return opener + lines.join("\n");
|
|
472
|
+
}
|
|
473
|
+
// The survey can only ask on a live terminal, so an agent-run `foo init` leaves
|
|
474
|
+
// foo not knowing who it is talking to. Then — and only then — the handoff asks
|
|
475
|
+
// the agent to run the four questions in its own voice. foo already knows
|
|
476
|
+
// whether a profile exists, so this decision belongs to the CLI, not to a static
|
|
477
|
+
// line in a launcher that would ask every user forever.
|
|
478
|
+
export function initHandoffSteps(root) {
|
|
479
|
+
if (loadProfile(root))
|
|
480
|
+
return [];
|
|
481
|
+
return [
|
|
482
|
+
'Get to know the user first — once, ever. Ask four quick questions in your own words, each one skippable: their role (product, engineer, designer, founder, or executive — any that fit), the coding agent they build with most, what they are building (a few words), and who is building with them (just them, a small team, a bigger org). Record the answers with `foo profile set --role <r> [--role <r2>] --harness <agent> --team <just-me|small-team|larger-org> --building "<their words>"`. This personalizes foo across every project on their machine; the free-text "building" answer stays on their machine and is never reported. Never re-ask once it is recorded.',
|
|
483
|
+
];
|
|
484
|
+
}
|
|
485
|
+
// init-onboarding-survey-v0 R-001, amended by machine-wide-profile-v0: the
|
|
486
|
+
// survey fires once per PERSON, not once per repo — so it gates on "no profile
|
|
487
|
+
// yet anywhere" rather than the per-repo first-run marker. Still only on a live
|
|
488
|
+
// terminal, a bare read, in a repo; piped/agent runs (--json, action flags,
|
|
489
|
+
// non-TTY) never see it. Answer in one project and every other project already
|
|
490
|
+
// leads with your view — no re-ask.
|
|
491
|
+
export function surveyApplies(root, args, io) {
|
|
492
|
+
let options;
|
|
493
|
+
try {
|
|
494
|
+
options = parseInitArgs(args);
|
|
495
|
+
}
|
|
496
|
+
catch {
|
|
497
|
+
return false; // bad args fail in runInit with today's message, not mid-survey
|
|
498
|
+
}
|
|
499
|
+
const bareRead = !options.json && options.pick === null && !options.intent && !options.attachProof;
|
|
500
|
+
return bareRead && io.inputTTY && io.outputTTY && isGitRepo(root) && !loadProfile(root);
|
|
501
|
+
}
|
|
502
|
+
// The interactive front door cli.ts dispatches to. When the survey applies it
|
|
503
|
+
// owns the whole first-run moment: opener lines, then the four skippable
|
|
504
|
+
// questions, then the repo read — and the marker is consumed up front so the
|
|
505
|
+
// moment can never replay (R-001). Any survey failure degrades to today's
|
|
506
|
+
// read untouched (R-005).
|
|
507
|
+
export async function runInitInteractive(root, args, io) {
|
|
508
|
+
const input = io?.input ?? process.stdin;
|
|
509
|
+
const output = io?.output ?? process.stdout;
|
|
510
|
+
const ttys = {
|
|
511
|
+
inputTTY: io?.inputTTY ?? Boolean(process.stdin.isTTY),
|
|
512
|
+
outputTTY: io?.outputTTY ?? Boolean(process.stdout.isTTY),
|
|
513
|
+
};
|
|
514
|
+
if (surveyApplies(root, args, ttys)) {
|
|
515
|
+
// Emit the opener only if this repo hasn't shown it; either way mark it so
|
|
516
|
+
// runInit doesn't repeat it after the survey.
|
|
517
|
+
if (!hasSeenFirstRun(root))
|
|
518
|
+
output.write(`${FIRST_RUN_OPENER.join("\n")}\n\n`);
|
|
519
|
+
markFirstRunSeen(root);
|
|
520
|
+
try {
|
|
521
|
+
const profile = await runFirstRunSurvey({ input, output });
|
|
522
|
+
saveProfile(profile); // machine-wide: the answer follows the person
|
|
523
|
+
// Record the fixed profile picks in the local agent log.
|
|
524
|
+
void reportProfile(root, profile, readPackageVersion(root));
|
|
525
|
+
}
|
|
526
|
+
catch {
|
|
527
|
+
// The read always renders (R-005); foo just never asks again.
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
// #913/#622: the boot path skips init so the offer comes HERE, after the
|
|
531
|
+
// survey, naming the agents the person just picked. Ask-first: nothing is
|
|
532
|
+
// written without an explicit yes; the answer is remembered.
|
|
533
|
+
if (ttys.inputTTY && ttys.outputTTY && !args.includes("--json")) {
|
|
534
|
+
try {
|
|
535
|
+
const { autoWireMessage, maybeAutoWireHarnesses } = await import("./commands/agent.js");
|
|
536
|
+
const outcome = await maybeAutoWireHarnesses(readPackageVersion(root), {
|
|
537
|
+
preferred: profileHarnesses(loadProfile(root)),
|
|
538
|
+
ask: async (question) => {
|
|
539
|
+
const readline = await import("node:readline/promises");
|
|
540
|
+
const rl = readline.createInterface({ input, output });
|
|
541
|
+
try {
|
|
542
|
+
// Enter means yes; only an explicit n/no declines (#913).
|
|
543
|
+
return !/^(n|no)$/i.test((await rl.question(question)).trim());
|
|
544
|
+
}
|
|
545
|
+
finally {
|
|
546
|
+
rl.close();
|
|
547
|
+
}
|
|
548
|
+
},
|
|
549
|
+
});
|
|
550
|
+
if (outcome)
|
|
551
|
+
output.write(autoWireMessage(outcome));
|
|
552
|
+
}
|
|
553
|
+
catch {
|
|
554
|
+
// Best-effort: the read always renders.
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
return runInit(root, args);
|
|
558
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { DenialText } from "./harnessGates.js";
|
|
2
|
+
/** A PreToolUse-shaped payload. Harness-neutral: only these two fields are read. */
|
|
3
|
+
export interface InterviewCall {
|
|
4
|
+
readonly tool_name?: string;
|
|
5
|
+
readonly tool_input?: Record<string, unknown>;
|
|
6
|
+
}
|
|
7
|
+
export interface InterviewDecision {
|
|
8
|
+
readonly allow: boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Present when allow=false. Two readers, two texts: `agent` carries the instruction and
|
|
11
|
+
* the machinery, `user` is the one line the human sees. See DenialText in harnessGates.ts.
|
|
12
|
+
*/
|
|
13
|
+
readonly reason?: DenialText;
|
|
14
|
+
/** Why the gate decided this — for tests and `--json`, never for the agent. */
|
|
15
|
+
readonly note?: string;
|
|
16
|
+
}
|
|
17
|
+
/** Record one question we let through. The accretion trip is only as good as its counter. */
|
|
18
|
+
export declare function recordInterviewAsk(root: string, now?: number): void;
|
|
19
|
+
/** Cleared when a governed interview starts — a real one must not trip its own gate. */
|
|
20
|
+
export declare function clearInterviewAsks(root: string): void;
|
|
21
|
+
/** Has the agent asked enough times that this is plainly an interview, unnamed? */
|
|
22
|
+
export declare function asksLookLikeInterview(root: string, now?: number): boolean;
|
|
23
|
+
/** How many questions this call hands over at once. A batch is a questionnaire. */
|
|
24
|
+
export declare function questionCount(call: InterviewCall): number;
|
|
25
|
+
export declare function evaluateInterviewGate(call: InterviewCall, root: string, env?: NodeJS.ProcessEnv, now?: number): InterviewDecision;
|