@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
|
@@ -16,29 +16,60 @@
|
|
|
16
16
|
# - never rotates the file (rotation is done by the Node writers only, DEC-019);
|
|
17
17
|
# - never blocks, never changes the policy's decision, and swallows every error.
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
_DOFLOW_SRC=${BASH_SOURCE[0]//\\//}; case $_DOFLOW_SRC in */*) _DOFLOW_CAPTURE_FAILURE_DIR=${_DOFLOW_SRC%/*} ;; *) _DOFLOW_CAPTURE_FAILURE_DIR=. ;; esac
|
|
20
20
|
# The line holds only the policy name and the point name from DoFlow's own code, the working
|
|
21
21
|
# directory, the harness name and the install version: never the tool call, its arguments or stdin.
|
|
22
|
-
# It is a no-op when no
|
|
23
|
-
# while capture is off (
|
|
24
|
-
#
|
|
22
|
+
# It is a no-op when there is no config home (neither XDG_CONFIG_HOME nor HOME is set to an absolute
|
|
23
|
+
# path; doflow_config_home below) and while capture is off (DOFLOW_FAILURE_CAPTURE=off|0|false|no,
|
|
24
|
+
# the `off` sentinel file, or a `failure.capture` value other than "on" in <config home>/settings.json,
|
|
25
|
+
# read by doflow_lex_capture below), the same rules the Node writer follows (IC-011, IC-014, IC-005).
|
|
26
|
+
# The two marked blocks are byte-identical to the ones in bin/doflow-run.
|
|
27
|
+
|
|
28
|
+
# BEGIN doflow-config-home v1 (rule: src/runtime/config-home.js; checked by test/guards/settings.test.js)
|
|
29
|
+
doflow_config_home() {
|
|
30
|
+
DOFLOW_HOME=""
|
|
31
|
+
case "${XDG_CONFIG_HOME:-}" in
|
|
32
|
+
/*) DOFLOW_HOME="${XDG_CONFIG_HOME}/doflow"; return 0 ;;
|
|
33
|
+
[A-Za-z]:[\\/]*) case "${OSTYPE:-}" in msys*|cygwin*|win32*) DOFLOW_HOME="${XDG_CONFIG_HOME}/doflow"; return 0 ;; esac ;;
|
|
34
|
+
esac
|
|
35
|
+
case "${HOME:-}" in
|
|
36
|
+
/*) DOFLOW_HOME="${HOME}/.config/doflow" ;;
|
|
37
|
+
[A-Za-z]:[\\/]*) case "${OSTYPE:-}" in msys*|cygwin*|win32*) DOFLOW_HOME="${HOME}/.config/doflow" ;; esac ;;
|
|
38
|
+
esac
|
|
39
|
+
return 0
|
|
40
|
+
}
|
|
41
|
+
# END doflow-config-home v1
|
|
42
|
+
|
|
43
|
+
# BEGIN doflow-settings-lexical v1 (rule: src/runtime/settings/lexical.js; checked by test/guards/settings.test.js)
|
|
44
|
+
doflow_lex_capture() {
|
|
45
|
+
local f="${1:-}" text="" rest="" d=""
|
|
46
|
+
local re='"failure\.capture"[[:space:]]*:[[:space:]]*("[^"]*"|[^,}"[:space:]]*)'
|
|
47
|
+
DOFLOW_LEX_CAPTURE=""
|
|
48
|
+
if [ ! -e "$f" ]; then
|
|
49
|
+
# Missing is no setting, unless the folder holding it cannot be searched (Node: EACCES is off).
|
|
50
|
+
d="${f%/*}"
|
|
51
|
+
if [ -n "$d" ] && [ "$d" != "$f" ] && [ -d "$d" ] && [ ! -x "$d" ]; then DOFLOW_LEX_CAPTURE="off"; fi
|
|
52
|
+
return 0
|
|
53
|
+
fi
|
|
54
|
+
if [ ! -f "$f" ] || [ ! -r "$f" ]; then DOFLOW_LEX_CAPTURE="off"; return 0; fi
|
|
55
|
+
IFS= read -r -d '' text < "$f" || true
|
|
56
|
+
rest="$text"
|
|
57
|
+
while [[ $rest =~ $re ]]; do
|
|
58
|
+
if [ "${BASH_REMATCH[1]}" = '"on"' ]; then DOFLOW_LEX_CAPTURE="${DOFLOW_LEX_CAPTURE:-on}"; else DOFLOW_LEX_CAPTURE="off"; fi
|
|
59
|
+
rest="${rest#*"${BASH_REMATCH[0]}"}"
|
|
60
|
+
done
|
|
61
|
+
return 0
|
|
62
|
+
}
|
|
63
|
+
# END doflow-settings-lexical v1
|
|
25
64
|
|
|
26
65
|
doflow_capture_failure() {
|
|
27
66
|
local policy="${1:-}" point="${2:-}"
|
|
28
67
|
local LC_ALL=C # byte-wise lengths and cuts; scoped to this function
|
|
29
68
|
local home="" setting="" version="" harness="" project="" cwd="" hp="" at="" line="" here="" dir=""
|
|
30
69
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
*) return 0 ;;
|
|
35
|
-
esac
|
|
36
|
-
else
|
|
37
|
-
case "${HOME:-}" in
|
|
38
|
-
/*) home="$HOME/.config/doflow/failures" ;;
|
|
39
|
-
*) return 0 ;;
|
|
40
|
-
esac
|
|
41
|
-
fi
|
|
70
|
+
doflow_config_home
|
|
71
|
+
[ -n "$DOFLOW_HOME" ] || return 0
|
|
72
|
+
home="$DOFLOW_HOME/failures"
|
|
42
73
|
|
|
43
74
|
# Case-insensitive, whitespace trimmed at the ends only: the same reading the Node writer has.
|
|
44
75
|
setting="$(printf '%s' "${DOFLOW_FAILURE_CAPTURE:-}" | tr '[:upper:]' '[:lower:]')" || return 0
|
|
@@ -48,6 +79,8 @@ doflow_capture_failure() {
|
|
|
48
79
|
off|0|false|no) return 0 ;;
|
|
49
80
|
esac
|
|
50
81
|
[ -f "$home/off" ] && return 0
|
|
82
|
+
doflow_lex_capture "$DOFLOW_HOME/settings.json"
|
|
83
|
+
[ "$DOFLOW_LEX_CAPTURE" = off ] && return 0
|
|
51
84
|
|
|
52
85
|
[[ "$policy" =~ ^[a-z][a-z0-9-]{0,39}$ ]] || policy="unknown"
|
|
53
86
|
[[ "$point" =~ ^[A-Za-z][A-Za-z0-9._:-]{0,39}$ ]] || return 0
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# IC-001 (feature 116): shared PreCompact text builder; sourced, not executed.
|
|
3
|
+
|
|
4
|
+
doflow_compact_text() {
|
|
5
|
+
local CWD="${1:-}"
|
|
6
|
+
local preserve branch sha uncommitted recent text
|
|
7
|
+
|
|
8
|
+
preserve='Preserve: decisions made, files modified, open questions, planned next steps, acceptance criteria and pending verification of the active task.'
|
|
9
|
+
|
|
10
|
+
if [[ -n "$CWD" ]] && is_git_worktree "$CWD"; then
|
|
11
|
+
branch=$(git_branch_of "$CWD" || echo "")
|
|
12
|
+
sha=$(git_short_sha_of "$CWD" || echo "")
|
|
13
|
+
uncommitted=$(git_uncommitted_count_of "$CWD" || echo "0")
|
|
14
|
+
recent=$(run_with_timeout 1 -- git -C "$CWD" log --format="%h %s" -2 2>/dev/null \
|
|
15
|
+
| awk 'NR>1{printf " | "}{printf "%s",$0}' || echo "")
|
|
16
|
+
|
|
17
|
+
text=$(printf '%s\nInclude in compact summary:\n- git branch: %s sha: %s\n- uncommitted files: %s\n- cwd: %s\n- recent commits: %s' \
|
|
18
|
+
"$preserve" "${branch:-unknown}" "${sha:-unknown}" "$uncommitted" "${CWD:-unknown}" "${recent:-none}")
|
|
19
|
+
else
|
|
20
|
+
text=$(printf '%s\nInclude in compact summary:\n- cwd: %s (not a git repository)' \
|
|
21
|
+
"$preserve" "${CWD:-unknown}")
|
|
22
|
+
fi
|
|
23
|
+
|
|
24
|
+
# The cap is 490 BYTES in every locale: LC_ALL=C makes the substring and length below count bytes,
|
|
25
|
+
# where a UTF-8 locale would count characters. A cut can then end inside a multi-byte character, so
|
|
26
|
+
# a trailing partial UTF-8 sequence is dropped (FU-tsq77m).
|
|
27
|
+
local LC_ALL=C cut i b need
|
|
28
|
+
cut="${text:0:490}"
|
|
29
|
+
i=$(( ${#cut} - 1 ))
|
|
30
|
+
# Walk back over at most three continuation bytes (0x80-0xBF) to the byte that starts the last character.
|
|
31
|
+
while [[ $i -ge 1 && $(( ${#cut} - i )) -le 3 ]]; do
|
|
32
|
+
printf -v b '%d' "'${cut:i:1}"
|
|
33
|
+
b=$(( b & 255 )) # the shell may print a byte above 127 as a negative number (bash 3.2) or a code unit
|
|
34
|
+
[[ $b -ge 128 && $b -lt 192 ]] || break
|
|
35
|
+
i=$(( i - 1 ))
|
|
36
|
+
done
|
|
37
|
+
printf -v b '%d' "'${cut:i:1}"
|
|
38
|
+
b=$(( b & 255 ))
|
|
39
|
+
need=1
|
|
40
|
+
[[ $b -ge 192 ]] && need=2
|
|
41
|
+
[[ $b -ge 224 ]] && need=3
|
|
42
|
+
[[ $b -ge 240 ]] && need=4
|
|
43
|
+
[[ $(( ${#cut} - i )) -lt $need ]] && cut="${cut:0:i}"
|
|
44
|
+
DF_COMPACT_TEXT="$cut"
|
|
45
|
+
return 0
|
|
46
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
+
case "${OSTYPE:-}" in msys*|cygwin*|win32*) if command -v jq >/dev/null 2>&1; then jq() { command jq -b "$@"; }; fi ;; esac # native jq.exe ends lines with CRLF unless -b
|
|
2
3
|
# contract.sh — shared decision and envelope contract for canonical policies.
|
|
3
4
|
#
|
|
4
5
|
# This file is sourced by policy scripts. It sets no shell options, installs no traps, reads no
|
|
@@ -43,6 +44,7 @@ doflow_read_envelope() {
|
|
|
43
44
|
DF_ENV_TOOL=
|
|
44
45
|
DF_ENV_PATHS=
|
|
45
46
|
DF_ENV_COMMAND=
|
|
47
|
+
DF_ENV_CWD=
|
|
46
48
|
DF_ENV_PATCH=
|
|
47
49
|
DF_ENV_ROOT=
|
|
48
50
|
DF_ENV_TASK=
|
|
@@ -67,6 +69,7 @@ doflow_read_envelope() {
|
|
|
67
69
|
shellvar("DF_ENV_TOOL"; field("tool")),
|
|
68
70
|
shellvar("DF_ENV_PATHS"; ([$fields.paths[]? | select(type == "string")] | join("\n"))),
|
|
69
71
|
shellvar("DF_ENV_COMMAND"; field("command")),
|
|
72
|
+
shellvar("DF_ENV_CWD"; ($object.cwd // "") | if type=="string" then . else "" end),
|
|
70
73
|
shellvar("DF_ENV_PATCH"; field("patch")),
|
|
71
74
|
shellvar("DF_ENV_ROOT"; field("projectRoot")),
|
|
72
75
|
shellvar("DF_ENV_TASK"; field("taskId"))][]
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
+
case "${OSTYPE:-}" in msys*|cygwin*|win32*) if command -v jq >/dev/null 2>&1; then jq() { command jq -b "$@"; }; fi ;; esac # native jq.exe ends lines with CRLF unless -b
|
|
2
3
|
# deny-json.sh — shared PreToolUse deny-JSON emitters for front-door dispatchers.
|
|
3
4
|
#
|
|
4
5
|
# Deliberately carries no `set` directive (unlike lib.sh, which sets -euo
|
|
@@ -10,7 +11,7 @@
|
|
|
10
11
|
#
|
|
11
12
|
# Usage: source "<policy-dir>/deny-json.sh"
|
|
12
13
|
|
|
13
|
-
|
|
14
|
+
_DOFLOW_SRC=${BASH_SOURCE[0]//\\//}; case $_DOFLOW_SRC in */*) _DOFLOW_DENY_JSON_DIR=${_DOFLOW_SRC%/*} ;; *) _DOFLOW_DENY_JSON_DIR=. ;; esac
|
|
14
15
|
|
|
15
16
|
# Escape a string as a JSON string body without external tools. Work bytewise so
|
|
16
17
|
# every control byte is handled the same way regardless of the caller's locale.
|
|
@@ -52,13 +53,3 @@ emit_pretooluse_deny_nested() {
|
|
|
52
53
|
printf '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny","permissionDecisionReason":%s}}\n' "$(_doflow_json_reason "$reason")"
|
|
53
54
|
fi
|
|
54
55
|
}
|
|
55
|
-
|
|
56
|
-
# Gemini shape: flat {decision, reason} (packages/core/src/hooks/types.ts).
|
|
57
|
-
emit_pretooluse_deny_flat() {
|
|
58
|
-
local reason="$1"
|
|
59
|
-
if command -v jq >/dev/null 2>&1; then
|
|
60
|
-
jq -n --arg reason "$reason" '{decision: "deny", reason: $reason}'
|
|
61
|
-
else
|
|
62
|
-
printf '{"decision":"deny","reason":%s}\n' "$(_doflow_json_reason "$reason")"
|
|
63
|
-
fi
|
|
64
|
-
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Generated by node src/runtime/context/emission-rules.js --write. Do not edit.
|
|
2
|
+
# rules-digest: sha256:3f344067dc5466521e89700b8ca03c5729dfe2e3bc0896629d4e08a5395dd4bb
|
|
3
|
+
DF_RULES_VERSION=1
|
|
4
|
+
DF_RULES_MAX_BYTES_DEFAULT=16384
|
|
5
|
+
DF_RULES_SUMMARY_CAP=4000
|
|
6
|
+
DF_RULES_SUMMARY_READ=65536
|
|
7
|
+
doflow_emission_rule() {
|
|
8
|
+
# $1 = event.segment, $2 = vector: input values joined with ':' in IC-002 order
|
|
9
|
+
case "$1|$2" in
|
|
10
|
+
'compact-instructions.instructions|main') DF_ACTION=include ;;
|
|
11
|
+
'compact-instructions.instructions|worker') DF_ACTION=include ;;
|
|
12
|
+
'compact-meta.meta|main:default-main') DF_ACTION=write ;;
|
|
13
|
+
'compact-store.summary|main:default-main') DF_ACTION=write ;;
|
|
14
|
+
'compact-store.summary|main:launched') DF_ACTION=write ;;
|
|
15
|
+
'compact-store.summary|worker:launched') DF_ACTION=write ;;
|
|
16
|
+
'delta.pack|true') DF_ACTION=include ;;
|
|
17
|
+
'launch.grant|fits:false') DF_ACTION=whole ;;
|
|
18
|
+
'launch.grant|fits:true') DF_ACTION=whole ;;
|
|
19
|
+
'launch.grant|over:false') DF_ACTION=pointer ;;
|
|
20
|
+
'launch.pack|false') DF_ACTION=include ;;
|
|
21
|
+
'launch.slot|false') DF_ACTION=claim ;;
|
|
22
|
+
'launch.summary|main:false:pending') DF_ACTION=truncate ;;
|
|
23
|
+
'launch.summary|worker:false:pending') DF_ACTION=truncate ;;
|
|
24
|
+
'legacy-adopt.legacy|main:default-main:false:false:true') DF_ACTION=adopt ;;
|
|
25
|
+
'prompt.git|main:false') DF_ACTION=include ;;
|
|
26
|
+
'prompt.grant|false:fits:false') DF_ACTION=whole ;;
|
|
27
|
+
'prompt.grant|false:fits:true') DF_ACTION=whole ;;
|
|
28
|
+
'prompt.grant|false:over:false') DF_ACTION=pointer ;;
|
|
29
|
+
'prompt.nudge|main:nudge') DF_ACTION=include ;;
|
|
30
|
+
'prompt.slot|false') DF_ACTION=claim ;;
|
|
31
|
+
'prompt.summary|main:default-main:false:false:pending') DF_ACTION=truncate ;;
|
|
32
|
+
'prompt.summary|main:launched:false:false:pending') DF_ACTION=truncate ;;
|
|
33
|
+
'prompt.summary|worker:launched:false:false:pending') DF_ACTION=truncate ;;
|
|
34
|
+
'prompt.warning|main:false:false:true') DF_ACTION=include ;;
|
|
35
|
+
*) DF_ACTION=skip ;;
|
|
36
|
+
esac
|
|
37
|
+
}
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
# emission.jq — one-pass renderer of the prompt segments and the hook response (078 IC-002, IC-004
|
|
2
|
+
# step 7). renderEmission() in src/runtime/context/arbitrate.ts is the reference; both must give
|
|
3
|
+
# expected.text, bytes, refused and dropped of test/fixtures/emission/render-corpus.json byte for
|
|
4
|
+
# byte (IC-022, RK7).
|
|
5
|
+
#
|
|
6
|
+
# Invocation (IC-004 step 7), one process:
|
|
7
|
+
# jq -n -r -f emission.jq --argjson plan "$PLAN" \
|
|
8
|
+
# --rawfile git <git-context.json> --rawfile summary <claimed summary> \
|
|
9
|
+
# --rawfile grant <claimed grant> --arg warning "$WARNING" --arg nudge "$NUDGE"
|
|
10
|
+
#
|
|
11
|
+
# All four names are always bound (jq refuses an undefined $name); emission.sh binds $warning with
|
|
12
|
+
# --arg, because the warning claim renames the file and reads it before the render. A file that does not
|
|
13
|
+
# exist is passed as /dev/null and its name listed in plan.absent; an empty existing file is not
|
|
14
|
+
# absent (an empty warning still renders, an empty git capture is "Not a git repository.").
|
|
15
|
+
#
|
|
16
|
+
# plan:
|
|
17
|
+
# actions IC-001 actions by segment; only git, summary, warning, grant and nudge render here
|
|
18
|
+
# maxBytes positive integer, the IC-002 byte budget
|
|
19
|
+
# harness the harness name (DOFLOW_AGENT); sessionTitle is added on every harness but
|
|
20
|
+
# "codex", whose envelope rejects unknown fields (DEC-030)
|
|
21
|
+
# title true when a title may be set (the payload carries no session_title)
|
|
22
|
+
# absent names among git, summary, grant, warning whose file does not exist (default [])
|
|
23
|
+
# summaryBytes the claimed summary file's full size, which can exceed the bounded read; it
|
|
24
|
+
# defaults to the UTF-8 size of $summary
|
|
25
|
+
# mode "response" (default) prints the hook response; "render" prints
|
|
26
|
+
# {text, bytes, refused, dropped, segments}, the renderEmission() result, for parity;
|
|
27
|
+
# "hook" (emission.sh, run with -r) prints one first line holding the dropped
|
|
28
|
+
# segment names joined with tabs (possibly empty), a second line holding the
|
|
29
|
+
# response digest (empty unless plan.digest), then the hook response
|
|
30
|
+
# digest hook mode: true computes response_digest (rider R1, 091); other modes ignore it
|
|
31
|
+
#
|
|
32
|
+
# Response bytes (jq's default pretty print): emission is
|
|
33
|
+
# {"hookSpecificOutput": {"hookEventName": "UserPromptSubmit", "additionalContext": ...}}
|
|
34
|
+
# with sessionTitle on every harness but Codex (DEC-030), when plan.title holds and the git action built a title
|
|
35
|
+
# ("{branch?unknown} — {sha?unknown}", or "no-git" outside a repository; none when the capture
|
|
36
|
+
# file is missing). Nothing rendered prints {} and a newline. Any error exits non-zero and the
|
|
37
|
+
# caller answers with the silent response.
|
|
38
|
+
#
|
|
39
|
+
# Counting (design R1): characters are code points (jq string length and slices), budgets are
|
|
40
|
+
# UTF-8 bytes (utf8bytelength). Portability: jq 1.6+ built with Oniguruma; utf8bytelength is the
|
|
41
|
+
# one builtin newer than 1.5. No index/rindex on strings (byte offsets in 1.6) and no 1.7-only
|
|
42
|
+
# builtin (trim, ltrim, rtrim, abs, pick, toarray, have_decnum). Every regex is anchored
|
|
43
|
+
# with \A or \z, never ^ or $, which Oniguruma reads per line.
|
|
44
|
+
|
|
45
|
+
def summary_cap: 4000;
|
|
46
|
+
def summary_read: 65536;
|
|
47
|
+
|
|
48
|
+
# Trailing newlines removed, as $(...) does.
|
|
49
|
+
def rstrip_nl: sub("\n+\\z"; "");
|
|
50
|
+
def no_cr: split("\r") | join("");
|
|
51
|
+
|
|
52
|
+
# `jq -r '<field> // empty'` in a $(...): null and false are empty, other scalars print as JSON.
|
|
53
|
+
def jq_field:
|
|
54
|
+
if . == null or . == false then ""
|
|
55
|
+
elif type == "string" then rstrip_nl
|
|
56
|
+
else tojson | rstrip_nl
|
|
57
|
+
end;
|
|
58
|
+
|
|
59
|
+
# A summary or grant record: \r removed, trailing newlines dropped, frontmatter keys from the lines
|
|
60
|
+
# between the first two `---` lines (first match wins, spaces after `key:` stripped), body from the
|
|
61
|
+
# first non-empty line after the second `---`, trailing newlines dropped. Fewer than two `---`
|
|
62
|
+
# lines give an empty body.
|
|
63
|
+
def parse_record:
|
|
64
|
+
(no_cr | rstrip_nl | split("\n"))
|
|
65
|
+
| reduce .[] as $line ({fences: 0, started: false, fields: {}, body: []};
|
|
66
|
+
if .fences < 2 and $line == "---" then .fences += 1
|
|
67
|
+
elif .fences == 1 then
|
|
68
|
+
($line | split(":")) as $parts
|
|
69
|
+
| if ($parts | length) > 1 and ($parts[0] | length) > 0 and (.fields | has($parts[0]) | not)
|
|
70
|
+
then .fields[$parts[0]] = ($parts[1:] | join(":") | sub("\\A +"; ""))
|
|
71
|
+
else . end
|
|
72
|
+
elif .fences >= 2 and (.started or $line != "") then .started = true | .body += [$line]
|
|
73
|
+
else . end)
|
|
74
|
+
| {fields: .fields, body: (.body | join("\n") | rstrip_nl)};
|
|
75
|
+
|
|
76
|
+
# A bracketed header value: `]` removed, then empty when it is "unknown".
|
|
77
|
+
def known: (. // "") | split("]") | join("") | if . == "unknown" then "" else . end;
|
|
78
|
+
|
|
79
|
+
def header_tail:
|
|
80
|
+
(.compacted_at | known) as $at | (.branch | known) as $branch
|
|
81
|
+
| (if $at != "" then ", compacted \($at)" else "" end)
|
|
82
|
+
+ (if $branch != "" then " on branch \($branch)" else "" end);
|
|
83
|
+
|
|
84
|
+
# The git capture as an object; anything unparseable or not an object reads as {}.
|
|
85
|
+
def capture($raw):
|
|
86
|
+
(try ($raw | fromjson) catch null) | if type == "object" then . else {} end;
|
|
87
|
+
|
|
88
|
+
def is_repo: (.is_git_repo | jq_field) == "true";
|
|
89
|
+
|
|
90
|
+
def render_git($raw; $missing):
|
|
91
|
+
if $missing then "Git context unavailable for this session."
|
|
92
|
+
else capture($raw)
|
|
93
|
+
| if is_repo | not then "Not a git repository."
|
|
94
|
+
else
|
|
95
|
+
((if (.commits | type) == "array" then .commits else [] end)
|
|
96
|
+
| map(jq_field) | map(select(. != "")) | .[0:5] | join(" · ")) as $commits
|
|
97
|
+
| (.stash_count | jq_field) as $stash
|
|
98
|
+
| "Git context — branch: \(.branch | jq_field | if . == "" then "unknown" else . end) | \(.sha | jq_field | if . == "" then "unknown" else . end)\n"
|
|
99
|
+
+ "Last commits: \(if $commits == "" then "none" else $commits end)\n"
|
|
100
|
+
+ "Uncommitted files: \(.uncommitted_count | jq_field | if . == "" then "0" else . end)"
|
|
101
|
+
+ (if ($stash | test("\\A[0-9]+\\z")) and ($stash | tonumber) > 0 then " | Stashed: \($stash)" else "" end)
|
|
102
|
+
end
|
|
103
|
+
end;
|
|
104
|
+
|
|
105
|
+
def git_title($raw; $missing):
|
|
106
|
+
if $missing then null
|
|
107
|
+
else capture($raw)
|
|
108
|
+
| if is_repo then
|
|
109
|
+
"\(.branch | jq_field | if . == "" then "unknown" else . end) — \(.sha | jq_field | if . == "" then "unknown" else . end)"
|
|
110
|
+
else "no-git" end
|
|
111
|
+
end;
|
|
112
|
+
|
|
113
|
+
# null when the body is empty: an empty summary renders nothing.
|
|
114
|
+
def render_summary($size):
|
|
115
|
+
parse_record
|
|
116
|
+
| if .body == "" then null
|
|
117
|
+
else (.body | length) as $n
|
|
118
|
+
| (if $n > summary_cap
|
|
119
|
+
then .body[0:summary_cap] + "\n[summary truncated: first \(summary_cap) of \(if $size > summary_read then "at least " else "" end)\($n) characters]"
|
|
120
|
+
else .body end) as $shown
|
|
121
|
+
| "\n\n[Prior session summary\(.fields | header_tail)]\n\($shown)"
|
|
122
|
+
end;
|
|
123
|
+
|
|
124
|
+
def render_grant: "[Granted summary from lineage \(.fields.from_lineage // "")\(.fields | header_tail)]\n\(.body)";
|
|
125
|
+
|
|
126
|
+
def render_pointer($max): "[Granted summary \(.fields.summary_id // "") withheld: \(.body | utf8bytelength) bytes exceed the \($max)-byte context budget]";
|
|
127
|
+
|
|
128
|
+
def join_order: ["git", "summary", "warning", "grant", "nudge"];
|
|
129
|
+
|
|
130
|
+
# IC-002 join: summary drops its leading blank line when nothing precedes it; grant and nudge gain
|
|
131
|
+
# one when something does.
|
|
132
|
+
def join_segments:
|
|
133
|
+
. as $p
|
|
134
|
+
| reduce (join_order[] | select($p[.] != null)) as $s ("";
|
|
135
|
+
if $s == "summary" then (if . == "" then . + ($p[$s] | .[2:]) else . + $p[$s] end)
|
|
136
|
+
elif $s == "grant" or $s == "nudge" then (if . == "" then "" else . + "\n\n" end) + $p[$s]
|
|
137
|
+
else . + $p[$s] end);
|
|
138
|
+
|
|
139
|
+
def render($plan; $in):
|
|
140
|
+
($plan.actions // {}) as $a
|
|
141
|
+
| $plan.maxBytes as $max
|
|
142
|
+
| if ($max | type) != "number" or $max <= 0 or ($max | floor) != $max then error("plan.maxBytes must be a positive integer") else . end
|
|
143
|
+
| ($plan.absent // []) as $absent
|
|
144
|
+
| def present($k): ($absent | map(select(. == $k)) | length) == 0;
|
|
145
|
+
({}
|
|
146
|
+
| if $a.git == "include" then .git = render_git($in.git; present("git") | not) else . end
|
|
147
|
+
| if $a.summary == "truncate" and present("summary")
|
|
148
|
+
then ($in.summary | render_summary($plan.summaryBytes // ($in.summary | utf8bytelength))) as $s
|
|
149
|
+
| if $s != null then .summary = $s else . end
|
|
150
|
+
else . end
|
|
151
|
+
| if $a.warning == "include" and present("warning") then .warning = "\n[Prior session warning: \($in.warning | rstrip_nl)]" else . end
|
|
152
|
+
| if $a.nudge == "include" and ($in.nudge | type) == "string" and $in.nudge != "" then .nudge = $in.nudge else . end
|
|
153
|
+
) as $optional
|
|
154
|
+
| (if ($a.grant == "whole" or $a.grant == "pointer") and present("grant")
|
|
155
|
+
then ($in.grant | parse_record) as $r
|
|
156
|
+
| ($r | render_grant) as $whole
|
|
157
|
+
| if $a.grant == "whole" and ($whole | utf8bytelength) <= $max
|
|
158
|
+
then {selected: {grant: $whole}, refused: false}
|
|
159
|
+
else {selected: {grant: ($r | render_pointer($max))}, refused: true} end
|
|
160
|
+
else {selected: {}, refused: false} end)
|
|
161
|
+
| . + {dropped: []}
|
|
162
|
+
| reduce ("git", "summary", "warning", "nudge") as $s (.;
|
|
163
|
+
if $optional[$s] == null then .
|
|
164
|
+
elif (.selected + {($s): $optional[$s]} | join_segments | utf8bytelength) <= $max then .selected[$s] = $optional[$s]
|
|
165
|
+
else .dropped += [$s] end)
|
|
166
|
+
| (.selected | join_segments) as $text
|
|
167
|
+
| {
|
|
168
|
+
text: (if $text == "" then null else $text end),
|
|
169
|
+
bytes: ($text | utf8bytelength),
|
|
170
|
+
refused: .refused,
|
|
171
|
+
dropped: .dropped,
|
|
172
|
+
segments: [join_order[] as $s | select(.selected[$s] != null) | $s]
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
def response($plan; $in; $result):
|
|
176
|
+
if $result.text == null then {}
|
|
177
|
+
else
|
|
178
|
+
(if $plan.harness != "codex" and $plan.title == true and ($plan.actions // {}).git == "include"
|
|
179
|
+
then git_title($in.git; ($plan.absent // []) | map(select(. == "git")) | length > 0) else null end) as $title
|
|
180
|
+
| {"hookSpecificOutput": ({"hookEventName": "UserPromptSubmit", "additionalContext": $result.text}
|
|
181
|
+
+ (if $title != null and $title != "" then {"sessionTitle": $title} else {} end))}
|
|
182
|
+
end;
|
|
183
|
+
|
|
184
|
+
# Rider R1 (091): the response exactly as jq's default pretty print writes it (indent 2, insertion
|
|
185
|
+
# order, the same string escaping as tojson), without the trailing newline. The response shape is
|
|
186
|
+
# fixed: {} or one hookSpecificOutput object of string values.
|
|
187
|
+
def pretty_response:
|
|
188
|
+
if . == {} then "{}"
|
|
189
|
+
else "{\n \"hookSpecificOutput\": {\n"
|
|
190
|
+
+ ([.hookSpecificOutput | to_entries[] | " \(.key | tojson): \(.value | tojson)"] | join(",\n"))
|
|
191
|
+
+ "\n }\n}"
|
|
192
|
+
end;
|
|
193
|
+
|
|
194
|
+
# 8 lowercase hex of h = (h*31 + c) mod 2^32 over the code points of the pretty response. Every step
|
|
195
|
+
# stays below 2^38, exact in doubles; mod and the nibbles use floor, not %, which casts to int on old jq.
|
|
196
|
+
def response_digest:
|
|
197
|
+
(pretty_response | explode | reduce .[] as $c (0; (. * 31 + $c) | . - ((. / 4294967296) | floor) * 4294967296)) as $h
|
|
198
|
+
| [268435456, 16777216, 1048576, 65536, 4096, 256, 16, 1]
|
|
199
|
+
| map(($h / . | floor) - (($h / . / 16) | floor) * 16)
|
|
200
|
+
| map("0123456789abcdef"[.:. + 1]) | join("");
|
|
201
|
+
|
|
202
|
+
{git: $git, summary: $summary, grant: $grant, warning: $warning, nudge: $nudge} as $in
|
|
203
|
+
| render($plan; $in) as $result
|
|
204
|
+
| ($plan.mode // "response") as $mode
|
|
205
|
+
| if $mode == "render" then $result
|
|
206
|
+
elif $mode == "hook" then
|
|
207
|
+
response($plan; $in; $result) as $response
|
|
208
|
+
| ($result.dropped | join("\t")), (if $plan.digest == true then $response | response_digest else "" end), $response
|
|
209
|
+
else response($plan; $in; $result) end
|