@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
|
@@ -164,11 +164,33 @@ function knownServerIds(registry ) {
|
|
|
164
164
|
return ids;
|
|
165
165
|
}
|
|
166
166
|
|
|
167
|
+
const MANIFEST_PATTERNS = Object.freeze([
|
|
168
|
+
/(?:^|[\\/])package(?:-lock)?\.json$/,
|
|
169
|
+
/(?:^|[\\/])pnpm-lock\.yaml$/,
|
|
170
|
+
/(?:^|[\\/])yarn\.lock$/,
|
|
171
|
+
/(?:^|[\\/])Cargo\.(?:toml|lock)$/,
|
|
172
|
+
/(?:^|[\\/])go\.(?:mod|sum)$/,
|
|
173
|
+
/(?:^|[\\/])requirements.*\.txt$/,
|
|
174
|
+
/(?:^|[\\/])pyproject\.toml$/,
|
|
175
|
+
/(?:^|[\\/])poetry\.lock$/,
|
|
176
|
+
/(?:^|[\\/])Gemfile(?:\.lock)?$/,
|
|
177
|
+
/(?:^|[\\/])composer\.(?:json|lock)$/,
|
|
178
|
+
/(?:^|[\\/])build\.gradle(?:\.kts)?$/,
|
|
179
|
+
/(?:^|[\\/])pom\.xml$/,
|
|
180
|
+
/(?:^|[\\/])Package\.swift$/,
|
|
181
|
+
/(?:^|[\\/])Podfile(?:\.lock)?$/,
|
|
182
|
+
]);
|
|
183
|
+
|
|
184
|
+
function touchesManifest(files ) {
|
|
185
|
+
if (!Array.isArray(files) || files.length === 0) return false;
|
|
186
|
+
return files.some((f) => MANIFEST_PATTERNS.some((pattern) => pattern.test(f)));
|
|
187
|
+
}
|
|
188
|
+
|
|
167
189
|
/**
|
|
168
190
|
* Servers a stage run names (IC-001 meaning). Sorted.
|
|
169
|
-
* @param {{registry: object, skill: string, stageId?: string, taskId?: string, requests?: {list: Function}}} input
|
|
191
|
+
* @param {{registry: object, skill: string, stageId?: string, taskId?: string, requests?: {list: Function}, taskClass?: string, diffFiles?: string[]}} input
|
|
170
192
|
*/
|
|
171
|
-
function namedServers({ registry, skill, stageId, taskId, requests } ) {
|
|
193
|
+
function namedServers({ registry, skill, stageId, taskId, requests, taskClass, diffFiles } ) {
|
|
172
194
|
let researchRequested ;
|
|
173
195
|
const hasRequest = () => {
|
|
174
196
|
if (researchRequested === undefined) {
|
|
@@ -178,12 +200,21 @@ function namedServers({ registry, skill, stageId, taskId, requests } )
|
|
|
178
200
|
}
|
|
179
201
|
return researchRequested;
|
|
180
202
|
};
|
|
203
|
+
|
|
204
|
+
const isDependencyChange = taskClass === 'dependency-change';
|
|
205
|
+
const hasManifestDiff = touchesManifest(diffFiles);
|
|
206
|
+
|
|
181
207
|
const named = new Set ();
|
|
182
208
|
for (const server of registry?.mcp || []) {
|
|
183
209
|
for (const step of server.steps || []) {
|
|
184
|
-
if (step.
|
|
185
|
-
|
|
186
|
-
|
|
210
|
+
if (step.skill !== skill) continue;
|
|
211
|
+
if (!step.expectedWhen) {
|
|
212
|
+
named.add(server.id);
|
|
213
|
+
} else if (step.expectedWhen === 'research-request' && hasRequest()) {
|
|
214
|
+
named.add(server.id);
|
|
215
|
+
} else if (step.expectedWhen === 'dependency-change' && isDependencyChange) {
|
|
216
|
+
named.add(server.id);
|
|
217
|
+
} else if (step.expectedWhen === 'manifest-review' && hasManifestDiff) {
|
|
187
218
|
named.add(server.id);
|
|
188
219
|
}
|
|
189
220
|
}
|
|
@@ -213,13 +244,14 @@ const bySortKey = (a , b ) => (a < b ? -1 : a > b ? 1 : 0);
|
|
|
213
244
|
function resolveConsultations({
|
|
214
245
|
taskId = null, stageId = null, skill, flags, registry, ledger, requests,
|
|
215
246
|
briefRecords = [], readReport, reach, addCommand, harnessName, since = null,
|
|
247
|
+
taskClass = null, diffFiles = [],
|
|
216
248
|
} = {}) {
|
|
217
249
|
const warnings = [];
|
|
218
250
|
const notices = [];
|
|
219
251
|
const evidenceToAdd = [];
|
|
220
252
|
const registered = new Set((registry?.mcp || []).map((server ) => server.id));
|
|
221
253
|
const known = knownServerIds(registry);
|
|
222
|
-
const named = namedServers({ registry, skill, stageId, taskId, requests });
|
|
254
|
+
const named = namedServers({ registry, skill, stageId, taskId, requests, taskClass, diffFiles });
|
|
223
255
|
|
|
224
256
|
// Rule 1: flags.
|
|
225
257
|
const parsedFlags = parseMcpOutcomeFlags(flags);
|
|
@@ -408,5 +440,7 @@ module.exports = {
|
|
|
408
440
|
parseMcpOutcomeFlags,
|
|
409
441
|
parseToolsUsed,
|
|
410
442
|
namedServers,
|
|
443
|
+
touchesManifest,
|
|
444
|
+
MANIFEST_PATTERNS,
|
|
411
445
|
resolveConsultations,
|
|
412
446
|
};
|
|
@@ -39,22 +39,58 @@ function availableProviderIds({ fsImpl = fs } = {})
|
|
|
39
39
|
.map(([id]) => id);
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
function normalizeFamilyList(value ) {
|
|
43
|
+
const values = Array.isArray(value) ? value : [value];
|
|
44
|
+
return [...new Set(values.flatMap((entry) => String(entry ?? '').split(',').map((family) => family.trim().toLowerCase()).filter(Boolean)))];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// families is a hand-kept stopgap; the model-facts registry (roadmap row 105) supersedes it and this field is removed then.
|
|
48
|
+
/** An unknown family is not evidence that a provider can review outside the author's family. */
|
|
49
|
+
function familyInfo(families , excludedFamilies ) {
|
|
50
|
+
const declared = Array.isArray(families) ? families : [];
|
|
51
|
+
const hasUnknown = declared.length === 0
|
|
52
|
+
|| declared.some((family) => typeof family !== 'string' || !/^[a-z][a-z0-9-]*$/.test(family) || family === 'unknown');
|
|
53
|
+
const overlapsAuthor = declared.some((family) => typeof family === 'string'
|
|
54
|
+
&& family !== 'unknown' && /^[a-z][a-z0-9-]*$/.test(family) && excludedFamilies.has(family));
|
|
55
|
+
const familyRelation = overlapsAuthor ? 'overlaps-author' : hasUnknown ? 'unverified' : 'cross-family';
|
|
56
|
+
const sameFamily = declared.length > 0 && declared.every((family) => typeof family === 'string' && excludedFamilies.has(family));
|
|
57
|
+
return {
|
|
58
|
+
families: [...declared],
|
|
59
|
+
familyVerified: familyRelation === 'cross-family',
|
|
60
|
+
familyRelation,
|
|
61
|
+
sameFamily,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
42
65
|
/**
|
|
43
66
|
* Resolve one role to ranked candidates.
|
|
44
67
|
* Ordering: available first, then preferred-tier match, then fallback-tier match, registry order
|
|
45
|
-
* breaking ties. `exclude` drops provider ids entirely
|
|
46
|
-
*
|
|
68
|
+
* breaking ties. `exclude` drops provider ids entirely; `excludeFamilies` drops providers whose
|
|
69
|
+
* complete, known catalogue is within the excluded model families. Unknown catalogues are kept
|
|
70
|
+
* unverified rather than being presented as cross-family.
|
|
47
71
|
* Availability unknown stays null — absence of evidence is not reported as absent.
|
|
48
72
|
*/
|
|
49
|
-
function resolveModelRole({ registry, roleId, isAvailable = null, exclude = [] } = {}) {
|
|
73
|
+
function resolveModelRole({ registry, roleId, isAvailable = null, exclude = [], excludeFamilies } = {}) {
|
|
50
74
|
const role = (registry.modelRoles || []).find((entry ) => entry.id === roleId);
|
|
51
75
|
if (!role) {
|
|
52
76
|
throw new Error(`Unknown model role '${roleId}'; valid: ${(registry.modelRoles || []).map((r ) => r.id).join(', ')}`);
|
|
53
77
|
}
|
|
54
78
|
const excluded = new Set(exclude);
|
|
79
|
+
const familyMode = excludeFamilies !== undefined && excludeFamilies !== null;
|
|
80
|
+
const normalizedFamilies = familyMode ? normalizeFamilyList(excludeFamilies) : [];
|
|
81
|
+
if (familyMode && normalizedFamilies.length === 0) {
|
|
82
|
+
throw new Error('--exclude-family requires at least one family name');
|
|
83
|
+
}
|
|
84
|
+
const excludedFamilies = new Set(normalizedFamilies);
|
|
55
85
|
const candidates = [];
|
|
86
|
+
const familyExcluded = [];
|
|
56
87
|
for (const [index, provider] of (registry.modelProviders || []).entries()) {
|
|
57
88
|
if (excluded.has(provider.id)) continue;
|
|
89
|
+
const family = familyInfo(provider.families, excludedFamilies);
|
|
90
|
+
if (familyMode && family.sameFamily) {
|
|
91
|
+
familyExcluded.push(provider.id);
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
58
94
|
const tiers = provider.tiers ?? [];
|
|
59
95
|
candidates.push({
|
|
60
96
|
id: provider.id,
|
|
@@ -64,6 +100,7 @@ function resolveModelRole({ registry, roleId, isAvailable = null, exclude = [] }
|
|
|
64
100
|
available: isAvailable ? Boolean(isAvailable(provider.id)) : null,
|
|
65
101
|
servesPreferredTier: role.prefer ? tiers.includes(role.prefer) : null,
|
|
66
102
|
servesFallbackTier: role.fallback ? tiers.includes(role.fallback) : null,
|
|
103
|
+
...(familyMode ? { families: family.families, familyRelation: family.familyRelation, familyVerified: family.familyVerified } : {}),
|
|
67
104
|
_index: index,
|
|
68
105
|
});
|
|
69
106
|
}
|
|
@@ -79,12 +116,19 @@ function resolveModelRole({ registry, roleId, isAvailable = null, exclude = [] }
|
|
|
79
116
|
return 0;
|
|
80
117
|
});
|
|
81
118
|
for (const candidate of candidates) delete candidate._index;
|
|
82
|
-
|
|
119
|
+
const result = {
|
|
83
120
|
roleId,
|
|
84
121
|
policy: { prefer: role.prefer ?? null, fallback: role.fallback ?? null, require: role.require ?? null },
|
|
85
122
|
candidates,
|
|
86
123
|
excluded: [...excluded],
|
|
87
124
|
};
|
|
125
|
+
// Keep the established result shape byte-for-byte for callers that do not request family
|
|
126
|
+
// filtering. Family metadata is included whenever that comparison is requested.
|
|
127
|
+
if (familyMode) {
|
|
128
|
+
result.excludedFamilies = [...excludedFamilies];
|
|
129
|
+
result.familyExcluded = familyExcluded;
|
|
130
|
+
}
|
|
131
|
+
return result;
|
|
88
132
|
}
|
|
89
133
|
|
|
90
134
|
/**
|
|
@@ -118,7 +162,7 @@ function resolveRetrievalSlot({ registry, slotId, isAvailable = null } = {}
|
|
|
118
162
|
|
|
119
163
|
/** CLI handler for `doflow model-role`. Read-only advisory routing; exits 1 on an unknown role
|
|
120
164
|
* because a silently-empty candidate list would read as "no providers" rather than "bad input". */
|
|
121
|
-
function handleModelRoleCommand({ role, exclude, json = false, repoRoot } = {}) {
|
|
165
|
+
function handleModelRoleCommand({ role, exclude, excludeFamilies, json = false, repoRoot } = {}) {
|
|
122
166
|
if (!role) return usageError('model-role', '--role is required (one of the roles in core/registry/models.json)', json);
|
|
123
167
|
const registry = (() => {
|
|
124
168
|
try { return loadRegistry({ repoRoot: repoRoot || REPO_ROOT }); }
|
|
@@ -127,20 +171,48 @@ function handleModelRoleCommand({ role, exclude, json = false, repoRoot } =
|
|
|
127
171
|
if (!registry) return undefined;
|
|
128
172
|
const available = new Set(availableProviderIds());
|
|
129
173
|
try {
|
|
174
|
+
const excludedProviderIds = Array.isArray(exclude) ? exclude : String(exclude ?? '').split(',').map((s ) => s.trim()).filter(Boolean);
|
|
175
|
+
const requestedFamilies = excludeFamilies === undefined || excludeFamilies === null ? null : normalizeFamilyList(excludeFamilies);
|
|
176
|
+
if (requestedFamilies !== null) {
|
|
177
|
+
const knownFamilies = [...new Set((registry.modelProviders || []).flatMap((provider ) => provider.families || []))]
|
|
178
|
+
.filter((family) => typeof family === 'string' && family !== 'unknown').sort();
|
|
179
|
+
const knownSet = new Set(knownFamilies);
|
|
180
|
+
const unknownFamilies = requestedFamilies.filter((family) => !knownSet.has(family));
|
|
181
|
+
if (requestedFamilies.length === 0) {
|
|
182
|
+
return usageError('model-role', `--exclude-family requires at least one family name; known families: ${knownFamilies.join(', ') || '(none)'}`, json);
|
|
183
|
+
}
|
|
184
|
+
if (requestedFamilies.includes('unknown')) {
|
|
185
|
+
return usageError('model-role', `unknown cannot be excluded because it names missing knowledge; known families: ${knownFamilies.join(', ') || '(none)'}`, json);
|
|
186
|
+
}
|
|
187
|
+
if (unknownFamilies.length) {
|
|
188
|
+
return usageError('model-role', `unknown family name${unknownFamilies.length === 1 ? '' : 's'}: ${unknownFamilies.join(', ')}; known families: ${knownFamilies.join(', ') || '(none)'}`, json);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
130
191
|
const resolution = resolveModelRole({
|
|
131
192
|
registry,
|
|
132
193
|
roleId: role,
|
|
133
194
|
isAvailable: (providerId ) => available.has(providerId),
|
|
134
|
-
exclude:
|
|
195
|
+
exclude: excludedProviderIds,
|
|
196
|
+
...(requestedFamilies === null ? {} : { excludeFamilies: requestedFamilies }),
|
|
135
197
|
});
|
|
136
198
|
if (json) console.log(JSON.stringify(resolution, null, 2));
|
|
137
199
|
else {
|
|
138
200
|
console.log(`Role '${resolution.roleId}' — prefer:${resolution.policy.prefer ?? '—'} fallback:${resolution.policy.fallback ?? '—'} require:${resolution.policy.require ?? '—'}`);
|
|
139
201
|
for (const candidate of resolution.candidates) {
|
|
140
202
|
const availability = candidate.available === null ? '?' : candidate.available ? 'yes' : 'no';
|
|
141
|
-
|
|
203
|
+
const familyStatus = requestedFamilies === null ? ''
|
|
204
|
+
: ` ${candidate.familyRelation}`;
|
|
205
|
+
console.log(` ${candidate.available ? '*' : ' '} ${candidate.id} (${candidate.kind}, via ${candidate.backendCli ?? 'hosted'}) available=${availability}${resolution.policy.prefer && candidate.servesPreferredTier ? ` serves ${resolution.policy.prefer}` : ''}${familyStatus}`);
|
|
142
206
|
}
|
|
143
207
|
if (resolution.excluded.length) console.log(`Excluded: ${resolution.excluded.join(', ')}`);
|
|
208
|
+
if (requestedFamilies !== null) {
|
|
209
|
+
const familySet = new Set(requestedFamilies);
|
|
210
|
+
const providerExcluded = new Set(excludedProviderIds);
|
|
211
|
+
const sameFamily = (registry.modelProviders || []).filter((provider ) => !providerExcluded.has(provider.id)
|
|
212
|
+
&& familyInfo(provider.families, familySet).sameFamily);
|
|
213
|
+
for (const provider of sameFamily) console.log(` ${provider.id} same-family (excluded)`);
|
|
214
|
+
if (resolution.excludedFamilies.length) console.log(`Excluded families: ${resolution.excludedFamilies.join(', ')}`);
|
|
215
|
+
}
|
|
144
216
|
}
|
|
145
217
|
return finishRuntime(0);
|
|
146
218
|
} catch (error ) {
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('node:fs');
|
|
4
|
+
const os = require('node:os');
|
|
5
|
+
const path = require('node:path');
|
|
6
|
+
|
|
7
|
+
const { PROBES, HARNESS_IDS } = require('../worker/probes/index.js');
|
|
8
|
+
const { configHome } = require('../config-home.js');
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
function getProjectCataloguePath(projectRoot ) {
|
|
48
|
+
return path.join(projectRoot, '.doflow', 'state', 'models', 'catalogue.json');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function getUserCataloguePath(homeDir , env = process.env) {
|
|
52
|
+
if (homeDir) {
|
|
53
|
+
return path.join(homeDir, '.config', 'doflow', 'state', 'models-observed.json');
|
|
54
|
+
}
|
|
55
|
+
const { dir } = configHome(env);
|
|
56
|
+
const baseDir = dir || path.join(os.homedir(), '.config', 'doflow');
|
|
57
|
+
return path.join(baseDir, 'state', 'models-observed.json');
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function resolveProjectRoot(projectRoot , fsImpl = fs) {
|
|
61
|
+
if (projectRoot) return path.resolve(projectRoot);
|
|
62
|
+
try {
|
|
63
|
+
const { projectRoot: findRoot } = require('../lifecycle/root.js');
|
|
64
|
+
const root = findRoot(process.cwd());
|
|
65
|
+
if (root && fsImpl.existsSync(path.join(root, '.doflow'))) return root;
|
|
66
|
+
} catch {
|
|
67
|
+
// fallback
|
|
68
|
+
}
|
|
69
|
+
if (fsImpl.existsSync(path.join(process.cwd(), '.doflow'))) {
|
|
70
|
+
return process.cwd();
|
|
71
|
+
}
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function readCatalogue(
|
|
76
|
+
projectRoot ,
|
|
77
|
+
options = {}
|
|
78
|
+
) {
|
|
79
|
+
const fsImpl = options.fsImpl || fs;
|
|
80
|
+
const root = projectRoot ? path.resolve(projectRoot) : resolveProjectRoot(undefined, fsImpl);
|
|
81
|
+
|
|
82
|
+
if (root) {
|
|
83
|
+
const projPath = getProjectCataloguePath(root);
|
|
84
|
+
if (fsImpl.existsSync(projPath)) {
|
|
85
|
+
try {
|
|
86
|
+
const raw = fsImpl.readFileSync(projPath, 'utf8');
|
|
87
|
+
return JSON.parse(raw);
|
|
88
|
+
} catch (err ) {
|
|
89
|
+
if (err instanceof SyntaxError) {
|
|
90
|
+
const corrupt = `${projPath}.corrupt-${Date.now()}`;
|
|
91
|
+
try {
|
|
92
|
+
fsImpl.renameSync(projPath, corrupt);
|
|
93
|
+
} catch {
|
|
94
|
+
// best-effort
|
|
95
|
+
}
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Fallback to user cache
|
|
104
|
+
const userPath = getUserCataloguePath(options.homeDir, options.env);
|
|
105
|
+
if (fsImpl.existsSync(userPath)) {
|
|
106
|
+
try {
|
|
107
|
+
const raw = fsImpl.readFileSync(userPath, 'utf8');
|
|
108
|
+
return JSON.parse(raw);
|
|
109
|
+
} catch (err ) {
|
|
110
|
+
if (err instanceof SyntaxError) {
|
|
111
|
+
const corrupt = `${userPath}.corrupt-${Date.now()}`;
|
|
112
|
+
try {
|
|
113
|
+
fsImpl.renameSync(userPath, corrupt);
|
|
114
|
+
} catch {
|
|
115
|
+
// best-effort
|
|
116
|
+
}
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function writeCatalogue(
|
|
127
|
+
catalogue ,
|
|
128
|
+
projectRoot ,
|
|
129
|
+
options = {}
|
|
130
|
+
) {
|
|
131
|
+
const fsImpl = options.fsImpl || fs;
|
|
132
|
+
const root = projectRoot ? path.resolve(projectRoot) : resolveProjectRoot(undefined, fsImpl);
|
|
133
|
+
const targetPath = root ? getProjectCataloguePath(root) : getUserCataloguePath(options.homeDir, options.env);
|
|
134
|
+
|
|
135
|
+
const targetDir = path.dirname(targetPath);
|
|
136
|
+
fsImpl.mkdirSync(targetDir, { recursive: true });
|
|
137
|
+
|
|
138
|
+
const tmpPath = `${targetPath}.${process.pid}.${Date.now()}-${Math.random().toString(36).slice(2)}.tmp`;
|
|
139
|
+
fsImpl.writeFileSync(tmpPath, JSON.stringify(catalogue, null, 2), 'utf8');
|
|
140
|
+
fsImpl.renameSync(tmpPath, targetPath);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
async function syncHarness(
|
|
144
|
+
harnessId ,
|
|
145
|
+
options = {}
|
|
146
|
+
) {
|
|
147
|
+
const probe = PROBES[harnessId];
|
|
148
|
+
if (!probe) {
|
|
149
|
+
return {
|
|
150
|
+
harnessId,
|
|
151
|
+
binary: harnessId,
|
|
152
|
+
installed: false,
|
|
153
|
+
version: null,
|
|
154
|
+
loginState: 'unsupported',
|
|
155
|
+
reloginHint: null,
|
|
156
|
+
detectedMode: 'unverified',
|
|
157
|
+
derivedBilling: 'unknown',
|
|
158
|
+
offeredModels: [],
|
|
159
|
+
lastSyncedAt: new Date().toISOString(),
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return await probe(options);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
async function syncAllHarnesses(
|
|
167
|
+
options = {}
|
|
168
|
+
) {
|
|
169
|
+
const results = {};
|
|
170
|
+
for (const id of HARNESS_IDS) {
|
|
171
|
+
results[id] = await syncHarness(id, options);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const catalogue = {
|
|
175
|
+
version: 1,
|
|
176
|
+
syncedAt: new Date().toISOString(),
|
|
177
|
+
harnesses: results,
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
writeCatalogue(catalogue, options.projectRoot, options);
|
|
181
|
+
return catalogue;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
module.exports = {
|
|
185
|
+
getProjectCataloguePath,
|
|
186
|
+
getUserCataloguePath,
|
|
187
|
+
readCatalogue,
|
|
188
|
+
writeCatalogue,
|
|
189
|
+
syncHarness,
|
|
190
|
+
syncAllHarnesses,
|
|
191
|
+
};
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { readCatalogue, writeCatalogue, syncHarness, syncAllHarnesses } = require('./catalogue.js');
|
|
4
|
+
const { readAllowedModels } = require('../worker/models.js');
|
|
5
|
+
const { finishRuntime, usageError } = require('../cli-result.js');
|
|
6
|
+
const { HARNESS_IDS } = require('../worker/probes/index.js');
|
|
7
|
+
|
|
8
|
+
async function handleModelsCommand({
|
|
9
|
+
action,
|
|
10
|
+
actionGiven,
|
|
11
|
+
positional,
|
|
12
|
+
harness,
|
|
13
|
+
model,
|
|
14
|
+
json = false,
|
|
15
|
+
projectRoot = process.cwd(),
|
|
16
|
+
env = process.env,
|
|
17
|
+
} ) {
|
|
18
|
+
const act = actionGiven ? action : (action || (positional && positional[0]) || 'list');
|
|
19
|
+
|
|
20
|
+
if (act === 'sync') {
|
|
21
|
+
if (harness) {
|
|
22
|
+
if (!HARNESS_IDS.includes(harness)) {
|
|
23
|
+
return usageError('models', `unknown harness '${harness}'; expected one of: ${HARNESS_IDS.join(', ')}`, json);
|
|
24
|
+
}
|
|
25
|
+
const res = await syncHarness(harness, { projectRoot });
|
|
26
|
+
const catalogue = readCatalogue(projectRoot) || {
|
|
27
|
+
version: 1,
|
|
28
|
+
syncedAt: new Date().toISOString(),
|
|
29
|
+
harnesses: {},
|
|
30
|
+
};
|
|
31
|
+
catalogue.harnesses[harness] = res;
|
|
32
|
+
catalogue.syncedAt = new Date().toISOString();
|
|
33
|
+
writeCatalogue(catalogue, projectRoot);
|
|
34
|
+
|
|
35
|
+
if (json) {
|
|
36
|
+
console.log(JSON.stringify(res, null, 2));
|
|
37
|
+
} else {
|
|
38
|
+
const hint = res.loginState === 'logged-out' && res.reloginHint ? ` (re-login: ${res.reloginHint})` : '';
|
|
39
|
+
console.log(`Synced harness '${harness}': ${res.loginState}${hint}, mode: ${res.detectedMode}, billing: ${res.derivedBilling}, models: ${res.offeredModels.length}`);
|
|
40
|
+
}
|
|
41
|
+
return finishRuntime(0);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const catalogue = await syncAllHarnesses({ projectRoot });
|
|
45
|
+
if (json) {
|
|
46
|
+
console.log(JSON.stringify(catalogue, null, 2));
|
|
47
|
+
} else {
|
|
48
|
+
console.log(`Synced ${Object.keys(catalogue.harnesses).length} harness(es) at ${catalogue.syncedAt}`);
|
|
49
|
+
for (const [id, h] of Object.entries(catalogue.harnesses)) {
|
|
50
|
+
const hint = h.loginState === 'logged-out' && h.reloginHint ? ` (re-login: ${h.reloginHint})` : '';
|
|
51
|
+
console.log(` ${id.padEnd(14)} ${h.loginState.padEnd(12)} mode: ${h.detectedMode.padEnd(14)} billing: ${h.derivedBilling.padEnd(9)} models: ${h.offeredModels.length}${hint}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return finishRuntime(0);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (act === 'list') {
|
|
58
|
+
const catalogue = readCatalogue(projectRoot);
|
|
59
|
+
const allowed = readAllowedModels({ env, projectRoot }) || [];
|
|
60
|
+
const rows = [];
|
|
61
|
+
|
|
62
|
+
if (catalogue && catalogue.harnesses) {
|
|
63
|
+
for (const [harnessId, h] of Object.entries(catalogue.harnesses)) {
|
|
64
|
+
for (const m of h.offeredModels || []) {
|
|
65
|
+
rows.push({
|
|
66
|
+
harness: harnessId,
|
|
67
|
+
model: m.id,
|
|
68
|
+
displayName: m.displayName || m.id,
|
|
69
|
+
loginState: h.loginState,
|
|
70
|
+
status: allowed.includes(m.id) ? 'enabled' : 'listed',
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (rows.length === 0) {
|
|
77
|
+
if (json) console.log(JSON.stringify({ models: [] }, null, 2));
|
|
78
|
+
else console.log('No observed models. Run `doflow models --action sync` to probe worker pool.');
|
|
79
|
+
return finishRuntime(0);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (json) {
|
|
83
|
+
console.log(JSON.stringify(rows, null, 2));
|
|
84
|
+
} else {
|
|
85
|
+
console.log(`Observed Models (${rows.length}):`);
|
|
86
|
+
console.log(` ${'HARNESS'.padEnd(14)} ${'MODEL'.padEnd(28)} ${'LOGIN'.padEnd(12)} ${'STATUS'}`);
|
|
87
|
+
for (const row of rows) {
|
|
88
|
+
console.log(` ${row.harness.padEnd(14)} ${row.model.padEnd(28)} ${row.loginState.padEnd(12)} ${row.status}`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return finishRuntime(0);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (act === 'describe') {
|
|
95
|
+
if (!model || typeof model !== 'string') {
|
|
96
|
+
return usageError('models', '--model <id> is required for describe action', json);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const catalogue = readCatalogue(projectRoot);
|
|
100
|
+
const allowed = readAllowedModels({ env, projectRoot }) || [];
|
|
101
|
+
const matchingHarnesses = [];
|
|
102
|
+
let modelMeta = null;
|
|
103
|
+
|
|
104
|
+
if (catalogue && catalogue.harnesses) {
|
|
105
|
+
for (const [harnessId, h] of Object.entries(catalogue.harnesses)) {
|
|
106
|
+
const found = (h.offeredModels || []).find((m ) => m.id === model);
|
|
107
|
+
if (found) {
|
|
108
|
+
if (!modelMeta) modelMeta = found;
|
|
109
|
+
matchingHarnesses.push({
|
|
110
|
+
harnessId,
|
|
111
|
+
loginState: h.loginState,
|
|
112
|
+
detectedMode: h.detectedMode,
|
|
113
|
+
derivedBilling: h.derivedBilling,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (matchingHarnesses.length === 0) {
|
|
120
|
+
if (json) {
|
|
121
|
+
console.log(JSON.stringify({ error: 'not-found', model }, null, 2));
|
|
122
|
+
} else {
|
|
123
|
+
console.error(`doflow models: model '${model}' not found in observed catalogue. Run 'doflow models --action sync' to refresh.`);
|
|
124
|
+
}
|
|
125
|
+
return finishRuntime(1);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const detail = {
|
|
129
|
+
model,
|
|
130
|
+
displayName: modelMeta?.displayName || model,
|
|
131
|
+
family: modelMeta?.family || 'unknown',
|
|
132
|
+
status: allowed.includes(model) ? 'enabled' : 'listed',
|
|
133
|
+
harnesses: matchingHarnesses,
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
if (json) {
|
|
137
|
+
console.log(JSON.stringify(detail, null, 2));
|
|
138
|
+
} else {
|
|
139
|
+
console.log(`Model: ${detail.model} (${detail.displayName})`);
|
|
140
|
+
console.log(` Family: ${detail.family}`);
|
|
141
|
+
console.log(` Status: ${detail.status}`);
|
|
142
|
+
console.log(' Offering Harnesses:');
|
|
143
|
+
for (const h of detail.harnesses) {
|
|
144
|
+
console.log(` - ${h.harnessId}: ${h.loginState} (mode: ${h.detectedMode}, billing: ${h.derivedBilling})`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return finishRuntime(0);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return usageError('models', `unknown action '${act}'; expected sync, list, or describe`, json);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
module.exports = { handleModelsCommand };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// TypeScript migration (agent-docs/BRIEF_GOAL_DOFLOW.md): run directly by Node native type-stripping.
|
|
4
|
+
|
|
5
|
+
/** Common opt-out values used without loading the settings resolver. */
|
|
6
|
+
const OFF_WORDS = new Set(['off', '0', 'false', 'no']);
|
|
7
|
+
|
|
8
|
+
function isOffWord(value ) {
|
|
9
|
+
return typeof value === 'string' && OFF_WORDS.has(value.trim().toLowerCase());
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
module.exports = { OFF_WORDS, isOffWord };
|
package/src/runtime/outcome.js
CHANGED
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
const fs = require('node:fs');
|
|
44
44
|
const path = require('node:path');
|
|
45
45
|
const { EvidenceLedger, assertSafeTaskId } = require('./evidence-ledger.js');
|
|
46
|
-
const { taskStoreDir } = require('./task-scope.js');
|
|
46
|
+
const { taskStoreDir, taskRecord } = require('./task-scope.js');
|
|
47
47
|
// The two verdict vocabularies, imported from the modules that own them rather than respelled
|
|
48
48
|
// here. A second copy would let this file accept a readiness state readiness itself has retired.
|
|
49
49
|
const { READINESS_STATES } = require('./readiness.js');
|
|
@@ -55,7 +55,7 @@ const { planPath, UNREACHED } = require('./retrieval-plan.js');
|
|
|
55
55
|
// One definition of the score refusal, applied at a further boundary. See the note on
|
|
56
56
|
// EVIDENCE_SCORE_FIELDS in cli.js: a terminal state that carried a confidence would be exactly the
|
|
57
57
|
// number NFR-001 exists to keep out of the one record the next worker reads first.
|
|
58
|
-
const { assertNoScoreFields } = require('./
|
|
58
|
+
const { assertNoScoreFields } = require('./evidence-fields.js');
|
|
59
59
|
const { finishRuntime, usageError } = require('./cli-result.js');
|
|
60
60
|
const { REPO_ROOT } = require('../helper/repo-root.js');
|
|
61
61
|
|
|
@@ -107,7 +107,7 @@ function outcomePath(projectRoot , taskId , slug = null) {
|
|
|
107
107
|
* @returns {Object|null} the record, or null when no outcome was recorded
|
|
108
108
|
*/
|
|
109
109
|
function readOutcome(projectRoot , taskId , slug = null) {
|
|
110
|
-
const file =
|
|
110
|
+
const file = taskRecord({ projectRoot, store: 'outcome', taskId: assertSafeTaskId(taskId), slug }).read;
|
|
111
111
|
if (!fs.existsSync(file)) return null;
|
|
112
112
|
try {
|
|
113
113
|
return JSON.parse(fs.readFileSync(file, 'utf8'));
|