@khoavu882/doflow 2.0.0-beta.4 → 2.0.0
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/README.md +12 -11
- package/bin/doflow.js +21 -11
- package/core/.antigravity-plugin/plugin.json +1 -3
- package/core/.claude-plugin/plugin.json +1 -1
- package/core/.codex-plugin/plugin.json +1 -1
- package/core/.plugin/plugin.json +1 -1
- package/core/harnesses/claude/hooks/lib.sh +43 -24
- package/core/harnesses/claude/hooks/mcp-tool-guard.sh +7 -17
- package/core/harnesses/claude/hooks/permission-audit.sh +3 -0
- package/core/harnesses/claude/hooks/post-compact.sh +35 -32
- package/core/harnesses/claude/hooks/post-edit-lint.sh +2 -0
- package/core/harnesses/claude/hooks/post-shell-observe.sh +48 -0
- package/core/harnesses/claude/hooks/post-tool-failure.sh +3 -0
- package/core/harnesses/claude/hooks/pre-bash-guard.sh +7 -17
- package/core/harnesses/claude/hooks/pre-compact.sh +23 -27
- package/core/harnesses/claude/hooks/pre-implement-gate.sh +7 -18
- package/core/harnesses/claude/hooks/session-end.sh +23 -10
- package/core/harnesses/claude/hooks/session-start.sh +5 -3
- package/core/harnesses/claude/hooks/skill-config-audit.sh +3 -0
- package/core/harnesses/claude/hooks/stop-check.sh +5 -3
- package/core/harnesses/claude/hooks/subagent-audit.sh +5 -5
- package/core/harnesses/claude/hooks/user-prompt-submit.sh +5 -3
- package/core/harnesses/claude/settings/settings.json +18 -0
- package/core/harnesses/claude/statusline/doflow-statusline.sh +1 -0
- package/core/harnesses/codex/agents/core-implementer.toml +1 -0
- package/core/harnesses/codex/agents/delivery-lead.toml +10 -0
- package/core/harnesses/codex/agents/quality-guardian.toml +1 -1
- package/core/harnesses/codex/agents/research-writer.toml +1 -1
- package/core/harnesses/codex/agents/reviewer.toml +10 -0
- package/core/harnesses/codex/agents/spec-analyst.toml +1 -1
- package/core/harnesses/codex/agents/system-architect.toml +1 -1
- package/core/harnesses/codex/hooks/lib.sh +44 -25
- package/core/harnesses/codex/hooks/mcp-tool-guard.sh +7 -15
- package/core/harnesses/codex/hooks/post-edit-lint.impl.sh +3 -1
- package/core/harnesses/codex/hooks/pre-bash-guard.sh +7 -15
- package/core/harnesses/codex/hooks/pre-compact.impl.sh +29 -26
- package/core/harnesses/codex/hooks/pre-implement-gate.sh +7 -16
- package/core/harnesses/codex/hooks/session-end.impl.sh +23 -10
- package/core/harnesses/codex/hooks/session-start.sh +5 -3
- package/core/harnesses/codex/hooks/stop-check.sh +6 -5
- package/core/harnesses/codex/hooks/subagent-audit.sh +18 -6
- package/core/harnesses/codex/hooks/user-prompt-submit.sh +5 -4
- package/core/harnesses/copilot/hooks/doflow-lib.sh +93 -0
- package/core/harnesses/copilot/hooks/doflow-mcp-tool-guard.sh +9 -0
- package/core/harnesses/copilot/hooks/doflow-pre-bash-guard.sh +9 -0
- package/core/harnesses/copilot/hooks/doflow-pre-implement-gate.sh +9 -0
- package/core/harnesses/copilot/hooks/doflow-session-start.sh +9 -0
- package/core/harnesses/copilot/hooks/doflow-stop-check.sh +9 -0
- package/core/harnesses/copilot/hooks/doflow-subagent-start.sh +9 -0
- package/core/harnesses/copilot/hooks/doflow-subagent-stop.sh +9 -0
- package/core/harnesses/copilot/hooks/doflow.json +57 -0
- package/core/harnesses/kiro/agents/doflow.json +1 -1
- package/core/harnesses/kiro/hooks/lib.sh +26 -6
- package/core/harnesses/kiro/hooks/mcp-tool-guard.sh +21 -5
- package/core/harnesses/kiro/hooks/pre-bash-guard.sh +21 -5
- package/core/harnesses/kiro/hooks/pre-implement-gate.sh +21 -5
- package/core/harnesses/kiro/hooks/session-start.sh +12 -5
- package/core/harnesses/kiro/hooks/stop-check.sh +22 -30
- package/core/harnesses/pi/extensions/doflow-guard.js +167 -0
- package/core/harnesses/shared/hooks/ENVELOPE_MIGRATION.md +27 -12
- package/core/harnesses/shared/hooks/adapters/antigravity.js +14 -57
- package/core/harnesses/shared/hooks/bridge/bridge.sh +277 -0
- package/core/harnesses/shared/hooks/bridge/envelope.jq +129 -0
- package/core/harnesses/shared/hooks/bridge/observe-model.sh +75 -0
- package/core/harnesses/shared/hooks/bridge/respond.sh +70 -0
- package/core/harnesses/shared/hooks/policies/blocked-patterns.conf +28 -14
- package/core/harnesses/shared/hooks/policies/capture-failure.sh +51 -16
- package/core/harnesses/shared/hooks/policies/compact-text.sh +46 -0
- package/core/harnesses/shared/hooks/policies/contract.sh +78 -0
- package/core/harnesses/shared/hooks/policies/deny-json.sh +35 -9
- package/core/harnesses/shared/hooks/policies/emission-rules.sh +37 -0
- package/core/harnesses/shared/hooks/policies/emission.jq +209 -0
- package/core/harnesses/shared/hooks/policies/emission.sh +383 -0
- package/core/harnesses/shared/hooks/policies/identity.sh +177 -0
- package/core/harnesses/shared/hooks/policies/lib.sh +65 -40
- package/core/harnesses/shared/hooks/policies/mcp-tool-guard.sh +48 -35
- package/core/harnesses/shared/hooks/policies/pre-bash-guard.sh +284 -33
- package/core/harnesses/shared/hooks/policies/pre-implementation-gate.sh +180 -110
- package/core/harnesses/shared/hooks/policies/session-context.sh +66 -7
- package/core/harnesses/shared/hooks/policies/stop-check.sh +61 -23
- package/core/harnesses/shared/hooks/policies/subagent-audit.sh +39 -6
- package/core/harnesses/shared/hooks/policies/summary-store.sh +347 -0
- package/core/harnesses/shared/hooks/policies/user-prompt-submit.sh +97 -159
- package/core/harnesses/shared/hooks/stream-hook-runner.js +114 -187
- package/core/harnesses/shared/locator/doflow-run +2 -3
- package/core/registry/advice.json +3 -3
- package/core/registry/assets.json +72 -80
- package/core/registry/capabilities.json +12 -0
- package/core/registry/contracts.json +60 -33
- package/core/registry/contribution-points.json +32 -0
- package/core/registry/gates.json +32 -0
- package/core/registry/guidance-caps.json +40 -0
- package/core/registry/harnesses.json +1542 -277
- package/core/registry/lifecycle.json +2837 -37
- package/core/registry/mcp.json +5 -1
- package/core/registry/models.json +7 -1
- package/core/registry/package-templates/README.md +19 -0
- package/core/registry/package-templates/agent/files/agent.md +9 -0
- package/core/registry/package-templates/agent/template.json +4 -0
- package/core/registry/package-templates/capability-provider/files/provider.json +9 -0
- package/core/registry/package-templates/capability-provider/template.json +11 -0
- package/core/registry/package-templates/debate-preset/files/preset.json +26 -0
- package/core/registry/package-templates/debate-preset/template.json +4 -0
- package/core/registry/package-templates/review-preset/files/preset.json +30 -0
- package/core/registry/package-templates/review-preset/template.json +4 -0
- package/core/registry/package-templates/skill/files/SKILL.md +8 -0
- package/core/registry/package-templates/skill/template.json +4 -0
- package/core/registry/package-templates/worker/files/worker.json +92 -0
- package/core/registry/package-templates/worker/template.json +11 -0
- package/core/registry/packages/doflow/doflow-package.json +15 -0
- package/core/registry/packages/doflow/presets/debate-3.json +26 -0
- package/core/registry/protocols.json +61 -0
- package/core/registry/routes.json +17 -0
- package/core/registry/rules.json +431 -0
- package/core/registry/settings.json +276 -0
- package/core/registry/storage.json +701 -30
- package/core/registry/telemetry.json +236 -0
- package/core/registry/transcripts.json +142 -0
- package/core/registry/verification.json +76 -1
- package/core/registry/workflows.json +55 -0
- package/core/shared/agent-specs/core-implementer.md +3 -0
- package/core/shared/agent-specs/delivery-lead.md +68 -0
- package/core/shared/agent-specs/quality-guardian.md +5 -1
- package/core/shared/agent-specs/research-writer.md +10 -3
- package/core/shared/agent-specs/reviewer.md +53 -0
- package/core/shared/agent-specs/spec-analyst.md +5 -6
- package/core/shared/agent-specs/system-architect.md +5 -1
- package/core/shared/guidance/DOFLOW_CORE.md +1 -5
- package/core/shared/guidance/modes/MODE_DeepResearch.md +1 -1
- package/core/shared/guidance/modes/MODE_Orchestration.md +4 -3
- package/core/shared/guidance/modes/MODE_Task_Management.md +14 -14
- package/core/shared/guidance/pointers/codex.md +1 -4
- package/core/shared/guidance/references/ARTIFACT_FORMAT.md +30 -16
- package/core/shared/guidance/references/ARTIFACT_VOICE.md +3 -2
- package/core/shared/guidance/references/CONSTITUTION_BASE.md +17 -15
- package/core/shared/guidance/references/DIAGRAM_GUIDE.md +1 -1
- package/core/shared/guidance/references/DOFLOW_CHAIN.md +17 -19
- package/core/shared/guidance/references/EVIDENCE_LEDGER.md +7 -8
- package/core/shared/guidance/references/MODEL_SELECTION.md +5 -3
- package/core/shared/guidance/references/ORCHESTRATION.md +1 -2
- package/core/shared/guidance/rules/RULES.md +45 -0
- package/core/shared/scripts/doflow/bash/do-args.sh +37 -0
- package/core/shared/scripts/doflow/bash/do-exec-paths.sh +4 -0
- package/core/shared/scripts/doflow/bash/do-git-state.sh +15 -4
- package/core/shared/scripts/doflow/bash/do-parallel-check.sh +4 -0
- package/core/shared/scripts/doflow/bash/do-paths.sh +40 -2
- package/core/shared/scripts/doflow/bash/do-prereqs.sh +2 -1
- package/core/shared/scripts/doflow/bash/do-review-package.sh +4 -0
- package/core/shared/scripts/doflow/bash/do-task-brief.sh +58 -16
- package/core/shared/scripts/doflow/bash/render-audit.sh +26 -2
- package/core/shared/scripts/doflow/bash/render-diagrams.sh +1 -0
- package/core/shared/scripts/doflow/bash/render-puml.sh +2 -1
- package/core/shared/scripts/doflow/bash/validate-artifacts.sh +48 -4
- package/core/shared/scripts/doflow/bin/doflow-run +154 -35
- package/core/shared/skills/do/SKILL.md +12 -10
- package/core/shared/skills/do/references/advice_calls.md +26 -0
- package/core/shared/skills/do/references/pm_routing.md +1 -2
- package/core/shared/skills/do/references/program_mode.md +31 -0
- package/core/shared/skills/do-brainstorm/SKILL.md +20 -74
- package/core/shared/skills/do-brainstorm/references/handoff_branches.md +35 -0
- package/core/shared/skills/do-brainstorm/references/intent_seed.md +21 -0
- package/core/shared/skills/do-brainstorm/references/round_log.md +17 -0
- package/core/shared/skills/do-code-review/SKILL.md +41 -144
- package/core/shared/skills/do-code-review/content-types/markdown.md +24 -2
- package/core/shared/skills/do-code-review/references/tools.md +90 -0
- package/core/shared/skills/do-code-review/scripts/doc_quality_checker.py +549 -7
- package/core/shared/skills/do-design/SKILL.md +24 -23
- package/core/shared/skills/do-diagnose/SKILL.md +14 -4
- package/core/shared/skills/do-document/SKILL.md +11 -1
- package/core/shared/skills/do-document/references/deep_research.md +1 -2
- package/core/shared/skills/do-document/references/embedded-research.md +18 -6
- package/core/shared/skills/do-document/references/implementation-flow.md +5 -6
- package/core/shared/skills/do-execute-plan/SKILL.md +17 -59
- package/core/shared/skills/do-execute-plan/references/handoff_record.md +7 -2
- package/core/shared/skills/do-execute-plan/references/parallel_dispatch.md +13 -0
- package/core/shared/skills/do-execute-plan/references/readiness_gate.md +28 -1
- package/core/shared/skills/do-execute-plan/references/run_position.md +13 -1
- package/core/shared/skills/do-execute-plan/references/scaffold.md +17 -9
- package/core/shared/skills/do-execute-plan/references/state_checkpoint.md +11 -0
- package/core/shared/skills/do-execute-plan/references/task_attempts.md +78 -24
- package/core/shared/skills/do-flow/SKILL.md +8 -9
- package/core/shared/skills/do-flow/references/task_classes.md +2 -2
- package/core/shared/skills/do-git/SKILL.md +4 -0
- package/core/shared/skills/do-implement/SKILL.md +7 -9
- package/core/shared/skills/do-plan/SKILL.md +29 -19
- package/core/shared/skills/do-test/SKILL.md +7 -4
- package/core/shared/templates/doflow/constitution-template.md +9 -3
- package/core/shared/templates/doflow/data-model-template.md +1 -1
- package/core/shared/templates/doflow/design-template.md +113 -16
- package/core/shared/templates/doflow/plan-template.md +11 -10
- package/core/shared/templates/doflow/question-log-template.md +14 -2
- package/core/shared/templates/doflow/requirement-template.md +1 -1
- package/core/worker-evidence/antigravity/checks.json +14 -0
- package/core/worker-evidence/codex/2026-10-18-cli-check.json +107 -0
- package/core/worker-evidence/codex/2026-10-18-live-run-edit.json +73 -0
- package/core/worker-evidence/codex/2026-10-18-live-run-read-only.json +62 -0
- package/core/worker-evidence/codex/2026-10-24-cli-check.json +126 -0
- package/core/worker-evidence/codex/checks.json +38 -0
- package/package.json +10 -6
- package/src/adapters/antigravity/index.js +226 -113
- package/src/adapters/claude/index.js +39 -5
- package/src/adapters/codex/agents.js +25 -15
- package/src/adapters/codex/hooks.js +40 -5
- package/src/adapters/codex/index.js +100 -22
- package/src/adapters/codex/native-projection.js +6 -2
- package/src/adapters/copilot/index.js +58 -23
- package/src/adapters/copy-tree.js +294 -48
- package/src/adapters/guidance-manifest.js +71 -0
- package/src/adapters/guidance-pointer.js +19 -0
- package/src/adapters/hook-commands.js +6 -10
- package/src/adapters/index.js +1 -0
- package/src/adapters/kiro/index.js +38 -13
- package/src/adapters/opencode/index.js +8 -8
- package/src/adapters/pi/hooks.js +120 -0
- package/src/adapters/pi/index.js +48 -16
- package/src/adapters/resolve-source.js +26 -2
- package/src/cli/commands/install.js +3 -2
- package/src/cli/commands/reconcile.js +53 -9
- package/src/cli/commands/remove.js +2 -2
- package/src/cli/commands/rollback.js +6 -3
- package/src/cli/commands/self-update.js +18 -9
- package/src/cli/commands/status.js +21 -2
- package/src/cli/commands/ui.js +99 -0
- package/src/cli/commands/update.js +3 -2
- package/src/cli/index.js +338 -33
- package/src/cli/runtime-commands.js +243 -52
- package/src/cli/shared.js +0 -2
- package/src/helper/git.js +1 -1
- package/src/helper/guardrails.js +1 -1
- package/src/helper/marker-merge.js +31 -13
- package/src/helper/package-ids.js +37 -0
- package/src/helper/semver.js +94 -0
- package/src/install/backup.js +105 -15
- package/src/install/context.js +1 -1
- package/src/install/targets.js +31 -16
- package/src/lifecycle/coverage.js +74 -0
- package/src/lifecycle/hook-step.js +61 -0
- package/src/lifecycle/hook-tier.js +160 -0
- package/src/lifecycle/index.js +434 -86
- package/src/lifecycle/retired-harnesses.js +318 -0
- package/src/lifecycle/view.js +35 -15
- package/src/registry/index.js +686 -32
- package/src/registry/worker-ids.js +45 -0
- package/src/release/build-package.js +0 -3
- package/src/release/docs-blocks.js +492 -0
- package/src/release/preflight.js +425 -0
- package/src/release/rehearse.js +401 -0
- package/src/release/release-workflow.js +733 -0
- package/src/release/sync-plugin-versions.js +43 -7
- package/src/runtime/advice/bench-gate.js +25 -0
- package/src/runtime/advice/cli.js +59 -16
- package/src/runtime/advice/client.js +32 -9
- package/src/runtime/advice/config.js +98 -133
- package/src/runtime/advice/doctor.js +1 -1
- package/src/runtime/advice/elevation.js +97 -0
- package/src/runtime/advice/endpoint-guard.js +9 -3
- package/src/runtime/advice/mode.js +37 -0
- package/src/runtime/advice/record.js +18 -5
- package/src/runtime/advice/registry.js +4 -1
- package/src/runtime/advice/shadow-config.js +229 -0
- package/src/runtime/advice/shadow-dispatcher.js +276 -0
- package/src/runtime/brief-rules.js +81 -0
- package/src/runtime/brief-tools.js +111 -34
- package/src/runtime/candidate.js +514 -0
- package/src/runtime/capabilities/executor.js +450 -0
- package/src/runtime/capabilities/loopback.js +41 -0
- package/src/runtime/capabilities/sanitizer.js +88 -0
- package/src/runtime/capability-router.js +135 -3
- package/src/runtime/checkouts.js +73 -11
- package/src/runtime/claims.js +27 -12
- package/src/runtime/cli-result.js +11 -4
- package/src/runtime/cli.js +221 -277
- package/src/runtime/config-home.js +42 -0
- package/src/runtime/context/arbitrate.js +767 -0
- package/src/runtime/context/budget.js +203 -0
- package/src/runtime/context/compose.js +1367 -0
- package/src/runtime/context/delivery-store.js +100 -0
- package/src/runtime/context/emission-rules.js +118 -0
- package/src/runtime/context/identity.js +227 -0
- package/src/runtime/context/mandatory.js +594 -0
- package/src/runtime/context/pointer.js +142 -0
- package/src/runtime/context/primary-command.js +117 -0
- package/src/runtime/context/primary.js +344 -0
- package/src/runtime/context/summary-store.js +655 -0
- package/src/runtime/context-pack.js +1106 -245
- package/src/runtime/decision-register.js +13 -4
- package/src/runtime/dispatch/admission.js +392 -0
- package/src/runtime/dispatch/attempt-end.js +274 -0
- package/src/runtime/dispatch/command.js +628 -0
- package/src/runtime/dispatch/controls.js +904 -0
- package/src/runtime/dispatch/envelope.js +276 -0
- package/src/runtime/dispatch/grants.js +310 -0
- package/src/runtime/dispatch/integrate.js +617 -0
- package/src/runtime/dispatch/loop.js +1835 -0
- package/src/runtime/dispatch/store.js +352 -0
- package/src/runtime/dispatch/verify-run.js +201 -0
- package/src/runtime/evidence-fields.js +39 -0
- package/src/runtime/evidence-ledger.js +41 -7
- package/src/runtime/failure/capture.js +3 -1
- package/src/runtime/failure/cli.js +25 -9
- package/src/runtime/failure/home.js +57 -30
- package/src/runtime/failure/store.js +7 -2
- package/src/runtime/feature-pointer.js +174 -0
- package/src/runtime/feature-resolve.js +13 -2
- package/src/runtime/fleet/command.js +77 -0
- package/src/runtime/fleet/projects.js +178 -0
- package/src/runtime/fleet/tree.js +383 -0
- package/src/runtime/freshness.js +77 -10
- package/src/runtime/git-memo.js +46 -0
- package/src/runtime/guidance/ablation.js +427 -0
- package/src/runtime/health.js +565 -17
- package/src/runtime/history-compactor.js +13 -3
- package/src/runtime/implementation-gate.js +277 -22
- package/src/runtime/inventory/coverage.js +1 -1
- package/src/runtime/inventory/index.js +1 -1
- package/src/runtime/inventory/precedence.js +2 -2
- package/src/runtime/inventory/siblings.js +6 -4
- package/src/runtime/knowledge/code-corpus.js +277 -0
- package/src/runtime/knowledge/code-lexical.js +130 -0
- package/src/runtime/knowledge/code-retrieval.js +307 -0
- package/src/runtime/knowledge/code-validation.js +106 -0
- package/src/runtime/knowledge/gp3-gate.js +74 -0
- package/src/runtime/knowledge/graph-adapter.js +288 -0
- package/src/runtime/knowledge/graph-fallback.js +394 -0
- package/src/runtime/knowledge/hybrid.js +136 -8
- package/src/runtime/knowledge/retrieval.js +34 -1
- package/src/runtime/knowledge/rtk-compress.js +77 -0
- package/src/runtime/knowledge/semble-bridge.py +106 -0
- package/src/runtime/knowledge/semble-lifecycle.js +114 -0
- package/src/runtime/knowledge/semble-provider.js +365 -0
- package/src/runtime/lifecycle/cli.js +16 -6
- package/src/runtime/lifecycle/event-store.js +8 -6
- package/src/runtime/lifecycle/followup.js +6 -1
- package/src/runtime/lifecycle/overview.js +24 -1
- package/src/runtime/lifecycle/report-store.js +8 -10
- package/src/runtime/lifecycle/retention.js +95 -31
- package/src/runtime/lifecycle/root.js +9 -1
- package/src/runtime/lifecycle/status.js +34 -17
- package/src/runtime/lifecycle/store-upkeep.js +56 -7
- package/src/runtime/mask.js +134 -7
- package/src/runtime/mcp-consultations.js +40 -6
- package/src/runtime/model-router.js +79 -7
- package/src/runtime/models/catalogue.js +191 -0
- package/src/runtime/models/command.js +153 -0
- package/src/runtime/off-words.js +12 -0
- package/src/runtime/outcome.js +3 -3
- package/src/runtime/packages/command.js +1009 -0
- package/src/runtime/packages/contributions.js +116 -0
- package/src/runtime/packages/digest.js +132 -0
- package/src/runtime/packages/fetch.js +182 -0
- package/src/runtime/packages/grants.js +192 -0
- package/src/runtime/packages/index-file.js +134 -0
- package/src/runtime/packages/instruction.js +90 -0
- package/src/runtime/packages/manifest.js +331 -0
- package/src/runtime/packages/points.js +477 -0
- package/src/runtime/packages/programs.js +216 -0
- package/src/runtime/packages/scaffold.js +277 -0
- package/src/runtime/packages/source.js +90 -0
- package/src/runtime/packages/state.js +164 -0
- package/src/runtime/packages/store.js +449 -0
- package/src/runtime/packages/tar.js +106 -0
- package/src/runtime/packages/view.js +406 -0
- package/src/runtime/plan-check.js +59 -0
- package/src/runtime/plan-content.js +324 -0
- package/src/runtime/policy-init.js +118 -0
- package/src/runtime/profiles/doctor.js +96 -0
- package/src/runtime/profiles/resolve.js +244 -0
- package/src/runtime/profiles/rollback.js +254 -0
- package/src/runtime/profiles/sampler.js +41 -0
- package/src/runtime/readiness-record.js +16 -11
- package/src/runtime/readiness.js +127 -16
- package/src/runtime/research-request.js +50 -25
- package/src/runtime/retrieval-plan.js +402 -73
- package/src/runtime/retrieval-record.js +293 -0
- package/src/runtime/review/command.js +246 -0
- package/src/runtime/review/dominance.js +68 -0
- package/src/runtime/review/findings.js +434 -0
- package/src/runtime/review/identity.js +255 -0
- package/src/runtime/review/protocol-command.js +109 -0
- package/src/runtime/review/protocols.js +405 -0
- package/src/runtime/review/resolve-protocol.js +302 -0
- package/src/runtime/review/start.js +530 -0
- package/src/runtime/roadmap/facts.js +479 -0
- package/src/runtime/roadmap/gates.js +270 -0
- package/src/runtime/roadmap/loop.js +1636 -0
- package/src/runtime/roadmap/merge.js +381 -0
- package/src/runtime/roadmap/rows.js +1113 -0
- package/src/runtime/roadmap/seed.js +951 -0
- package/src/runtime/rules-report.js +336 -0
- package/src/runtime/scaffold/artifacts.js +63 -9
- package/src/runtime/scaffold/generate.js +21 -9
- package/src/runtime/settings/autopilot.js +106 -0
- package/src/runtime/settings/cli.js +280 -0
- package/src/runtime/settings/config-write.js +314 -0
- package/src/runtime/settings/files.js +271 -0
- package/src/runtime/settings/legacy.js +154 -0
- package/src/runtime/settings/lexical.js +56 -0
- package/src/runtime/settings/prepared-run.js +269 -0
- package/src/runtime/settings/project-layers.js +118 -0
- package/src/runtime/settings/refs.js +288 -0
- package/src/runtime/settings/registry.js +553 -0
- package/src/runtime/settings/resolve.js +713 -0
- package/src/runtime/settings/shared.js +37 -0
- package/src/runtime/settings/worker-billing.js +107 -0
- package/src/runtime/settings/write.js +269 -0
- package/src/runtime/slot-command.js +78 -0
- package/src/runtime/slots.js +671 -0
- package/src/runtime/source-version.js +290 -0
- package/src/runtime/state-root.js +217 -0
- package/src/runtime/storage/cli.js +12 -5
- package/src/runtime/storage/engine.js +9 -2
- package/src/runtime/storage/registry.js +14 -1
- package/src/runtime/storage/roots.js +66 -16
- package/src/runtime/storage/rules.js +82 -10
- package/src/runtime/storage/upkeep.js +10 -2
- package/src/runtime/storage/work-status.js +245 -26
- package/src/runtime/task-attempts.js +589 -69
- package/src/runtime/task-classifier.js +47 -11
- package/src/runtime/task-graph.js +373 -0
- package/src/runtime/task-run.js +778 -0
- package/src/runtime/task-scope.js +202 -56
- package/src/runtime/task-sources.js +147 -0
- package/src/runtime/task-state.js +440 -65
- package/src/runtime/team/admission.js +301 -0
- package/src/runtime/team/envelope.js +324 -0
- package/src/runtime/team/review-guard.js +156 -0
- package/src/runtime/trace/analyze.js +427 -0
- package/src/runtime/trace/baseline.js +770 -0
- package/src/runtime/trace/ledger.js +63 -140
- package/src/runtime/trace/otlp-export.js +568 -0
- package/src/runtime/trace/otlp-map.js +481 -0
- package/src/runtime/trace/spans.js +745 -0
- package/src/runtime/trace/telemetry.js +225 -0
- package/src/runtime/trace/views.js +1 -0
- package/src/runtime/transcripts/command.js +98 -0
- package/src/runtime/transcripts/cursor.js +326 -0
- package/src/runtime/transcripts/read.js +126 -0
- package/src/runtime/transcripts/readers/claude-jsonl.js +74 -0
- package/src/runtime/transcripts/readers/codex-rollout.js +70 -0
- package/src/runtime/transcripts/readers/copilot-events.js +90 -0
- package/src/runtime/transcripts/readers/kiro-jsonl.js +77 -0
- package/src/runtime/transcripts/readers/pi-jsonl.js +59 -0
- package/src/runtime/transcripts/registry.js +161 -0
- package/src/runtime/transcripts/stats.js +161 -0
- package/src/runtime/verification/check-key.js +628 -0
- package/src/runtime/verification/contract-runner.js +546 -11
- package/src/runtime/verification/engine.js +499 -9
- package/src/runtime/verification/impact.js +617 -0
- package/src/runtime/verification/inflight.js +205 -0
- package/src/runtime/verification/registry.js +176 -0
- package/src/runtime/verification/reuse.js +184 -0
- package/src/runtime/verification/telemetry-emit.js +254 -0
- package/src/runtime/verification/test-selection.js +67 -7
- package/src/runtime/worker/active.js +90 -0
- package/src/runtime/worker/cancel.js +222 -0
- package/src/runtime/worker/catalogue.js +122 -0
- package/src/runtime/worker/command.js +677 -0
- package/src/runtime/worker/evidence.js +288 -0
- package/src/runtime/worker/launch.js +288 -0
- package/src/runtime/worker/models.js +137 -0
- package/src/runtime/worker/parsers.js +218 -0
- package/src/runtime/worker/probes/index.js +706 -0
- package/src/runtime/worker/process-tree.js +415 -0
- package/src/runtime/worker/quota.js +43 -0
- package/src/runtime/worker/readiness.js +713 -0
- package/src/runtime/worker/run-store.js +166 -0
- package/src/runtime/worker/supervisor.js +541 -0
- package/src/runtime/worker/worktree-check.js +252 -0
- package/src/runtime/workflow-engine.js +5 -1
- package/src/runtime/workflow-orchestrator.js +578 -63
- package/src/runtime/worktree.js +149 -22
- package/src/state/index.js +1 -1
- package/src/state/lockfile.js +64 -10
- package/src/state/run-lock.js +1 -1
- package/types/node-commonjs.d.ts +106 -7
- package/core/.antigravity-plugin/hooks.json +0 -39
- package/core/harnesses/gemini/hooks/hooks.json +0 -77
- package/core/harnesses/gemini/hooks/lib.sh +0 -302
- package/core/harnesses/gemini/hooks/mcp-tool-guard.sh +0 -21
- package/core/harnesses/gemini/hooks/post-edit-lint.sh +0 -39
- package/core/harnesses/gemini/hooks/pre-bash-guard.sh +0 -21
- package/core/harnesses/gemini/hooks/pre-compact.sh +0 -38
- package/core/harnesses/gemini/hooks/pre-implement-gate.sh +0 -22
- package/core/harnesses/gemini/hooks/session-end.impl.sh +0 -89
- package/core/harnesses/gemini/hooks/session-end.sh +0 -5
- package/core/harnesses/gemini/hooks/session-start.sh +0 -5
- package/core/harnesses/gemini/settings/adapter-defaults.json +0 -4
- package/core/harnesses/shared/hooks/adapters/arg-fields.js +0 -19
- package/core/harnesses/shared/hooks/adapters/gemini.js +0 -114
- package/core/harnesses/shared/hooks/hooks.json +0 -47
- package/core/shared/guidance/FLAGS.md +0 -25
- package/core/shared/guidance/rules/RULE_01_SAFETY.md +0 -25
- package/core/shared/guidance/rules/RULE_02_WORKFLOW.md +0 -23
- package/core/shared/guidance/rules/RULE_03_QUALITY.md +0 -14
- package/core/shared/guidance/rules/RULE_04_QUESTIONS.md +0 -46
- package/src/adapters/gemini/hooks.js +0 -210
- package/src/adapters/gemini/index.js +0 -390
|
@@ -18,12 +18,14 @@
|
|
|
18
18
|
// handle<Name>Command(...)` — to cross-check the dispatcher's verb table in both directions. Keep
|
|
19
19
|
// every case in exactly that shape.
|
|
20
20
|
// TypeScript migration (agent-docs/BRIEF_GOAL_DOFLOW.md): run directly by Node native type-stripping.
|
|
21
|
-
const fs = require('node:fs');
|
|
22
21
|
const os = require('node:os');
|
|
23
22
|
const path = require('node:path');
|
|
24
23
|
const {
|
|
25
24
|
handleCapabilitiesCommand, handleReadinessCommand, handleEvidenceCommand,
|
|
25
|
+
handleContextEmitCommand, handleContextGrantCommand,
|
|
26
26
|
} = require('../runtime/cli.js');
|
|
27
|
+
const { loadRegistry } = require('../registry/index.js');
|
|
28
|
+
const { enforcementFor, UnknownEnforcementTarget } = require('../lifecycle/coverage.js');
|
|
27
29
|
// `doctor` comes from the health module rather than src/runtime/cli.js: the health-probe report
|
|
28
30
|
// (FR-013) supersedes the presence-check version, and one verb must have one implementation.
|
|
29
31
|
const { handleDoctorCommand } = require('../runtime/health.js');
|
|
@@ -39,37 +41,131 @@ const { handleWorkflowCommand } = require('../runtime/workflow-engine.js');
|
|
|
39
41
|
const { handleOrchestrateCommand } = require('../runtime/workflow-orchestrator.js');
|
|
40
42
|
const { handleResearchRequestCommand } = require('../runtime/research-request.js');
|
|
41
43
|
const { handleTaskAttemptCommand } = require('../runtime/task-attempts.js');
|
|
44
|
+
const { handleWorkerCommand } = require('../runtime/worker/command.js');
|
|
45
|
+
const { handleDispatchCommand } = require('../runtime/dispatch/command.js');
|
|
42
46
|
const { handleRetrieveCommand } = require('../runtime/knowledge/retrieval.js');
|
|
43
47
|
const { handleModelRoleCommand } = require('../runtime/model-router.js');
|
|
44
48
|
const { handleRouteCommand } = require('../runtime/capability-router.js');
|
|
45
49
|
const { handleContextPackCommand } = require('../runtime/context-pack.js');
|
|
46
50
|
const { handleRetrievalPlanCommand } = require('../runtime/retrieval-plan.js');
|
|
47
51
|
const { handleOutcomeCommand } = require('../runtime/outcome.js');
|
|
48
|
-
const { handleVerifyCommand } = require('../runtime/verification/engine.js');
|
|
52
|
+
const { handleVerifyCommand, verifyStateRoot } = require('../runtime/verification/engine.js');
|
|
49
53
|
const { handleLeakScanCommand } = require('../runtime/leak-scan.js');
|
|
50
54
|
const { handleRecoverCommand } = require('../runtime/recovery.js');
|
|
51
55
|
const { handleScaffoldCommand } = require('../runtime/scaffold/generate.js');
|
|
52
|
-
const { handleDecisionCommand } = require('../runtime/decision-register.js');
|
|
56
|
+
const { handleDecisionCommand, isReservedChannel, CHANNEL_RESERVED } = require('../runtime/decision-register.js');
|
|
53
57
|
const { handleFollowupCommand, handleLifecycleCommand, handleGoalCommand } = require('../runtime/lifecycle/cli.js');
|
|
54
58
|
const { projectRoot: lifecycleProjectRoot } = require('../runtime/lifecycle/root.js');
|
|
55
59
|
const { upkeepAfterVerb } = require('../runtime/storage/upkeep.js');
|
|
56
60
|
const { handleStorageCommand } = require('../runtime/storage/cli.js');
|
|
61
|
+
const { handleRoadmapCommand, resolveMainRoot } = require('../runtime/roadmap/loop.js');
|
|
62
|
+
const { handlePlanCheckCommand } = require('../runtime/plan-check.js');
|
|
63
|
+
const { handleSlotCommand } = require('../runtime/slot-command.js');
|
|
64
|
+
const { handleReviewCommand } = require('../runtime/review/command.js');
|
|
65
|
+
const { handleProtocolCommand } = require('../runtime/review/protocol-command.js');
|
|
66
|
+
const { handleRulesCommand } = require('../runtime/rules-report.js');
|
|
67
|
+
const { handlePackageCommand } = require('../runtime/packages/command.js');
|
|
68
|
+
const { handleModelsCommand } = require('../runtime/models/command.js');
|
|
69
|
+
// `plan-check` is read-only (115 IC-001): no upkeep, which would write `.gitignore` and `upkeep-due`.
|
|
70
|
+
// `review` writes only its one telemetry line (095 IC-003).
|
|
71
|
+
// `protocol` only prints the registry and the resolved protocol (119 IC-004), so it has nothing to keep up.
|
|
72
|
+
// `rules` only prints the values the runtime owns, with their sources, and writes nothing.
|
|
73
|
+
// `primary` only prints the resolved main session (120 IC-008) and writes nothing.
|
|
74
|
+
// `fleet` only lists the projects this machine knows from two read-only stores (093 IC-019) and writes nothing.
|
|
75
|
+
// `transcript` only reads agents' transcripts and DoFlow's own records and prints them (093 IC-022, IC-023); it writes nothing.
|
|
76
|
+
// `package` stays here (122 IC-012): `new` writes only the target folder; `add --plan`, `update --plan` and `remove` write the store and lock and run upkeep (see `runsUpkeep`).
|
|
77
|
+
// `slot` is not here: `run`, `list` and `release` write the slot files and run upkeep; only `slot --action peek` is read-only and skips it (093 IC-018 b, see `runsUpkeep`).
|
|
78
|
+
const NO_UPKEEP = new Set(['storage', 'config', 'plan-check', 'review', 'protocol', 'rules', 'primary', 'package', 'models', 'fleet', 'transcript']);
|
|
79
|
+
const runsUpkeep = (o ) => (!NO_UPKEEP.has(o.cmd) && !(o.cmd === 'slot' && o.actionGiven && o.action === 'peek'))
|
|
80
|
+
|| (o.cmd === 'package' && ((typeof o.planId === 'string' && (o.action === 'add' || o.action === 'update')) || o.action === 'remove'));
|
|
57
81
|
// Required on first use, so a CLI whose failure modules cannot be loaded still runs every other verb.
|
|
58
82
|
function handleFailureCommand(options ) { return require('../runtime/failure/cli.js').handleFailureCommand(options); }
|
|
83
|
+
// The seed validator loads only for `roadmap seed`, and only this file may require it (G54).
|
|
84
|
+
function handleSeedCommand(options ) { return require('../runtime/roadmap/seed.js').handleSeedCommand(options); }
|
|
85
|
+
// maint-thin: `roadmap promote <id...>` lives in seed.ts too, so it stays out of every autopilot module (G54).
|
|
86
|
+
function handlePromoteCommand(options ) { return require('../runtime/roadmap/seed.js').handlePromoteCommand(options); }
|
|
87
|
+
// Settings support is needed only when the config verb runs.
|
|
88
|
+
function handleConfigCommand(options ) { return require('../runtime/settings/cli.js').handleConfigCommand(options); }
|
|
89
|
+
// The primary verb (row 120 A.4) needs the settings resolver only when it runs.
|
|
90
|
+
function handlePrimaryCommand(options ) { return require('../runtime/context/primary-command.js').handlePrimaryCommand(options); }
|
|
91
|
+
// The fleet verb (093 V.3) loads only when it runs.
|
|
92
|
+
function handleFleetCommand(options ) { return require('../runtime/fleet/command.js').handleFleetCommand(options); }
|
|
93
|
+
// The transcript verb (093 V.6) loads only when it runs.
|
|
94
|
+
function handleTranscriptCommand(options ) { return require('../runtime/transcripts/command.js').handleTranscriptCommand(options); }
|
|
59
95
|
const { handleInventoryCommand } = require('../runtime/inventory/index.js');
|
|
60
96
|
const { finishRuntime, usageError } = require('../runtime/cli-result.js');
|
|
61
|
-
const {
|
|
62
|
-
const { listCheckouts } = require('../runtime/checkouts.js');
|
|
97
|
+
const { setRecordSlug, callerFeatureSlug, invalidSlugRefusal, slugNamesNoFeature } = require('../runtime/task-scope.js');
|
|
98
|
+
const { listCheckouts, mayBeLinked } = require('../runtime/checkouts.js');
|
|
99
|
+
const { taskStateRoot, sweepWorktreeRecords } = require('../runtime/state-root.js');
|
|
63
100
|
const { featureSlugFor } = require('../runtime/implementation-gate.js');
|
|
64
101
|
const { handleBriefToolsCommand } = require('../runtime/brief-tools.js');
|
|
65
|
-
|
|
102
|
+
// Advice writers load settings/write.ts, so keep that surface off installer and other verb paths.
|
|
103
|
+
function handleAdviseCommand(options ) { return require('../runtime/advice/cli.js').handleAdviseCommand(options); }
|
|
66
104
|
const { REPO_ROOT, buildAdapterRegistry } = require('./shared.js');
|
|
67
105
|
|
|
68
106
|
/** Where `readiness`/`evidence` read and write per-task state. Mirrors scopeOf()'s rules so these
|
|
69
107
|
* commands are scope-aware like the rest of the CLI, rather than defaulting to the DoFlow install
|
|
70
108
|
* directory — which for an npm install is inside node_modules/. */
|
|
71
109
|
function evidenceRoot(o ) {
|
|
72
|
-
|
|
110
|
+
if (o.global) return os.homedir();
|
|
111
|
+
// `roadmap seed [<project>]` (113 IC-001): the sub-verb takes the first positional slot, so the project root is the one after it.
|
|
112
|
+
if (o.cmd === 'roadmap' && o.positional[0] === 'seed') return path.resolve(o.positional[1] || '.');
|
|
113
|
+
return path.resolve(o.positional[0] || '.');
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** The `trace` views that take the first positional slot: `spans` (088 IC-011), `analyze` (091 IC-001), `export` (091 IC-006). */
|
|
117
|
+
const TRACE_VIEWS = new Set(['spans', 'analyze', 'export']);
|
|
118
|
+
|
|
119
|
+
/** `trace spans|analyze|export [<project>]`: the view name takes the first positional slot, so the
|
|
120
|
+
* project root is the one after it. Every other call is `evidenceRoot(o)`. */
|
|
121
|
+
function traceViewRoot(o ) {
|
|
122
|
+
return o.cmd === 'trace' && TRACE_VIEWS.has(o.positional[0]) && !o.global ? path.resolve(o.positional[1] || '.') : evidenceRoot(o);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** `roadmap`: the runner, the `seed` sub-verb (113 IC-001), or the `promote` sub-verb (maint-thin), each taking the
|
|
126
|
+
* first positional slot and setting the exit code itself; `promote` runs on the main checkout of the working directory. */
|
|
127
|
+
function handleRoadmapVerbCommand(o ) {
|
|
128
|
+
const action = o.actionGiven ? o.action : undefined;
|
|
129
|
+
if (o.positional[0] === 'seed') return finishRuntime(handleSeedCommand({ action, draft: o.draft, json: o.json, cwd: process.cwd(), root: resolveMainRoot(evidenceRoot(o)) }));
|
|
130
|
+
if (o.positional[0] === 'promote') return finishRuntime(handlePromoteCommand({ ids: o.positional.slice(1), json: o.json, root: resolveMainRoot(process.cwd()) }));
|
|
131
|
+
// `init-policy --commit` commits the policy onto develop; it lives outside the loop's tree (G53, G54). Any other action with --commit is the loop's exit 2.
|
|
132
|
+
if (o.commit && action === 'init-policy') return require('../runtime/policy-init.js').commitPolicyCommand({ json: o.json, root: resolveMainRoot(evidenceRoot(o)), repoRoot: REPO_ROOT });
|
|
133
|
+
return handleRoadmapCommand({ action, check: o.check, commit: o.commit, json: o.json, run: o.run, row: o.row, cwd: evidenceRoot(o), repoRoot: REPO_ROOT });
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Where `trace analyze --emit followups --task-id` reads the task's evidence ledger: the store root
|
|
138
|
+
* and record slug the `evidence` verb writes under (115 IC-004, C-1), so a linked worktree reads the
|
|
139
|
+
* main checkout's namespaced ledger. Read only: no sweep, so a record still left in the worktree's
|
|
140
|
+
* own store is not cited. Undefined when no ledger is read; the handler refuses the flag mix itself.
|
|
141
|
+
*/
|
|
142
|
+
function analyzeLedgerRoot(o ) {
|
|
143
|
+
if (o.emit !== 'followups' || typeof o.taskId !== 'string') return undefined;
|
|
144
|
+
const caller = traceViewRoot(o);
|
|
145
|
+
const checkouts = !o.global && mayBeLinked(caller) ? listCheckouts({ cwd: caller }) : null;
|
|
146
|
+
setRecordSlug(() => o.slug || callerFeatureSlug({ projectRoot: caller, taskId: o.taskId }) || null);
|
|
147
|
+
return taskStateRoot({ global: o.global, positional: [caller] }, checkouts).root;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/** `trace`: the ledger trajectory, unchanged, or the `spans`, `analyze` or `export` view, whose modules load
|
|
151
|
+
* only for that view so `trace` and `stats` read nothing new (NFR-010, 091 NFR-009). */
|
|
152
|
+
function handleTraceViewCommand(o ) {
|
|
153
|
+
if (o.positional[0] === 'analyze') {
|
|
154
|
+
return require('../runtime/trace/analyze.js').handleTraceAnalyze({ positional: o.positional.slice(1), run: o.run, json: o.json, global: o.global,
|
|
155
|
+
emit: o.emit, taskId: o.taskId, stateRoot: analyzeLedgerRoot(o) });
|
|
156
|
+
}
|
|
157
|
+
if (o.positional[0] === 'export') {
|
|
158
|
+
return require('../runtime/trace/otlp-export.js').handleTraceExport({
|
|
159
|
+
positional: o.positional.slice(1),
|
|
160
|
+
run: o.run,
|
|
161
|
+
json: o.json,
|
|
162
|
+
global: o.global,
|
|
163
|
+
dryRun: o.dryRun,
|
|
164
|
+
otlpHttp: o.otlpHttp,
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
if (o.positional[0] !== 'spans') return handleTraceCommand({ json: o.json, days: o.days, global: o.global, projectRoot: evidenceRoot(o) });
|
|
168
|
+
return require('../runtime/trace/spans.js').handleTraceSpans({ positional: o.positional.slice(1), run: o.run, json: o.json, global: o.global });
|
|
73
169
|
}
|
|
74
170
|
|
|
75
171
|
/**
|
|
@@ -111,6 +207,9 @@ function evidenceItemFromFlags(o ) {
|
|
|
111
207
|
if (o.locator !== undefined) item.locator = o.locator;
|
|
112
208
|
if (o.content !== undefined) item.content = o.content;
|
|
113
209
|
if (o.establishes !== undefined) item.establishes = o.establishes;
|
|
210
|
+
if (o.need !== undefined) item.need = o.need;
|
|
211
|
+
if (o.result !== undefined) item.result = o.result;
|
|
212
|
+
if (o.absence !== undefined) item.absence = o.absence;
|
|
114
213
|
// Both halves of an observation travel together; a lone half must reach the write boundary as
|
|
115
214
|
// the partial object it is, so the refusal names the missing field instead of dropping the pair.
|
|
116
215
|
if (o.observedCommand !== undefined || o.observedExit !== undefined) {
|
|
@@ -125,28 +224,21 @@ function evidenceItemFromFlags(o ) {
|
|
|
125
224
|
return item;
|
|
126
225
|
}
|
|
127
226
|
|
|
128
|
-
/** Verbs that read or write per-task records, and so accept `--slug` (IC-002).
|
|
129
|
-
|
|
227
|
+
/** Verbs that read or write per-task records, and so accept `--slug` (IC-002). Their records, and
|
|
228
|
+
* `orchestrate`'s run and `context-emit`'s delivery, live in `taskStateRoot` (115 IC-004). */
|
|
229
|
+
const TASK_STORE_VERBS = new Set(['evidence', 'claim', 'readiness', 'context-pack', 'research-request', 'outcome', 'retrieval-plan', 'retrieve']);
|
|
130
230
|
|
|
131
|
-
/**
|
|
132
|
-
|
|
133
|
-
|
|
231
|
+
/** The checkout a call runs in: `context-emit`'s `--cwd`, else the positional project root. */
|
|
232
|
+
function callerRoot(o ) {
|
|
233
|
+
return o.cmd === 'context-emit' && typeof o.cwd === 'string' && o.cwd !== '' ? path.resolve(o.cwd) : evidenceRoot(o);
|
|
234
|
+
}
|
|
134
235
|
|
|
135
|
-
/**
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
*/
|
|
142
|
-
function featureStoreRoot(o ) {
|
|
143
|
-
if (!FEATURE_STORE_VERBS.has(o.cmd) || o.global) return null;
|
|
144
|
-
const checkouts = listCheckouts({ cwd: evidenceRoot(o) });
|
|
145
|
-
if (!checkouts.isLinked) return null;
|
|
146
|
-
const slug = featureSlugFor({ projectRoot: checkouts.current, slug: o.slug });
|
|
147
|
-
const folder = (root ) => path.join(root, 'agent-docs', 'doflow', slug || '');
|
|
148
|
-
if (!slug || fs.existsSync(folder(checkouts.current)) || !fs.existsSync(folder(checkouts.main))) return null;
|
|
149
|
-
return { root: checkouts.main, slug };
|
|
236
|
+
/** The store conflicts a sweep found, one line each (IC-006). */
|
|
237
|
+
function conflictText(o , sweep ) {
|
|
238
|
+
const lines = sweep.conflicts.map((c ) => (c.reason === 'link' ? ` ${c.worktree} -> ${c.main}: a link on the way, nothing is moved through it`
|
|
239
|
+
: c.reason === 'same-file' ? ` ${c.worktree} and ${c.main} are one file` : ` ${c.worktree} differs from ${c.main}`));
|
|
240
|
+
return `doflow ${o.cmd}: store-conflict: ${sweep.conflicts.length} record(s) in this worktree could not be moved to the main checkout; `
|
|
241
|
+
+ `files already moved stay moved. Keep one copy of each pair and remove the other, then re-run.\n${lines.join('\n')}`;
|
|
150
242
|
}
|
|
151
243
|
|
|
152
244
|
/**
|
|
@@ -156,6 +248,14 @@ function featureStoreRoot(o ) {
|
|
|
156
248
|
* to the engine module each case names.
|
|
157
249
|
*/
|
|
158
250
|
function dispatchRuntimeCommandInner(o , moment ) {
|
|
251
|
+
// IC-005: no caller names a decider. orchestrate takes no --by, and the channel `policy` (decided
|
|
252
|
+
// by autopilot) is refused on every verb, before any state is read or written.
|
|
253
|
+
if (o.cmd === 'orchestrate' && o.by !== undefined) {
|
|
254
|
+
return usageError('orchestrate', '--by is not accepted; the runtime derives the gate decider', o.json);
|
|
255
|
+
}
|
|
256
|
+
if (isReservedChannel(o.channel)) {
|
|
257
|
+
return usageError(o.cmd, CHANNEL_RESERVED, o.json);
|
|
258
|
+
}
|
|
159
259
|
// A slug becomes a directory name and a state key, so one that could name a path is refused
|
|
160
260
|
// here, once, for every verb that reads `--slug`, before any of them reads or writes state
|
|
161
261
|
// (FR-013, IC-009). A well-formed slug that names no feature is the verbs' own business.
|
|
@@ -169,34 +269,75 @@ function dispatchRuntimeCommandInner(o , moment ) {
|
|
|
169
269
|
// here so the verbs whose handlers build their own ledger (readiness, evidence) route the same
|
|
170
270
|
// way as the ones that take `slug` directly. The orchestration journal is keyed by slug already.
|
|
171
271
|
// Reset on every dispatch, so one invocation's slug can never carry into the next in-process call.
|
|
172
|
-
|
|
173
|
-
|
|
272
|
+
// `retrieve` is a task-store verb only as bound code retrieval (--scope code with --task-id or --slug):
|
|
273
|
+
// guidance retrieval and unbound code retrieval record nothing in a feature store, so they keep the
|
|
274
|
+
// pre-079 dispatch (no checkout listing, no feature resolver, no store note).
|
|
275
|
+
const storeVerb = (verbs ) => verbs.has(o.cmd) && (o.cmd !== 'retrieve' || (o.scope === 'code' && Boolean(o.taskId || o.slug)));
|
|
276
|
+
const recordVerb = storeVerb(TASK_STORE_VERBS) || o.cmd === 'orchestrate' || o.cmd === 'context-emit';
|
|
277
|
+
const caller = callerRoot(o);
|
|
278
|
+
// `evidence` always lists: its attempt lookup reuses the main checkout from this one listing.
|
|
279
|
+
const checkouts = recordVerb && !o.global && (o.cmd === 'evidence' || mayBeLinked(caller))
|
|
280
|
+
? listCheckouts({ cwd: caller }) : null;
|
|
281
|
+
// 115 IC-004: a linked, non-sandbox worktree keeps every per-task record in the main checkout.
|
|
282
|
+
const { root: storeRoot, redirected } = recordVerb ? taskStateRoot(o, checkouts) : { root: evidenceRoot(o), redirected: false };
|
|
283
|
+
const attemptRoot = checkouts?.ok && !checkouts.sandbox ? (checkouts.main || checkouts.current || null) : null;
|
|
174
284
|
// Use the same root resolver as the handler: task redirection, the nearest run ledger,
|
|
175
285
|
// and lifecycle's shared main-worktree store are deliberately different scopes.
|
|
176
286
|
try {
|
|
177
287
|
if (['trace', 'stats', 'discover'].includes(o.cmd)) {
|
|
178
|
-
moment.projectRoot = path.dirname(resolveRunsLocation({ start:
|
|
179
|
-
} else if (['followup', 'lifecycle', 'goal', 'task-attempt'].includes(o.cmd)) {
|
|
288
|
+
moment.projectRoot = path.dirname(resolveRunsLocation({ start: traceViewRoot(o), global: o.global }).configDir);
|
|
289
|
+
} else if (['followup', 'lifecycle', 'goal', 'task-attempt', 'worker', 'dispatch'].includes(o.cmd)) {
|
|
180
290
|
moment.projectRoot = lifecycleProjectRoot(evidenceRoot(o));
|
|
291
|
+
} else if (o.cmd === 'plan-check' || o.cmd === 'slot') {
|
|
292
|
+
moment.projectRoot = process.cwd(); // the first positional of plan-check is a file, never a project root
|
|
293
|
+
} else if (o.cmd === 'verify') {
|
|
294
|
+
moment.projectRoot = verifyStateRoot({ start: evidenceRoot(o) }).projectRoot; // the store verify writes, never a cwd fragment
|
|
181
295
|
} else {
|
|
182
296
|
moment.projectRoot = storeRoot;
|
|
183
297
|
}
|
|
184
298
|
} catch { /* a failed upkeep lookup must not change the verb's answer */ }
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
299
|
+
// 115 C-1: one record slug per call, `--slug`, else the feature of the checkout the verb runs in,
|
|
300
|
+
// used by every store the call touches (task-scope.ts). It is looked up on first use, so a
|
|
301
|
+
// `context-emit` event that compiles no pack spawns no resolver. Reset on every dispatch, so one
|
|
302
|
+
// invocation's slug can never carry into the next in-process call. `retrieve` is a task-store verb
|
|
303
|
+
// only as bound code retrieval (--scope code with --task-id or --slug).
|
|
304
|
+
let slugMemo ;
|
|
305
|
+
const recordSlug = () => {
|
|
306
|
+
if (slugMemo === undefined) {
|
|
307
|
+
try { slugMemo = o.slug || callerFeatureSlug({ projectRoot: caller, taskId: o.taskId }) || null; } catch { slugMemo = null; }
|
|
308
|
+
}
|
|
309
|
+
return slugMemo ;
|
|
310
|
+
};
|
|
311
|
+
setRecordSlug(recordVerb ? recordSlug : undefined);
|
|
312
|
+
const storeSlug = recordVerb && o.cmd !== 'context-emit' ? recordSlug() : undefined;
|
|
313
|
+
if (redirected && o.cmd !== 'context-emit') {
|
|
314
|
+
console.error(`doflow ${o.cmd}: note: records are kept in the main checkout ${storeRoot}`);
|
|
189
315
|
}
|
|
190
|
-
// A well-formed slug that names no feature
|
|
191
|
-
//
|
|
192
|
-
if (
|
|
193
|
-
&& slugNamesNoFeature({
|
|
194
|
-
console.error(`doflow ${o.cmd}: note: --slug '${o.slug}' names no feature;
|
|
316
|
+
// A well-formed slug that names no feature folder still names the records' namespace, but the
|
|
317
|
+
// caller typed it expecting a feature, so say so once, on stderr only.
|
|
318
|
+
if (storeVerb(TASK_STORE_VERBS) && typeof o.slug === 'string' && o.slug !== ''
|
|
319
|
+
&& slugNamesNoFeature({ projectRoots: redirected ? [caller, storeRoot] : [caller], slug: o.slug })) {
|
|
320
|
+
console.error(`doflow ${o.cmd}: note: --slug '${o.slug}' names no feature folder; its records are kept under that slug`);
|
|
321
|
+
}
|
|
322
|
+
// 115 IC-006: every record left in the worktree's own store moves to the main checkout first, in one
|
|
323
|
+
// locked sweep; a record held in both with different bytes refuses the call before the verb runs.
|
|
324
|
+
// 092 IC-001, 093 IC-012: the orchestrate reads (list, status, timeline) write nothing, so they never sweep: they read the
|
|
325
|
+
// main checkout's store and see a record still left in this worktree as another checkout's
|
|
326
|
+
// (`orchestrationRuns`, `findRunFile`). The next write verb from here sweeps it as before.
|
|
327
|
+
const orchestrateRead = o.cmd === 'orchestrate' && (o.action === 'list' || o.action === 'status' || o.action === 'timeline');
|
|
328
|
+
if (redirected && !orchestrateRead) {
|
|
329
|
+
const sweep = sweepWorktreeRecords({ mainRoot: storeRoot, worktreeRoot: checkouts.current, recordSlug });
|
|
330
|
+
if (!sweep.ok) {
|
|
331
|
+
if (o.json) console.log(JSON.stringify(sweep, null, 2));
|
|
332
|
+
else console.error(conflictText(o, sweep));
|
|
333
|
+
return finishRuntime(2);
|
|
334
|
+
}
|
|
195
335
|
}
|
|
196
336
|
switch (o.cmd) {
|
|
197
337
|
// REPO_ROOT locates the capability registry; projectRoot is the tree whose index freshness
|
|
198
338
|
// and build/test commands are being reported on, which follows the usual scope rules.
|
|
199
339
|
case 'capabilities': return handleCapabilitiesCommand({ json: o.json, check: o.check, repoRoot: REPO_ROOT });
|
|
340
|
+
case 'enforcement': return handleEnforcementCommand(o);
|
|
200
341
|
case 'doctor': return handleDoctorCommand({ json: o.json, repoRoot: REPO_ROOT, projectRoot: evidenceRoot(o), adapters: buildAdapterRegistry() });
|
|
201
342
|
// REPO_ROOT locates the registry (templates ship with the package); stateRoot locates the
|
|
202
343
|
// caller's evidence, which follows the same scope rules as every other command: -g means
|
|
@@ -211,14 +352,14 @@ function dispatchRuntimeCommandInner(o , moment ) {
|
|
|
211
352
|
// than from evidence, so the gate had one reachable answer for every task. Forwarding is
|
|
212
353
|
// all this does: the handler names them back under `callerAsserted` so a stated input is
|
|
213
354
|
// never mistaken for a measured one.
|
|
214
|
-
case 'readiness': return handleReadinessCommand({ taskClass: requireTaskClass(o), taskId: requireTaskId(o), verificationPlan: o.verificationPlan, scopeClear: o.scope, invariants: o.invariants, userDecisionPending: o.userDecisionPending, mode: o.mode, slug: storeSlug, json: o.json, repoRoot: REPO_ROOT, stateRoot: storeRoot });
|
|
215
|
-
case 'evidence': return handleEvidenceCommand({ taskId: requireTaskId(o), action: o.action, item: evidenceItemFromFlags(o), batchPath: o.batchPath, evidenceId: o.evidenceId, replacedBy: o.replacedBy, json: o.json, repoRoot: REPO_ROOT, stateRoot: storeRoot });
|
|
355
|
+
case 'readiness': return handleReadinessCommand({ taskClass: requireTaskClass(o), taskId: requireTaskId(o), verificationPlan: o.verificationPlan, scopeClear: o.scope, invariants: o.invariants, userDecisionPending: o.userDecisionPending, mode: o.mode, slug: storeSlug, json: o.json, repoRoot: REPO_ROOT, stateRoot: storeRoot, sourceRoot: evidenceRoot(o) });
|
|
356
|
+
case 'evidence': return handleEvidenceCommand({ taskId: requireTaskId(o), action: o.action, item: evidenceItemFromFlags(o), batchPath: o.batchPath, evidenceId: o.evidenceId, replacedBy: o.replacedBy, stale: o.stale, json: o.json, repoRoot: REPO_ROOT, stateRoot: storeRoot, slug: storeSlug, sourceRoot: evidenceRoot(o), attemptRoot });
|
|
216
357
|
// Run-ledger views. They resolve their own ledger the way the dispatcher does (nearest
|
|
217
358
|
// `.doflow` walking up, or the global one) rather than assuming cwd is the project root, so
|
|
218
359
|
// a view invoked from a subdirectory reads the runs that were actually recorded.
|
|
219
360
|
// Exit codes follow design §4.2 and are set by the handler itself: 0 = answered, 1 = a
|
|
220
361
|
// finding the caller must act on.
|
|
221
|
-
case 'trace': return
|
|
362
|
+
case 'trace': return handleTraceViewCommand(o);
|
|
222
363
|
case 'stats': return handleStatsCommand({ json: o.json, days: o.days, global: o.global, projectRoot: evidenceRoot(o) });
|
|
223
364
|
case 'indicators': return handleIndicatorsCommand({ json: o.json, projectRoot: evidenceRoot(o) });
|
|
224
365
|
case 'discover': return handleDiscoverCommand({ json: o.json, days: o.days, global: o.global, projectRoot: evidenceRoot(o) });
|
|
@@ -229,6 +370,7 @@ function dispatchRuntimeCommandInner(o , moment ) {
|
|
|
229
370
|
// the process home directory inside the lifecycle view (design R7) and is not an argument.
|
|
230
371
|
case 'inventory': return handleInventoryCommand({ json: o.json, global: o.global, targets: o.targets, repoRoot: REPO_ROOT, projectRoot: path.resolve(o.positional[0] || '.') });
|
|
231
372
|
case 'storage': return handleStorageCommand({ action: o.actionGiven ? o.action : 'report', json: o.json, global: o.global, projectRoot: evidenceRoot(o) });
|
|
373
|
+
case 'config': return handleConfigCommand({ json: o.json, global: o.global, showOrigin: o.showOrigin, positional: o.positional, layer: o.layer, preparedRun: o.preparedRun, repoRoot: REPO_ROOT });
|
|
232
374
|
// No REPO_ROOT: the scaffold's repo root is the *caller's* repo, reported by the resolver,
|
|
233
375
|
// because the plan's `files:` paths are relative to it. Passing the DoFlow install here
|
|
234
376
|
// would detect the wrong language and mirror the wrong tree.
|
|
@@ -249,23 +391,47 @@ function dispatchRuntimeCommandInner(o , moment ) {
|
|
|
249
391
|
// state and source tree, following the same scope rules as every other command.
|
|
250
392
|
case 'classify': return handleClassifyCommand({ taskClass: o.taskClass, rationale: o.rationale, proposedBy: o.proposedBy, callingSkill: o.callingSkill, request: o.request, requestFile: o.requestFile, taskId: o.taskId, projectRoot: evidenceRoot(o), json: o.json });
|
|
251
393
|
case 'workflow': return handleWorkflowCommand({ taskClass: o.taskClass, json: o.json });
|
|
252
|
-
case 'orchestrate': return handleOrchestrateCommand({ action: o.action, taskId: o.taskId, taskClass: o.taskClass, stage: o.stage, gate: o.gate, node: o.node, decision: o.decision, note: o.note, reason: o.reason, forced: o.forced, verificationPlan: o.verificationPlan, scope: o.scope, invariants: o.invariants, result: o.result, mcpOutcome: o.mcpOutcome, callingSkill: o.callingSkill, slug: o.slug, json: o.json, repoRoot: REPO_ROOT, stateRoot: evidenceRoot(o), buildAdapters: buildAdapterRegistry });
|
|
253
|
-
case 'research-request': return handleResearchRequestCommand({ slug:
|
|
394
|
+
case 'orchestrate': return handleOrchestrateCommand({ action: o.action, taskId: o.taskId, taskClass: o.taskClass, stage: o.stage, gate: o.gate, node: o.node, decision: o.decision, policy: o.policy, note: o.note, reason: o.reason, forced: o.forced, verificationPlan: o.verificationPlan, scope: o.scope, invariants: o.invariants, result: o.result, mcpOutcome: o.mcpOutcome, callingSkill: o.callingSkill, slug: o.slug, recordSlug: storeSlug, dryRun: o.dryRun, json: o.json, repoRoot: REPO_ROOT, stateRoot: storeRoot, sourceRoot: evidenceRoot(o), buildAdapters: buildAdapterRegistry });
|
|
395
|
+
case 'research-request': return handleResearchRequestCommand({ slug: storeSlug, action: o.action === 'status' ? 'list' : o.action, taskId: requireTaskId(o), stageId: o.stageId, question: o.question, reason: o.reason, blocking: o.blocking === undefined ? undefined : o.blocking === 'true' ? true : o.blocking === 'false' ? false : o.blocking, requestId: o.requestId, outcome: o.researchOutcome, claimId: o.claimId, evidenceIds: o.evidenceIds, gap: o.gap, json: o.json, projectRoot: storeRoot, sourceRoot: evidenceRoot(o) });
|
|
254
396
|
// The store is shared by every linked worktree of the clone (lifecycle's main-worktree root); the
|
|
255
397
|
// feature is `--slug`, else the branch's, resolved the way decision and scaffold resolve it.
|
|
256
|
-
case 'task-attempt': return handleTaskAttemptCommand({ action: o.actionGiven ? o.action : undefined, slug: o.slug, task: o.task, owner: o.owner, mode: o.mode, token: o.token, result: o.result, evidenceId: o.evidenceId, reason: o.reason, json: o.json, cwd: evidenceRoot(o), resolveSlug: (cwd ) => featureSlugFor({ projectRoot: cwd }) });
|
|
257
|
-
|
|
398
|
+
case 'task-attempt': return handleTaskAttemptCommand({ action: o.actionGiven ? o.action : undefined, slug: o.slug, task: o.task, owner: o.owner, mode: o.mode, token: o.token, result: o.result, evidenceId: o.evidenceId, reason: o.reason, ownerOverride: o.ownerOverride, epoch: o.epoch, reserveTokens: o.reserveTokens, execWorktree: o.execWorktree, tokens: o.tokens, tokensBasis: o.tokensBasis, budgetAttempts: o.budgetAttempts, budgetTokens: o.budgetTokens, by: o.by, ack: o.ack, adoptUnowned: Boolean(o.adoptUnowned), json: o.json, cwd: evidenceRoot(o), resolveSlug: (cwd ) => featureSlugFor({ projectRoot: cwd }) });
|
|
399
|
+
// 081 IC-026: the worker adapter reads and writes the same main-worktree store as task-attempt.
|
|
400
|
+
case 'worker': return handleWorkerCommand({ action: o.actionGiven ? o.action : undefined, slug: o.slug, harness: o.harness, need: o.need, modelCheck: o.modelCheck, budgetTokens: o.budgetTokens, task: o.task, token: o.token, promptFile: o.promptFile, timeoutSeconds: o.timeoutSeconds, wait: Boolean(o.wait), edit: Boolean(o.edit), childOf: o.childOf, request: o.request, execWorktree: o.execWorktree, workerRun: o.workerRun, checks: o.checks, out: o.out, by: o.by, reason: o.reason, json: o.json, env: process.env, cwd: evidenceRoot(o), resolveSlug: (cwd ) => featureSlugFor({ projectRoot: cwd }) });
|
|
401
|
+
// 082 IC-001, IC-038: the dispatch loop shares the main-worktree store root with task-attempt.
|
|
402
|
+
// `--status` is parsed under `attemptStatus` (retrieval-plan's key), so it is renamed here.
|
|
403
|
+
case 'dispatch': return handleDispatchCommand({ action: o.actionGiven ? o.action : undefined, slug: o.slug, by: o.by, reason: o.reason, concurrency: o.concurrency, mode: o.mode, billingCap: o.billingCap, verifyArgv: o.verifyArgv, verifySeconds: o.verifySeconds, attemptSeconds: o.attemptSeconds, reserveTokens: o.reserveTokens, budgetAttempts: o.budgetAttempts, budgetTokens: o.budgetTokens, spawnGrant: o.spawnGrant, harness: o.harness, need: o.need, maxSeconds: o.maxSeconds, dispatch: o.dispatch, status: o.attemptStatus, summary: o.summary, blocker: o.blocker, tokens: o.tokens, tokensBasis: o.tokensBasis, promptFile: o.promptFile, requestId: o.requestId, task: o.task, ack: o.ack, fallback: o.fallback, ladder: o.ladder, json: o.json, env: process.env, cwd: evidenceRoot(o), resolveSlug: (cwd ) => featureSlugFor({ projectRoot: cwd }) });
|
|
404
|
+
// Code scope keeps two roots: the search root is --root or cwd (the invoking checkout), the state root is
|
|
405
|
+
// the feature store above. Guidance gets no stateRoot, exactly as before 079, so it resolves from cwd.
|
|
406
|
+
case 'retrieve': return handleRetrieveCommand({ query: o.query, top: o.top, json: o.json, scope: o.scope,
|
|
407
|
+
profile: o.profile, root: o.root, indexAction: o.indexAction, modelPath: o.modelPath,
|
|
408
|
+
taskId: o.taskId, need: o.need, slug: storeSlug, stateRoot: o.scope === 'code' ? storeRoot : undefined, repoRoot: REPO_ROOT });
|
|
258
409
|
case 'brief-tools': return handleBriefToolsCommand({ owner: o.owner, tier: o.tier, harness: o.harness, slug: o.slug, headingLevel: o.headingLevel, tasks: o.tasks, json: o.json, repoRoot: REPO_ROOT, projectRoot: storeRoot, buildAdapters: buildAdapterRegistry });
|
|
259
410
|
case 'advise': return handleAdviseCommand({ action: o.action, actionGiven: o.actionGiven, kind: o.kind, server: o.server, state: o.state, stateFile: o.stateFile, staticAnswer: o.staticAnswer, questionsFile: o.questionsFile, taskId: o.taskId, pickId: o.pickId, actual: o.actual, model: o.model, endpoint: o.endpoint, off: o.off, project: o.project, force: o.force, global: o.global, json: o.json, projectRoot: evidenceRoot(o) });
|
|
260
|
-
case 'model-role': return handleModelRoleCommand({ role: o.role, exclude: o.exclude, json: o.json, repoRoot: REPO_ROOT });
|
|
411
|
+
case 'model-role': return handleModelRoleCommand({ role: o.role, exclude: o.exclude, excludeFamilies: o.excludeFamily, json: o.json, repoRoot: REPO_ROOT });
|
|
261
412
|
case 'route': return handleRouteCommand({ intent: o.intent, query: o.query, check: o.check, json: o.json, projectRoot: evidenceRoot(o) });
|
|
262
413
|
case 'claim': return handleClaimCommand({ slug: storeSlug, taskId: requireTaskId(o), action: o.action, statement: o.statement, claimId: o.claimId, evidenceId: o.evidenceId, replacedBy: o.replacedBy, relation: o.relation, role: o.role, json: o.json, stateRoot: storeRoot });
|
|
263
|
-
case 'context-pack': return handleContextPackCommand({ taskId: requireTaskId(o), taskClass: o.taskClass, objective: o.objective, json: o.json, stateRoot: evidenceRoot(o), slug: o.slug });
|
|
264
|
-
|
|
265
|
-
case '
|
|
414
|
+
case 'context-pack': return handleContextPackCommand({ taskId: requireTaskId(o), taskClass: o.taskClass, objective: o.objective, json: o.json, stateRoot: storeRoot, sourceRoot: evidenceRoot(o), slug: storeSlug, explicitSlug: o.slug || null, mandatoryFile: o.mandatoryFile, harness: o.harness, maxBytes: o.maxBytes, bare: o.bare, noRecord: o.noRecord, reason: o.reason, since: o.since, expand: o.expand });
|
|
415
|
+
// 078 IC-005 and IC-013: identity is the process environment's alone, never a flag.
|
|
416
|
+
case 'context-emit': return handleContextEmitCommand({ event: o.event, cwd: o.cwd, session: o.session, harness: o.harness, nudge: o.nudge, maxBytes: o.maxBytes, taskId: o.taskId || undefined, slug: o.slug || undefined, stateRoot: redirected ? storeRoot : undefined, peek: o.peek, json: o.json });
|
|
417
|
+
case 'context-grant': return handleContextGrantCommand({ summary: o.summary, toRun: o.toRun, toLineage: o.toLineage, fromWorktree: o.fromWorktree, fromRun: o.fromRun, fromLineage: o.fromLineage, maxBytes: o.maxBytes, json: o.json });
|
|
418
|
+
case 'retrieval-plan': return handleRetrievalPlanCommand({ slug: storeSlug, taskId: requireTaskId(o), action: o.action, need: o.need, stage: o.stage, provider: o.provider, attemptStatus: o.attemptStatus, reason: o.reason, note: o.note, json: o.json, repoRoot: REPO_ROOT, stateRoot: storeRoot, sourceRoot: evidenceRoot(o) });
|
|
419
|
+
case 'outcome': return handleOutcomeCommand({ slug: storeSlug, taskId: requireTaskId(o), action: o.action, state: o.state, taskClass: o.taskClass, stage: o.stage, readiness: o.readiness, verification: o.verification, json: o.json, repoRoot: REPO_ROOT, stateRoot: storeRoot });
|
|
266
420
|
case 'verify': return handleVerifyCommand({ slug: o.slug, taskId: requireTaskId(o), action: o.action, risk: o.risk, planPath: o.planPath, scope: o.scope, verificationInput: o.verificationInput, verificationPhase: o.verificationPhase, baselineRef: o.baselineRef, json: o.json, projectRoot: evidenceRoot(o) });
|
|
267
421
|
case 'leak-scan': return handleLeakScanCommand({ paths: o.paths, exclude: o.exclude, json: o.json, repoRoot: evidenceRoot(o) });
|
|
268
422
|
case 'recover': return handleRecoverCommand({ errorMessage: o.errorMessage, failedChecks: o.failedChecks, iteration: o.iteration, agent: o.agent, json: o.json });
|
|
423
|
+
case 'roadmap': return handleRoadmapVerbCommand(o);
|
|
424
|
+
case 'plan-check': return handlePlanCheckCommand({ positional: o.positional, extraFlags: o.extraFlags, json: o.json, cwd: process.cwd() });
|
|
425
|
+
// One --path only: a second occurrence reaches the handler as a list, which it refuses as usage.
|
|
426
|
+
case 'review': return handleReviewCommand({ action: o.actionGiven ? o.action : undefined, slug: o.slug, path: o.paths?.length === 1 ? o.paths[0] : o.paths, base: o.base, preset: o.preset, json: o.json, cwd: process.cwd(), env: process.env });
|
|
427
|
+
case 'protocol': return handleProtocolCommand({ action: o.actionGiven ? o.action : undefined, kind: o.kind, taskClass: o.taskClass, risk: o.risk, preset: o.preset, positional: o.positional, json: o.json, cwd: process.cwd() });
|
|
428
|
+
case 'rules': return handleRulesCommand({ taskClass: o.taskClass, json: o.json, global: o.global, positional: o.positional, env: process.env, cwd: process.cwd() });
|
|
429
|
+
case 'primary': return handlePrimaryCommand({ action: o.actionGiven ? o.action : undefined, json: o.json, flags: o.flagsGiven, env: process.env, cwd: process.cwd() });
|
|
430
|
+
case 'package': return handlePackageCommand({ action: o.actionGiven ? o.action : undefined, path: o.paths?.length === 1 ? o.paths[0] : o.paths, id: o.id, source: o.source, index: o.index, packageVersion: o.packageVersion, plan: o.planId, repair: o.repair, points: o.points, dir: o.dir, json: o.json });
|
|
431
|
+
case 'slot': return handleSlotCommand({ action: o.actionGiven ? o.action : undefined, name: o.name, label: o.label, timeout: o.timeout, noWait: Boolean(o.noWait), command: o.slotCommand, by: o.by, reason: o.reason, positional: o.positional, extraFlags: o.extraFlags, json: o.json, env: process.env, cwd: process.cwd() });
|
|
432
|
+
case 'fleet': return handleFleetCommand({ action: o.actionGiven ? o.action : undefined, json: o.json, flags: o.flagsGiven, env: process.env, cwd: process.cwd() });
|
|
433
|
+
case 'transcript': return handleTranscriptCommand({ action: o.actionGiven ? o.action : undefined, agent: o.agent, cursor: o.cursor, limit: o.limit, window: o.window, json: o.json, flags: o.flagsGiven, env: process.env, cwd: process.cwd() });
|
|
434
|
+
case 'models': return handleModelsCommand({ action: o.actionGiven ? o.action : (o.positional?.[0] || 'list'), positional: o.positional, harness: o.harness, model: o.model, json: o.json, projectRoot: evidenceRoot(o) });
|
|
269
435
|
default: console.error(`doflow: unknown command '${o.cmd}'`); process.exit(1);
|
|
270
436
|
}
|
|
271
437
|
}
|
|
@@ -274,8 +440,33 @@ function dispatchRuntimeCommandInner(o , moment ) {
|
|
|
274
440
|
async function dispatchRuntimeCommand(o ) {
|
|
275
441
|
const moment = {};
|
|
276
442
|
const result = await dispatchRuntimeCommandInner(o, moment);
|
|
277
|
-
if (o
|
|
443
|
+
if (runsUpkeep(o)) upkeepAfterVerb({ projectRoot: moment.projectRoot });
|
|
278
444
|
return result;
|
|
279
445
|
}
|
|
280
446
|
|
|
447
|
+
function handleEnforcementCommand(o ) {
|
|
448
|
+
const fail = (error , detail ) => {
|
|
449
|
+
if (o.json) console.log(JSON.stringify({ error, detail }));
|
|
450
|
+
else console.error(`doflow enforcement: ${detail}`);
|
|
451
|
+
process.exitCode = 2;
|
|
452
|
+
return 2;
|
|
453
|
+
};
|
|
454
|
+
if (typeof o.harness !== 'string' || !o.harness || typeof o.policy !== 'string' || !o.policy || (o.profile !== undefined && typeof o.profile !== 'string')) return fail('usage', 'requires --harness <id> --policy <id> [--profile <id>]');
|
|
455
|
+
try {
|
|
456
|
+
const registry = loadRegistry({ repoRoot: REPO_ROOT });
|
|
457
|
+
const answer = enforcementFor(registry.coverage, { harness: o.harness, policy: o.policy, ...(o.profile ? { profile: o.profile } : {}) });
|
|
458
|
+
if (o.json) console.log(JSON.stringify(answer));
|
|
459
|
+
else {
|
|
460
|
+
console.log(`${answer.harness} ${answer.policy}: ${answer.enforced ? 'enforced' : 'not enforced'} (${answer.class}, ${answer.verification})`);
|
|
461
|
+
for (const item of answer.doesNotCover) console.log(`does not cover: ${item}`);
|
|
462
|
+
for (const item of answer.prerequisites) console.log(`prerequisite: ${item}`);
|
|
463
|
+
}
|
|
464
|
+
process.exitCode = answer.enforced ? 0 : 1;
|
|
465
|
+
return process.exitCode;
|
|
466
|
+
} catch (error ) {
|
|
467
|
+
if (error instanceof UnknownEnforcementTarget) return fail(error.code, error.message);
|
|
468
|
+
return fail('usage', error.message);
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
|
|
281
472
|
module.exports = { dispatchRuntimeCommand };
|
package/src/cli/shared.js
CHANGED
|
@@ -20,7 +20,6 @@ const { createAdapterRegistry } = require('../adapters/index.js');
|
|
|
20
20
|
const { declaredHarnessPaths } = require('../helper/harness-paths.js');
|
|
21
21
|
const claudeAdapter = require('../adapters/claude/index.js');
|
|
22
22
|
const codexAdapter = require('../adapters/codex/index.js');
|
|
23
|
-
const { createGeminiAdapter } = require('../adapters/gemini/index.js');
|
|
24
23
|
const { createOpenCodeAdapter } = require('../adapters/opencode/index.js');
|
|
25
24
|
const { createPiAdapter } = require('../adapters/pi/index.js');
|
|
26
25
|
const { createCopilotAdapter } = require('../adapters/copilot/index.js');
|
|
@@ -55,7 +54,6 @@ function buildAdapterRegistry() {
|
|
|
55
54
|
return createAdapterRegistry({
|
|
56
55
|
claude: claudeAdapter.createClaudeAdapter({ declaredPaths: declared.claude }),
|
|
57
56
|
codex: codexAdapter.createCodexAdapter({ declaredPaths: declared.codex }),
|
|
58
|
-
gemini: createGeminiAdapter({ declaredPaths: declared.gemini }),
|
|
59
57
|
opencode: createOpenCodeAdapter({ declaredPaths: declared.opencode }),
|
|
60
58
|
pi: createPiAdapter({ declaredPaths: declared.pi }),
|
|
61
59
|
copilot: createCopilotAdapter({ declaredPaths: declared.copilot }),
|
package/src/helper/git.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
//
|
|
6
6
|
// First module of the TypeScript migration (agent-docs/BRIEF_GOAL_DOFLOW.md). Authored as `.ts` and
|
|
7
7
|
// run directly by Node's native type-stripping (process.features.typescript === 'strip', Node
|
|
8
|
-
//
|
|
8
|
+
// >=24.22.1), so no build step and no runtime dependency are added. The body stays CommonJS
|
|
9
9
|
// (`module.exports`) so a `require('../helper/git.js')` from a `.js` caller keeps working while the
|
|
10
10
|
// rest of the tree is still `.js`; the explicit `.ts` extension on those requires is what the
|
|
11
11
|
// CommonJS resolver needs to find this file.
|
package/src/helper/guardrails.js
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
// the inner command glob is what every other harness wants.
|
|
11
11
|
//
|
|
12
12
|
// TypeScript migration (agent-docs/BRIEF_GOAL_DOFLOW.md): authored as `.ts`, run directly by Node
|
|
13
|
-
// native type-stripping (process.features.typescript === 'strip', Node
|
|
13
|
+
// native type-stripping (process.features.typescript === 'strip', Node >=24.22.1) — no build step and
|
|
14
14
|
// no runtime dependency. The body stays CommonJS so a `.js` caller's `require('../helper/guardrails.js')`
|
|
15
15
|
// keeps working while the rest of the tree is still `.js`; the explicit `.ts` extension is what the
|
|
16
16
|
// CommonJS resolver needs to find this file.
|
|
@@ -16,9 +16,12 @@ const MARKER_END = '<!-- doflow:end -->';
|
|
|
16
16
|
/**
|
|
17
17
|
* Merge `srcAbs`'s content into `dstAbs` inside a doflow-owned marker span,
|
|
18
18
|
* preserving any of `dstAbs`'s own content outside that span byte-for-byte.
|
|
19
|
+
* With `content`, that text is merged instead of the file `srcAbs` names.
|
|
19
20
|
*/
|
|
20
|
-
function mergeMarkedSection(srcAbs , dstAbs , { dryRun = false }
|
|
21
|
-
|
|
21
|
+
function mergeMarkedSection(srcAbs , dstAbs , { dryRun = false, content } = {}) {
|
|
22
|
+
// `content` is already-rendered text (a pointer with its per-scope path filled in); it replaces
|
|
23
|
+
// reading `srcAbs`, so a caller never has to stage a temporary source file.
|
|
24
|
+
const srcContent = (content !== undefined ? content : fs.readFileSync(srcAbs, 'utf8')).replace(/\s+$/, '');
|
|
22
25
|
const section = `${MARKER_START}\n${srcContent}\n${MARKER_END}\n`;
|
|
23
26
|
|
|
24
27
|
// Read once, reused both for parsing and for the final no-op comparison below.
|
|
@@ -81,28 +84,43 @@ function mergeMarkedSection(srcAbs , dstAbs , { dryRun = false }
|
|
|
81
84
|
return { changed: true };
|
|
82
85
|
}
|
|
83
86
|
|
|
87
|
+
/**
|
|
88
|
+
* Where `text`'s doflow span is: the first of `startMarkers`, the first MARKER_END after it, and no
|
|
89
|
+
* start marker after that end (a second span is `malformed`). `after` is past the end marker and the
|
|
90
|
+
* one '\n' that follows it.
|
|
91
|
+
*/
|
|
92
|
+
function markedSpan(text , startMarkers = [MARKER_START]) {
|
|
93
|
+
const found = startMarkers.map((marker) => ({ at: text.indexOf(marker), length: marker.length })).filter((item) => item.at !== -1);
|
|
94
|
+
if (!found.length) return { state: 'none' };
|
|
95
|
+
const first = found.reduce((a, b) => (b.at < a.at ? b : a));
|
|
96
|
+
const end = text.indexOf(MARKER_END, first.at + first.length);
|
|
97
|
+
if (end === -1) return { state: 'malformed' };
|
|
98
|
+
let after = end + MARKER_END.length;
|
|
99
|
+
if (startMarkers.some((marker) => text.indexOf(marker, after) !== -1)) return { state: 'malformed' };
|
|
100
|
+
if (text[after] === '\n') after += 1;
|
|
101
|
+
return { state: 'ok', start: first.at, after };
|
|
102
|
+
}
|
|
103
|
+
|
|
84
104
|
/**
|
|
85
105
|
* Strip only the doflow-managed span from `file`, leaving any surrounding content (before/after
|
|
86
106
|
* the markers) byte-for-byte untouched. Companion to `mergeMarkedSection` — shared by the Claude
|
|
87
107
|
* and Codex adapters' `remove()`, which had each carried an identical private copy of this.
|
|
88
108
|
* A file that held nothing but the span is DoFlow's own and is deleted; any other file is written
|
|
89
|
-
* back, even when only whitespace remains.
|
|
109
|
+
* back, even when only whitespace remains. `startMarkers` (default: MARKER_START alone) lets a
|
|
110
|
+
* caller also accept an older start marker; the retirement sweep is the only one that does.
|
|
90
111
|
* @returns whether a managed span was found and stripped (false if the file doesn't
|
|
91
112
|
* exist or has no doflow markers — both are no-ops, not errors)
|
|
92
113
|
*/
|
|
93
|
-
function removeMarkedSection(file ) {
|
|
114
|
+
function removeMarkedSection(file , { startMarkers = [MARKER_START] } = {}) {
|
|
94
115
|
if (!fs.existsSync(file)) return false;
|
|
95
116
|
const existing = fs.readFileSync(file, 'utf8');
|
|
96
|
-
const
|
|
97
|
-
if (
|
|
98
|
-
|
|
99
|
-
if (end === -1 || existing.indexOf(MARKER_START, end + MARKER_END.length) !== -1) {
|
|
117
|
+
const span = markedSpan(existing, startMarkers);
|
|
118
|
+
if (span.state === 'none') return false;
|
|
119
|
+
if (span.state === 'malformed') {
|
|
100
120
|
throw new Error(`Refusing to remove malformed DoFlow markers in ${file}`);
|
|
101
121
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
const before = existing.slice(0, start);
|
|
105
|
-
const rest = existing.slice(after);
|
|
122
|
+
const before = existing.slice(0, span.start);
|
|
123
|
+
const rest = existing.slice(span.after);
|
|
106
124
|
if (before === '' && rest === '') {
|
|
107
125
|
fs.unlinkSync(file);
|
|
108
126
|
return true;
|
|
@@ -113,4 +131,4 @@ function removeMarkedSection(file ) {
|
|
|
113
131
|
return true;
|
|
114
132
|
}
|
|
115
133
|
|
|
116
|
-
module.exports = { mergeMarkedSection, removeMarkedSection, MARKER_START, MARKER_END };
|
|
134
|
+
module.exports = { mergeMarkedSection, removeMarkedSection, markedSpan, MARKER_START, MARKER_END };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// Package, local, qualified and projected identifiers (122 IC-003, PN-3). Pure and dependency-free so
|
|
4
|
+
// `src/registry/` (row 120's worker ids) and `src/runtime/` import the one definition.
|
|
5
|
+
|
|
6
|
+
const PACKAGE_ID = /^[a-z][a-z0-9-]{0,14}[a-z0-9]$/;
|
|
7
|
+
const LOCAL_ID = /^[a-z][a-z0-9-]{0,13}[a-z0-9]$/;
|
|
8
|
+
const QUALIFIED_MAX = 32;
|
|
9
|
+
// Refused as a package id (reserved-id); `doflow` is usable only by the bundled first-party package.
|
|
10
|
+
const RESERVED = ['doflow', 'do', 'core', 'user', 'project', 'local', 'env', 'auto', 'package', 'packages'];
|
|
11
|
+
|
|
12
|
+
const isPackageId = (value ) => typeof value === 'string' && PACKAGE_ID.test(value) && !value.includes('--');
|
|
13
|
+
const isLocalId = (value ) => typeof value === 'string' && LOCAL_ID.test(value) && !value.includes('--');
|
|
14
|
+
|
|
15
|
+
/** True for a package id the grammar accepts but IC-003 reserves: the listed names and any `do-` or `doflow-` prefix. */
|
|
16
|
+
function isReservedPackageId(value ) {
|
|
17
|
+
return typeof value === 'string' && (RESERVED.includes(value) || value.startsWith('do-') || value.startsWith('doflow-'));
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function isQualifiedId(value ) {
|
|
21
|
+
if (typeof value !== 'string' || value.length > QUALIFIED_MAX) return false;
|
|
22
|
+
const parts = value.split('.');
|
|
23
|
+
return parts.length === 2 && isPackageId(parts[0]) && isLocalId(parts[1]);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** `<package id>.<local id>`, or null when either part breaks its grammar. */
|
|
27
|
+
function qualifiedId(packageId , localId ) {
|
|
28
|
+
const joined = `${packageId}.${localId}`;
|
|
29
|
+
return isPackageId(packageId) && isLocalId(localId) && joined.length <= QUALIFIED_MAX ? joined : null;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** The harness-file name of a qualified id, `<package id>-<local id>`; null when the input is not a qualified id. */
|
|
33
|
+
function projectedName(qualified ) {
|
|
34
|
+
return isQualifiedId(qualified) ? qualified.replace('.', '-') : null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
module.exports = { isPackageId, isLocalId, isQualifiedId, isReservedPackageId, qualifiedId, projectedName };
|