@khoavu882/doflow 2.0.0-beta.4 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -11
- package/bin/doflow.js +21 -11
- package/core/.antigravity-plugin/plugin.json +1 -3
- package/core/.claude-plugin/plugin.json +1 -1
- package/core/.codex-plugin/plugin.json +1 -1
- package/core/.plugin/plugin.json +1 -1
- package/core/harnesses/claude/hooks/lib.sh +43 -24
- package/core/harnesses/claude/hooks/mcp-tool-guard.sh +7 -17
- package/core/harnesses/claude/hooks/permission-audit.sh +3 -0
- package/core/harnesses/claude/hooks/post-compact.sh +35 -32
- package/core/harnesses/claude/hooks/post-edit-lint.sh +2 -0
- package/core/harnesses/claude/hooks/post-shell-observe.sh +48 -0
- package/core/harnesses/claude/hooks/post-tool-failure.sh +3 -0
- package/core/harnesses/claude/hooks/pre-bash-guard.sh +7 -17
- package/core/harnesses/claude/hooks/pre-compact.sh +23 -27
- package/core/harnesses/claude/hooks/pre-implement-gate.sh +7 -18
- package/core/harnesses/claude/hooks/session-end.sh +23 -10
- package/core/harnesses/claude/hooks/session-start.sh +5 -3
- package/core/harnesses/claude/hooks/skill-config-audit.sh +3 -0
- package/core/harnesses/claude/hooks/stop-check.sh +5 -3
- package/core/harnesses/claude/hooks/subagent-audit.sh +5 -5
- package/core/harnesses/claude/hooks/user-prompt-submit.sh +5 -3
- package/core/harnesses/claude/settings/settings.json +18 -0
- package/core/harnesses/claude/statusline/doflow-statusline.sh +1 -0
- package/core/harnesses/codex/agents/core-implementer.toml +1 -0
- package/core/harnesses/codex/agents/delivery-lead.toml +10 -0
- package/core/harnesses/codex/agents/quality-guardian.toml +1 -1
- package/core/harnesses/codex/agents/research-writer.toml +1 -1
- package/core/harnesses/codex/agents/reviewer.toml +10 -0
- package/core/harnesses/codex/agents/spec-analyst.toml +1 -1
- package/core/harnesses/codex/agents/system-architect.toml +1 -1
- package/core/harnesses/codex/hooks/lib.sh +44 -25
- package/core/harnesses/codex/hooks/mcp-tool-guard.sh +7 -15
- package/core/harnesses/codex/hooks/post-edit-lint.impl.sh +3 -1
- package/core/harnesses/codex/hooks/pre-bash-guard.sh +7 -15
- package/core/harnesses/codex/hooks/pre-compact.impl.sh +29 -26
- package/core/harnesses/codex/hooks/pre-implement-gate.sh +7 -16
- package/core/harnesses/codex/hooks/session-end.impl.sh +23 -10
- package/core/harnesses/codex/hooks/session-start.sh +5 -3
- package/core/harnesses/codex/hooks/stop-check.sh +6 -5
- package/core/harnesses/codex/hooks/subagent-audit.sh +18 -6
- package/core/harnesses/codex/hooks/user-prompt-submit.sh +5 -4
- package/core/harnesses/copilot/hooks/doflow-lib.sh +93 -0
- package/core/harnesses/copilot/hooks/doflow-mcp-tool-guard.sh +9 -0
- package/core/harnesses/copilot/hooks/doflow-pre-bash-guard.sh +9 -0
- package/core/harnesses/copilot/hooks/doflow-pre-implement-gate.sh +9 -0
- package/core/harnesses/copilot/hooks/doflow-session-start.sh +9 -0
- package/core/harnesses/copilot/hooks/doflow-stop-check.sh +9 -0
- package/core/harnesses/copilot/hooks/doflow-subagent-start.sh +9 -0
- package/core/harnesses/copilot/hooks/doflow-subagent-stop.sh +9 -0
- package/core/harnesses/copilot/hooks/doflow.json +57 -0
- package/core/harnesses/kiro/agents/doflow.json +1 -1
- package/core/harnesses/kiro/hooks/lib.sh +26 -6
- package/core/harnesses/kiro/hooks/mcp-tool-guard.sh +21 -5
- package/core/harnesses/kiro/hooks/pre-bash-guard.sh +21 -5
- package/core/harnesses/kiro/hooks/pre-implement-gate.sh +21 -5
- package/core/harnesses/kiro/hooks/session-start.sh +12 -5
- package/core/harnesses/kiro/hooks/stop-check.sh +22 -30
- package/core/harnesses/pi/extensions/doflow-guard.js +167 -0
- package/core/harnesses/shared/hooks/ENVELOPE_MIGRATION.md +27 -12
- package/core/harnesses/shared/hooks/adapters/antigravity.js +14 -57
- package/core/harnesses/shared/hooks/bridge/bridge.sh +277 -0
- package/core/harnesses/shared/hooks/bridge/envelope.jq +129 -0
- package/core/harnesses/shared/hooks/bridge/observe-model.sh +75 -0
- package/core/harnesses/shared/hooks/bridge/respond.sh +70 -0
- package/core/harnesses/shared/hooks/policies/blocked-patterns.conf +28 -14
- package/core/harnesses/shared/hooks/policies/capture-failure.sh +51 -16
- package/core/harnesses/shared/hooks/policies/compact-text.sh +46 -0
- package/core/harnesses/shared/hooks/policies/contract.sh +78 -0
- package/core/harnesses/shared/hooks/policies/deny-json.sh +35 -9
- package/core/harnesses/shared/hooks/policies/emission-rules.sh +37 -0
- package/core/harnesses/shared/hooks/policies/emission.jq +209 -0
- package/core/harnesses/shared/hooks/policies/emission.sh +383 -0
- package/core/harnesses/shared/hooks/policies/identity.sh +177 -0
- package/core/harnesses/shared/hooks/policies/lib.sh +65 -40
- package/core/harnesses/shared/hooks/policies/mcp-tool-guard.sh +48 -35
- package/core/harnesses/shared/hooks/policies/pre-bash-guard.sh +284 -33
- package/core/harnesses/shared/hooks/policies/pre-implementation-gate.sh +180 -110
- package/core/harnesses/shared/hooks/policies/session-context.sh +66 -7
- package/core/harnesses/shared/hooks/policies/stop-check.sh +61 -23
- package/core/harnesses/shared/hooks/policies/subagent-audit.sh +39 -6
- package/core/harnesses/shared/hooks/policies/summary-store.sh +347 -0
- package/core/harnesses/shared/hooks/policies/user-prompt-submit.sh +97 -159
- package/core/harnesses/shared/hooks/stream-hook-runner.js +114 -187
- package/core/harnesses/shared/locator/doflow-run +2 -3
- package/core/registry/advice.json +3 -3
- package/core/registry/assets.json +72 -80
- package/core/registry/capabilities.json +12 -0
- package/core/registry/contracts.json +60 -33
- package/core/registry/contribution-points.json +32 -0
- package/core/registry/gates.json +32 -0
- package/core/registry/guidance-caps.json +40 -0
- package/core/registry/harnesses.json +1542 -277
- package/core/registry/lifecycle.json +2837 -37
- package/core/registry/mcp.json +5 -1
- package/core/registry/models.json +7 -1
- package/core/registry/package-templates/README.md +19 -0
- package/core/registry/package-templates/agent/files/agent.md +9 -0
- package/core/registry/package-templates/agent/template.json +4 -0
- package/core/registry/package-templates/capability-provider/files/provider.json +9 -0
- package/core/registry/package-templates/capability-provider/template.json +11 -0
- package/core/registry/package-templates/debate-preset/files/preset.json +26 -0
- package/core/registry/package-templates/debate-preset/template.json +4 -0
- package/core/registry/package-templates/review-preset/files/preset.json +30 -0
- package/core/registry/package-templates/review-preset/template.json +4 -0
- package/core/registry/package-templates/skill/files/SKILL.md +8 -0
- package/core/registry/package-templates/skill/template.json +4 -0
- package/core/registry/package-templates/worker/files/worker.json +92 -0
- package/core/registry/package-templates/worker/template.json +11 -0
- package/core/registry/packages/doflow/doflow-package.json +15 -0
- package/core/registry/packages/doflow/presets/debate-3.json +26 -0
- package/core/registry/protocols.json +61 -0
- package/core/registry/routes.json +17 -0
- package/core/registry/rules.json +431 -0
- package/core/registry/settings.json +276 -0
- package/core/registry/storage.json +701 -30
- package/core/registry/telemetry.json +236 -0
- package/core/registry/transcripts.json +142 -0
- package/core/registry/verification.json +76 -1
- package/core/registry/workflows.json +55 -0
- package/core/shared/agent-specs/core-implementer.md +3 -0
- package/core/shared/agent-specs/delivery-lead.md +68 -0
- package/core/shared/agent-specs/quality-guardian.md +5 -1
- package/core/shared/agent-specs/research-writer.md +10 -3
- package/core/shared/agent-specs/reviewer.md +53 -0
- package/core/shared/agent-specs/spec-analyst.md +5 -6
- package/core/shared/agent-specs/system-architect.md +5 -1
- package/core/shared/guidance/DOFLOW_CORE.md +1 -5
- package/core/shared/guidance/modes/MODE_DeepResearch.md +1 -1
- package/core/shared/guidance/modes/MODE_Orchestration.md +4 -3
- package/core/shared/guidance/modes/MODE_Task_Management.md +14 -14
- package/core/shared/guidance/pointers/codex.md +1 -4
- package/core/shared/guidance/references/ARTIFACT_FORMAT.md +30 -16
- package/core/shared/guidance/references/ARTIFACT_VOICE.md +3 -2
- package/core/shared/guidance/references/CONSTITUTION_BASE.md +17 -15
- package/core/shared/guidance/references/DIAGRAM_GUIDE.md +1 -1
- package/core/shared/guidance/references/DOFLOW_CHAIN.md +17 -19
- package/core/shared/guidance/references/EVIDENCE_LEDGER.md +7 -8
- package/core/shared/guidance/references/MODEL_SELECTION.md +5 -3
- package/core/shared/guidance/references/ORCHESTRATION.md +1 -2
- package/core/shared/guidance/rules/RULES.md +45 -0
- package/core/shared/scripts/doflow/bash/do-args.sh +37 -0
- package/core/shared/scripts/doflow/bash/do-exec-paths.sh +4 -0
- package/core/shared/scripts/doflow/bash/do-git-state.sh +15 -4
- package/core/shared/scripts/doflow/bash/do-parallel-check.sh +4 -0
- package/core/shared/scripts/doflow/bash/do-paths.sh +40 -2
- package/core/shared/scripts/doflow/bash/do-prereqs.sh +2 -1
- package/core/shared/scripts/doflow/bash/do-review-package.sh +4 -0
- package/core/shared/scripts/doflow/bash/do-task-brief.sh +58 -16
- package/core/shared/scripts/doflow/bash/render-audit.sh +26 -2
- package/core/shared/scripts/doflow/bash/render-diagrams.sh +1 -0
- package/core/shared/scripts/doflow/bash/render-puml.sh +2 -1
- package/core/shared/scripts/doflow/bash/validate-artifacts.sh +48 -4
- package/core/shared/scripts/doflow/bin/doflow-run +154 -35
- package/core/shared/skills/do/SKILL.md +12 -10
- package/core/shared/skills/do/references/advice_calls.md +26 -0
- package/core/shared/skills/do/references/pm_routing.md +1 -2
- package/core/shared/skills/do/references/program_mode.md +31 -0
- package/core/shared/skills/do-brainstorm/SKILL.md +20 -74
- package/core/shared/skills/do-brainstorm/references/handoff_branches.md +35 -0
- package/core/shared/skills/do-brainstorm/references/intent_seed.md +21 -0
- package/core/shared/skills/do-brainstorm/references/round_log.md +17 -0
- package/core/shared/skills/do-code-review/SKILL.md +41 -144
- package/core/shared/skills/do-code-review/content-types/markdown.md +24 -2
- package/core/shared/skills/do-code-review/references/tools.md +90 -0
- package/core/shared/skills/do-code-review/scripts/doc_quality_checker.py +549 -7
- package/core/shared/skills/do-design/SKILL.md +24 -23
- package/core/shared/skills/do-diagnose/SKILL.md +14 -4
- package/core/shared/skills/do-document/SKILL.md +11 -1
- package/core/shared/skills/do-document/references/deep_research.md +1 -2
- package/core/shared/skills/do-document/references/embedded-research.md +18 -6
- package/core/shared/skills/do-document/references/implementation-flow.md +5 -6
- package/core/shared/skills/do-execute-plan/SKILL.md +17 -59
- package/core/shared/skills/do-execute-plan/references/handoff_record.md +7 -2
- package/core/shared/skills/do-execute-plan/references/parallel_dispatch.md +13 -0
- package/core/shared/skills/do-execute-plan/references/readiness_gate.md +28 -1
- package/core/shared/skills/do-execute-plan/references/run_position.md +13 -1
- package/core/shared/skills/do-execute-plan/references/scaffold.md +17 -9
- package/core/shared/skills/do-execute-plan/references/state_checkpoint.md +11 -0
- package/core/shared/skills/do-execute-plan/references/task_attempts.md +78 -24
- package/core/shared/skills/do-flow/SKILL.md +8 -9
- package/core/shared/skills/do-flow/references/task_classes.md +2 -2
- package/core/shared/skills/do-git/SKILL.md +4 -0
- package/core/shared/skills/do-implement/SKILL.md +7 -9
- package/core/shared/skills/do-plan/SKILL.md +29 -19
- package/core/shared/skills/do-test/SKILL.md +7 -4
- package/core/shared/templates/doflow/constitution-template.md +9 -3
- package/core/shared/templates/doflow/data-model-template.md +1 -1
- package/core/shared/templates/doflow/design-template.md +113 -16
- package/core/shared/templates/doflow/plan-template.md +11 -10
- package/core/shared/templates/doflow/question-log-template.md +14 -2
- package/core/shared/templates/doflow/requirement-template.md +1 -1
- package/core/worker-evidence/antigravity/checks.json +14 -0
- package/core/worker-evidence/codex/2026-10-18-cli-check.json +107 -0
- package/core/worker-evidence/codex/2026-10-18-live-run-edit.json +73 -0
- package/core/worker-evidence/codex/2026-10-18-live-run-read-only.json +62 -0
- package/core/worker-evidence/codex/2026-10-24-cli-check.json +126 -0
- package/core/worker-evidence/codex/checks.json +38 -0
- package/package.json +10 -6
- package/src/adapters/antigravity/index.js +226 -113
- package/src/adapters/claude/index.js +39 -5
- package/src/adapters/codex/agents.js +25 -15
- package/src/adapters/codex/hooks.js +40 -5
- package/src/adapters/codex/index.js +100 -22
- package/src/adapters/codex/native-projection.js +6 -2
- package/src/adapters/copilot/index.js +58 -23
- package/src/adapters/copy-tree.js +294 -48
- package/src/adapters/guidance-manifest.js +71 -0
- package/src/adapters/guidance-pointer.js +19 -0
- package/src/adapters/hook-commands.js +6 -10
- package/src/adapters/index.js +1 -0
- package/src/adapters/kiro/index.js +38 -13
- package/src/adapters/opencode/index.js +8 -8
- package/src/adapters/pi/hooks.js +120 -0
- package/src/adapters/pi/index.js +48 -16
- package/src/adapters/resolve-source.js +26 -2
- package/src/cli/commands/install.js +3 -2
- package/src/cli/commands/reconcile.js +53 -9
- package/src/cli/commands/remove.js +2 -2
- package/src/cli/commands/rollback.js +6 -3
- package/src/cli/commands/self-update.js +18 -9
- package/src/cli/commands/status.js +21 -2
- package/src/cli/commands/ui.js +99 -0
- package/src/cli/commands/update.js +3 -2
- package/src/cli/index.js +338 -33
- package/src/cli/runtime-commands.js +243 -52
- package/src/cli/shared.js +0 -2
- package/src/helper/git.js +1 -1
- package/src/helper/guardrails.js +1 -1
- package/src/helper/marker-merge.js +31 -13
- package/src/helper/package-ids.js +37 -0
- package/src/helper/semver.js +94 -0
- package/src/install/backup.js +105 -15
- package/src/install/context.js +1 -1
- package/src/install/targets.js +31 -16
- package/src/lifecycle/coverage.js +74 -0
- package/src/lifecycle/hook-step.js +61 -0
- package/src/lifecycle/hook-tier.js +160 -0
- package/src/lifecycle/index.js +434 -86
- package/src/lifecycle/retired-harnesses.js +318 -0
- package/src/lifecycle/view.js +35 -15
- package/src/registry/index.js +686 -32
- package/src/registry/worker-ids.js +45 -0
- package/src/release/build-package.js +0 -3
- package/src/release/docs-blocks.js +492 -0
- package/src/release/preflight.js +425 -0
- package/src/release/rehearse.js +401 -0
- package/src/release/release-workflow.js +733 -0
- package/src/release/sync-plugin-versions.js +43 -7
- package/src/runtime/advice/bench-gate.js +25 -0
- package/src/runtime/advice/cli.js +59 -16
- package/src/runtime/advice/client.js +32 -9
- package/src/runtime/advice/config.js +98 -133
- package/src/runtime/advice/doctor.js +1 -1
- package/src/runtime/advice/elevation.js +97 -0
- package/src/runtime/advice/endpoint-guard.js +9 -3
- package/src/runtime/advice/mode.js +37 -0
- package/src/runtime/advice/record.js +18 -5
- package/src/runtime/advice/registry.js +4 -1
- package/src/runtime/advice/shadow-config.js +229 -0
- package/src/runtime/advice/shadow-dispatcher.js +276 -0
- package/src/runtime/brief-rules.js +81 -0
- package/src/runtime/brief-tools.js +111 -34
- package/src/runtime/candidate.js +514 -0
- package/src/runtime/capabilities/executor.js +450 -0
- package/src/runtime/capabilities/loopback.js +41 -0
- package/src/runtime/capabilities/sanitizer.js +88 -0
- package/src/runtime/capability-router.js +135 -3
- package/src/runtime/checkouts.js +73 -11
- package/src/runtime/claims.js +27 -12
- package/src/runtime/cli-result.js +11 -4
- package/src/runtime/cli.js +221 -277
- package/src/runtime/config-home.js +42 -0
- package/src/runtime/context/arbitrate.js +767 -0
- package/src/runtime/context/budget.js +203 -0
- package/src/runtime/context/compose.js +1367 -0
- package/src/runtime/context/delivery-store.js +100 -0
- package/src/runtime/context/emission-rules.js +118 -0
- package/src/runtime/context/identity.js +227 -0
- package/src/runtime/context/mandatory.js +594 -0
- package/src/runtime/context/pointer.js +142 -0
- package/src/runtime/context/primary-command.js +117 -0
- package/src/runtime/context/primary.js +344 -0
- package/src/runtime/context/summary-store.js +655 -0
- package/src/runtime/context-pack.js +1106 -245
- package/src/runtime/decision-register.js +13 -4
- package/src/runtime/dispatch/admission.js +392 -0
- package/src/runtime/dispatch/attempt-end.js +274 -0
- package/src/runtime/dispatch/command.js +628 -0
- package/src/runtime/dispatch/controls.js +904 -0
- package/src/runtime/dispatch/envelope.js +276 -0
- package/src/runtime/dispatch/grants.js +310 -0
- package/src/runtime/dispatch/integrate.js +617 -0
- package/src/runtime/dispatch/loop.js +1835 -0
- package/src/runtime/dispatch/store.js +352 -0
- package/src/runtime/dispatch/verify-run.js +201 -0
- package/src/runtime/evidence-fields.js +39 -0
- package/src/runtime/evidence-ledger.js +41 -7
- package/src/runtime/failure/capture.js +3 -1
- package/src/runtime/failure/cli.js +25 -9
- package/src/runtime/failure/home.js +57 -30
- package/src/runtime/failure/store.js +7 -2
- package/src/runtime/feature-pointer.js +174 -0
- package/src/runtime/feature-resolve.js +13 -2
- package/src/runtime/fleet/command.js +77 -0
- package/src/runtime/fleet/projects.js +178 -0
- package/src/runtime/fleet/tree.js +383 -0
- package/src/runtime/freshness.js +77 -10
- package/src/runtime/git-memo.js +46 -0
- package/src/runtime/guidance/ablation.js +427 -0
- package/src/runtime/health.js +565 -17
- package/src/runtime/history-compactor.js +13 -3
- package/src/runtime/implementation-gate.js +277 -22
- package/src/runtime/inventory/coverage.js +1 -1
- package/src/runtime/inventory/index.js +1 -1
- package/src/runtime/inventory/precedence.js +2 -2
- package/src/runtime/inventory/siblings.js +6 -4
- package/src/runtime/knowledge/code-corpus.js +277 -0
- package/src/runtime/knowledge/code-lexical.js +130 -0
- package/src/runtime/knowledge/code-retrieval.js +307 -0
- package/src/runtime/knowledge/code-validation.js +106 -0
- package/src/runtime/knowledge/gp3-gate.js +74 -0
- package/src/runtime/knowledge/graph-adapter.js +288 -0
- package/src/runtime/knowledge/graph-fallback.js +394 -0
- package/src/runtime/knowledge/hybrid.js +136 -8
- package/src/runtime/knowledge/retrieval.js +34 -1
- package/src/runtime/knowledge/rtk-compress.js +77 -0
- package/src/runtime/knowledge/semble-bridge.py +106 -0
- package/src/runtime/knowledge/semble-lifecycle.js +114 -0
- package/src/runtime/knowledge/semble-provider.js +365 -0
- package/src/runtime/lifecycle/cli.js +16 -6
- package/src/runtime/lifecycle/event-store.js +8 -6
- package/src/runtime/lifecycle/followup.js +6 -1
- package/src/runtime/lifecycle/overview.js +24 -1
- package/src/runtime/lifecycle/report-store.js +8 -10
- package/src/runtime/lifecycle/retention.js +95 -31
- package/src/runtime/lifecycle/root.js +9 -1
- package/src/runtime/lifecycle/status.js +34 -17
- package/src/runtime/lifecycle/store-upkeep.js +56 -7
- package/src/runtime/mask.js +134 -7
- package/src/runtime/mcp-consultations.js +40 -6
- package/src/runtime/model-router.js +79 -7
- package/src/runtime/models/catalogue.js +191 -0
- package/src/runtime/models/command.js +153 -0
- package/src/runtime/off-words.js +12 -0
- package/src/runtime/outcome.js +3 -3
- package/src/runtime/packages/command.js +1009 -0
- package/src/runtime/packages/contributions.js +116 -0
- package/src/runtime/packages/digest.js +132 -0
- package/src/runtime/packages/fetch.js +182 -0
- package/src/runtime/packages/grants.js +192 -0
- package/src/runtime/packages/index-file.js +134 -0
- package/src/runtime/packages/instruction.js +90 -0
- package/src/runtime/packages/manifest.js +331 -0
- package/src/runtime/packages/points.js +477 -0
- package/src/runtime/packages/programs.js +216 -0
- package/src/runtime/packages/scaffold.js +277 -0
- package/src/runtime/packages/source.js +90 -0
- package/src/runtime/packages/state.js +164 -0
- package/src/runtime/packages/store.js +449 -0
- package/src/runtime/packages/tar.js +106 -0
- package/src/runtime/packages/view.js +406 -0
- package/src/runtime/plan-check.js +59 -0
- package/src/runtime/plan-content.js +324 -0
- package/src/runtime/policy-init.js +118 -0
- package/src/runtime/profiles/doctor.js +96 -0
- package/src/runtime/profiles/resolve.js +244 -0
- package/src/runtime/profiles/rollback.js +254 -0
- package/src/runtime/profiles/sampler.js +41 -0
- package/src/runtime/readiness-record.js +16 -11
- package/src/runtime/readiness.js +127 -16
- package/src/runtime/research-request.js +50 -25
- package/src/runtime/retrieval-plan.js +402 -73
- package/src/runtime/retrieval-record.js +293 -0
- package/src/runtime/review/command.js +246 -0
- package/src/runtime/review/dominance.js +68 -0
- package/src/runtime/review/findings.js +434 -0
- package/src/runtime/review/identity.js +255 -0
- package/src/runtime/review/protocol-command.js +109 -0
- package/src/runtime/review/protocols.js +405 -0
- package/src/runtime/review/resolve-protocol.js +302 -0
- package/src/runtime/review/start.js +530 -0
- package/src/runtime/roadmap/facts.js +479 -0
- package/src/runtime/roadmap/gates.js +270 -0
- package/src/runtime/roadmap/loop.js +1636 -0
- package/src/runtime/roadmap/merge.js +381 -0
- package/src/runtime/roadmap/rows.js +1113 -0
- package/src/runtime/roadmap/seed.js +951 -0
- package/src/runtime/rules-report.js +336 -0
- package/src/runtime/scaffold/artifacts.js +63 -9
- package/src/runtime/scaffold/generate.js +21 -9
- package/src/runtime/settings/autopilot.js +106 -0
- package/src/runtime/settings/cli.js +280 -0
- package/src/runtime/settings/config-write.js +314 -0
- package/src/runtime/settings/files.js +271 -0
- package/src/runtime/settings/legacy.js +154 -0
- package/src/runtime/settings/lexical.js +56 -0
- package/src/runtime/settings/prepared-run.js +269 -0
- package/src/runtime/settings/project-layers.js +118 -0
- package/src/runtime/settings/refs.js +288 -0
- package/src/runtime/settings/registry.js +553 -0
- package/src/runtime/settings/resolve.js +713 -0
- package/src/runtime/settings/shared.js +37 -0
- package/src/runtime/settings/worker-billing.js +107 -0
- package/src/runtime/settings/write.js +269 -0
- package/src/runtime/slot-command.js +78 -0
- package/src/runtime/slots.js +671 -0
- package/src/runtime/source-version.js +290 -0
- package/src/runtime/state-root.js +217 -0
- package/src/runtime/storage/cli.js +12 -5
- package/src/runtime/storage/engine.js +9 -2
- package/src/runtime/storage/registry.js +14 -1
- package/src/runtime/storage/roots.js +66 -16
- package/src/runtime/storage/rules.js +82 -10
- package/src/runtime/storage/upkeep.js +10 -2
- package/src/runtime/storage/work-status.js +245 -26
- package/src/runtime/task-attempts.js +589 -69
- package/src/runtime/task-classifier.js +47 -11
- package/src/runtime/task-graph.js +373 -0
- package/src/runtime/task-run.js +778 -0
- package/src/runtime/task-scope.js +202 -56
- package/src/runtime/task-sources.js +147 -0
- package/src/runtime/task-state.js +440 -65
- package/src/runtime/team/admission.js +301 -0
- package/src/runtime/team/envelope.js +324 -0
- package/src/runtime/team/review-guard.js +156 -0
- package/src/runtime/trace/analyze.js +427 -0
- package/src/runtime/trace/baseline.js +770 -0
- package/src/runtime/trace/ledger.js +63 -140
- package/src/runtime/trace/otlp-export.js +568 -0
- package/src/runtime/trace/otlp-map.js +481 -0
- package/src/runtime/trace/spans.js +745 -0
- package/src/runtime/trace/telemetry.js +225 -0
- package/src/runtime/trace/views.js +1 -0
- package/src/runtime/transcripts/command.js +98 -0
- package/src/runtime/transcripts/cursor.js +326 -0
- package/src/runtime/transcripts/read.js +126 -0
- package/src/runtime/transcripts/readers/claude-jsonl.js +74 -0
- package/src/runtime/transcripts/readers/codex-rollout.js +70 -0
- package/src/runtime/transcripts/readers/copilot-events.js +90 -0
- package/src/runtime/transcripts/readers/kiro-jsonl.js +77 -0
- package/src/runtime/transcripts/readers/pi-jsonl.js +59 -0
- package/src/runtime/transcripts/registry.js +161 -0
- package/src/runtime/transcripts/stats.js +161 -0
- package/src/runtime/verification/check-key.js +628 -0
- package/src/runtime/verification/contract-runner.js +546 -11
- package/src/runtime/verification/engine.js +499 -9
- package/src/runtime/verification/impact.js +617 -0
- package/src/runtime/verification/inflight.js +205 -0
- package/src/runtime/verification/registry.js +176 -0
- package/src/runtime/verification/reuse.js +184 -0
- package/src/runtime/verification/telemetry-emit.js +254 -0
- package/src/runtime/verification/test-selection.js +67 -7
- package/src/runtime/worker/active.js +90 -0
- package/src/runtime/worker/cancel.js +222 -0
- package/src/runtime/worker/catalogue.js +122 -0
- package/src/runtime/worker/command.js +677 -0
- package/src/runtime/worker/evidence.js +288 -0
- package/src/runtime/worker/launch.js +288 -0
- package/src/runtime/worker/models.js +137 -0
- package/src/runtime/worker/parsers.js +218 -0
- package/src/runtime/worker/probes/index.js +706 -0
- package/src/runtime/worker/process-tree.js +415 -0
- package/src/runtime/worker/quota.js +43 -0
- package/src/runtime/worker/readiness.js +713 -0
- package/src/runtime/worker/run-store.js +166 -0
- package/src/runtime/worker/supervisor.js +541 -0
- package/src/runtime/worker/worktree-check.js +252 -0
- package/src/runtime/workflow-engine.js +5 -1
- package/src/runtime/workflow-orchestrator.js +578 -63
- package/src/runtime/worktree.js +149 -22
- package/src/state/index.js +1 -1
- package/src/state/lockfile.js +64 -10
- package/src/state/run-lock.js +1 -1
- package/types/node-commonjs.d.ts +106 -7
- package/core/.antigravity-plugin/hooks.json +0 -39
- package/core/harnesses/gemini/hooks/hooks.json +0 -77
- package/core/harnesses/gemini/hooks/lib.sh +0 -302
- package/core/harnesses/gemini/hooks/mcp-tool-guard.sh +0 -21
- package/core/harnesses/gemini/hooks/post-edit-lint.sh +0 -39
- package/core/harnesses/gemini/hooks/pre-bash-guard.sh +0 -21
- package/core/harnesses/gemini/hooks/pre-compact.sh +0 -38
- package/core/harnesses/gemini/hooks/pre-implement-gate.sh +0 -22
- package/core/harnesses/gemini/hooks/session-end.impl.sh +0 -89
- package/core/harnesses/gemini/hooks/session-end.sh +0 -5
- package/core/harnesses/gemini/hooks/session-start.sh +0 -5
- package/core/harnesses/gemini/settings/adapter-defaults.json +0 -4
- package/core/harnesses/shared/hooks/adapters/arg-fields.js +0 -19
- package/core/harnesses/shared/hooks/adapters/gemini.js +0 -114
- package/core/harnesses/shared/hooks/hooks.json +0 -47
- package/core/shared/guidance/FLAGS.md +0 -25
- package/core/shared/guidance/rules/RULE_01_SAFETY.md +0 -25
- package/core/shared/guidance/rules/RULE_02_WORKFLOW.md +0 -23
- package/core/shared/guidance/rules/RULE_03_QUALITY.md +0 -14
- package/core/shared/guidance/rules/RULE_04_QUESTIONS.md +0 -46
- package/src/adapters/gemini/hooks.js +0 -210
- package/src/adapters/gemini/index.js +0 -390
|
@@ -2,26 +2,62 @@
|
|
|
2
2
|
|
|
3
3
|
// TypeScript migration (agent-docs/BRIEF_GOAL_DOFLOW.md): run directly by Node native type-stripping.
|
|
4
4
|
|
|
5
|
+
const fs = require('node:fs');
|
|
6
|
+
const path = require('node:path');
|
|
7
|
+
const crypto = require('node:crypto');
|
|
5
8
|
const { EvidenceLedger } = require('./evidence-ledger.js');
|
|
6
9
|
const { ClaimsManager } = require('./claims.js');
|
|
7
10
|
const { ResearchRequestStore } = require('./research-request.js');
|
|
8
|
-
const { finishRuntime, usageError } = require('./cli-result.js');
|
|
9
|
-
const
|
|
11
|
+
const { finishRuntime, usageError, EXIT } = require('./cli-result.js');
|
|
12
|
+
const nativeConsoleLog = console.log;
|
|
13
|
+
const { resolveFeature } = require('./task-scope.js');
|
|
10
14
|
const { readRegister } = require('./decision-register.js');
|
|
15
|
+
const compose = require('./context/compose.js');
|
|
16
|
+
const {
|
|
17
|
+
FIELD_CLASSES,
|
|
18
|
+
buildPackItem,
|
|
19
|
+
buildObjectiveItem,
|
|
20
|
+
buildConstraintItem,
|
|
21
|
+
buildAcceptanceCriteriaItem,
|
|
22
|
+
buildVerificationRequirementItem,
|
|
23
|
+
buildScopeExcludedItem,
|
|
24
|
+
buildClaimConflictItem,
|
|
25
|
+
buildBlockingGapItem,
|
|
26
|
+
buildResearchRequestItem,
|
|
27
|
+
buildDecisionReasonItem,
|
|
28
|
+
buildDecisionLiveItem,
|
|
29
|
+
buildClaimSupportedItem,
|
|
30
|
+
buildClaimHypothesisItem,
|
|
31
|
+
buildPointerItem,
|
|
32
|
+
buildRelevantFileItem,
|
|
33
|
+
buildEvidenceSummaryItem,
|
|
34
|
+
buildStructuralContextItem,
|
|
35
|
+
computeEnvelopes,
|
|
36
|
+
linearFit,
|
|
37
|
+
groupOmissions,
|
|
38
|
+
computePackDigest,
|
|
39
|
+
formatOverflowMessage,
|
|
40
|
+
formatMarkdown,
|
|
41
|
+
formatJson,
|
|
42
|
+
} = require('./context/compose.js');
|
|
43
|
+
const {
|
|
44
|
+
extractMandatory,
|
|
45
|
+
parseMandatoryFile,
|
|
46
|
+
applyMandatoryOverride,
|
|
47
|
+
} = require('./context/mandatory.js');
|
|
11
48
|
|
|
12
49
|
const NO_DECISIONS = Object.freeze({ available: false, live: [], liveCount: 0 });
|
|
13
50
|
|
|
14
|
-
const TASK_CLASS_BUDGETS
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
});
|
|
51
|
+
const { TASK_CLASS_BUDGETS, resolveBudget, getRegisteredHarnessIds, getRegisteredHarnesses } = require('./context/budget.js');
|
|
52
|
+
const { createDeliveryEntry, readDeliveryEntry, recordDelivery, makeTokenRecord } = require('./context/delivery-store.js');
|
|
53
|
+
const { boundedAcquire } = require('./task-state.js');
|
|
54
|
+
const pointerTools = require('./context/pointer.js');
|
|
55
|
+
const { arbitrate, emitContext } = require('./context/arbitrate.js');
|
|
56
|
+
const { updateTaskState } = require('./task-state.js');
|
|
57
|
+
const { taskRecord } = require('./task-scope.js');
|
|
58
|
+
|
|
59
|
+
let correctiveTrimFallbackCount = 0;
|
|
60
|
+
function getCorrectiveTrimFallbackCount() { return correctiveTrimFallbackCount; }
|
|
25
61
|
|
|
26
62
|
/**
|
|
27
63
|
* The live decisions of the feature the caller is working on (IC-012). The feature is resolved
|
|
@@ -34,7 +70,7 @@ const TASK_CLASS_BUDGETS = Object.freeze({
|
|
|
34
70
|
*/
|
|
35
71
|
function loadLiveDecisions({ projectRoot, slug = null } ) {
|
|
36
72
|
try {
|
|
37
|
-
const feature =
|
|
73
|
+
const feature = resolveFeature({ projectRoot, slug });
|
|
38
74
|
if (feature.error) return { ...NO_DECISIONS };
|
|
39
75
|
let register;
|
|
40
76
|
try {
|
|
@@ -55,6 +91,66 @@ function loadLiveDecisions({ projectRoot, slug = null } ) {
|
|
|
55
91
|
}
|
|
56
92
|
}
|
|
57
93
|
|
|
94
|
+
function hashSourceFiles(root , paths ) {
|
|
95
|
+
const result = {};
|
|
96
|
+
for (const source of [...new Set(paths)].sort()) {
|
|
97
|
+
if (typeof source !== 'string' || source === '') continue;
|
|
98
|
+
const absolute = path.resolve(root, source);
|
|
99
|
+
const relative = path.relative(path.resolve(root), absolute);
|
|
100
|
+
if (!relative || relative.startsWith(`..${path.sep}`) || relative === '..' || path.isAbsolute(relative)) continue;
|
|
101
|
+
try {
|
|
102
|
+
result[relative.split(path.sep).join('/')] = `sha256:${crypto.createHash('sha256').update(fs.readFileSync(absolute)).digest('hex')}`;
|
|
103
|
+
} catch { /* unavailable source paths cannot be represented as verified sources */ }
|
|
104
|
+
}
|
|
105
|
+
return result;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function sourcesChanged(root , sources ) {
|
|
109
|
+
for (const [source, digest] of Object.entries(sources || {})) {
|
|
110
|
+
const current = hashSourceFiles(root, [source])[source];
|
|
111
|
+
if (current !== digest) return true;
|
|
112
|
+
}
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function classifyStoreFailure(error ) {
|
|
117
|
+
if (error?.code === 'store-locked' || error?.message === 'store-locked') return 'store-locked';
|
|
118
|
+
// Another writer reclaimed the lock mid-write; nothing was recorded and the store is intact.
|
|
119
|
+
if (error?.code === 'lock-lost') return 'lock-lost';
|
|
120
|
+
if (error?.code === 'store-unreadable') return 'store-unreadable';
|
|
121
|
+
if (['EACCES', 'EROFS', 'EPERM', 'ENOSPC'].includes(error?.code)) return 'store-unwritable';
|
|
122
|
+
return 'store-unwritable';
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function profileRetention(harnessId , profiles ) {
|
|
126
|
+
if (!harnessId) return null;
|
|
127
|
+
const harnesses = profiles || getRegisteredHarnesses();
|
|
128
|
+
return harnesses.find((item ) => item.id === harnessId)?.contextProfile?.retention || null;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function appendPointerExpansion({ projectRoot, taskId, slug, key, expansion, fsImpl = fs } ) {
|
|
132
|
+
const { file, seed } = taskRecord({ projectRoot, store: 'delivery', taskId, slug, fsImpl });
|
|
133
|
+
updateTaskState({
|
|
134
|
+
fsImpl, file, prepare: seed,
|
|
135
|
+
acquire: (impl , target ) => boundedAcquire(impl, target, { retries: 3, waitMs: 5 }),
|
|
136
|
+
build(disk ) {
|
|
137
|
+
const deliveries = Array.isArray(disk?.deliveries) ? disk.deliveries : [];
|
|
138
|
+
let found = false;
|
|
139
|
+
const updated = deliveries.map((entry ) => {
|
|
140
|
+
if (entry.key !== key) return entry;
|
|
141
|
+
found = true;
|
|
142
|
+
return { ...entry, expansions: [...(entry.expansions || []), expansion] };
|
|
143
|
+
});
|
|
144
|
+
if (!found) {
|
|
145
|
+
const error = new Error('delivery entry disappeared');
|
|
146
|
+
error.code = 'entry-evicted';
|
|
147
|
+
throw error;
|
|
148
|
+
}
|
|
149
|
+
return { taskId, deliveries: updated };
|
|
150
|
+
},
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
|
|
58
154
|
class ContextPackCompiler {
|
|
59
155
|
|
|
60
156
|
/**
|
|
@@ -69,189 +165,517 @@ class ContextPackCompiler {
|
|
|
69
165
|
maxClaims: defaultOptions.maxClaims || 20,
|
|
70
166
|
maxEvidenceItems: defaultOptions.maxEvidenceItems || 25,
|
|
71
167
|
maxResearchRequests: defaultOptions.maxResearchRequests || 20,
|
|
168
|
+
maxStructuralItems: defaultOptions.maxStructuralItems || 5,
|
|
169
|
+
enableCorrective: defaultOptions.enableCorrective !== false,
|
|
170
|
+
selfRefWidth: defaultOptions.selfRefWidth ?? null,
|
|
72
171
|
};
|
|
73
172
|
}
|
|
74
173
|
|
|
75
174
|
/**
|
|
76
|
-
* Compiles a ContextPack from task evidence and claims.
|
|
175
|
+
* Compiles a ContextPack from task evidence and claims through compose.ts.
|
|
77
176
|
* @param {Object} params
|
|
78
|
-
* @param {string} params.taskId
|
|
79
|
-
* @param {string} [params.taskClass='feature']
|
|
80
|
-
* @param {string} [params.objective='']
|
|
81
|
-
* @param {Array<string>} [params.constraints=[]]
|
|
82
|
-
* @param {Array<string>} [params.acceptanceCriteria=[]]
|
|
83
|
-
* @param {Object} params.evidenceLedger
|
|
84
|
-
* @param {Object} params.claimsManager
|
|
85
177
|
* @param {Object} [budgetOverrides={}]
|
|
86
178
|
* @returns {Object} ContextPack
|
|
87
179
|
*/
|
|
88
180
|
compileContextPack(params , budgetOverrides = {}) {
|
|
89
181
|
const {
|
|
90
|
-
taskId,
|
|
182
|
+
taskId = 'default',
|
|
91
183
|
taskClass = 'feature',
|
|
92
|
-
objective
|
|
93
|
-
constraints = [],
|
|
94
|
-
acceptanceCriteria = [],
|
|
184
|
+
objective: paramObjective,
|
|
185
|
+
constraints: paramConstraints = [],
|
|
186
|
+
acceptanceCriteria: paramAc = [],
|
|
187
|
+
verificationRequirements: paramVr = [],
|
|
188
|
+
scopeExcluded: paramScope = [],
|
|
189
|
+
blockingGaps: paramGaps = [],
|
|
95
190
|
evidenceLedger,
|
|
96
191
|
claimsManager,
|
|
97
192
|
researchRequests = [],
|
|
98
193
|
decisions = NO_DECISIONS,
|
|
194
|
+
mandatory: paramMandatory,
|
|
195
|
+
budget: paramBudget,
|
|
196
|
+
maxBytes,
|
|
197
|
+
harness,
|
|
198
|
+
bare = false,
|
|
199
|
+
mode: paramMode,
|
|
200
|
+
noRecord = false,
|
|
201
|
+
reason,
|
|
202
|
+
since,
|
|
203
|
+
expand,
|
|
204
|
+
pointers: suppliedPointers = [],
|
|
205
|
+
expansion = null,
|
|
99
206
|
} = params;
|
|
100
207
|
|
|
101
208
|
const limits = { ...this.options, ...budgetOverrides };
|
|
209
|
+
const contentLimits = {
|
|
210
|
+
maxFiles: limits.maxFiles,
|
|
211
|
+
maxClaims: limits.maxClaims,
|
|
212
|
+
maxEvidenceItems: limits.maxEvidenceItems,
|
|
213
|
+
maxResearchRequests: limits.maxResearchRequests,
|
|
214
|
+
maxStructuralItems: limits.maxStructuralItems,
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
const effectiveTaskClass = (!taskClass || typeof taskClass !== 'string' || taskClass.trim() === '') ? 'feature' : taskClass.trim();
|
|
218
|
+
const resolvedBudget = paramBudget || resolveBudget({ taskClass: effectiveTaskClass, maxBytes, harnessFlag: harness });
|
|
219
|
+
|
|
220
|
+
// Determine mandatory fields and provenance
|
|
221
|
+
const mandatoryFields = paramMandatory?.fields || {};
|
|
222
|
+
const mandatoryProv = paramMandatory?.provenance || {};
|
|
102
223
|
|
|
103
|
-
const
|
|
104
|
-
const
|
|
224
|
+
const hasParamObjective = paramObjective !== undefined && paramObjective !== null;
|
|
225
|
+
const objective = hasParamObjective
|
|
226
|
+
? paramObjective
|
|
227
|
+
: (mandatoryFields.objective || '');
|
|
105
228
|
|
|
106
|
-
|
|
107
|
-
const
|
|
108
|
-
const
|
|
109
|
-
const
|
|
229
|
+
const acSource = (paramAc.length > 0 ? paramAc : (mandatoryFields.acceptanceCriteria || []));
|
|
230
|
+
const constraintsSource = (paramConstraints.length > 0 ? paramConstraints : (mandatoryFields.constraints || []));
|
|
231
|
+
const vrSource = (paramVr.length > 0 ? paramVr : (mandatoryFields.verificationRequirements || []));
|
|
232
|
+
const scopeSource = (paramScope.length > 0 ? paramScope : (mandatoryFields.scopeExcluded || []));
|
|
233
|
+
const gapsSource = (paramGaps.length > 0 ? paramGaps : (mandatoryFields.blockingGaps || []));
|
|
234
|
+
|
|
235
|
+
const mandatoryProvenance = {
|
|
236
|
+
objective: hasParamObjective
|
|
237
|
+
? { supplied: Boolean(objective), source: 'caller', locator: null, digest: null, maturity: null, reason: objective ? null : 'caller-supplied-empty', gaps: [] }
|
|
238
|
+
: (mandatoryProv.objective || { supplied: Boolean(objective), source: objective ? 'caller' : 'none', locator: null, digest: null, maturity: null, reason: objective ? null : 'none-in-artifact', gaps: [] }),
|
|
239
|
+
acceptanceCriteria: mandatoryProv.acceptanceCriteria || { supplied: acSource.length > 0, source: acSource.length > 0 ? 'requirement' : 'none', locator: null, digest: null, maturity: null, reason: acSource.length > 0 ? null : 'artifact-absent', gaps: [] },
|
|
240
|
+
constraints: mandatoryProv.constraints || { supplied: constraintsSource.length > 0, source: constraintsSource.length > 0 ? 'requirement' : 'none', locator: null, digest: null, maturity: null, reason: constraintsSource.length > 0 ? null : 'artifact-absent', gaps: [] },
|
|
241
|
+
verificationRequirements: mandatoryProv.verificationRequirements || { supplied: vrSource.length > 0, source: vrSource.length > 0 ? 'requirement' : 'none', locator: null, digest: null, maturity: null, reason: vrSource.length > 0 ? null : 'artifact-absent', gaps: [] },
|
|
242
|
+
scopeExcluded: mandatoryProv.scopeExcluded || { supplied: scopeSource.length > 0, source: scopeSource.length > 0 ? 'requirement' : 'none', locator: null, digest: null, maturity: null, reason: scopeSource.length > 0 ? null : 'artifact-absent', gaps: [] },
|
|
243
|
+
blockingGaps: mandatoryProv.blockingGaps || { supplied: gapsSource.length > 0, source: gapsSource.length > 0 ? 'requirement' : 'none', locator: null, digest: null, maturity: null, reason: gapsSource.length > 0 ? null : 'artifact-absent', gaps: [] },
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
// Claims
|
|
247
|
+
let rawClaims = [];
|
|
248
|
+
if (claimsManager) {
|
|
249
|
+
rawClaims = claimsManager.getClaims(taskId);
|
|
250
|
+
} else if (params.claims) {
|
|
251
|
+
if (Array.isArray(params.claims)) {
|
|
252
|
+
rawClaims = params.claims;
|
|
253
|
+
} else {
|
|
254
|
+
const cList = (params.claims.conflicts || []).map((c ) => ({ ...c, status: 'conflicted' }));
|
|
255
|
+
const sList = (params.claims.supported || []).map((s ) => ({ ...s, status: s.status || 'supported' }));
|
|
256
|
+
const hList = (params.claims.hypotheses || []).map((h ) => ({ ...h, status: h.status || 'hypothesis' }));
|
|
257
|
+
rawClaims = [...cList, ...sList, ...hList];
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
const conflictedClaims = [];
|
|
261
|
+
const supportedClaims = [];
|
|
262
|
+
const activeHypotheses = [];
|
|
110
263
|
|
|
111
264
|
for (const claim of rawClaims) {
|
|
112
|
-
if (claim.status === '
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
} else if (claim.status === 'hypothesis') {
|
|
121
|
-
activeHypotheses.push({
|
|
122
|
-
id: claim.id,
|
|
123
|
-
statement: claim.statement,
|
|
124
|
-
});
|
|
125
|
-
} else if (claim.status === 'conflicted') {
|
|
126
|
-
conflictedClaims.push({
|
|
127
|
-
id: claim.id,
|
|
128
|
-
statement: claim.statement,
|
|
129
|
-
supportingEvidence: claim.supportingEvidence,
|
|
130
|
-
contradictingEvidence: claim.contradictingEvidence,
|
|
265
|
+
if (claim.status === 'conflicted' || (Array.isArray(claim.contradictingEvidence) && claim.contradictingEvidence.length > 0)) {
|
|
266
|
+
conflictedClaims.push(claim);
|
|
267
|
+
} else if (claim.status === 'supported') {
|
|
268
|
+
supportedClaims.push({
|
|
269
|
+
...claim,
|
|
270
|
+
evidenceIds: Array.isArray(claim.evidenceIds)
|
|
271
|
+
? claim.evidenceIds
|
|
272
|
+
: (Array.isArray(claim.supportingEvidence) ? claim.supportingEvidence : []),
|
|
131
273
|
});
|
|
274
|
+
} else if (claim.status === 'hypothesis') {
|
|
275
|
+
activeHypotheses.push(claim);
|
|
132
276
|
}
|
|
133
277
|
}
|
|
134
278
|
|
|
135
|
-
//
|
|
136
|
-
const
|
|
137
|
-
const
|
|
138
|
-
const
|
|
279
|
+
// Evidence
|
|
280
|
+
const rawEvidence = evidenceLedger ? evidenceLedger.queryEvidence({ taskId }) : (params.evidence || []);
|
|
281
|
+
const relevantFileSet = new Set ();
|
|
282
|
+
const structuralNodes = [];
|
|
283
|
+
const freshEvidenceItems = [];
|
|
284
|
+
const nonFreshOmissions = [];
|
|
139
285
|
|
|
140
286
|
for (const ev of rawEvidence) {
|
|
141
|
-
if (ev.
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
if (
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
287
|
+
if (ev.status === 'superseded') {
|
|
288
|
+
nonFreshOmissions.push({
|
|
289
|
+
id: ev.id,
|
|
290
|
+
field: 'evidenceSummary',
|
|
291
|
+
reason: 'superseded',
|
|
292
|
+
});
|
|
293
|
+
} else if (ev.freshness?.status === 'FRESH') {
|
|
294
|
+
if (ev.locator?.file) relevantFileSet.add(ev.locator.file);
|
|
295
|
+
if (ev.kind === 'structural' && ev.content) structuralNodes.push(ev.content);
|
|
296
|
+
freshEvidenceItems.push({
|
|
297
|
+
id: ev.id,
|
|
298
|
+
kind: ev.kind,
|
|
299
|
+
locator: ev.locator,
|
|
300
|
+
summary: typeof ev.content === 'string' ? ev.content.slice(0, 120) : null,
|
|
301
|
+
freshness: 'FRESH',
|
|
302
|
+
});
|
|
303
|
+
} else {
|
|
304
|
+
const status = ev.freshness?.status === 'STALE' ? 'STALE' : 'UNKNOWN';
|
|
305
|
+
nonFreshOmissions.push({
|
|
306
|
+
id: ev.id,
|
|
307
|
+
field: 'evidenceSummary',
|
|
308
|
+
reason: 'not-fresh',
|
|
309
|
+
freshness: status,
|
|
310
|
+
});
|
|
156
311
|
}
|
|
157
312
|
}
|
|
313
|
+
const relevantFiles = params.relevantFiles
|
|
314
|
+
? Array.from(new Set([...params.relevantFiles, ...relevantFileSet]))
|
|
315
|
+
: Array.from(relevantFileSet);
|
|
158
316
|
|
|
159
|
-
|
|
317
|
+
// Build items
|
|
318
|
+
const items = [];
|
|
319
|
+
if (objective) items.push(buildObjectiveItem(objective));
|
|
160
320
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
taskId: taskId || 'default',
|
|
164
|
-
taskClass,
|
|
165
|
-
compiledAt: new Date().toISOString(),
|
|
166
|
-
objective,
|
|
167
|
-
constraints: [...constraints],
|
|
168
|
-
// Ported from `evidence/context_pack.py` (plan task B.3): the only field the Python pack
|
|
169
|
-
// carried that this one did not. What the task must satisfy belongs beside the evidence
|
|
170
|
-
// gathered to satisfy it, otherwise the verification engine has to re-read the requirement
|
|
171
|
-
// to find out what it is verifying against.
|
|
172
|
-
verificationRequirements: [...acceptanceCriteria],
|
|
173
|
-
claims: {
|
|
174
|
-
supported: supportedClaims,
|
|
175
|
-
hypotheses: activeHypotheses,
|
|
176
|
-
conflicts: conflictedClaims,
|
|
177
|
-
},
|
|
178
|
-
relevantFiles,
|
|
179
|
-
structuralContext: structuralNodes.slice(0, 5),
|
|
180
|
-
evidenceCount: freshEvidenceItems.length,
|
|
181
|
-
evidenceSummary: freshEvidenceItems,
|
|
182
|
-
researchRequests: [...researchRequests]
|
|
183
|
-
.sort((a, b) => Number(b.blocking && b.status !== 'ANSWERED')
|
|
184
|
-
- Number(a.blocking && a.status !== 'ANSWERED'))
|
|
185
|
-
.slice(0, limits.maxResearchRequests).map(r => ({
|
|
186
|
-
id: r.id, stageId: r.stageId, question: r.question, status: r.status,
|
|
187
|
-
blocking: r.blocking, claimId: r.claimId, evidenceIds: r.evidenceIds, gap: r.gap,
|
|
188
|
-
})),
|
|
189
|
-
decisions: {
|
|
190
|
-
available: decisions.available, live: [...decisions.live], liveCount: decisions.liveCount,
|
|
191
|
-
...(decisions.reason ? { reason: decisions.reason } : {}),
|
|
192
|
-
},
|
|
193
|
-
budgetEnforcement: {
|
|
194
|
-
totalFiles: relevantFiles.length,
|
|
195
|
-
totalSupportedClaims: supportedClaims.length,
|
|
196
|
-
totalActiveHypotheses: activeHypotheses.length,
|
|
197
|
-
limits,
|
|
198
|
-
},
|
|
199
|
-
};
|
|
200
|
-
}
|
|
321
|
+
const blockingUnanswered = researchRequests.filter((r ) => r.blocking && r.status !== 'ANSWERED');
|
|
322
|
+
const otherRequests = researchRequests.filter((r ) => !(r.blocking && r.status !== 'ANSWERED'));
|
|
201
323
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
if (pack.objective) {
|
|
210
|
-
md += `**Objective:** ${pack.objective}\n\n`;
|
|
211
|
-
}
|
|
324
|
+
if (!bare) {
|
|
325
|
+
acSource.forEach((ac , i ) => items.push(buildAcceptanceCriteriaItem(ac, i)));
|
|
326
|
+
constraintsSource.forEach((c , i ) => items.push(buildConstraintItem(c, i)));
|
|
327
|
+
vrSource.forEach((vr , i ) => items.push(buildVerificationRequirementItem(vr, i)));
|
|
328
|
+
scopeSource.forEach((se , i ) => items.push(buildScopeExcludedItem(se, i)));
|
|
329
|
+
gapsSource.forEach((bg , i ) => items.push(buildBlockingGapItem(bg, i)));
|
|
330
|
+
conflictedClaims.forEach((c ) => items.push(buildClaimConflictItem(c)));
|
|
212
331
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
for (const c of pack.claims.supported) {
|
|
216
|
-
md += `- ✓ ${c.statement} *(ev: ${c.evidenceIds.join(', ')})*\n`;
|
|
217
|
-
}
|
|
218
|
-
md += '\n';
|
|
219
|
-
}
|
|
332
|
+
blockingUnanswered.forEach((r ) => items.push(buildResearchRequestItem(r)));
|
|
333
|
+
if (decisions.reason) items.push(buildDecisionReasonItem(decisions.reason));
|
|
220
334
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
for (const h of pack.claims.hypotheses) {
|
|
224
|
-
md += `- ? ${h.statement}\n`;
|
|
335
|
+
if (decisions.available && Array.isArray(decisions.live)) {
|
|
336
|
+
decisions.live.forEach((d ) => items.push(buildDecisionLiveItem(d)));
|
|
225
337
|
}
|
|
226
|
-
|
|
338
|
+
supportedClaims.forEach((c ) => items.push(buildClaimSupportedItem(c)));
|
|
339
|
+
otherRequests.forEach((r ) => items.push(buildResearchRequestItem(r)));
|
|
340
|
+
activeHypotheses.forEach((h ) => items.push(buildClaimHypothesisItem(h)));
|
|
341
|
+
suppliedPointers.forEach((p ) => items.push(buildPointerItem(p)));
|
|
342
|
+
relevantFiles.forEach((f ) => items.push(buildRelevantFileItem(f)));
|
|
343
|
+
freshEvidenceItems.forEach((ev ) => items.push(buildEvidenceSummaryItem(ev)));
|
|
344
|
+
structuralNodes.forEach((sn , i ) => items.push(buildStructuralContextItem(sn, i)));
|
|
227
345
|
}
|
|
228
346
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
347
|
+
const hasMandatoryItems = {
|
|
348
|
+
objective: Boolean(objective),
|
|
349
|
+
acceptanceCriteria: !bare && acSource.length > 0,
|
|
350
|
+
constraints: !bare && constraintsSource.length > 0,
|
|
351
|
+
verificationRequirements: !bare && vrSource.length > 0,
|
|
352
|
+
scopeExcluded: !bare && scopeSource.length > 0,
|
|
353
|
+
blockingGaps: !bare && (gapsSource.length > 0 || blockingUnanswered.length > 0),
|
|
354
|
+
'claims.conflicts': !bare && conflictedClaims.length > 0,
|
|
355
|
+
researchRequests: !bare && blockingUnanswered.length > 0,
|
|
356
|
+
};
|
|
357
|
+
|
|
358
|
+
const empty = rawEvidence.length === 0
|
|
359
|
+
&& rawClaims.length === 0
|
|
360
|
+
&& researchRequests.length === 0
|
|
361
|
+
&& (!decisions || decisions.liveCount === 0);
|
|
362
|
+
|
|
363
|
+
const enableCorrective = budgetOverrides.enableCorrective !== undefined
|
|
364
|
+
? budgetOverrides.enableCorrective
|
|
365
|
+
: (this.options.enableCorrective !== false);
|
|
366
|
+
const registeredHarnessIds = getRegisteredHarnessIds();
|
|
367
|
+
const reservedHarnessWidth = Math.max(...registeredHarnessIds.map((id ) => id.length), 0);
|
|
368
|
+
const selfRefWidth = Math.max(budgetOverrides.selfRefWidth ?? this.options.selfRefWidth ?? 0, reservedHarnessWidth);
|
|
369
|
+
const longestHarnessId = registeredHarnessIds.reduce((longest , id ) => id.length > longest.length ? id : longest, 'unstated');
|
|
370
|
+
const envelopeBudget = {
|
|
371
|
+
maxBytes: resolvedBudget.maxBytes,
|
|
372
|
+
source: resolvedBudget.source,
|
|
373
|
+
harness: { ...resolvedBudget.harness, id: longestHarnessId },
|
|
374
|
+
capacity: { value: null, basis: 'unknown:values belong to 085 (A-19)' },
|
|
375
|
+
toolResultLimitBytes: null,
|
|
376
|
+
...(resolvedBudget.startupTokens ? { startupTokens: resolvedBudget.startupTokens } : {}),
|
|
377
|
+
};
|
|
378
|
+
|
|
379
|
+
const { envelopeMd, envelopeJson } = computeEnvelopes({
|
|
380
|
+
taskId,
|
|
381
|
+
taskClass: effectiveTaskClass,
|
|
382
|
+
budget: envelopeBudget,
|
|
383
|
+
mandatory: paramMandatory,
|
|
384
|
+
empty,
|
|
385
|
+
mode: bare ? 'bare' : (paramMode || 'full'),
|
|
386
|
+
hasMandatoryItems,
|
|
387
|
+
limits,
|
|
388
|
+
selfRefWidth,
|
|
389
|
+
recordingExpected: params.recordingExpected === true,
|
|
390
|
+
// Reserve the longest registered identity and delivery form for parity.
|
|
391
|
+
form: 'markdown',
|
|
392
|
+
harnessId: longestHarnessId,
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
const hasMandatoryRequests = !bare && blockingUnanswered.length > 0;
|
|
396
|
+
let deltaInfo = null;
|
|
397
|
+
let unchangedOmissions = [];
|
|
398
|
+
let removedIds = [];
|
|
399
|
+
let fitItems = items;
|
|
400
|
+
if (params.deltaSinceEntry && paramMode === 'delta') {
|
|
401
|
+
const oldItems = params.deltaSinceEntry.items || {};
|
|
402
|
+
const currentIds = new Set(items.map((item ) => item.id));
|
|
403
|
+
const added = [];
|
|
404
|
+
const changed = [];
|
|
405
|
+
const unchanged = [];
|
|
406
|
+
fitItems = [];
|
|
407
|
+
for (const item of items) {
|
|
408
|
+
const oldDigest = oldItems[item.id];
|
|
409
|
+
if (item.cls === 'mandatory') {
|
|
410
|
+
if (!oldDigest) added.push(item.id);
|
|
411
|
+
else if (oldDigest !== item.digest) changed.push(item.id);
|
|
412
|
+
else unchanged.push(item.id);
|
|
413
|
+
fitItems.push(item);
|
|
414
|
+
} else if (!oldDigest) {
|
|
415
|
+
added.push(item.id); fitItems.push({ ...item, deltaForced: true });
|
|
416
|
+
} else if (oldDigest === item.digest) {
|
|
417
|
+
unchanged.push(item.id);
|
|
418
|
+
unchangedOmissions.push({ id: item.id, field: item.field, reason: 'unchanged' });
|
|
419
|
+
} else {
|
|
420
|
+
changed.push(item.id); fitItems.push({ ...item, deltaForced: true });
|
|
421
|
+
}
|
|
236
422
|
}
|
|
237
|
-
|
|
423
|
+
removedIds = Object.keys(oldItems).filter((id ) => !currentIds.has(id));
|
|
424
|
+
deltaInfo = { since, added, changed, removed: removedIds, unchanged };
|
|
238
425
|
}
|
|
239
426
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
427
|
+
const fit = linearFit({
|
|
428
|
+
items: fitItems,
|
|
429
|
+
budget: resolvedBudget.maxBytes,
|
|
430
|
+
taskId,
|
|
431
|
+
taskClass: effectiveTaskClass,
|
|
432
|
+
envelopeMd,
|
|
433
|
+
envelopeJson,
|
|
434
|
+
initialOmissions: bare ? [] : [...nonFreshOmissions, ...unchangedOmissions],
|
|
435
|
+
sectionHeadingsJson: {
|
|
436
|
+
'decisions.live': 5,
|
|
437
|
+
'claims.supported': 5,
|
|
438
|
+
'researchRequests (others)': hasMandatoryRequests ? 0 : 3,
|
|
439
|
+
'claims.hypotheses': 4,
|
|
440
|
+
pointers: 3,
|
|
441
|
+
relevantFiles: 3,
|
|
442
|
+
evidenceSummary: 3,
|
|
443
|
+
structuralContext: 3,
|
|
444
|
+
},
|
|
445
|
+
itemCapLimits: {
|
|
446
|
+
relevantFiles: limits.maxFiles ?? 15,
|
|
447
|
+
'claims.supported': limits.maxClaims ?? 20,
|
|
448
|
+
'claims.hypotheses': limits.maxClaims ?? 20,
|
|
449
|
+
evidenceSummary: limits.maxEvidenceItems ?? 25,
|
|
450
|
+
'researchRequests (others)': Math.max(0, (limits.maxResearchRequests ?? 20) - blockingUnanswered.length),
|
|
451
|
+
structuralContext: limits.maxStructuralItems ?? 5,
|
|
452
|
+
},
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
const assemblePack = (keptItems , omissionsList , isOverflow = false, overflowCause = null) => {
|
|
456
|
+
const keptAc = keptItems.filter((i ) => i.field === 'acceptanceCriteria').map((i ) => i.value);
|
|
457
|
+
const keptConstraints = keptItems.filter((i ) => i.field === 'constraints').map((i ) => i.value);
|
|
458
|
+
const keptVr = keptItems.filter((i ) => i.field === 'verificationRequirements').map((i ) => i.value);
|
|
459
|
+
const keptScope = keptItems.filter((i ) => i.field === 'scopeExcluded').map((i ) => i.value);
|
|
460
|
+
const keptGaps = keptItems.filter((i ) => i.field === 'blockingGaps').map((i ) => i.value);
|
|
461
|
+
const keptConflicts = keptItems.filter((i ) => i.field === 'claims.conflicts').map((i ) => i.value);
|
|
462
|
+
const keptLiveDecisions = keptItems.filter((i ) => i.field === 'decisions.live').map((i ) => i.value);
|
|
463
|
+
const keptSupported = keptItems.filter((i ) => i.field === 'claims.supported').map((i ) => i.value);
|
|
464
|
+
const keptRequests = keptItems.filter((i ) => i.field.startsWith('researchRequests')).map((i ) => i.value);
|
|
465
|
+
const keptHypotheses = keptItems.filter((i ) => i.field === 'claims.hypotheses').map((i ) => i.value);
|
|
466
|
+
const keptPointers = keptItems.filter((i ) => i.field === 'pointers').map((i ) => i.value);
|
|
467
|
+
const keptFiles = keptItems.filter((i ) => i.field === 'relevantFiles').map((i ) => i.value);
|
|
468
|
+
const keptEvidence = keptItems.filter((i ) => i.field === 'evidenceSummary').map((i ) => i.value);
|
|
469
|
+
const keptStructural = keptItems.filter((i ) => i.field === 'structuralContext').map((i ) => i.value);
|
|
470
|
+
|
|
471
|
+
const omissions = groupOmissions(omissionsList);
|
|
472
|
+
const packDigest = computePackDigest(keptItems);
|
|
473
|
+
|
|
474
|
+
const cause = overflowCause || (isOverflow ? (fit.cause || 'mandatory') : null);
|
|
475
|
+
const packTotalBytes = fit.totalBytes;
|
|
476
|
+
const packMandatoryBytes = fit.mandatoryBytesByForm?.[params.form === 'markdown' ? 'markdown' : 'json'] ?? fit.mandatoryBytes;
|
|
477
|
+
const packOptionalBytes = packTotalBytes - packMandatoryBytes;
|
|
478
|
+
|
|
479
|
+
const packed = {
|
|
480
|
+
version: 1,
|
|
481
|
+
status: isOverflow ? 'OVERFLOW' : (empty ? 'EMPTY' : 'OK'),
|
|
482
|
+
exitCode: isOverflow ? EXIT.OVERFLOW : (empty ? EXIT.EMPTY : EXIT.OK),
|
|
483
|
+
taskId,
|
|
484
|
+
taskClass: effectiveTaskClass,
|
|
485
|
+
compiledAt: new Date().toISOString(),
|
|
486
|
+
mode: bare ? 'bare' : (paramMode || 'full'),
|
|
487
|
+
budget: envelopeBudget,
|
|
488
|
+
overflow: isOverflow ? {
|
|
489
|
+
cause,
|
|
490
|
+
mandatoryBytes: packMandatoryBytes,
|
|
491
|
+
budgetBytes: resolvedBudget.maxBytes,
|
|
492
|
+
excessBytes: Math.max(0, packTotalBytes - resolvedBudget.maxBytes),
|
|
493
|
+
action: 'split-or-new-session',
|
|
494
|
+
} : null,
|
|
495
|
+
overflowAction: isOverflow ? {
|
|
496
|
+
message: formatOverflowMessage({
|
|
497
|
+
cause,
|
|
498
|
+
mandatoryBytes: packMandatoryBytes,
|
|
499
|
+
totalBytes: packTotalBytes,
|
|
500
|
+
budgetBytes: resolvedBudget.maxBytes,
|
|
501
|
+
source: resolvedBudget.source,
|
|
502
|
+
}),
|
|
503
|
+
} : null,
|
|
504
|
+
toolLimitNotice: null,
|
|
505
|
+
objective,
|
|
506
|
+
acceptanceCriteria: keptAc,
|
|
507
|
+
constraints: keptConstraints,
|
|
508
|
+
verificationRequirements: keptVr,
|
|
509
|
+
scopeExcluded: keptScope,
|
|
510
|
+
blockingGaps: keptGaps,
|
|
511
|
+
claims: {
|
|
512
|
+
conflicts: keptConflicts,
|
|
513
|
+
supported: keptSupported,
|
|
514
|
+
hypotheses: keptHypotheses,
|
|
515
|
+
},
|
|
516
|
+
researchRequests: keptRequests,
|
|
517
|
+
mandatory: mandatoryProvenance,
|
|
518
|
+
decisions: {
|
|
519
|
+
available: Boolean(decisions && decisions.available),
|
|
520
|
+
live: keptLiveDecisions,
|
|
521
|
+
liveCount: keptLiveDecisions.length,
|
|
522
|
+
...(decisions?.reason ? { reason: decisions.reason } : {}),
|
|
523
|
+
},
|
|
524
|
+
pointers: keptPointers,
|
|
525
|
+
...(expansion ? { expansion } : {}),
|
|
526
|
+
relevantFiles: keptFiles,
|
|
527
|
+
evidenceCount: keptEvidence.length,
|
|
528
|
+
evidenceSummary: keptEvidence,
|
|
529
|
+
structuralContext: keptStructural,
|
|
530
|
+
budgetEnforcement: {
|
|
531
|
+
totalFiles: relevantFiles.length,
|
|
532
|
+
totalSupportedClaims: supportedClaims.length,
|
|
533
|
+
totalActiveHypotheses: activeHypotheses.length,
|
|
534
|
+
limits: contentLimits,
|
|
535
|
+
},
|
|
536
|
+
empty,
|
|
537
|
+
omissions: bare ? { total: 0, groups: [] } : omissions,
|
|
538
|
+
size: {
|
|
539
|
+
totalBytes: packTotalBytes,
|
|
540
|
+
mandatoryBytes: packMandatoryBytes,
|
|
541
|
+
optionalBytes: packOptionalBytes,
|
|
542
|
+
fittedOn: fit.fittedOn,
|
|
543
|
+
},
|
|
544
|
+
accounting: {
|
|
545
|
+
tokens: makeTokenRecord(packTotalBytes),
|
|
546
|
+
},
|
|
547
|
+
delivery: {
|
|
548
|
+
key: params.recordingExpected ? `${packDigest}.${params.form || 'json'}.${params.harness?.id || 'unstated'}` : null,
|
|
549
|
+
packDigest,
|
|
550
|
+
recorded: params.recordingExpected === true,
|
|
551
|
+
reason: null,
|
|
552
|
+
since: since || null,
|
|
553
|
+
deltaRefused: params.deltaRefused || null,
|
|
554
|
+
},
|
|
555
|
+
delta: deltaInfo,
|
|
556
|
+
packEnd: {
|
|
557
|
+
mode: bare ? 'bare' : (paramMode || 'full'),
|
|
558
|
+
objective: objective ? 1 : 0,
|
|
559
|
+
acceptanceCriteria: keptAc.length,
|
|
560
|
+
constraints: keptConstraints.length,
|
|
561
|
+
verificationRequirements: keptVr.length,
|
|
562
|
+
scopeExcluded: keptScope.length,
|
|
563
|
+
conflicts: keptConflicts.length,
|
|
564
|
+
blockingGaps: keptGaps.length,
|
|
565
|
+
omitted: bare ? 0 : omissions.total,
|
|
566
|
+
bytes: packTotalBytes,
|
|
567
|
+
digest: packDigest.slice(0, 19),
|
|
568
|
+
},
|
|
569
|
+
};
|
|
570
|
+
Object.defineProperties(packed, {
|
|
571
|
+
deliveryItems: { value: keptItems.map((item ) => ({ ...item, cls: item.cls || item.class })) },
|
|
572
|
+
deliveryOmissions: { value: bare ? [] : omissionsList.map((item ) => ({ ...item })) },
|
|
573
|
+
deliveryAllItems: { value: items.map((item ) => ({ id: item.id, digest: item.digest, cls: item.cls || item.class })) },
|
|
574
|
+
trimOptional: { value: () => {
|
|
575
|
+
const currentItems = (packed ).deliveryItems ;
|
|
576
|
+
let trimIndex = -1;
|
|
577
|
+
for (let i = currentItems.length - 1; i >= 0; i -= 1) {
|
|
578
|
+
if (currentItems[i].cls === 'optional' && !currentItems[i].deltaForced) { trimIndex = i; break; }
|
|
579
|
+
}
|
|
580
|
+
if (trimIndex < 0) return null;
|
|
581
|
+
const dropped = currentItems[trimIndex];
|
|
582
|
+
const nextItems = currentItems.filter((_ , i ) => i !== trimIndex);
|
|
583
|
+
const nextOmissions = [...(packed ).deliveryOmissions, {
|
|
584
|
+
id: dropped.id, field: dropped.field, reason: 'budget', ...(dropped.freshness ? { freshness: dropped.freshness } : {}),
|
|
585
|
+
}];
|
|
586
|
+
return assemblePack(nextItems, nextOmissions, false, null);
|
|
587
|
+
} },
|
|
588
|
+
});
|
|
589
|
+
return packed;
|
|
590
|
+
};
|
|
591
|
+
|
|
592
|
+
let pack = assemblePack(fit.kept, fit.omissions, fit.overflow, fit.cause);
|
|
593
|
+
|
|
594
|
+
if (enableCorrective && pack.status === 'OK') {
|
|
595
|
+
let currentKept = [...fit.kept];
|
|
596
|
+
let currentOmissions = [...fit.omissions];
|
|
597
|
+
let fallbackCounted = false;
|
|
598
|
+
|
|
599
|
+
while (pack.status === 'OK') {
|
|
600
|
+
const mdOut = formatMarkdown(pack, { throwOnOverBudget: false });
|
|
601
|
+
const jsonOut = formatJson(pack, { throwOnOverBudget: false });
|
|
602
|
+
const mdLen = Buffer.byteLength(mdOut, 'utf8');
|
|
603
|
+
const jsonLen = Buffer.byteLength(jsonOut, 'utf8');
|
|
245
604
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
605
|
+
if (mdLen <= resolvedBudget.maxBytes && jsonLen <= resolvedBudget.maxBytes) {
|
|
606
|
+
pack.size.fittedOn = jsonLen >= mdLen ? 'json' : 'markdown';
|
|
607
|
+
break;
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
let lastOptIdx = -1;
|
|
611
|
+
for (let idx = currentKept.length - 1; idx >= 0; idx--) {
|
|
612
|
+
const it = currentKept[idx];
|
|
613
|
+
if ((it.cls === 'optional' || it.class === 'optional') && !it.deltaForced) {
|
|
614
|
+
lastOptIdx = idx;
|
|
615
|
+
break;
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
if (lastOptIdx === -1) {
|
|
620
|
+
const mandatoryOnlyKept = currentKept.filter((i ) => i.cls === 'mandatory' || i.class === 'mandatory' || i.deltaForced);
|
|
621
|
+
const allOptOmitted = [
|
|
622
|
+
...(bare ? [] : nonFreshOmissions),
|
|
623
|
+
...items.filter((i ) => (i.cls === 'optional' || i.class === 'optional') && !i.deltaForced).map((i ) => ({
|
|
624
|
+
id: i.id,
|
|
625
|
+
field: i.field,
|
|
626
|
+
reason: 'mandatory-overflow',
|
|
627
|
+
...(i.freshness ? { freshness: i.freshness } : {}),
|
|
628
|
+
})),
|
|
629
|
+
];
|
|
630
|
+
const cause = Math.max(fit.mandatoryBytes, mdLen, jsonLen) > resolvedBudget.maxBytes ? 'mandatory' : 'accounting';
|
|
631
|
+
pack = assemblePack(mandatoryOnlyKept, allOptOmitted, true, cause);
|
|
632
|
+
break;
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
if (!fallbackCounted) {
|
|
636
|
+
correctiveTrimFallbackCount += 1;
|
|
637
|
+
fallbackCounted = true;
|
|
638
|
+
}
|
|
639
|
+
const [dropped] = currentKept.splice(lastOptIdx, 1);
|
|
640
|
+
currentOmissions.push({
|
|
641
|
+
id: dropped.id,
|
|
642
|
+
field: dropped.field,
|
|
643
|
+
reason: 'budget',
|
|
644
|
+
...(dropped.freshness ? { freshness: dropped.freshness } : {}),
|
|
645
|
+
});
|
|
646
|
+
pack = assemblePack(currentKept, currentOmissions, false, null);
|
|
250
647
|
}
|
|
251
|
-
md += '\n';
|
|
252
648
|
}
|
|
253
649
|
|
|
254
|
-
|
|
650
|
+
const fittedOutput = params.form === 'markdown'
|
|
651
|
+
? formatMarkdown(pack, { throwOnOverBudget: false })
|
|
652
|
+
: formatJson(pack, { throwOnOverBudget: false });
|
|
653
|
+
pack.size.totalBytes = Buffer.byteLength(fittedOutput, 'utf8');
|
|
654
|
+
pack.size.optionalBytes = pack.size.totalBytes - pack.size.mandatoryBytes;
|
|
655
|
+
pack.packEnd.bytes = pack.size.totalBytes;
|
|
656
|
+
pack.accounting.tokens = makeTokenRecord(pack.size.totalBytes);
|
|
657
|
+
|
|
658
|
+
return pack;
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
/**
|
|
662
|
+
* Formats a ContextPack into markdown per IC-005.
|
|
663
|
+
* @param {Object} pack
|
|
664
|
+
* @param {Object} [options]
|
|
665
|
+
* @returns {string}
|
|
666
|
+
*/
|
|
667
|
+
formatMarkdown(pack , options = {}) {
|
|
668
|
+
return formatMarkdown(pack, options);
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
/**
|
|
672
|
+
* Formats a ContextPack into JSON per IC-004.
|
|
673
|
+
* @param {Object} pack
|
|
674
|
+
* @param {Object} [options]
|
|
675
|
+
* @returns {string}
|
|
676
|
+
*/
|
|
677
|
+
formatJson(pack , options = {}) {
|
|
678
|
+
return formatJson(pack, options);
|
|
255
679
|
}
|
|
256
680
|
|
|
257
681
|
/**
|
|
@@ -281,9 +705,8 @@ class ContextPackCompiler {
|
|
|
281
705
|
optional = {},
|
|
282
706
|
} = options;
|
|
283
707
|
|
|
284
|
-
const
|
|
285
|
-
|
|
286
|
-
: (TASK_CLASS_BUDGETS[taskClass] || 225000);
|
|
708
|
+
const resolvedBudget = resolveBudget({ taskClass, maxBytes });
|
|
709
|
+
const budgetBytes = resolvedBudget.maxBytes;
|
|
287
710
|
|
|
288
711
|
const acceptanceCriteria = Array.isArray(mandatory.acceptanceCriteria) ? [...mandatory.acceptanceCriteria] : [];
|
|
289
712
|
const constraints = Array.isArray(mandatory.constraints) ? [...mandatory.constraints] : [];
|
|
@@ -314,17 +737,75 @@ class ContextPackCompiler {
|
|
|
314
737
|
|
|
315
738
|
const mandatoryBytes = Buffer.byteLength(mandatoryMd, 'utf8');
|
|
316
739
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
740
|
+
const hypotheses = Array.isArray(optional.hypotheses) ? [...optional.hypotheses] : [];
|
|
741
|
+
const unverifiedClaims = Array.isArray(optional.unverifiedClaims) ? [...optional.unverifiedClaims] : [];
|
|
742
|
+
const narrative = Array.isArray(optional.narrative) ? [...optional.narrative] : [];
|
|
743
|
+
|
|
744
|
+
const items = [];
|
|
745
|
+
hypotheses.forEach((h , idx ) => {
|
|
746
|
+
const line = `- ? ${h}\n`;
|
|
747
|
+
items.push({
|
|
748
|
+
id: `hypothesis-${idx + 1}`,
|
|
749
|
+
field: 'hypotheses',
|
|
750
|
+
value: h,
|
|
751
|
+
class: 'optional',
|
|
752
|
+
cls: 'optional',
|
|
753
|
+
priority: 1,
|
|
754
|
+
md: line,
|
|
755
|
+
mdBytes: Buffer.byteLength(line, 'utf8'),
|
|
756
|
+
jsonBytes: 0,
|
|
757
|
+
});
|
|
758
|
+
});
|
|
323
759
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
760
|
+
unverifiedClaims.forEach((c , idx ) => {
|
|
761
|
+
const line = `- ? ${c}\n`;
|
|
762
|
+
items.push({
|
|
763
|
+
id: `claim-${idx + 1}`,
|
|
764
|
+
field: 'unverifiedClaims',
|
|
765
|
+
value: c,
|
|
766
|
+
class: 'optional',
|
|
767
|
+
cls: 'optional',
|
|
768
|
+
priority: 2,
|
|
769
|
+
md: line,
|
|
770
|
+
mdBytes: Buffer.byteLength(line, 'utf8'),
|
|
771
|
+
jsonBytes: 0,
|
|
772
|
+
});
|
|
773
|
+
});
|
|
327
774
|
|
|
775
|
+
narrative.forEach((n , idx ) => {
|
|
776
|
+
const line = `- ${n}\n`;
|
|
777
|
+
items.push({
|
|
778
|
+
id: `narrative-${idx + 1}`,
|
|
779
|
+
field: 'narrative',
|
|
780
|
+
value: n,
|
|
781
|
+
class: 'optional',
|
|
782
|
+
cls: 'optional',
|
|
783
|
+
priority: 3,
|
|
784
|
+
md: line,
|
|
785
|
+
mdBytes: Buffer.byteLength(line, 'utf8'),
|
|
786
|
+
jsonBytes: 0,
|
|
787
|
+
});
|
|
788
|
+
});
|
|
789
|
+
|
|
790
|
+
const fit = compose.linearFit({
|
|
791
|
+
items,
|
|
792
|
+
budget: budgetBytes,
|
|
793
|
+
taskId,
|
|
794
|
+
taskClass,
|
|
795
|
+
envelopeMd: mandatoryBytes,
|
|
796
|
+
envelopeJson: mandatoryBytes,
|
|
797
|
+
includeOmissionCosts: false,
|
|
798
|
+
sectionHeadingsMd: {
|
|
799
|
+
hypotheses: Buffer.byteLength('### Active Hypotheses (Unverified)\n\n', 'utf8'),
|
|
800
|
+
unverifiedClaims: Buffer.byteLength('### Unverified Claims\n\n', 'utf8'),
|
|
801
|
+
narrative: Buffer.byteLength('### Background Narrative\n\n', 'utf8'),
|
|
802
|
+
},
|
|
803
|
+
sectionHeadingsJson: {},
|
|
804
|
+
itemCapLimits: {},
|
|
805
|
+
});
|
|
806
|
+
|
|
807
|
+
if (fit.overflow) {
|
|
808
|
+
const omissions = items.map((i ) => ({ id: i.id, reason: 'budget-cap-exceeded' }));
|
|
328
809
|
return {
|
|
329
810
|
taskId,
|
|
330
811
|
taskClass,
|
|
@@ -339,74 +820,30 @@ class ContextPackCompiler {
|
|
|
339
820
|
};
|
|
340
821
|
}
|
|
341
822
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
const hypotheses = Array.isArray(optional.hypotheses) ? [...optional.hypotheses] : [];
|
|
346
|
-
const unverifiedClaims = Array.isArray(optional.unverifiedClaims) ? [...optional.unverifiedClaims] : [];
|
|
347
|
-
const narrative = Array.isArray(optional.narrative) ? [...optional.narrative] : [];
|
|
348
|
-
|
|
349
|
-
const keptHypotheses = [];
|
|
350
|
-
const keptClaims = [];
|
|
351
|
-
const keptNarrative = [];
|
|
352
|
-
const omissions = [];
|
|
353
|
-
|
|
354
|
-
const buildPayload = (hList , cList , nList ) => {
|
|
355
|
-
let md = mandatoryMd;
|
|
356
|
-
if (hList.length > 0) {
|
|
357
|
-
md += `### Active Hypotheses (Unverified)\n`;
|
|
358
|
-
for (const h of hList) md += `- ? ${h}\n`;
|
|
359
|
-
md += '\n';
|
|
360
|
-
}
|
|
361
|
-
if (cList.length > 0) {
|
|
362
|
-
md += `### Unverified Claims\n`;
|
|
363
|
-
for (const c of cList) md += `- ? ${c}\n`;
|
|
364
|
-
md += '\n';
|
|
365
|
-
}
|
|
366
|
-
if (nList.length > 0) {
|
|
367
|
-
md += `### Background Narrative\n`;
|
|
368
|
-
for (const n of nList) md += `- ${n}\n`;
|
|
369
|
-
md += '\n';
|
|
370
|
-
}
|
|
371
|
-
return md;
|
|
372
|
-
};
|
|
823
|
+
const keptHypotheses = fit.kept.filter((i ) => i.field === 'hypotheses').map((i ) => i.value);
|
|
824
|
+
const keptClaims = fit.kept.filter((i ) => i.field === 'unverifiedClaims').map((i ) => i.value);
|
|
825
|
+
const keptNarrative = fit.kept.filter((i ) => i.field === 'narrative').map((i ) => i.value);
|
|
373
826
|
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
const
|
|
378
|
-
|
|
379
|
-
keptHypotheses.push(hypotheses[i]);
|
|
380
|
-
} else {
|
|
381
|
-
omissions.push({ id: `hypothesis-${i + 1}`, reason: 'budget-cap-exceeded' });
|
|
382
|
-
}
|
|
827
|
+
let payload = mandatoryMd;
|
|
828
|
+
if (keptHypotheses.length > 0) {
|
|
829
|
+
payload += `### Active Hypotheses (Unverified)\n`;
|
|
830
|
+
for (const h of keptHypotheses) payload += `- ? ${h}\n`;
|
|
831
|
+
payload += '\n';
|
|
383
832
|
}
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
const trialMd = buildPayload(keptHypotheses, trial, []);
|
|
389
|
-
if (Buffer.byteLength(trialMd, 'utf8') <= budgetBytes) {
|
|
390
|
-
keptClaims.push(unverifiedClaims[i]);
|
|
391
|
-
} else {
|
|
392
|
-
omissions.push({ id: `claim-${i + 1}`, reason: 'budget-cap-exceeded' });
|
|
393
|
-
}
|
|
833
|
+
if (keptClaims.length > 0) {
|
|
834
|
+
payload += `### Unverified Claims\n`;
|
|
835
|
+
for (const c of keptClaims) payload += `- ? ${c}\n`;
|
|
836
|
+
payload += '\n';
|
|
394
837
|
}
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
const trialMd = buildPayload(keptHypotheses, keptClaims, trial);
|
|
400
|
-
if (Buffer.byteLength(trialMd, 'utf8') <= budgetBytes) {
|
|
401
|
-
keptNarrative.push(narrative[i]);
|
|
402
|
-
} else {
|
|
403
|
-
omissions.push({ id: `narrative-${i + 1}`, reason: 'budget-cap-exceeded' });
|
|
404
|
-
}
|
|
838
|
+
if (keptNarrative.length > 0) {
|
|
839
|
+
payload += `### Background Narrative\n`;
|
|
840
|
+
for (const n of keptNarrative) payload += `- ${n}\n`;
|
|
841
|
+
payload += '\n';
|
|
405
842
|
}
|
|
406
843
|
|
|
407
|
-
const payload = buildPayload(keptHypotheses, keptClaims, keptNarrative);
|
|
408
844
|
const totalBytes = Buffer.byteLength(payload, 'utf8');
|
|
409
845
|
const optionalBytes = totalBytes - mandatoryBytes;
|
|
846
|
+
const omissions = fit.omissions.map((o ) => ({ id: o.id, reason: 'budget-cap-exceeded' }));
|
|
410
847
|
|
|
411
848
|
return {
|
|
412
849
|
taskId,
|
|
@@ -443,50 +880,474 @@ class ContextPackCompiler {
|
|
|
443
880
|
* @param {string} [options.objective]
|
|
444
881
|
* @param {boolean} [options.json=false]
|
|
445
882
|
* @param {string} [options.stateRoot]
|
|
883
|
+
* @param {string} [options.sourceRoot] the checkout the verb runs in (default stateRoot)
|
|
446
884
|
* @param {string} [options.slug] feature slug, when the task id is not the feature's own
|
|
885
|
+
* @param {string|null} [options.explicitSlug] the `--slug` the caller typed, if any (default `slug`).
|
|
886
|
+
* Only this selects a run for the stage-pack link: a branch-derived `slug` still keys the delivery
|
|
887
|
+
* store, but the branch name alone never picks a run (docs/specs/orchestrator-context-modes.md).
|
|
447
888
|
* @returns {number} exit code
|
|
448
889
|
*/
|
|
449
|
-
function handleContextPackCommand({
|
|
890
|
+
function handleContextPackCommand({
|
|
891
|
+
taskId,
|
|
892
|
+
taskClass = 'feature',
|
|
893
|
+
objective,
|
|
894
|
+
json = false,
|
|
895
|
+
stateRoot,
|
|
896
|
+
sourceRoot,
|
|
897
|
+
slug,
|
|
898
|
+
explicitSlug,
|
|
899
|
+
mandatoryFile,
|
|
900
|
+
harness = null,
|
|
901
|
+
maxBytes,
|
|
902
|
+
bare = false,
|
|
903
|
+
noRecord = false,
|
|
904
|
+
reason = null,
|
|
905
|
+
since = null,
|
|
906
|
+
expand = null,
|
|
907
|
+
profiles = null,
|
|
908
|
+
} = {}) {
|
|
450
909
|
const root = stateRoot || process.cwd();
|
|
910
|
+
// 115 IC-004/IC-007: records live under `root`; the feature folder, its plan and pointers, and the
|
|
911
|
+
// source files a delivery hashes are read in the checkout the verb runs in.
|
|
912
|
+
const source = sourceRoot || root;
|
|
913
|
+
const effectiveTaskClass = (!taskClass || typeof taskClass !== 'string' || taskClass.trim() === '') ? 'feature' : taskClass.trim();
|
|
914
|
+
|
|
915
|
+
// IC-001 Usage errors
|
|
916
|
+
if (!taskId || typeof taskId !== 'string' || taskId.trim() === '') {
|
|
917
|
+
return usageError('context-pack', '--task-id is required', json);
|
|
918
|
+
}
|
|
919
|
+
if (bare && expand) {
|
|
920
|
+
return usageError('context-pack', '--bare cannot be combined with --expand', json);
|
|
921
|
+
}
|
|
922
|
+
if (since && !/^sha256:[0-9a-f]{64}$/.test(since)) {
|
|
923
|
+
return usageError('context-pack', "--since must be 'sha256:' followed by 64 lowercase hex", json);
|
|
924
|
+
}
|
|
925
|
+
if (expand && (!since || !reason)) {
|
|
926
|
+
return usageError('context-pack', '--expand requires both --since and --reason', json);
|
|
927
|
+
}
|
|
928
|
+
if (harness) {
|
|
929
|
+
const validIds = getRegisteredHarnessIds();
|
|
930
|
+
if (!validIds.includes(harness)) {
|
|
931
|
+
return usageError('context-pack', `Unknown harness '${harness}'. Valid harnesses: ${validIds.join(', ')}`, json);
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
let parsedMaxBytes ;
|
|
936
|
+
let baseBudget = null;
|
|
937
|
+
if (maxBytes !== undefined && maxBytes !== null) {
|
|
938
|
+
const parsed = typeof maxBytes === 'number' ? maxBytes : parseInt(String(maxBytes).trim(), 10);
|
|
939
|
+
if (!Number.isInteger(parsed) || parsed <= 0 || (typeof maxBytes === 'string' && !/^[1-9]\d*$/.test(maxBytes.trim()))) {
|
|
940
|
+
return usageError('context-pack', '--max-bytes must be a positive integer', json);
|
|
941
|
+
}
|
|
942
|
+
parsedMaxBytes = parsed;
|
|
943
|
+
|
|
944
|
+
baseBudget = resolveBudget({ taskClass: effectiveTaskClass, harnessFlag: harness, profiles });
|
|
945
|
+
if (parsedMaxBytes > baseBudget.maxBytes && !reason) {
|
|
946
|
+
return usageError('context-pack', `--max-bytes (${parsedMaxBytes}) exceeds resolved budget (${baseBudget.maxBytes}) and requires --reason`, json);
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
const budget = resolveBudget({ taskClass: effectiveTaskClass, maxBytes: parsedMaxBytes, harnessFlag: harness, profiles });
|
|
951
|
+
|
|
952
|
+
const feature = resolveFeature({ projectRoot: source, slug: slug || null });
|
|
953
|
+
|
|
954
|
+
let deltaExpansions = [];
|
|
955
|
+
if (parsedMaxBytes !== undefined) {
|
|
956
|
+
if (!baseBudget) {
|
|
957
|
+
baseBudget = resolveBudget({ taskClass: effectiveTaskClass, harnessFlag: harness, profiles });
|
|
958
|
+
}
|
|
959
|
+
if (parsedMaxBytes > baseBudget.maxBytes) {
|
|
960
|
+
deltaExpansions.push({ at: new Date().toISOString(), kind: 'cap-raised', target: null, reason, bytesAdded: null });
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
const basis = resolveDeltaBasis({ root, source, taskId, slug, since: expand ? null : since, budget, profiles });
|
|
964
|
+
const { sinceEntry, deltaRefused, retention } = basis;
|
|
965
|
+
if (basis.expansion) deltaExpansions.push(basis.expansion);
|
|
966
|
+
|
|
967
|
+
if (expand) {
|
|
968
|
+
const prior = readDeliveryEntry({ projectRoot: root, taskId, slug, packDigest: since });
|
|
969
|
+
if (!prior) return usageError('context-pack', `Unknown digest '${since}'`, json);
|
|
970
|
+
const pointer = (prior.pointers || []).find((candidate ) => candidate.id === expand);
|
|
971
|
+
if (!pointer) return usageError('context-pack', `Unknown pointer '${expand}' in digest '${since}'`, json);
|
|
972
|
+
const current = pointerTools.readPointerSlice({ projectRoot: source, pointer });
|
|
973
|
+
if (!current) return usageError('context-pack', `Unknown pointer '${expand}' in digest '${since}'`, json);
|
|
974
|
+
const compiler = new ContextPackCompiler();
|
|
975
|
+
const pack = compiler.compileContextPack({ taskId, taskClass: effectiveTaskClass, objective: '', mandatory: { fields: {}, provenance: {} }, budget,
|
|
976
|
+
mode: 'expand', expansion: { id: expand, path: pointer.path, content: current.slice, targetChanged: current.digest !== pointer.digest } });
|
|
977
|
+
pack.status = 'OK';
|
|
978
|
+
pack.exitCode = EXIT.OK;
|
|
979
|
+
pack.mode = 'expand';
|
|
980
|
+
pack.delivery = { key: prior.key, packDigest: since, recorded: false, reason: noRecord ? 'no-record' : null,
|
|
981
|
+
since, deltaRefused: null, expansionRecorded: false };
|
|
982
|
+
pack.packEnd.mode = 'expand';
|
|
983
|
+
pack.packEnd.digest = since.slice(7, 19);
|
|
984
|
+
const sliceBytes = Buffer.byteLength(current.slice, 'utf8');
|
|
985
|
+
let output = '';
|
|
986
|
+
let emitted = 0;
|
|
987
|
+
for (let render = 0; render < 3; render += 1) {
|
|
988
|
+
output = json ? compiler.formatJson(pack, { throwOnOverBudget: false }) : compiler.formatMarkdown(pack, { throwOnOverBudget: false });
|
|
989
|
+
emitted = Buffer.byteLength(output, 'utf8');
|
|
990
|
+
const tokenValue = Math.ceil(emitted / 4);
|
|
991
|
+
if (pack.accounting.tokens?.estimated?.value === tokenValue) break;
|
|
992
|
+
pack.accounting.tokens = makeTokenRecord(emitted);
|
|
993
|
+
}
|
|
994
|
+
if (emitted > budget.maxBytes) {
|
|
995
|
+
return usageError('context-pack', `slice is ${emitted} B, over the ${budget.maxBytes} B cap (${budget.source}); re-run with --max-bytes ${emitted} --reason "${reason}"`, json);
|
|
996
|
+
}
|
|
997
|
+
let expansionRecorded = false;
|
|
998
|
+
let recordReason = noRecord ? 'no-record' : null;
|
|
999
|
+
if (!noRecord) {
|
|
1000
|
+
const expansionRecord = { at: new Date().toISOString(), kind: 'pointer-followed', target: expand, reason,
|
|
1001
|
+
bytesAdded: sliceBytes, targetChanged: current.digest !== pointer.digest };
|
|
1002
|
+
try {
|
|
1003
|
+
appendPointerExpansion({ projectRoot: root, taskId, slug, key: prior.key, expansion: expansionRecord });
|
|
1004
|
+
expansionRecorded = true;
|
|
1005
|
+
recordReason = null;
|
|
1006
|
+
} catch (error ) {
|
|
1007
|
+
recordReason = error?.code === 'entry-evicted' ? 'entry-evicted' : classifyStoreFailure(error);
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
pack.delivery.recorded = expansionRecorded;
|
|
1011
|
+
pack.delivery.reason = recordReason;
|
|
1012
|
+
pack.delivery.expansionRecorded = expansionRecorded;
|
|
1013
|
+
pack.expansionRecorded = expansionRecorded;
|
|
1014
|
+
for (let render = 0; render < 3; render += 1) {
|
|
1015
|
+
output = json ? compiler.formatJson(pack, { throwOnOverBudget: false }) : compiler.formatMarkdown(pack, { throwOnOverBudget: false });
|
|
1016
|
+
emitted = Buffer.byteLength(output, 'utf8');
|
|
1017
|
+
const tokenValue = Math.ceil(emitted / 4);
|
|
1018
|
+
if (pack.accounting.tokens?.estimated?.value === tokenValue) break;
|
|
1019
|
+
pack.accounting.tokens = makeTokenRecord(emitted);
|
|
1020
|
+
}
|
|
1021
|
+
if (console.log !== nativeConsoleLog) console.log(output);
|
|
1022
|
+
else process.stdout.write(output);
|
|
1023
|
+
return finishRuntime(EXIT.OK);
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
let mandatory = gatherMandatory({ root: source, taskId, feature });
|
|
1027
|
+
|
|
1028
|
+
if (mandatoryFile) {
|
|
1029
|
+
try {
|
|
1030
|
+
let fileContent ;
|
|
1031
|
+
if (mandatoryFile === '-') {
|
|
1032
|
+
fileContent = fs.readFileSync(0, 'utf8');
|
|
1033
|
+
} else {
|
|
1034
|
+
if (!fs.existsSync(mandatoryFile)) {
|
|
1035
|
+
const err = new Error(`--mandatory-file '${mandatoryFile}' does not exist`);
|
|
1036
|
+
err.code = 'USAGE_ERROR';
|
|
1037
|
+
throw err;
|
|
1038
|
+
}
|
|
1039
|
+
fileContent = fs.readFileSync(mandatoryFile, 'utf8');
|
|
1040
|
+
}
|
|
1041
|
+
const override = parseMandatoryFile(fileContent, mandatoryFile);
|
|
1042
|
+
mandatory = applyMandatoryOverride(mandatory, override);
|
|
1043
|
+
} catch (err ) {
|
|
1044
|
+
return usageError('context-pack', err.message, json, err);
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
const { pack, output } = deliverPack({
|
|
1049
|
+
root, source, taskId, slug, effectiveTaskClass, objective, mandatory, budget, harness, parsedMaxBytes, bare, noRecord,
|
|
1050
|
+
json, reason, since, sinceEntry, deltaRefused, deltaExpansions, expand, retention, feature,
|
|
1051
|
+
});
|
|
1052
|
+
// Issue #9 stage 3: a recorded delivery is named on the run stage active now (best effort, never fails the verb).
|
|
1053
|
+
if (pack.delivery?.recorded === true) {
|
|
1054
|
+
try {
|
|
1055
|
+
require('./workflow-orchestrator.js').recordStagePack({ stateRoot: root, sourceRoot: source, taskId, slug: (explicitSlug === undefined ? slug : explicitSlug) || null, digest: pack.delivery.packDigest,
|
|
1056
|
+
checkout: !feature.error && feature.paths?.repo_root ? { repoRoot: feature.paths.repo_root, branch: feature.paths.branch || null } : null });
|
|
1057
|
+
} catch { /* an unrecorded link is unknown, not a failure */ }
|
|
1058
|
+
}
|
|
1059
|
+
if (console.log !== nativeConsoleLog) {
|
|
1060
|
+
console.log(output);
|
|
1061
|
+
} else {
|
|
1062
|
+
process.stdout.write(output);
|
|
1063
|
+
}
|
|
1064
|
+
return finishRuntime(pack.exitCode);
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
/**
|
|
1068
|
+
* The context-pack verb's compile, fit, render and delivery-record steps for a full or delta pack,
|
|
1069
|
+
* with no output: `handleContextPackCommand()` prints the result and `packForEmission()` hands it
|
|
1070
|
+
* to `emitContext()`. Returns the final pack and its rendered text in the requested form.
|
|
1071
|
+
*/
|
|
1072
|
+
function deliverPack({
|
|
1073
|
+
root, source = root, taskId, slug, effectiveTaskClass, objective, mandatory, budget, harness, parsedMaxBytes, bare, noRecord,
|
|
1074
|
+
json, reason, since, sinceEntry, deltaRefused, deltaExpansions, expand, retention, feature,
|
|
1075
|
+
} ) {
|
|
451
1076
|
const ledger = new EvidenceLedger({ repoRoot: root, slug });
|
|
452
1077
|
ledger.load(taskId);
|
|
453
1078
|
const claims = new ClaimsManager({ evidenceLedger: ledger, repoRoot: root, slug });
|
|
454
1079
|
claims.load(taskId);
|
|
455
1080
|
claims.evaluateAll();
|
|
1081
|
+
|
|
456
1082
|
const researchRequests = new ResearchRequestStore({ projectRoot: root, slug }).list(taskId);
|
|
457
1083
|
|
|
458
1084
|
const compiler = new ContextPackCompiler();
|
|
459
|
-
|
|
1085
|
+
let pack = compiler.compileContextPack({
|
|
460
1086
|
taskId,
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
1087
|
+
taskClass: effectiveTaskClass,
|
|
1088
|
+
objective: objective !== undefined && objective !== null ? objective : undefined,
|
|
1089
|
+
mandatory,
|
|
1090
|
+
budget,
|
|
1091
|
+
harness,
|
|
1092
|
+
maxBytes: parsedMaxBytes,
|
|
1093
|
+
bare,
|
|
1094
|
+
noRecord,
|
|
1095
|
+
recordingExpected: !noRecord,
|
|
1096
|
+
form: json ? 'json' : 'markdown',
|
|
1097
|
+
reason,
|
|
1098
|
+
since,
|
|
1099
|
+
mode: since && !deltaRefused && !expand ? 'delta' : undefined,
|
|
1100
|
+
deltaSinceEntry: since && !deltaRefused && !expand ? sinceEntry : null,
|
|
1101
|
+
deltaRefused,
|
|
1102
|
+
expand,
|
|
1103
|
+
pointers: pointerTools.collectPointers({ projectRoot: source, feature }),
|
|
466
1104
|
evidenceLedger: ledger,
|
|
467
1105
|
claimsManager: claims,
|
|
468
1106
|
researchRequests,
|
|
469
|
-
decisions: loadLiveDecisions({ projectRoot:
|
|
1107
|
+
decisions: loadLiveDecisions({ projectRoot: source, slug: slug || null }),
|
|
470
1108
|
});
|
|
471
1109
|
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
1110
|
+
let deliverySources = null;
|
|
1111
|
+
let deliveryRetention = null;
|
|
1112
|
+
const form = json ? 'json' : 'markdown';
|
|
1113
|
+
let deliveryRecorded = !noRecord;
|
|
1114
|
+
let deliveryReason = noRecord ? 'no-record' : null;
|
|
1115
|
+
pack.delivery.recorded = deliveryRecorded;
|
|
1116
|
+
pack.delivery.reason = deliveryReason;
|
|
1117
|
+
pack.delivery.key = noRecord ? null : `${pack.delivery.packDigest}.${form}.${budget.harness?.id || 'unstated'}`;
|
|
1118
|
+
pack.omissions = pack.mode === 'bare' ? pack.omissions : compose.groupOmissions(pack.deliveryOmissions, !noRecord);
|
|
1119
|
+
if (pack.status === 'OVERFLOW') {
|
|
1120
|
+
pack = { ...pack, deliveryOmissions: pack.deliveryOmissions.map((item ) => item.reason === 'budget' ? { ...item, reason: 'mandatory-overflow' } : item) };
|
|
1121
|
+
pack.omissions = pack.mode === 'bare' ? pack.omissions : compose.groupOmissions(pack.deliveryOmissions, !noRecord);
|
|
1122
|
+
}
|
|
1123
|
+
if (!noRecord) {
|
|
1124
|
+
deliverySources = hashSourceFiles(source, pack.relevantFiles || []);
|
|
1125
|
+
deliveryRetention = retention?.value === 'supported' || retention?.value === 'unsupported'
|
|
1126
|
+
? { status: retention.value, basis: `declared:${retention.source || 'profile'}` }
|
|
1127
|
+
: { status: 'unknown', basis: retention?.unverified || 'contextProfile.retention is unverified' };
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
const renderTrimmed = () => {
|
|
1131
|
+
while (true) {
|
|
1132
|
+
let mdOutput = '';
|
|
1133
|
+
let jsonOutput = '';
|
|
1134
|
+
let mdBytes = 0;
|
|
1135
|
+
let jsonBytes = 0;
|
|
1136
|
+
let stable = false;
|
|
1137
|
+
for (let render = 0; render < 3; render += 1) {
|
|
1138
|
+
mdOutput = compiler.formatMarkdown(pack, { throwOnOverBudget: false });
|
|
1139
|
+
jsonOutput = compiler.formatJson(pack, { throwOnOverBudget: false });
|
|
1140
|
+
mdBytes = Buffer.byteLength(mdOutput, 'utf8');
|
|
1141
|
+
jsonBytes = Buffer.byteLength(jsonOutput, 'utf8');
|
|
1142
|
+
const emitted = json ? jsonBytes : mdBytes;
|
|
1143
|
+
const priorBytes = pack.size.totalBytes;
|
|
1144
|
+
const priorOptionalBytes = pack.size.optionalBytes;
|
|
1145
|
+
const tokens = makeTokenRecord(emitted);
|
|
1146
|
+
const priorValue = pack.accounting.tokens?.estimated?.value;
|
|
1147
|
+
pack.size.totalBytes = emitted;
|
|
1148
|
+
pack.size.optionalBytes = emitted - pack.size.mandatoryBytes;
|
|
1149
|
+
pack.accounting.tokens = tokens;
|
|
1150
|
+
if (priorValue === tokens.estimated.value && priorBytes === emitted && priorOptionalBytes === pack.size.optionalBytes) { stable = true; break; }
|
|
1151
|
+
}
|
|
1152
|
+
if (!stable) {
|
|
1153
|
+
mdOutput = compiler.formatMarkdown(pack, { throwOnOverBudget: false });
|
|
1154
|
+
jsonOutput = compiler.formatJson(pack, { throwOnOverBudget: false });
|
|
1155
|
+
mdBytes = Buffer.byteLength(mdOutput, 'utf8');
|
|
1156
|
+
jsonBytes = Buffer.byteLength(jsonOutput, 'utf8');
|
|
1157
|
+
pack.size.totalBytes = json ? jsonBytes : mdBytes;
|
|
1158
|
+
pack.size.optionalBytes = pack.size.totalBytes - pack.size.mandatoryBytes;
|
|
1159
|
+
pack.accounting.tokens = makeTokenRecord(pack.size.totalBytes);
|
|
1160
|
+
}
|
|
1161
|
+
if (pack.status !== 'OK' || (mdBytes <= budget.maxBytes && jsonBytes <= budget.maxBytes)) {
|
|
1162
|
+
const output = json ? jsonOutput : mdOutput;
|
|
1163
|
+
const bytes = json ? jsonBytes : mdBytes;
|
|
1164
|
+
pack.packEnd.bytes = bytes;
|
|
1165
|
+
pack.size.totalBytes = bytes;
|
|
1166
|
+
pack.size.optionalBytes = bytes - pack.size.mandatoryBytes;
|
|
1167
|
+
pack.accounting.tokens = makeTokenRecord(bytes);
|
|
1168
|
+
return { output, bytes };
|
|
1169
|
+
}
|
|
1170
|
+
const trimmed = (pack ).trimOptional?.();
|
|
1171
|
+
if (trimmed) {
|
|
1172
|
+
pack = trimmed;
|
|
1173
|
+
pack.delivery.recorded = deliveryRecorded;
|
|
1174
|
+
pack.delivery.reason = deliveryReason;
|
|
1175
|
+
pack.delivery.key = deliveryRecorded ? `${pack.delivery.packDigest}.${form}.${budget.harness?.id || 'unstated'}` : null;
|
|
1176
|
+
pack.accounting.tokens = makeTokenRecord(json ? jsonBytes : mdBytes);
|
|
1177
|
+
pack.omissions = pack.mode === 'bare' ? pack.omissions : compose.groupOmissions(pack.deliveryOmissions, !noRecord);
|
|
1178
|
+
continue;
|
|
1179
|
+
}
|
|
1180
|
+
const cause = pack.size.mandatoryBytes > budget.maxBytes ? 'mandatory' : 'accounting';
|
|
1181
|
+
pack.status = 'OVERFLOW';
|
|
1182
|
+
pack.exitCode = EXIT.OVERFLOW;
|
|
1183
|
+
if (cause === 'mandatory') {
|
|
1184
|
+
pack = { ...pack, deliveryOmissions: pack.deliveryOmissions.map((item ) => item.reason === 'budget' ? { ...item, reason: 'mandatory-overflow' } : item) };
|
|
1185
|
+
pack.omissions = pack.mode === 'bare' ? pack.omissions : compose.groupOmissions(pack.deliveryOmissions, !noRecord);
|
|
1186
|
+
}
|
|
1187
|
+
pack.overflow = { cause, mandatoryBytes: pack.size.mandatoryBytes, budgetBytes: budget.maxBytes,
|
|
1188
|
+
excessBytes: Math.max(0, Math.max(mdBytes, jsonBytes) - budget.maxBytes), action: 'split-or-new-session' };
|
|
1189
|
+
pack.overflowAction = { message: cause === 'accounting'
|
|
1190
|
+
? `The omission record brings the pack to ${Math.max(mdBytes, jsonBytes)} B against a ${budget.maxBytes} B budget.`
|
|
1191
|
+
: `It is ${pack.size.mandatoryBytes} B against a ${budget.maxBytes} B budget (${budget.source}).` };
|
|
1192
|
+
let output = '';
|
|
1193
|
+
let bytes = 0;
|
|
1194
|
+
for (let render = 0; render < 3; render += 1) {
|
|
1195
|
+
output = json ? compiler.formatJson(pack, { throwOnOverBudget: false }) : compiler.formatMarkdown(pack, { throwOnOverBudget: false });
|
|
1196
|
+
bytes = Buffer.byteLength(output, 'utf8');
|
|
1197
|
+
const tokenValue = Math.ceil(bytes / 4);
|
|
1198
|
+
if (pack.accounting.tokens?.estimated?.value === tokenValue) break;
|
|
1199
|
+
pack.accounting.tokens = makeTokenRecord(bytes);
|
|
1200
|
+
}
|
|
1201
|
+
pack.packEnd.bytes = bytes;
|
|
1202
|
+
pack.size.totalBytes = bytes;
|
|
1203
|
+
return { output, bytes };
|
|
1204
|
+
}
|
|
1205
|
+
};
|
|
1206
|
+
let rendered = renderTrimmed();
|
|
1207
|
+
let output = rendered.output;
|
|
1208
|
+
let emittedBytes = rendered.bytes;
|
|
1209
|
+
if (!noRecord) {
|
|
1210
|
+
const entry = createDeliveryEntry({ pack: { ...pack, deliveryOmissions: pack.deliveryOmissions }, form, harness: budget.harness?.id || null,
|
|
1211
|
+
sources: deliverySources, expansions: deltaExpansions, retention: deliveryRetention });
|
|
1212
|
+
entry.bytes = emittedBytes;
|
|
1213
|
+
entry.tokens = makeTokenRecord(emittedBytes);
|
|
1214
|
+
try {
|
|
1215
|
+
const result = recordDelivery({ projectRoot: root, taskId, slug, entry, acquire: boundedAcquire });
|
|
1216
|
+
pack.delivery.key = result?.key || entry.key;
|
|
1217
|
+
deliveryRecorded = true;
|
|
1218
|
+
deliveryReason = null;
|
|
1219
|
+
pack.delivery.recorded = deliveryRecorded;
|
|
1220
|
+
pack.delivery.reason = deliveryReason;
|
|
1221
|
+
} catch (error ) {
|
|
1222
|
+
deliveryRecorded = false;
|
|
1223
|
+
deliveryReason = classifyStoreFailure(error);
|
|
1224
|
+
pack.delivery.key = null;
|
|
1225
|
+
pack.delivery.recorded = deliveryRecorded;
|
|
1226
|
+
pack.delivery.reason = deliveryReason;
|
|
1227
|
+
}
|
|
1228
|
+
pack.omissions = pack.mode === 'bare' ? pack.omissions : compose.groupOmissions(pack.deliveryOmissions, pack.delivery.recorded);
|
|
1229
|
+
rendered = renderTrimmed();
|
|
1230
|
+
output = rendered.output;
|
|
1231
|
+
emittedBytes = rendered.bytes;
|
|
1232
|
+
}
|
|
1233
|
+
if (pack.status === 'OVERFLOW') {
|
|
1234
|
+
pack.overflow.excessBytes = Math.max(0, emittedBytes - budget.maxBytes);
|
|
1235
|
+
pack.overflowAction.message = formatOverflowMessage({
|
|
1236
|
+
cause: pack.overflow.cause,
|
|
1237
|
+
mandatoryBytes: pack.size.mandatoryBytes,
|
|
1238
|
+
totalBytes: emittedBytes,
|
|
1239
|
+
budgetBytes: budget.maxBytes,
|
|
1240
|
+
source: budget.source,
|
|
1241
|
+
});
|
|
1242
|
+
rendered = renderTrimmed();
|
|
1243
|
+
output = rendered.output;
|
|
1244
|
+
emittedBytes = rendered.bytes;
|
|
1245
|
+
pack.packEnd.bytes = emittedBytes;
|
|
1246
|
+
pack.size.totalBytes = emittedBytes;
|
|
1247
|
+
}
|
|
1248
|
+
return { pack, output };
|
|
1249
|
+
}
|
|
1250
|
+
|
|
1251
|
+
/** The delta basis of a `since` digest: its delivery entry, or why a delta was refused (widened to full). */
|
|
1252
|
+
function resolveDeltaBasis({ root, source = root, taskId, slug, since, budget, profiles } ) {
|
|
1253
|
+
const retention = profileRetention(budget.harness?.id || null, profiles);
|
|
1254
|
+
let sinceEntry = null;
|
|
1255
|
+
let deltaRefused = null;
|
|
1256
|
+
let expansion = null;
|
|
1257
|
+
if (since) {
|
|
1258
|
+
sinceEntry = readDeliveryEntry({ projectRoot: root, taskId, slug, packDigest: since });
|
|
1259
|
+
if (!sinceEntry) deltaRefused = 'since-unknown';
|
|
1260
|
+
else if (sourcesChanged(source, sinceEntry.sources || {})) deltaRefused = 'sources-changed';
|
|
1261
|
+
else if (!budget.harness?.id) deltaRefused = 'harness-unstated';
|
|
1262
|
+
else if (retention?.value !== 'supported') deltaRefused = 'retention-unproven';
|
|
1263
|
+
if (deltaRefused) {
|
|
1264
|
+
expansion = { at: new Date().toISOString(), kind: 'delta-widened', target: null, reason: deltaRefused, bytesAdded: null };
|
|
1265
|
+
}
|
|
483
1266
|
}
|
|
484
|
-
return
|
|
1267
|
+
return { sinceEntry, deltaRefused, retention, expansion };
|
|
1268
|
+
}
|
|
1269
|
+
|
|
1270
|
+
/** The mandatory fields of a task from its feature's requirement.md and the task's plan stories. */
|
|
1271
|
+
function gatherMandatory({ root, taskId, feature } ) {
|
|
1272
|
+
let reqText = null;
|
|
1273
|
+
let reqPath = 'requirement.md';
|
|
1274
|
+
if (!feature.error && feature.featureDir) {
|
|
1275
|
+
reqPath = feature.paths?.requirement
|
|
1276
|
+
? path.resolve(feature.repoRoot || root, feature.paths.requirement)
|
|
1277
|
+
: path.join(feature.featureDir, 'intention', 'requirement.md');
|
|
1278
|
+
try {
|
|
1279
|
+
if (fs.existsSync(reqPath)) {
|
|
1280
|
+
reqText = fs.readFileSync(reqPath, 'utf8');
|
|
1281
|
+
}
|
|
1282
|
+
} catch {
|
|
1283
|
+
reqText = null;
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
let taskStories = [];
|
|
1288
|
+
if (!feature.error && feature.featureDir && taskId) {
|
|
1289
|
+
let planPath = null;
|
|
1290
|
+
if (feature.paths?.plan) {
|
|
1291
|
+
planPath = path.resolve(feature.repoRoot || root, feature.paths.plan);
|
|
1292
|
+
} else {
|
|
1293
|
+
const nestedPlan = path.join(feature.featureDir, 'plan', 'plan.md');
|
|
1294
|
+
const flatPlan = path.join(feature.featureDir, 'plan.md');
|
|
1295
|
+
if (fs.existsSync(nestedPlan)) planPath = nestedPlan;
|
|
1296
|
+
else if (fs.existsSync(flatPlan)) planPath = flatPlan;
|
|
1297
|
+
}
|
|
1298
|
+
if (planPath && fs.existsSync(planPath)) {
|
|
1299
|
+
try {
|
|
1300
|
+
const planText = fs.readFileSync(planPath, 'utf8');
|
|
1301
|
+
const { parsePlan } = require('./scaffold/artifacts.js');
|
|
1302
|
+
const parsedPlan = parsePlan(planText);
|
|
1303
|
+
const matchedTask = (parsedPlan.tasks || []).find(
|
|
1304
|
+
(t ) => t.id === taskId || t.id.toLowerCase() === taskId.toLowerCase()
|
|
1305
|
+
);
|
|
1306
|
+
if (matchedTask && Array.isArray(matchedTask.stories)) {
|
|
1307
|
+
taskStories = matchedTask.stories;
|
|
1308
|
+
}
|
|
1309
|
+
} catch {
|
|
1310
|
+
taskStories = [];
|
|
1311
|
+
}
|
|
1312
|
+
}
|
|
1313
|
+
}
|
|
1314
|
+
|
|
1315
|
+
return extractMandatory({
|
|
1316
|
+
text: reqText,
|
|
1317
|
+
path: reqPath,
|
|
1318
|
+
featureError: feature.error ? (feature.message || feature.error) : null,
|
|
1319
|
+
taskStories,
|
|
1320
|
+
});
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1323
|
+
/**
|
|
1324
|
+
* 078 IC-001: the context pack `emitContext()` delivers on `launch` and `delta`, compiled by
|
|
1325
|
+
* compileContextPack() through the verb's own steps, with `maxBytes` as the budget and `since` the
|
|
1326
|
+
* unit's last delivered pack digest (a delta when its entry qualifies, else widened to full).
|
|
1327
|
+
* `noRecord` (peek) leaves the delivery store untouched. Rendered as markdown.
|
|
1328
|
+
*/
|
|
1329
|
+
function packForEmission({ root, stateRoot = root, taskId = 'default', taskClass = 'feature', slug = null, harness = null, maxBytes, since = null, noRecord = false, env = process.env } ) {
|
|
1330
|
+
const budget = resolveBudget({ taskClass, maxBytes, harnessFlag: harness, env });
|
|
1331
|
+
const feature = resolveFeature({ projectRoot: root, slug: slug || null });
|
|
1332
|
+
// 115 C-2: the delivery record goes where `context-pack` puts it, under the state root; the feature
|
|
1333
|
+
// folder, the plan and the hashed source files are read in `root`, the checkout emitting.
|
|
1334
|
+
const basis = resolveDeltaBasis({ root: stateRoot, source: root, taskId, slug, since, budget, profiles: null });
|
|
1335
|
+
return deliverPack({
|
|
1336
|
+
root: stateRoot, source: root, taskId, slug, effectiveTaskClass: taskClass, objective: undefined, mandatory: gatherMandatory({ root, taskId, feature }),
|
|
1337
|
+
budget, harness, parsedMaxBytes: maxBytes, bare: false, noRecord, json: false, reason: null, since,
|
|
1338
|
+
sinceEntry: basis.sinceEntry, deltaRefused: basis.deltaRefused, deltaExpansions: basis.expansion ? [basis.expansion] : [],
|
|
1339
|
+
expand: null, retention: basis.retention, feature,
|
|
1340
|
+
});
|
|
485
1341
|
}
|
|
486
1342
|
|
|
487
1343
|
module.exports = {
|
|
1344
|
+
classifyStoreFailure,
|
|
488
1345
|
ContextPackCompiler,
|
|
1346
|
+
arbitrate,
|
|
1347
|
+
emitContext,
|
|
489
1348
|
TASK_CLASS_BUDGETS,
|
|
490
1349
|
handleContextPackCommand,
|
|
491
1350
|
loadLiveDecisions,
|
|
1351
|
+
packForEmission,
|
|
1352
|
+
getCorrectiveTrimFallbackCount,
|
|
492
1353
|
};
|