@khoavu882/doflow 2.0.0-beta.5 → 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 -2
- 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/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-compact.sh +23 -27
- package/core/harnesses/claude/hooks/session-end.sh +23 -10
- package/core/harnesses/claude/hooks/skill-config-audit.sh +3 -0
- 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/post-edit-lint.impl.sh +3 -1
- package/core/harnesses/codex/hooks/pre-compact.impl.sh +29 -26
- package/core/harnesses/codex/hooks/session-end.impl.sh +23 -10
- package/core/harnesses/codex/hooks/subagent-audit.sh +1 -0
- 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 +1 -0
- package/core/harnesses/kiro/hooks/pre-bash-guard.sh +1 -0
- package/core/harnesses/kiro/hooks/pre-implement-gate.sh +1 -0
- package/core/harnesses/kiro/hooks/session-start.sh +1 -0
- package/core/harnesses/kiro/hooks/stop-check.sh +1 -0
- package/core/harnesses/pi/extensions/doflow-guard.js +8 -0
- package/core/harnesses/shared/hooks/ENVELOPE_MIGRATION.md +0 -1
- package/core/harnesses/shared/hooks/bridge/bridge.sh +102 -9
- package/core/harnesses/shared/hooks/bridge/envelope.jq +87 -18
- package/core/harnesses/shared/hooks/bridge/observe-model.sh +75 -0
- package/core/harnesses/shared/hooks/bridge/respond.sh +10 -2
- package/core/harnesses/shared/hooks/policies/blocked-patterns.conf +28 -14
- package/core/harnesses/shared/hooks/policies/capture-failure.sh +48 -15
- package/core/harnesses/shared/hooks/policies/compact-text.sh +46 -0
- package/core/harnesses/shared/hooks/policies/contract.sh +3 -0
- package/core/harnesses/shared/hooks/policies/deny-json.sh +2 -11
- 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 +63 -40
- package/core/harnesses/shared/hooks/policies/mcp-tool-guard.sh +3 -2
- package/core/harnesses/shared/hooks/policies/pre-bash-guard.sh +213 -12
- package/core/harnesses/shared/hooks/policies/pre-implementation-gate.sh +114 -38
- package/core/harnesses/shared/hooks/policies/session-context.sh +30 -1
- package/core/harnesses/shared/hooks/policies/stop-check.sh +20 -9
- package/core/harnesses/shared/hooks/policies/subagent-audit.sh +5 -2
- package/core/harnesses/shared/hooks/policies/summary-store.sh +347 -0
- package/core/harnesses/shared/hooks/policies/user-prompt-submit.sh +60 -155
- package/core/harnesses/shared/hooks/stream-hook-runner.js +47 -8
- package/core/harnesses/shared/locator/doflow-run +2 -3
- package/core/registry/advice.json +3 -3
- package/core/registry/assets.json +55 -82
- package/core/registry/capabilities.json +12 -0
- package/core/registry/contracts.json +58 -31
- 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 +1442 -363
- package/core/registry/lifecycle.json +485 -304
- 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 +679 -31
- 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 +149 -34
- 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 +18 -17
- 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 +15 -58
- 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 +26 -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 +4 -7
- package/core/shared/skills/do-plan/SKILL.md +26 -15
- 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 +143 -66
- package/src/adapters/claude/index.js +24 -4
- package/src/adapters/codex/agents.js +25 -15
- package/src/adapters/codex/index.js +48 -13
- package/src/adapters/codex/native-projection.js +6 -2
- package/src/adapters/copilot/index.js +58 -23
- package/src/adapters/copy-tree.js +290 -44
- 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 +23 -12
- package/src/adapters/opencode/index.js +8 -8
- package/src/adapters/pi/hooks.js +2 -1
- package/src/adapters/pi/index.js +14 -7
- package/src/adapters/resolve-source.js +26 -2
- package/src/cli/commands/install.js +2 -1
- 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 +2 -1
- package/src/cli/index.js +322 -29
- package/src/cli/runtime-commands.js +209 -57
- 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 +20 -3
- package/src/lifecycle/hook-tier.js +160 -0
- package/src/lifecycle/index.js +412 -78
- package/src/lifecycle/retired-harnesses.js +318 -0
- package/src/lifecycle/view.js +35 -15
- package/src/registry/index.js +551 -26
- 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 +20 -11
- 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 +13 -7
- package/src/runtime/cli.js +196 -19
- package/src/runtime/config-home.js +42 -0
- package/src/runtime/context/arbitrate.js +767 -0
- package/src/runtime/context/delivery-store.js +4 -6
- package/src/runtime/context/emission-rules.js +118 -0
- package/src/runtime/context/identity.js +227 -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 +154 -78
- 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-ledger.js +34 -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 +33 -3
- 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 +2 -2
- 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 +46 -5
- package/src/runtime/research-request.js +50 -25
- package/src/runtime/retrieval-plan.js +10 -30
- package/src/runtime/retrieval-record.js +75 -5
- 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 +60 -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 +1 -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 +176 -55
- package/src/runtime/task-sources.js +147 -0
- package/src/runtime/task-state.js +374 -64
- 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/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 -10
- package/core/harnesses/gemini/hooks/post-edit-lint.sh +0 -39
- package/core/harnesses/gemini/hooks/pre-bash-guard.sh +0 -10
- package/core/harnesses/gemini/hooks/pre-compact.sh +0 -38
- package/core/harnesses/gemini/hooks/pre-implement-gate.sh +0 -10
- 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 -7
- package/core/harnesses/gemini/settings/adapter-defaults.json +0 -4
- 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 -251
- package/src/adapters/gemini/index.js +0 -429
|
@@ -18,11 +18,11 @@
|
|
|
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
27
|
const { loadRegistry } = require('../registry/index.js');
|
|
28
28
|
const { enforcementFor, UnknownEnforcementTarget } = require('../lifecycle/coverage.js');
|
|
@@ -41,37 +41,131 @@ const { handleWorkflowCommand } = require('../runtime/workflow-engine.js');
|
|
|
41
41
|
const { handleOrchestrateCommand } = require('../runtime/workflow-orchestrator.js');
|
|
42
42
|
const { handleResearchRequestCommand } = require('../runtime/research-request.js');
|
|
43
43
|
const { handleTaskAttemptCommand } = require('../runtime/task-attempts.js');
|
|
44
|
+
const { handleWorkerCommand } = require('../runtime/worker/command.js');
|
|
45
|
+
const { handleDispatchCommand } = require('../runtime/dispatch/command.js');
|
|
44
46
|
const { handleRetrieveCommand } = require('../runtime/knowledge/retrieval.js');
|
|
45
47
|
const { handleModelRoleCommand } = require('../runtime/model-router.js');
|
|
46
48
|
const { handleRouteCommand } = require('../runtime/capability-router.js');
|
|
47
49
|
const { handleContextPackCommand } = require('../runtime/context-pack.js');
|
|
48
50
|
const { handleRetrievalPlanCommand } = require('../runtime/retrieval-plan.js');
|
|
49
51
|
const { handleOutcomeCommand } = require('../runtime/outcome.js');
|
|
50
|
-
const { handleVerifyCommand } = require('../runtime/verification/engine.js');
|
|
52
|
+
const { handleVerifyCommand, verifyStateRoot } = require('../runtime/verification/engine.js');
|
|
51
53
|
const { handleLeakScanCommand } = require('../runtime/leak-scan.js');
|
|
52
54
|
const { handleRecoverCommand } = require('../runtime/recovery.js');
|
|
53
55
|
const { handleScaffoldCommand } = require('../runtime/scaffold/generate.js');
|
|
54
|
-
const { handleDecisionCommand } = require('../runtime/decision-register.js');
|
|
56
|
+
const { handleDecisionCommand, isReservedChannel, CHANNEL_RESERVED } = require('../runtime/decision-register.js');
|
|
55
57
|
const { handleFollowupCommand, handleLifecycleCommand, handleGoalCommand } = require('../runtime/lifecycle/cli.js');
|
|
56
58
|
const { projectRoot: lifecycleProjectRoot } = require('../runtime/lifecycle/root.js');
|
|
57
59
|
const { upkeepAfterVerb } = require('../runtime/storage/upkeep.js');
|
|
58
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'));
|
|
59
81
|
// Required on first use, so a CLI whose failure modules cannot be loaded still runs every other verb.
|
|
60
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); }
|
|
61
95
|
const { handleInventoryCommand } = require('../runtime/inventory/index.js');
|
|
62
96
|
const { finishRuntime, usageError } = require('../runtime/cli-result.js');
|
|
63
|
-
const {
|
|
64
|
-
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');
|
|
65
100
|
const { featureSlugFor } = require('../runtime/implementation-gate.js');
|
|
66
101
|
const { handleBriefToolsCommand } = require('../runtime/brief-tools.js');
|
|
67
|
-
|
|
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); }
|
|
68
104
|
const { REPO_ROOT, buildAdapterRegistry } = require('./shared.js');
|
|
69
105
|
|
|
70
106
|
/** Where `readiness`/`evidence` read and write per-task state. Mirrors scopeOf()'s rules so these
|
|
71
107
|
* commands are scope-aware like the rest of the CLI, rather than defaulting to the DoFlow install
|
|
72
108
|
* directory — which for an npm install is inside node_modules/. */
|
|
73
109
|
function evidenceRoot(o ) {
|
|
74
|
-
|
|
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 });
|
|
75
169
|
}
|
|
76
170
|
|
|
77
171
|
/**
|
|
@@ -130,33 +224,21 @@ function evidenceItemFromFlags(o ) {
|
|
|
130
224
|
return item;
|
|
131
225
|
}
|
|
132
226
|
|
|
133
|
-
/** Verbs that read or write per-task records, and so accept `--slug` (IC-002).
|
|
134
|
-
|
|
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']);
|
|
135
230
|
|
|
136
|
-
/**
|
|
137
|
-
|
|
138
|
-
|
|
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
|
+
}
|
|
139
235
|
|
|
140
|
-
/**
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
*/
|
|
147
|
-
function featureStoreRoot(o , checkouts ) {
|
|
148
|
-
if (!FEATURE_STORE_VERBS.has(o.cmd) || o.global) return null;
|
|
149
|
-
if (!checkouts.isLinked) return null;
|
|
150
|
-
let slug = o.slug || null;
|
|
151
|
-
if (!slug) {
|
|
152
|
-
try {
|
|
153
|
-
const feature = resolveFeature({ projectRoot: checkouts.current });
|
|
154
|
-
slug = !feature.error && feature.paths ? feature.paths.feature_slug : null;
|
|
155
|
-
} catch { /* a failed branch lookup cannot route state to a guessed feature */ }
|
|
156
|
-
}
|
|
157
|
-
const folder = (root ) => path.join(root, 'agent-docs', 'doflow', slug || '');
|
|
158
|
-
if (!slug || fs.existsSync(folder(checkouts.current)) || !fs.existsSync(folder(checkouts.main))) return null;
|
|
159
|
-
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')}`;
|
|
160
242
|
}
|
|
161
243
|
|
|
162
244
|
/**
|
|
@@ -166,6 +248,14 @@ function featureStoreRoot(o , checkouts )
|
|
|
166
248
|
* to the engine module each case names.
|
|
167
249
|
*/
|
|
168
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
|
+
}
|
|
169
259
|
// A slug becomes a directory name and a state key, so one that could name a path is refused
|
|
170
260
|
// here, once, for every verb that reads `--slug`, before any of them reads or writes state
|
|
171
261
|
// (FR-013, IC-009). A well-formed slug that names no feature is the verbs' own business.
|
|
@@ -179,32 +269,69 @@ function dispatchRuntimeCommandInner(o , moment ) {
|
|
|
179
269
|
// here so the verbs whose handlers build their own ledger (readiness, evidence) route the same
|
|
180
270
|
// way as the ones that take `slug` directly. The orchestration journal is keyed by slug already.
|
|
181
271
|
// Reset on every dispatch, so one invocation's slug can never carry into the next in-process call.
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
const
|
|
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 };
|
|
186
283
|
const attemptRoot = checkouts?.ok && !checkouts.sandbox ? (checkouts.main || checkouts.current || null) : null;
|
|
187
284
|
// Use the same root resolver as the handler: task redirection, the nearest run ledger,
|
|
188
285
|
// and lifecycle's shared main-worktree store are deliberately different scopes.
|
|
189
286
|
try {
|
|
190
287
|
if (['trace', 'stats', 'discover'].includes(o.cmd)) {
|
|
191
|
-
moment.projectRoot = path.dirname(resolveRunsLocation({ start:
|
|
192
|
-
} 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)) {
|
|
193
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
|
|
194
295
|
} else {
|
|
195
296
|
moment.projectRoot = storeRoot;
|
|
196
297
|
}
|
|
197
298
|
} catch { /* a failed upkeep lookup must not change the verb's answer */ }
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
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}`);
|
|
202
315
|
}
|
|
203
|
-
// A well-formed slug that names no feature
|
|
204
|
-
//
|
|
205
|
-
if (
|
|
206
|
-
&& slugNamesNoFeature({
|
|
207
|
-
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
|
+
}
|
|
208
335
|
}
|
|
209
336
|
switch (o.cmd) {
|
|
210
337
|
// REPO_ROOT locates the capability registry; projectRoot is the tree whose index freshness
|
|
@@ -226,13 +353,13 @@ function dispatchRuntimeCommandInner(o , moment ) {
|
|
|
226
353
|
// all this does: the handler names them back under `callerAsserted` so a stated input is
|
|
227
354
|
// never mistaken for a measured one.
|
|
228
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) });
|
|
229
|
-
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, slug: storeSlug, sourceRoot: evidenceRoot(o), attemptRoot });
|
|
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 });
|
|
230
357
|
// Run-ledger views. They resolve their own ledger the way the dispatcher does (nearest
|
|
231
358
|
// `.doflow` walking up, or the global one) rather than assuming cwd is the project root, so
|
|
232
359
|
// a view invoked from a subdirectory reads the runs that were actually recorded.
|
|
233
360
|
// Exit codes follow design §4.2 and are set by the handler itself: 0 = answered, 1 = a
|
|
234
361
|
// finding the caller must act on.
|
|
235
|
-
case 'trace': return
|
|
362
|
+
case 'trace': return handleTraceViewCommand(o);
|
|
236
363
|
case 'stats': return handleStatsCommand({ json: o.json, days: o.days, global: o.global, projectRoot: evidenceRoot(o) });
|
|
237
364
|
case 'indicators': return handleIndicatorsCommand({ json: o.json, projectRoot: evidenceRoot(o) });
|
|
238
365
|
case 'discover': return handleDiscoverCommand({ json: o.json, days: o.days, global: o.global, projectRoot: evidenceRoot(o) });
|
|
@@ -243,6 +370,7 @@ function dispatchRuntimeCommandInner(o , moment ) {
|
|
|
243
370
|
// the process home directory inside the lifecycle view (design R7) and is not an argument.
|
|
244
371
|
case 'inventory': return handleInventoryCommand({ json: o.json, global: o.global, targets: o.targets, repoRoot: REPO_ROOT, projectRoot: path.resolve(o.positional[0] || '.') });
|
|
245
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 });
|
|
246
374
|
// No REPO_ROOT: the scaffold's repo root is the *caller's* repo, reported by the resolver,
|
|
247
375
|
// because the plan's `files:` paths are relative to it. Passing the DoFlow install here
|
|
248
376
|
// would detect the wrong language and mirror the wrong tree.
|
|
@@ -263,23 +391,47 @@ function dispatchRuntimeCommandInner(o , moment ) {
|
|
|
263
391
|
// state and source tree, following the same scope rules as every other command.
|
|
264
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 });
|
|
265
393
|
case 'workflow': return handleWorkflowCommand({ taskClass: o.taskClass, json: o.json });
|
|
266
|
-
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 });
|
|
267
|
-
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) });
|
|
268
396
|
// The store is shared by every linked worktree of the clone (lifecycle's main-worktree root); the
|
|
269
397
|
// feature is `--slug`, else the branch's, resolved the way decision and scaffold resolve it.
|
|
270
|
-
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 }) });
|
|
271
|
-
|
|
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 });
|
|
272
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 });
|
|
273
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) });
|
|
274
|
-
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 });
|
|
275
412
|
case 'route': return handleRouteCommand({ intent: o.intent, query: o.query, check: o.check, json: o.json, projectRoot: evidenceRoot(o) });
|
|
276
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 });
|
|
277
|
-
case 'context-pack': return handleContextPackCommand({ taskId: requireTaskId(o), taskClass: o.taskClass, objective: o.objective, json: o.json, stateRoot: evidenceRoot(o), slug: o.slug, mandatoryFile: o.mandatoryFile, harness: o.harness, maxBytes: o.maxBytes, bare: o.bare, noRecord: o.noRecord, reason: o.reason, since: o.since, expand: o.expand });
|
|
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 });
|
|
278
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) });
|
|
279
|
-
case 'outcome': return handleOutcomeCommand({ slug:
|
|
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 });
|
|
280
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) });
|
|
281
421
|
case 'leak-scan': return handleLeakScanCommand({ paths: o.paths, exclude: o.exclude, json: o.json, repoRoot: evidenceRoot(o) });
|
|
282
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) });
|
|
283
435
|
default: console.error(`doflow: unknown command '${o.cmd}'`); process.exit(1);
|
|
284
436
|
}
|
|
285
437
|
}
|
|
@@ -288,7 +440,7 @@ function dispatchRuntimeCommandInner(o , moment ) {
|
|
|
288
440
|
async function dispatchRuntimeCommand(o ) {
|
|
289
441
|
const moment = {};
|
|
290
442
|
const result = await dispatchRuntimeCommandInner(o, moment);
|
|
291
|
-
if (o
|
|
443
|
+
if (runsUpkeep(o)) upkeepAfterVerb({ projectRoot: moment.projectRoot });
|
|
292
444
|
return result;
|
|
293
445
|
}
|
|
294
446
|
|
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 };
|