@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
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// 093 V.1, IC-021: loader, validator and doctor view for core/registry/transcripts.json, the data that
|
|
4
|
+
// says where each harness keeps its transcripts. Like advice.json it stays outside REGISTRY_FILES: a bad
|
|
5
|
+
// file turns the transcript feature off (`config-invalid`), it must not fail every install command.
|
|
6
|
+
|
|
7
|
+
const fs = require('node:fs');
|
|
8
|
+
const path = require('node:path');
|
|
9
|
+
const { REPO_ROOT } = require('../../helper/repo-root.js');
|
|
10
|
+
|
|
11
|
+
const TRANSCRIPTS_FILE = 'core/registry/transcripts.json';
|
|
12
|
+
const HARNESSES_FILE = 'core/registry/harnesses.json';
|
|
13
|
+
const STALE_DAYS = 90;
|
|
14
|
+
const DAY_MS = 86400000;
|
|
15
|
+
const STATUSES = ['supported', 'events-only', 'unknown'];
|
|
16
|
+
const FORMATS = ['jsonl', 'sqlite', 'jsonl+json'];
|
|
17
|
+
const APPEND_ONLY = ['yes', 'no', 'unknown'];
|
|
18
|
+
const JOINS = ['session-id', 'cwd', 'none'];
|
|
19
|
+
const OSES = ['darwin', 'linux', 'win32'];
|
|
20
|
+
const PLACEHOLDERS = new Set(['sessionId', 'cwdEncoded']);
|
|
21
|
+
const ENTRY_KEYS = ['harness', 'reader', 'status', 'locations', 'format', 'appendOnly', 'join', 'requiredKeys', 'evidence', 'verifiedOn', 'versions'];
|
|
22
|
+
|
|
23
|
+
function isObject(value ) {
|
|
24
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function isStringArray(value ) {
|
|
28
|
+
return Array.isArray(value) && value.every((item) => typeof item === 'string' && item.length > 0);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** True for a real calendar date written YYYY-MM-DD. */
|
|
32
|
+
function isDate(value ) {
|
|
33
|
+
if (typeof value !== 'string' || !/^\d{4}-\d{2}-\d{2}$/.test(value)) return false;
|
|
34
|
+
const at = new Date(`${value}T00:00:00Z`);
|
|
35
|
+
return !Number.isNaN(at.getTime()) && at.toISOString().slice(0, 10) === value;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function validateLocation(location , where , errors ) {
|
|
39
|
+
if (!isObject(location)) { errors.push(`${where} must be an object`); return; }
|
|
40
|
+
if (!OSES.includes(location.os)) errors.push(`${where}.os must be one of ${OSES.join(', ')}`);
|
|
41
|
+
if (!(typeof location.base === 'string' && /^(home|xdg-data|env:[A-Z_][A-Z0-9_]*)$/.test(location.base))) {
|
|
42
|
+
errors.push(`${where}.base must be home, xdg-data or env:<NAME>`);
|
|
43
|
+
}
|
|
44
|
+
if (!isStringArray(location.segments)) errors.push(`${where}.segments must be an array of non-empty strings`);
|
|
45
|
+
if (typeof location.glob !== 'string' || !location.glob) {
|
|
46
|
+
errors.push(`${where}.glob must be a non-empty string`);
|
|
47
|
+
} else {
|
|
48
|
+
for (const [, name] of location.glob.matchAll(/\{([^}]*)\}/g)) {
|
|
49
|
+
if (!PLACEHOLDERS.has(name)) errors.push(`${where}.glob has an unknown placeholder {${name}}`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
// R28: a Windows location stays unverified until someone measures it, and only Windows may say so.
|
|
53
|
+
if (location.os === 'win32') {
|
|
54
|
+
if (location.status !== 'unknown') errors.push(`${where} is win32, so its status must be "unknown"`);
|
|
55
|
+
} else if (location.status !== undefined) {
|
|
56
|
+
errors.push(`${where}.status is only allowed on a win32 location`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function validateEntry(entry , index , errors ) {
|
|
61
|
+
const label = isObject(entry) && typeof entry.harness === 'string' ? entry.harness : `entries[${index}]`;
|
|
62
|
+
if (!isObject(entry)) { errors.push(`${label} must be an object`); return; }
|
|
63
|
+
for (const key of ENTRY_KEYS) {
|
|
64
|
+
if (!Object.hasOwn(entry, key)) errors.push(`${label}.${key} is missing`);
|
|
65
|
+
}
|
|
66
|
+
if (typeof entry.harness !== 'string' || !entry.harness) errors.push(`${label}.harness must be a non-empty string`);
|
|
67
|
+
if (Object.hasOwn(entry, 'reader') && entry.reader !== null && (typeof entry.reader !== 'string' || !entry.reader)) {
|
|
68
|
+
errors.push(`${label}.reader must be a module id or null`);
|
|
69
|
+
}
|
|
70
|
+
if (Object.hasOwn(entry, 'status') && !STATUSES.includes(entry.status)) errors.push(`${label}.status must be one of ${STATUSES.join(', ')}`);
|
|
71
|
+
// A reader exists exactly when the harness is supported (IC-021: OpenCode moves only with its reader).
|
|
72
|
+
if (STATUSES.includes(entry.status) && entry.reader !== undefined) {
|
|
73
|
+
if (entry.status === 'supported' && entry.reader === null) errors.push(`${label}.reader must be set when status is supported`);
|
|
74
|
+
if (entry.status !== 'supported' && entry.reader !== null) errors.push(`${label}.reader must be null unless status is supported`);
|
|
75
|
+
}
|
|
76
|
+
if (Object.hasOwn(entry, 'locations')) {
|
|
77
|
+
if (!Array.isArray(entry.locations) || entry.locations.length === 0) errors.push(`${label}.locations must be a non-empty array`);
|
|
78
|
+
else entry.locations.forEach((location , i ) => validateLocation(location, `${label}.locations[${i}]`, errors));
|
|
79
|
+
}
|
|
80
|
+
if (Object.hasOwn(entry, 'format') && !FORMATS.includes(entry.format)) errors.push(`${label}.format must be one of ${FORMATS.join(', ')}`);
|
|
81
|
+
if (Object.hasOwn(entry, 'appendOnly') && !APPEND_ONLY.includes(entry.appendOnly)) errors.push(`${label}.appendOnly must be one of ${APPEND_ONLY.join(', ')}`);
|
|
82
|
+
if (Object.hasOwn(entry, 'join') && !JOINS.includes(entry.join)) errors.push(`${label}.join must be one of ${JOINS.join(', ')}`);
|
|
83
|
+
if (Object.hasOwn(entry, 'requiredKeys') && !isStringArray(entry.requiredKeys)) errors.push(`${label}.requiredKeys must be an array of non-empty strings`);
|
|
84
|
+
if (Object.hasOwn(entry, 'evidence') && (!isStringArray(entry.evidence) || entry.evidence.length === 0)) errors.push(`${label}.evidence must be a non-empty array of strings`);
|
|
85
|
+
if (Object.hasOwn(entry, 'verifiedOn') && !isDate(entry.verifiedOn)) errors.push(`${label}.verifiedOn must be a YYYY-MM-DD date`);
|
|
86
|
+
if (Object.hasOwn(entry, 'versions') && entry.versions !== null && (typeof entry.versions !== 'string' || !entry.versions)) {
|
|
87
|
+
errors.push(`${label}.versions must be a version range or null`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** The registry ids of core/registry/harnesses.json, read as plain data. */
|
|
92
|
+
function readHarnessIds(repoRoot , fsImpl = fs) {
|
|
93
|
+
const parsed = JSON.parse(fsImpl.readFileSync(path.join(path.resolve(repoRoot), HARNESSES_FILE), 'utf8'));
|
|
94
|
+
return parsed.harnesses.map((harness ) => harness.id);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Checks the registry's shape and the id guard: the entry ids and `harnessIds` are the same set, with no
|
|
99
|
+
* exception (row 127 retired Gemini CLI, so there is no Gemini entry and no allowance for one).
|
|
100
|
+
*/
|
|
101
|
+
function validateTranscriptRegistry(registry , { harnessIds } ) {
|
|
102
|
+
const errors = [];
|
|
103
|
+
if (!isObject(registry)) return { ok: false, errors: ['registry must be an object'] };
|
|
104
|
+
if (registry.version !== 1) errors.push('version must be 1');
|
|
105
|
+
if (!Array.isArray(registry.entries)) {
|
|
106
|
+
errors.push('entries must be an array');
|
|
107
|
+
return { ok: false, errors };
|
|
108
|
+
}
|
|
109
|
+
registry.entries.forEach((entry , i ) => validateEntry(entry, i, errors));
|
|
110
|
+
const seen = new Set ();
|
|
111
|
+
for (const entry of registry.entries) {
|
|
112
|
+
if (!isObject(entry) || typeof entry.harness !== 'string') continue;
|
|
113
|
+
if (seen.has(entry.harness)) errors.push(`${entry.harness} is a duplicate entry`);
|
|
114
|
+
seen.add(entry.harness);
|
|
115
|
+
if (!harnessIds.includes(entry.harness)) errors.push(`${entry.harness} is not a harnesses.json id`);
|
|
116
|
+
}
|
|
117
|
+
for (const id of harnessIds) {
|
|
118
|
+
if (!seen.has(id)) errors.push(`${id} has no entry (every harnesses.json id needs one)`);
|
|
119
|
+
}
|
|
120
|
+
return { ok: errors.length === 0, errors };
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function loadTranscriptRegistry({ repoRoot = REPO_ROOT, file, fsImpl = fs } = {}) {
|
|
124
|
+
const root = path.resolve(repoRoot);
|
|
125
|
+
const target = file || path.join(root, TRANSCRIPTS_FILE);
|
|
126
|
+
let registry ;
|
|
127
|
+
let harnessIds ;
|
|
128
|
+
try {
|
|
129
|
+
registry = JSON.parse(fsImpl.readFileSync(target, 'utf8'));
|
|
130
|
+
harnessIds = readHarnessIds(root, fsImpl);
|
|
131
|
+
} catch (error ) {
|
|
132
|
+
return { ok: false, reason: 'config-invalid', detail: `${target}: ${error.message}` };
|
|
133
|
+
}
|
|
134
|
+
const validation = validateTranscriptRegistry(registry, { harnessIds });
|
|
135
|
+
if (!validation.ok) return { ok: false, reason: 'config-invalid', detail: validation.errors.join('; ') };
|
|
136
|
+
return { ok: true, registry };
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/** Entries whose `verifiedOn` is more than STALE_DAYS before `now`. */
|
|
140
|
+
function staleEntries(registry , now = new Date()) {
|
|
141
|
+
const out = [];
|
|
142
|
+
for (const entry of registry.entries) {
|
|
143
|
+
const ageDays = Math.floor((now.getTime() - new Date(`${entry.verifiedOn}T00:00:00Z`).getTime()) / DAY_MS);
|
|
144
|
+
if (ageDays > STALE_DAYS) out.push({ harness: entry.harness, verifiedOn: entry.verifiedOn, ageDays });
|
|
145
|
+
}
|
|
146
|
+
return out;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* The doctor's `transcripts` row: `ok`, `stale` (a `verifiedOn` older than 90 days) or `drift` (the file or
|
|
151
|
+
* the id guard is invalid, so the transcript feature is off). Read-only; never a finding, so the exit code
|
|
152
|
+
* does not change. A `format-unrecognized` seen at run time joins this row when V.4's readers exist.
|
|
153
|
+
*/
|
|
154
|
+
function transcriptsDoctorView({ repoRoot = REPO_ROOT, file, fsImpl = fs, now = new Date() } = {}) {
|
|
155
|
+
const loaded = loadTranscriptRegistry({ repoRoot, file, fsImpl });
|
|
156
|
+
if (!loaded.ok) return { state: 'drift', entries: 0, stale: [], errors: (loaded.detail ).split('; ') };
|
|
157
|
+
const stale = staleEntries(loaded.registry, now);
|
|
158
|
+
return { state: stale.length ? 'stale' : 'ok', entries: loaded.registry.entries.length, stale, errors: [] };
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
module.exports = { loadTranscriptRegistry, validateTranscriptRegistry, staleEntries, transcriptsDoctorView, STALE_DAYS, TRANSCRIPTS_FILE };
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* `transcript --action stats` (093 IC-023): traffic over the last window and who works with whom, for one
|
|
5
|
+
* project. The agents are `buildTree`'s nodes (newest first, at most 32; the rest counted in `notChecked`).
|
|
6
|
+
* A linked transcript is read in metadata mode (no text, no arguments), at most its last 256 KiB, in pages.
|
|
7
|
+
* An event without a time (Kiro keeps none per record) takes the transcript's newest known time, which for
|
|
8
|
+
* Kiro is the newest turn `end_timestamp`; if there is none, the window is unknown and the counts are null.
|
|
9
|
+
* Unknown is never zero: a harness that does not record a value gives null, and an agent with no readable
|
|
10
|
+
* transcript gives null everywhere. Zero is reported only for a transcript that was read and held nothing.
|
|
11
|
+
* `pairs` says who works with whom: equal model id (`same-model`), active attempts or running worker runs on
|
|
12
|
+
* one task id (`same-task`, `task`), and a plan `overlaps` pair held by two agents (`overlap`, `tasks`).
|
|
13
|
+
* Nothing is written; no path, pid or raw session id is printed.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const fs = require('node:fs');
|
|
17
|
+
const { buildTree, READERS } = require('../fleet/tree.js');
|
|
18
|
+
const { loadPlan } = require('../task-attempts.js');
|
|
19
|
+
const { overlaps } = require('../task-graph.js');
|
|
20
|
+
const { parseCursor, toMs } = require('./cursor.js');
|
|
21
|
+
const { inCheckouts, checkoutRoots, registryById } = require('./read.js');
|
|
22
|
+
|
|
23
|
+
const DEFAULT_WINDOW = 10;
|
|
24
|
+
const MAX_AGENTS = 32;
|
|
25
|
+
const MAX_PAGES = 8;
|
|
26
|
+
const TAIL_RECORDS = 4096;
|
|
27
|
+
const TOKEN_FIELDS = ['input', 'output', 'cacheRead', 'cacheWrite', 'reasoning'];
|
|
28
|
+
|
|
29
|
+
/** Sums of the fields any event recorded; a field no event recorded stays null, and none at all is null. */
|
|
30
|
+
function sumTokens(list ) {
|
|
31
|
+
const out = {};
|
|
32
|
+
for (const field of TOKEN_FIELDS) {
|
|
33
|
+
const values = list.map((t) => t[field]).filter((v) => Number.isFinite(v));
|
|
34
|
+
out[field] = values.length ? values.reduce((a, b) => a + b, 0) : null;
|
|
35
|
+
}
|
|
36
|
+
return Object.values(out).some((v) => v !== null) ? out : null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const round2 = (n ) => Math.round(n * 100) / 100;
|
|
40
|
+
|
|
41
|
+
/** Every event of the transcript's window, in pages, with the newest time the reader knew. */
|
|
42
|
+
function readWindow(mod , node , internal ) {
|
|
43
|
+
const events = [];
|
|
44
|
+
let cursor ;
|
|
45
|
+
let clock = NaN;
|
|
46
|
+
for (let page = 0; page < MAX_PAGES; page += 1) {
|
|
47
|
+
const r = mod.read({ file: internal.file, companion: internal.companion, mode: 'metadata', cursor, limit: 500, tailRecords: TAIL_RECORDS, agentKey: node.agentKey });
|
|
48
|
+
events.push(...r.events);
|
|
49
|
+
const c = parseCursor(r.cursor);
|
|
50
|
+
clock = c && c.atMs > 0 ? c.atMs : clock;
|
|
51
|
+
cursor = r.cursor;
|
|
52
|
+
if (r.eof) break;
|
|
53
|
+
}
|
|
54
|
+
return { events, clock };
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** The per-agent numbers of the events at or after `startMs`. */
|
|
58
|
+
function summarize(events , clock , startMs , windowMin ) {
|
|
59
|
+
if (events.length === 0) {
|
|
60
|
+
return { eventsPerMin: 0, toolCalls: 0, toolErrors: 0, toolDurationMs: null, tokens: null };
|
|
61
|
+
}
|
|
62
|
+
const timed = events.map((e) => ({ e, t: Number.isFinite(toMs(e.at)) ? toMs(e.at) : clock })).filter((x) => Number.isFinite(x.t));
|
|
63
|
+
if (timed.length === 0) return { eventsPerMin: null, toolCalls: null, toolErrors: null, toolDurationMs: null, tokens: null };
|
|
64
|
+
const inWindow = timed.filter((x) => x.t >= startMs).map((x) => x.e);
|
|
65
|
+
const results = inWindow.filter((e) => e.kind === 'tool-result');
|
|
66
|
+
const known = results.filter((e) => e.tool && e.tool.status !== null && e.tool.status !== undefined);
|
|
67
|
+
const durations = results.map((e) => e.tool && e.tool.durationMs).filter((d) => Number.isFinite(d)).sort((a, b) => a - b);
|
|
68
|
+
const usage = inWindow.filter((e) => e.kind === 'usage' && e.tokens).map((e) => e.tokens);
|
|
69
|
+
return {
|
|
70
|
+
eventsPerMin: round2(inWindow.length / windowMin),
|
|
71
|
+
toolCalls: inWindow.filter((e) => e.kind === 'tool-call').length,
|
|
72
|
+
toolErrors: results.length > 0 && known.length === 0 ? null : known.filter((e) => e.tool.status === 'error').length,
|
|
73
|
+
toolDurationMs: durations.length ? { p50: durations[Math.ceil(durations.length / 2) - 1], max: durations[durations.length - 1], n: durations.length } : null,
|
|
74
|
+
tokens: sumTokens(usage),
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function groupModels(agents ) {
|
|
79
|
+
const byModel = new Map ();
|
|
80
|
+
for (const a of agents) if (a.model !== null) byModel.set(a.model, [...(byModel.get(a.model) ?? []), a]);
|
|
81
|
+
const sum = (list , key ) => {
|
|
82
|
+
const values = list.map((a) => a[key]).filter((v) => v !== null);
|
|
83
|
+
return values.length ? round2(values.reduce((x, y) => x + y, 0)) : null;
|
|
84
|
+
};
|
|
85
|
+
return [...byModel.entries()].sort((x, y) => (x[0] < y[0] ? -1 : 1)).map(([model, list]) => ({
|
|
86
|
+
model, agents: list.length, eventsPerMin: sum(list, 'eventsPerMin'), toolCalls: sum(list, 'toolCalls'), tokens: sumTokens(list.map((a) => a.tokens).filter(Boolean)),
|
|
87
|
+
}));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function pairsOf(agents , holds , planOverlaps ) {
|
|
91
|
+
const out = new Map ();
|
|
92
|
+
const add = (a , b , basis , task , tasks ) => {
|
|
93
|
+
out.set(`${a}|${b}|${basis}|${task ?? ''}|${(tasks ?? []).join(',')}`, { a, b, basis, task, tasks });
|
|
94
|
+
};
|
|
95
|
+
const sorted = [...agents].sort((x, y) => (x.agentKey < y.agentKey ? -1 : 1));
|
|
96
|
+
for (let i = 0; i < sorted.length; i += 1) {
|
|
97
|
+
for (let j = i + 1; j < sorted.length; j += 1) {
|
|
98
|
+
const [x, y] = [sorted[i], sorted[j]];
|
|
99
|
+
if (x.model !== null && x.model === y.model) add(x.agentKey, y.agentKey, 'same-model', null, null);
|
|
100
|
+
const [hx, hy] = [holds.get(x.agentKey) ?? [], holds.get(y.agentKey) ?? []];
|
|
101
|
+
for (const h of hx) {
|
|
102
|
+
if (hy.some((g) => g.slug === h.slug && g.task === h.task)) add(x.agentKey, y.agentKey, 'same-task', h.task, null);
|
|
103
|
+
for (const pair of planOverlaps(h.slug)) {
|
|
104
|
+
const other = pair.a === h.task ? pair.b : pair.b === h.task ? pair.a : null;
|
|
105
|
+
if (other !== null && hy.some((g) => g.slug === h.slug && g.task === other)) add(x.agentKey, y.agentKey, 'overlap', null, [h.task, other]);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return [...out.values()].sort((p, q) => (p.a < q.a ? -1 : p.a > q.a ? 1 : p.b < q.b ? -1 : p.b > q.b ? 1 : p.basis < q.basis ? -1 : p.basis > q.basis ? 1 : String(p.task ?? p.tasks).localeCompare(String(q.task ?? q.tasks))));
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function computeStats({
|
|
114
|
+
env = process.env, cwd = process.cwd(), windowMin = DEFAULT_WINDOW, exec, alive, fsImpl = fs, platform, home, now = Date.now,
|
|
115
|
+
} = {}) {
|
|
116
|
+
const built = buildTree({ env, cwd, ...(exec ? { exec } : {}), ...(alive ? { alive } : {}), ...(fsImpl !== fs ? { fsImpl } : {}), ...(platform ? { platform } : {}), ...(home ? { home } : {}) });
|
|
117
|
+
if (!built.ok) return { ok: false, error: built.error };
|
|
118
|
+
const registry = registryById();
|
|
119
|
+
const roots = checkoutRoots({ cwd, exec, fsImpl });
|
|
120
|
+
const startMs = now() - windowMin * 60000;
|
|
121
|
+
const ranked = [...built.body.nodes].sort((a , b ) => (a.lastRecordAt === b.lastRecordAt ? 0 : a.lastRecordAt === null ? 1 : b.lastRecordAt === null ? -1 : a.lastRecordAt < b.lastRecordAt ? 1 : -1) || (a.agentKey < b.agentKey ? -1 : 1));
|
|
122
|
+
const chosen = ranked.slice(0, MAX_AGENTS);
|
|
123
|
+
|
|
124
|
+
const holds = new Map ();
|
|
125
|
+
const agents = chosen.map((node ) => {
|
|
126
|
+
const internal = built.internal.get(node.agentKey) ?? {};
|
|
127
|
+
holds.set(node.agentKey, internal.holds ?? []);
|
|
128
|
+
let numbers = { eventsPerMin: null, toolCalls: null, toolErrors: null, toolDurationMs: null, tokens: null };
|
|
129
|
+
if (node.transcript.linked && internal.file) {
|
|
130
|
+
try {
|
|
131
|
+
const mod = READERS[registry[node.harness].reader]();
|
|
132
|
+
const header = mod.header({ file: internal.file, companion: internal.companion });
|
|
133
|
+
if (inCheckouts(header.cwd, roots, fsImpl)) {
|
|
134
|
+
const { events, clock } = readWindow(mod, node, internal);
|
|
135
|
+
numbers = summarize(events, clock, startMs, windowMin);
|
|
136
|
+
}
|
|
137
|
+
} catch { /* an unreadable transcript is unknown, not zero */ }
|
|
138
|
+
}
|
|
139
|
+
return { agentKey: node.agentKey, harness: node.harness, model: node.model, ...numbers, lastRecordAt: node.lastRecordAt };
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
const planCache = new Map ();
|
|
143
|
+
const planOverlaps = (slug ) => {
|
|
144
|
+
if (!planCache.has(slug)) {
|
|
145
|
+
let list = [];
|
|
146
|
+
try { list = overlaps(loadPlan({ roots, slug, fsImpl }).graph); } catch { /* no readable plan: no overlap pairs */ }
|
|
147
|
+
planCache.set(slug, list);
|
|
148
|
+
}
|
|
149
|
+
return planCache.get(slug) ;
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
return {
|
|
153
|
+
ok: true,
|
|
154
|
+
body: {
|
|
155
|
+
v: 1, projectKey: built.body.projectKey, windowMin, agents, models: groupModels(agents),
|
|
156
|
+
pairs: pairsOf(agents, holds, planOverlaps), notChecked: Math.max(0, ranked.length - MAX_AGENTS),
|
|
157
|
+
},
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
module.exports = { computeStats, DEFAULT_WINDOW, MAX_AGENTS };
|