harnery 0.32.0 → 0.34.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 +2 -0
- package/dist/commander.d.ts.map +1 -1
- package/dist/commander.js +7 -1
- package/dist/commands/adapter.js +2 -2
- package/dist/commands/agents.d.ts +144 -1
- package/dist/commands/agents.d.ts.map +1 -1
- package/dist/commands/agents.js +1408 -565
- package/dist/commands/artifacts.d.ts.map +1 -1
- package/dist/commands/artifacts.js +7 -6
- package/dist/commands/backup.d.ts +1 -1
- package/dist/commands/backup.d.ts.map +1 -1
- package/dist/commands/backup.js +29 -16
- package/dist/commands/browse.d.ts.map +1 -1
- package/dist/commands/browse.js +234 -12
- package/dist/commands/checkpoint.d.ts.map +1 -1
- package/dist/commands/checkpoint.js +3 -2
- package/dist/commands/claude-desktop.d.ts +2 -2
- package/dist/commands/claude-desktop.d.ts.map +1 -1
- package/dist/commands/claude-desktop.js +2 -2
- package/dist/commands/context.js +1 -6
- package/dist/commands/decision.d.ts.map +1 -1
- package/dist/commands/decision.js +22 -38
- package/dist/commands/docs.d.ts.map +1 -1
- package/dist/commands/docs.js +91 -28
- package/dist/commands/doctor.d.ts +4 -2
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +55 -7
- package/dist/commands/events.d.ts +5 -0
- package/dist/commands/events.d.ts.map +1 -0
- package/dist/commands/events.js +189 -0
- package/dist/commands/governor.d.ts.map +1 -1
- package/dist/commands/governor.js +13 -4
- package/dist/commands/init.d.ts +10 -2
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +233 -51
- package/dist/commands/instructions.d.ts +4 -0
- package/dist/commands/instructions.d.ts.map +1 -0
- package/dist/commands/instructions.js +100 -0
- package/dist/commands/journal.d.ts.map +1 -1
- package/dist/commands/journal.js +4 -13
- package/dist/commands/ledger-v3.d.ts +5 -0
- package/dist/commands/ledger-v3.d.ts.map +1 -0
- package/dist/commands/ledger-v3.js +91 -0
- package/dist/commands/presence.d.ts.map +1 -1
- package/dist/commands/presence.js +15 -6
- package/dist/commands/sync.d.ts +1 -1
- package/dist/commands/sync.js +1 -1
- package/dist/commands/web.d.ts +6 -0
- package/dist/commands/web.d.ts.map +1 -1
- package/dist/commands/web.js +67 -7
- package/dist/commands/work.d.ts.map +1 -1
- package/dist/commands/work.js +22 -5
- package/dist/core/adapter.d.ts +5 -0
- package/dist/core/adapter.d.ts.map +1 -0
- package/dist/core/adapter.js +1 -0
- package/dist/core/adapters/attest.d.ts +5 -2
- package/dist/core/adapters/attest.d.ts.map +1 -1
- package/dist/core/adapters/attest.js +8 -3
- package/dist/core/adapters/profiles.d.ts +6 -6
- package/dist/core/adapters/profiles.d.ts.map +1 -1
- package/dist/core/adapters/profiles.js +4 -4
- package/dist/core/agents/canonical-emit.d.ts +17 -15
- package/dist/core/agents/canonical-emit.d.ts.map +1 -1
- package/dist/core/agents/canonical-emit.js +27 -25
- package/dist/core/agents/cli.js +212 -235
- package/dist/core/agents/codex-archive-v3.d.ts +14 -0
- package/dist/core/agents/codex-archive-v3.d.ts.map +1 -0
- package/dist/core/agents/codex-archive-v3.js +110 -0
- package/dist/core/agents/coord-client.d.ts +19 -70
- package/dist/core/agents/coord-client.d.ts.map +1 -1
- package/dist/core/agents/coord-client.js +65 -155
- package/dist/core/agents/finalization.d.ts +4 -1
- package/dist/core/agents/finalization.d.ts.map +1 -1
- package/dist/core/agents/finalization.js +89 -32
- package/dist/core/agents/index.d.ts +5 -5
- package/dist/core/agents/index.d.ts.map +1 -1
- package/dist/core/agents/index.js +5 -5
- package/dist/core/agents/live-authority-v3.d.ts +59 -0
- package/dist/core/agents/live-authority-v3.d.ts.map +1 -0
- package/dist/core/agents/live-authority-v3.js +233 -0
- package/dist/core/agents/live-lifecycle-v3.d.ts +20 -0
- package/dist/core/agents/live-lifecycle-v3.d.ts.map +1 -0
- package/dist/core/agents/live-lifecycle-v3.js +91 -0
- package/dist/core/agents/live-observation-v3.d.ts +25 -0
- package/dist/core/agents/live-observation-v3.d.ts.map +1 -0
- package/dist/core/agents/live-observation-v3.js +157 -0
- package/dist/core/agents/render/prompt-context.d.ts +10 -4
- package/dist/core/agents/render/prompt-context.d.ts.map +1 -1
- package/dist/core/agents/render/prompt-context.js +61 -55
- package/dist/core/agents/render/session-context.d.ts +1 -1
- package/dist/core/agents/render/session-context.d.ts.map +1 -1
- package/dist/core/agents/render/session-context.js +15 -33
- package/dist/core/agents/rules/claim-conflict.d.ts +3 -3
- package/dist/core/agents/rules/claim-conflict.d.ts.map +1 -1
- package/dist/core/agents/rules/claim-conflict.js +79 -127
- package/dist/core/agents/rules/commit-conflict.d.ts.map +1 -1
- package/dist/core/agents/rules/commit-conflict.js +3 -18
- package/dist/core/agents/rules/stop-hook.d.ts +9 -50
- package/dist/core/agents/rules/stop-hook.d.ts.map +1 -1
- package/dist/core/agents/rules/stop-hook.js +193 -236
- package/dist/core/agents/session-events.d.ts +5 -7
- package/dist/core/agents/session-events.d.ts.map +1 -1
- package/dist/core/agents/session-events.js +127 -95
- package/dist/core/agents/session-finalization-state-v3.d.ts +30 -0
- package/dist/core/agents/session-finalization-state-v3.d.ts.map +1 -0
- package/dist/core/agents/session-finalization-state-v3.js +40 -0
- package/dist/core/agents/session-finalizer-v3.d.ts +107 -0
- package/dist/core/agents/session-finalizer-v3.d.ts.map +1 -0
- package/dist/core/agents/session-finalizer-v3.js +734 -0
- package/dist/core/agents/session-name-display.d.ts +40 -0
- package/dist/core/agents/session-name-display.d.ts.map +1 -0
- package/dist/core/agents/session-name-display.js +119 -0
- package/dist/core/agents/state/activity-log.d.ts +3 -3
- package/dist/core/agents/state/activity-log.d.ts.map +1 -1
- package/dist/core/agents/state/activity-log.js +7 -16
- package/dist/core/agents/state/heartbeat-writer.d.ts +29 -46
- package/dist/core/agents/state/heartbeat-writer.d.ts.map +1 -1
- package/dist/core/agents/state/heartbeat-writer.js +59 -199
- package/dist/core/agents/state/live-coordination-view.d.ts +31 -0
- package/dist/core/agents/state/live-coordination-view.d.ts.map +1 -0
- package/dist/core/agents/state/live-coordination-view.js +209 -0
- package/dist/core/agents/state/session-state.d.ts +45 -0
- package/dist/core/agents/state/session-state.d.ts.map +1 -0
- package/dist/core/agents/state/session-state.js +90 -0
- package/dist/core/agents/state/stale-sweep.d.ts +1 -1
- package/dist/core/agents/state/stale-sweep.d.ts.map +1 -1
- package/dist/core/agents/state/stale-sweep.js +26 -15
- package/dist/core/artifacts/index.d.ts.map +1 -1
- package/dist/core/artifacts/index.js +5 -7
- package/dist/core/config.d.ts +33 -2
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +98 -2
- package/dist/core/context/index.d.ts +1 -4
- package/dist/core/context/index.d.ts.map +1 -1
- package/dist/core/context/index.js +9 -9
- package/dist/core/events/span-parent.d.ts +15 -0
- package/dist/core/events/span-parent.d.ts.map +1 -0
- package/dist/core/events/span-parent.js +34 -0
- package/dist/core/events/v3/advance.d.ts +14 -0
- package/dist/core/events/v3/advance.d.ts.map +1 -0
- package/dist/core/events/v3/advance.js +134 -0
- package/dist/core/events/v3/authority-outbox.d.ts +78 -0
- package/dist/core/events/v3/authority-outbox.d.ts.map +1 -0
- package/dist/core/events/v3/authority-outbox.js +399 -0
- package/dist/core/events/v3/base-builder.d.ts +20 -0
- package/dist/core/events/v3/base-builder.d.ts.map +1 -0
- package/dist/core/events/v3/base-builder.js +29 -0
- package/dist/core/events/v3/base-contract.d.ts +7576 -0
- package/dist/core/events/v3/base-contract.d.ts.map +1 -0
- package/dist/core/events/v3/base-contract.js +647 -0
- package/dist/core/events/v3/bootstrap.d.ts +34 -0
- package/dist/core/events/v3/bootstrap.d.ts.map +1 -0
- package/dist/core/events/v3/bootstrap.js +175 -0
- package/dist/core/events/v3/builder.d.ts +20 -0
- package/dist/core/events/v3/builder.d.ts.map +1 -0
- package/dist/core/events/v3/builder.js +28 -0
- package/dist/core/events/v3/canonical.d.ts +31 -0
- package/dist/core/events/v3/canonical.d.ts.map +1 -0
- package/dist/core/events/v3/canonical.js +100 -0
- package/dist/core/events/v3/capabilities.d.ts +31 -0
- package/dist/core/events/v3/capabilities.d.ts.map +1 -0
- package/dist/core/events/v3/capabilities.js +107 -0
- package/dist/core/events/v3/capability-drift.d.ts +22 -0
- package/dist/core/events/v3/capability-drift.d.ts.map +1 -0
- package/dist/core/events/v3/capability-drift.js +134 -0
- package/dist/core/events/v3/catalog.d.ts +38 -0
- package/dist/core/events/v3/catalog.d.ts.map +1 -0
- package/dist/core/events/v3/catalog.js +135 -0
- package/dist/core/events/v3/clock-order.d.ts +34 -0
- package/dist/core/events/v3/clock-order.d.ts.map +1 -0
- package/dist/core/events/v3/clock-order.js +35 -0
- package/dist/core/events/v3/contract.d.ts +171 -0
- package/dist/core/events/v3/contract.d.ts.map +1 -0
- package/dist/core/events/v3/contract.js +180 -0
- package/dist/core/events/v3/control.d.ts +111 -0
- package/dist/core/events/v3/control.d.ts.map +1 -0
- package/dist/core/events/v3/control.js +419 -0
- package/dist/core/events/v3/coordination-view.d.ts +69 -0
- package/dist/core/events/v3/coordination-view.d.ts.map +1 -0
- package/dist/core/events/v3/coordination-view.js +119 -0
- package/dist/core/events/v3/economics.d.ts +77 -0
- package/dist/core/events/v3/economics.d.ts.map +1 -0
- package/dist/core/events/v3/economics.js +274 -0
- package/dist/core/events/v3/finalization-view.d.ts +26 -0
- package/dist/core/events/v3/finalization-view.d.ts.map +1 -0
- package/dist/core/events/v3/finalization-view.js +37 -0
- package/dist/core/events/v3/fingerprint-keys.d.ts +25 -0
- package/dist/core/events/v3/fingerprint-keys.d.ts.map +1 -0
- package/dist/core/events/v3/fingerprint-keys.js +217 -0
- package/dist/core/events/v3/generated.d.ts +4 -0
- package/dist/core/events/v3/generated.d.ts.map +1 -0
- package/dist/core/events/v3/generated.js +47 -0
- package/dist/core/events/v3/ids.d.ts +9 -0
- package/dist/core/events/v3/ids.d.ts.map +1 -0
- package/dist/core/events/v3/ids.js +25 -0
- package/dist/core/events/v3/index.d.ts +35 -0
- package/dist/core/events/v3/index.d.ts.map +1 -0
- package/dist/core/events/v3/index.js +33 -0
- package/dist/core/events/v3/latency.d.ts +63 -0
- package/dist/core/events/v3/latency.d.ts.map +1 -0
- package/dist/core/events/v3/latency.js +412 -0
- package/dist/core/events/v3/live-feed.d.ts +45 -0
- package/dist/core/events/v3/live-feed.d.ts.map +1 -0
- package/dist/core/events/v3/live-feed.js +246 -0
- package/dist/core/events/v3/live-observation.d.ts +35 -0
- package/dist/core/events/v3/live-observation.d.ts.map +1 -0
- package/dist/core/events/v3/live-observation.js +1 -0
- package/dist/core/events/v3/live-routing.d.ts +57 -0
- package/dist/core/events/v3/live-routing.d.ts.map +1 -0
- package/dist/core/events/v3/live-routing.js +107 -0
- package/dist/core/events/v3/producers/command-recorder.d.ts +67 -0
- package/dist/core/events/v3/producers/command-recorder.d.ts.map +1 -0
- package/dist/core/events/v3/producers/command-recorder.js +477 -0
- package/dist/core/events/v3/producers/command.d.ts +50 -0
- package/dist/core/events/v3/producers/command.d.ts.map +1 -0
- package/dist/core/events/v3/producers/command.js +135 -0
- package/dist/core/events/v3/producers/coordination-recorder.d.ts +53 -0
- package/dist/core/events/v3/producers/coordination-recorder.d.ts.map +1 -0
- package/dist/core/events/v3/producers/coordination-recorder.js +376 -0
- package/dist/core/events/v3/producers/coordination.d.ts +90 -0
- package/dist/core/events/v3/producers/coordination.d.ts.map +1 -0
- package/dist/core/events/v3/producers/coordination.js +229 -0
- package/dist/core/events/v3/producers/hook-base.d.ts +54 -0
- package/dist/core/events/v3/producers/hook-base.d.ts.map +1 -0
- package/dist/core/events/v3/producers/hook-base.js +424 -0
- package/dist/core/events/v3/producers/hook.d.ts +29 -0
- package/dist/core/events/v3/producers/hook.d.ts.map +1 -0
- package/dist/core/events/v3/producers/hook.js +71 -0
- package/dist/core/events/v3/producers/intake.d.ts +65 -0
- package/dist/core/events/v3/producers/intake.d.ts.map +1 -0
- package/dist/core/events/v3/producers/intake.js +244 -0
- package/dist/core/events/v3/producers/recorder.d.ts +240 -0
- package/dist/core/events/v3/producers/recorder.d.ts.map +1 -0
- package/dist/core/events/v3/producers/recorder.js +2176 -0
- package/dist/core/events/v3/projection.d.ts +101 -0
- package/dist/core/events/v3/projection.d.ts.map +1 -0
- package/dist/core/events/v3/projection.js +479 -0
- package/dist/core/events/v3/reader.d.ts +75 -0
- package/dist/core/events/v3/reader.d.ts.map +1 -0
- package/dist/core/events/v3/reader.js +778 -0
- package/dist/core/events/v3/recovery-record.d.ts +47 -0
- package/dist/core/events/v3/recovery-record.d.ts.map +1 -0
- package/dist/core/events/v3/recovery-record.js +167 -0
- package/dist/core/events/v3/recovery.d.ts +22 -0
- package/dist/core/events/v3/recovery.d.ts.map +1 -0
- package/dist/core/events/v3/recovery.js +227 -0
- package/dist/core/events/v3/span-state.d.ts +52 -0
- package/dist/core/events/v3/span-state.d.ts.map +1 -0
- package/dist/core/events/v3/span-state.js +142 -0
- package/dist/core/events/v3/targets.d.ts +23 -0
- package/dist/core/events/v3/targets.d.ts.map +1 -0
- package/dist/core/events/v3/targets.js +134 -0
- package/dist/core/events/v3/turn-telemetry.d.ts +41 -0
- package/dist/core/events/v3/turn-telemetry.d.ts.map +1 -0
- package/dist/core/events/v3/turn-telemetry.js +168 -0
- package/dist/core/events/v3/validate.d.ts +9 -0
- package/dist/core/events/v3/validate.d.ts.map +1 -0
- package/dist/core/events/v3/validate.js +281 -0
- package/dist/core/events/v3/writer.d.ts +56 -0
- package/dist/core/events/v3/writer.d.ts.map +1 -0
- package/dist/core/events/v3/writer.js +335 -0
- package/dist/core/governor/index.d.ts +1 -1
- package/dist/core/governor/index.d.ts.map +1 -1
- package/dist/core/governor/index.js +1 -1
- package/dist/core/governor/plan-api.d.ts +2 -1
- package/dist/core/governor/plan-api.d.ts.map +1 -1
- package/dist/core/governor/plan-api.js +6 -3
- package/dist/core/governor/read.d.ts +1 -1
- package/dist/core/governor/read.d.ts.map +1 -1
- package/dist/core/governor/read.js +1 -1
- package/dist/core/governor/state.d.ts +9 -0
- package/dist/core/governor/state.d.ts.map +1 -1
- package/dist/core/governor/state.js +40 -3
- package/dist/core/guard/config.d.ts +5 -0
- package/dist/core/guard/config.d.ts.map +1 -0
- package/dist/core/guard/config.js +157 -0
- package/dist/core/guard/coordinator.d.ts +14 -0
- package/dist/core/guard/coordinator.d.ts.map +1 -0
- package/dist/core/guard/coordinator.js +173 -0
- package/dist/core/guard/evaluator.d.ts +4 -0
- package/dist/core/guard/evaluator.d.ts.map +1 -0
- package/dist/core/guard/evaluator.js +242 -0
- package/dist/core/guard/evidence-v3.d.ts +15 -0
- package/dist/core/guard/evidence-v3.d.ts.map +1 -0
- package/dist/core/guard/evidence-v3.js +171 -0
- package/dist/core/guard/index.d.ts +10 -0
- package/dist/core/guard/index.d.ts.map +1 -0
- package/dist/core/guard/index.js +6 -0
- package/dist/core/guard/live-source-v3.d.ts +40 -0
- package/dist/core/guard/live-source-v3.d.ts.map +1 -0
- package/dist/core/guard/live-source-v3.js +128 -0
- package/dist/core/guard/storage.d.ts +27 -0
- package/dist/core/guard/storage.d.ts.map +1 -0
- package/dist/core/guard/storage.js +140 -0
- package/dist/core/guard/types.d.ts +119 -0
- package/dist/core/guard/types.d.ts.map +1 -0
- package/dist/core/guard/types.js +1 -0
- package/dist/core/hooks/adapter/detect.d.ts +18 -1
- package/dist/core/hooks/adapter/detect.d.ts.map +1 -1
- package/dist/core/hooks/adapter/detect.js +29 -0
- package/dist/core/hooks/adapter/events.d.ts +7 -4
- package/dist/core/hooks/adapter/events.d.ts.map +1 -1
- package/dist/core/hooks/adapter/events.js +13 -4
- package/dist/core/hooks/adapter/output.d.ts +2 -2
- package/dist/core/hooks/adapter/output.d.ts.map +1 -1
- package/dist/core/hooks/adapter/parse.d.ts +7 -4
- package/dist/core/hooks/adapter/parse.d.ts.map +1 -1
- package/dist/core/hooks/adapter/parse.js +64 -24
- package/dist/core/hooks/adapter/wiring.d.ts +30 -4
- package/dist/core/hooks/adapter/wiring.d.ts.map +1 -1
- package/dist/core/hooks/adapter/wiring.js +89 -11
- package/dist/core/hooks/cli.d.ts +1 -1
- package/dist/core/hooks/cli.js +345 -400
- package/dist/core/hooks/codex-authorization.d.ts +30 -0
- package/dist/core/hooks/codex-authorization.d.ts.map +1 -0
- package/dist/core/hooks/codex-authorization.js +199 -0
- package/dist/core/hooks/effects/image-capture.d.ts +20 -34
- package/dist/core/hooks/effects/image-capture.d.ts.map +1 -1
- package/dist/core/hooks/effects/image-capture.js +212 -221
- package/dist/core/hooks/effects/index.d.ts +1 -9
- package/dist/core/hooks/effects/index.d.ts.map +1 -1
- package/dist/core/hooks/effects/index.js +1 -24
- package/dist/core/hooks/events/input-hash.d.ts +7 -0
- package/dist/core/hooks/events/input-hash.d.ts.map +1 -0
- package/dist/core/hooks/events/input-hash.js +43 -0
- package/dist/core/hooks/index.d.ts +4 -3
- package/dist/core/hooks/index.d.ts.map +1 -1
- package/dist/core/hooks/index.js +2 -3
- package/dist/core/hooks/resolve/coord-root.d.ts +1 -1
- package/dist/core/hooks/resolve/coord-root.js +1 -1
- package/dist/core/hooks/resolve/owner.d.ts +16 -15
- package/dist/core/hooks/resolve/owner.d.ts.map +1 -1
- package/dist/core/hooks/resolve/owner.js +51 -42
- package/dist/core/hooks/resolve/transcript.d.ts +33 -3
- package/dist/core/hooks/resolve/transcript.d.ts.map +1 -1
- package/dist/core/hooks/resolve/transcript.js +155 -14
- package/dist/core/hooks/session-name-presence.d.ts +9 -10
- package/dist/core/hooks/session-name-presence.d.ts.map +1 -1
- package/dist/core/hooks/session-name-presence.js +15 -15
- package/dist/core/hooks/unsafe-cross-shell.d.ts +1 -1
- package/dist/core/hooks/unsafe-cross-shell.d.ts.map +1 -1
- package/dist/core/journal/index.d.ts +2 -2
- package/dist/core/journal/index.d.ts.map +1 -1
- package/dist/core/journal/index.js +9 -22
- package/dist/core/presence/blob.d.ts +8 -3
- package/dist/core/presence/blob.d.ts.map +1 -1
- package/dist/core/presence/blob.js +54 -41
- package/dist/core/presence/codec-digest.d.ts +29 -0
- package/dist/core/presence/codec-digest.d.ts.map +1 -0
- package/dist/core/presence/codec-digest.js +170 -0
- package/dist/core/presence/index.js +15 -1
- package/dist/core/presence/relay-client.d.ts +1 -1
- package/dist/core/presence/relay-client.d.ts.map +1 -1
- package/dist/core/presence/relay-client.js +5 -5
- package/dist/core/work/index.d.ts +1 -1
- package/dist/core/work/index.d.ts.map +1 -1
- package/dist/core/work/index.js +1 -1
- package/dist/core/work/read.d.ts +1 -1
- package/dist/core/work/read.d.ts.map +1 -1
- package/dist/core/work/read.js +1 -1
- package/dist/core/work/runner.d.ts.map +1 -1
- package/dist/core/work/runner.js +6 -0
- package/dist/core/work/state.d.ts +9 -0
- package/dist/core/work/state.d.ts.map +1 -1
- package/dist/core/work/state.js +17 -3
- package/dist/core/workflow/engine.js +24 -25
- package/dist/core/workflow/live-session-v3.d.ts +19 -0
- package/dist/core/workflow/live-session-v3.d.ts.map +1 -0
- package/dist/core/workflow/live-session-v3.js +86 -0
- package/dist/core/workflow/scope-id.d.ts +3 -0
- package/dist/core/workflow/scope-id.d.ts.map +1 -0
- package/dist/core/workflow/scope-id.js +5 -0
- package/dist/core/workflow/workspaces/leases.d.ts +4 -0
- package/dist/core/workflow/workspaces/leases.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/leases.js +53 -19
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/lib/browser/client.d.ts +41 -0
- package/dist/lib/browser/client.d.ts.map +1 -1
- package/dist/lib/browser/client.js +203 -0
- package/dist/lib/browser/critique.d.ts +28 -2
- package/dist/lib/browser/critique.d.ts.map +1 -1
- package/dist/lib/browser/critique.js +74 -18
- package/dist/lib/browser/geometry.d.ts +1 -1
- package/dist/lib/browser/geometry.d.ts.map +1 -1
- package/dist/lib/browser/geometry.js +130 -6
- package/dist/lib/browser/index.d.ts +3 -0
- package/dist/lib/browser/index.d.ts.map +1 -1
- package/dist/lib/browser/index.js +3 -0
- package/dist/lib/browser/qa-plan.d.ts +174 -0
- package/dist/lib/browser/qa-plan.d.ts.map +1 -0
- package/dist/lib/browser/qa-plan.js +321 -0
- package/dist/lib/browser/qa-reuse.d.ts +99 -0
- package/dist/lib/browser/qa-reuse.d.ts.map +1 -0
- package/dist/lib/browser/qa-reuse.js +222 -0
- package/dist/lib/browser/qa-snapshot.d.ts +64 -0
- package/dist/lib/browser/qa-snapshot.d.ts.map +1 -0
- package/dist/lib/browser/qa-snapshot.js +171 -0
- package/dist/lib/browser/runts.d.ts.map +1 -1
- package/dist/lib/browser/runts.js +22 -1
- package/dist/lib/browser/tiling.d.ts +71 -0
- package/dist/lib/browser/tiling.d.ts.map +1 -0
- package/dist/lib/browser/tiling.js +118 -0
- package/dist/lib/context/index.d.ts +0 -3
- package/dist/lib/context/index.d.ts.map +1 -1
- package/dist/lib/context/index.js +20 -42
- package/dist/lib/council/index.d.ts +2 -2
- package/dist/lib/council/index.d.ts.map +1 -1
- package/dist/lib/council/index.js +9 -20
- package/dist/lib/docs-frontmatter.d.ts +1 -6
- package/dist/lib/docs-frontmatter.d.ts.map +1 -1
- package/dist/lib/docs-frontmatter.js +12 -78
- package/dist/lib/docs-index.d.ts +9 -0
- package/dist/lib/docs-index.d.ts.map +1 -1
- package/dist/lib/docs-index.js +32 -3
- package/dist/lib/docs-lint.d.ts.map +1 -1
- package/dist/lib/docs-lint.js +14 -30
- package/dist/lib/docs-metadata-audit.d.ts +19 -0
- package/dist/lib/docs-metadata-audit.d.ts.map +1 -0
- package/dist/lib/docs-metadata-audit.js +132 -0
- package/dist/lib/docs-metadata-managed.d.ts +23 -0
- package/dist/lib/docs-metadata-managed.d.ts.map +1 -0
- package/dist/lib/docs-metadata-managed.js +78 -0
- package/dist/lib/docs-metadata-sync.d.ts +20 -0
- package/dist/lib/docs-metadata-sync.d.ts.map +1 -0
- package/dist/lib/docs-metadata-sync.js +222 -0
- package/dist/lib/docs-metadata-v2-schema.d.ts +273 -0
- package/dist/lib/docs-metadata-v2-schema.d.ts.map +1 -0
- package/dist/lib/docs-metadata-v2-schema.js +134 -0
- package/dist/lib/docs-metadata-v2.d.ts +21 -0
- package/dist/lib/docs-metadata-v2.d.ts.map +1 -0
- package/dist/lib/docs-metadata-v2.js +424 -0
- package/dist/lib/docs-new.d.ts +11 -0
- package/dist/lib/docs-new.d.ts.map +1 -0
- package/dist/lib/docs-new.js +52 -0
- package/dist/lib/docs-sweep.d.ts.map +1 -1
- package/dist/lib/docs-sweep.js +45 -29
- package/dist/lib/headless/index.d.ts +98 -0
- package/dist/lib/headless/index.d.ts.map +1 -0
- package/dist/lib/headless/index.js +211 -0
- package/dist/lib/identities/assume.d.ts +4 -4
- package/dist/lib/identities/assume.d.ts.map +1 -1
- package/dist/lib/identities/assume.js +52 -68
- package/dist/lib/instructions/apply.d.ts +5 -4
- package/dist/lib/instructions/apply.d.ts.map +1 -1
- package/dist/lib/instructions/apply.js +32 -20
- package/dist/lib/instructions/bundle.d.ts +33 -0
- package/dist/lib/instructions/bundle.d.ts.map +1 -0
- package/dist/lib/instructions/bundle.js +149 -0
- package/dist/lib/instructions/splice.d.ts +0 -1
- package/dist/lib/instructions/splice.d.ts.map +1 -1
- package/dist/lib/instructions/splice.js +22 -6
- package/dist/lib/instructions/templates.d.ts +7 -5
- package/dist/lib/instructions/templates.d.ts.map +1 -1
- package/dist/lib/instructions/templates.js +79 -9
- package/package.json +27 -6
- package/schemas/config.schema.json +120 -2
- package/schemas/docs-metadata-v2.schema.json +441 -0
- package/schemas/event-v3.schema.json +24472 -0
- package/src/commander.ts +7 -1
- package/src/commands/adapter.ts +2 -2
- package/src/commands/agents.ts +1737 -570
- package/src/commands/artifacts.ts +7 -6
- package/src/commands/backup.ts +29 -21
- package/src/commands/browse.ts +349 -8
- package/src/commands/checkpoint.ts +4 -3
- package/src/commands/claude-desktop.ts +7 -5
- package/src/commands/context.ts +1 -6
- package/src/commands/decision.ts +27 -44
- package/src/commands/docs.ts +100 -33
- package/src/commands/doctor.ts +73 -8
- package/src/commands/events.ts +256 -0
- package/src/commands/governor.ts +18 -4
- package/src/commands/init.ts +264 -57
- package/src/commands/instructions.ts +129 -0
- package/src/commands/journal.ts +4 -13
- package/src/commands/ledger-v3.ts +111 -0
- package/src/commands/presence.ts +18 -11
- package/src/commands/sync.ts +1 -1
- package/src/commands/web.ts +67 -8
- package/src/commands/work.ts +28 -5
- package/src/core/adapter.ts +5 -0
- package/src/core/adapters/attest.ts +8 -3
- package/src/core/adapters/profiles.ts +4 -6
- package/src/core/agents/canonical-emit.ts +39 -28
- package/src/core/agents/cli.ts +242 -263
- package/src/core/agents/codex-archive-v3.ts +138 -0
- package/src/core/agents/coord-client.ts +75 -177
- package/src/core/agents/finalization.ts +120 -38
- package/src/core/agents/index.ts +5 -5
- package/src/core/agents/live-authority-v3.ts +375 -0
- package/src/core/agents/live-lifecycle-v3.ts +140 -0
- package/src/core/agents/live-observation-v3.ts +216 -0
- package/src/core/agents/render/prompt-context.ts +89 -55
- package/src/core/agents/render/session-context.ts +23 -32
- package/src/core/agents/rules/claim-conflict.ts +85 -126
- package/src/core/agents/rules/commit-conflict.ts +3 -14
- package/src/core/agents/rules/stop-hook.ts +239 -293
- package/src/core/agents/session-events.ts +137 -104
- package/src/core/agents/session-finalization-state-v3.ts +90 -0
- package/src/core/agents/session-finalizer-v3.ts +953 -0
- package/src/core/agents/session-name-display.ts +149 -0
- package/src/core/agents/state/activity-log.ts +6 -14
- package/src/core/agents/state/heartbeat-writer.ts +98 -242
- package/src/core/agents/state/live-coordination-view.ts +290 -0
- package/src/core/agents/state/session-state.ts +143 -0
- package/src/core/agents/state/stale-sweep.ts +40 -17
- package/src/core/artifacts/index.ts +4 -5
- package/src/core/config.ts +148 -3
- package/src/core/context/index.ts +9 -17
- package/src/core/events/span-parent.ts +46 -0
- package/src/core/events/v3/advance.ts +168 -0
- package/src/core/events/v3/authority-outbox.ts +548 -0
- package/src/core/events/v3/base-builder.ts +60 -0
- package/src/core/events/v3/base-contract.ts +882 -0
- package/src/core/events/v3/bootstrap.ts +226 -0
- package/src/core/events/v3/builder.ts +59 -0
- package/src/core/events/v3/canonical.ts +153 -0
- package/src/core/events/v3/capabilities.ts +171 -0
- package/src/core/events/v3/capability-drift.ts +177 -0
- package/src/core/events/v3/catalog.ts +202 -0
- package/src/core/events/v3/clock-order.ts +41 -0
- package/src/core/events/v3/contract.ts +365 -0
- package/src/core/events/v3/control.ts +576 -0
- package/src/core/events/v3/coordination-view.ts +193 -0
- package/src/core/events/v3/economics.ts +384 -0
- package/src/core/events/v3/finalization-view.ts +67 -0
- package/src/core/events/v3/fingerprint-keys.ts +260 -0
- package/src/core/events/v3/generated.ts +48 -0
- package/src/core/events/v3/ids.ts +33 -0
- package/src/core/events/v3/index.ts +322 -0
- package/src/core/events/v3/latency.ts +551 -0
- package/src/core/events/v3/live-feed.ts +319 -0
- package/src/core/events/v3/live-observation.ts +39 -0
- package/src/core/events/v3/live-routing.ts +135 -0
- package/src/core/events/v3/producers/command-recorder.ts +631 -0
- package/src/core/events/v3/producers/command.ts +201 -0
- package/src/core/events/v3/producers/coordination-recorder.ts +538 -0
- package/src/core/events/v3/producers/coordination.ts +355 -0
- package/src/core/events/v3/producers/hook-base.ts +578 -0
- package/src/core/events/v3/producers/hook.ts +119 -0
- package/src/core/events/v3/producers/intake.ts +319 -0
- package/src/core/events/v3/producers/recorder.ts +2805 -0
- package/src/core/events/v3/projection.ts +653 -0
- package/src/core/events/v3/reader.ts +1127 -0
- package/src/core/events/v3/recovery-record.ts +244 -0
- package/src/core/events/v3/recovery.ts +271 -0
- package/src/core/events/v3/span-state.ts +187 -0
- package/src/core/events/v3/targets.ts +182 -0
- package/src/core/events/v3/turn-telemetry.ts +259 -0
- package/src/core/events/v3/validate.ts +361 -0
- package/src/core/events/v3/writer.ts +419 -0
- package/src/core/governor/index.ts +3 -0
- package/src/core/governor/plan-api.ts +10 -2
- package/src/core/governor/read.ts +3 -0
- package/src/core/governor/state.ts +52 -5
- package/src/core/guard/config.ts +206 -0
- package/src/core/guard/coordinator.ts +227 -0
- package/src/core/guard/evaluator.ts +343 -0
- package/src/core/guard/evidence-v3.ts +227 -0
- package/src/core/guard/index.ts +35 -0
- package/src/core/guard/live-source-v3.ts +204 -0
- package/src/core/guard/storage.ts +188 -0
- package/src/core/guard/types.ts +152 -0
- package/src/core/hooks/adapter/detect.ts +28 -1
- package/src/core/hooks/adapter/events.ts +15 -6
- package/src/core/hooks/adapter/output.ts +7 -2
- package/src/core/hooks/adapter/parse.ts +81 -36
- package/src/core/hooks/adapter/wiring.ts +119 -13
- package/src/core/hooks/cli.ts +398 -422
- package/src/core/hooks/codex-authorization.ts +253 -0
- package/src/core/hooks/effects/image-capture.ts +228 -238
- package/src/core/hooks/effects/index.ts +1 -36
- package/src/core/hooks/events/input-hash.ts +47 -0
- package/src/core/hooks/index.ts +4 -11
- package/src/core/hooks/resolve/coord-root.ts +1 -1
- package/src/core/hooks/resolve/owner.ts +52 -45
- package/src/core/hooks/resolve/transcript.ts +165 -14
- package/src/core/hooks/session-name-presence.ts +14 -15
- package/src/core/hooks/unsafe-cross-shell.ts +1 -1
- package/src/core/journal/index.ts +15 -22
- package/src/core/presence/blob.ts +63 -38
- package/src/core/presence/codec-digest.ts +215 -0
- package/src/core/presence/index.ts +18 -1
- package/src/core/presence/relay-client.ts +5 -5
- package/src/core/work/index.ts +3 -0
- package/src/core/work/read.ts +3 -0
- package/src/core/work/runner.ts +6 -0
- package/src/core/work/state.ts +27 -3
- package/src/core/workflow/engine.ts +24 -24
- package/src/core/workflow/live-session-v3.ts +126 -0
- package/src/core/workflow/scope-id.ts +6 -0
- package/src/core/workflow/workspaces/leases.ts +56 -19
- package/src/index.ts +1 -1
- package/src/lib/browser/client.ts +230 -0
- package/src/lib/browser/critique.ts +104 -27
- package/src/lib/browser/geometry.ts +143 -14
- package/src/lib/browser/index.ts +34 -0
- package/src/lib/browser/qa-plan.ts +501 -0
- package/src/lib/browser/qa-reuse.ts +306 -0
- package/src/lib/browser/qa-snapshot.ts +223 -0
- package/src/lib/browser/runts.ts +27 -2
- package/src/lib/browser/tiling.ts +164 -0
- package/src/lib/context/index.ts +22 -46
- package/src/lib/council/index.ts +9 -21
- package/src/lib/docs-frontmatter.ts +8 -79
- package/src/lib/docs-index.ts +33 -3
- package/src/lib/docs-lint.ts +15 -29
- package/src/lib/docs-metadata-audit.ts +166 -0
- package/src/lib/docs-metadata-managed.ts +83 -0
- package/src/lib/docs-metadata-sync.ts +262 -0
- package/src/lib/docs-metadata-v2-schema.ts +138 -0
- package/src/lib/docs-metadata-v2.ts +646 -0
- package/src/lib/docs-new.ts +63 -0
- package/src/lib/docs-sweep.ts +42 -28
- package/src/lib/headless/index.ts +287 -0
- package/src/lib/identities/assume.ts +67 -86
- package/src/lib/instructions/apply.ts +33 -20
- package/src/lib/instructions/bundle.ts +199 -0
- package/src/lib/instructions/splice.ts +21 -7
- package/src/lib/instructions/templates.ts +85 -13
- package/dist/core/agents/cli-emit.d.ts +0 -27
- package/dist/core/agents/cli-emit.d.ts.map +0 -1
- package/dist/core/agents/cli-emit.js +0 -57
- package/dist/core/agents/codex-replay.d.ts +0 -29
- package/dist/core/agents/codex-replay.d.ts.map +0 -1
- package/dist/core/agents/codex-replay.js +0 -138
- package/dist/core/agents/events/consume.d.ts +0 -82
- package/dist/core/agents/events/consume.d.ts.map +0 -1
- package/dist/core/agents/events/consume.js +0 -195
- package/dist/core/agents/events/emit.d.ts +0 -42
- package/dist/core/agents/events/emit.d.ts.map +0 -1
- package/dist/core/agents/events/emit.js +0 -75
- package/dist/core/agents/events/ulid.d.ts +0 -11
- package/dist/core/agents/events/ulid.d.ts.map +0 -1
- package/dist/core/agents/events/ulid.js +0 -47
- package/dist/core/agents/state/heartbeat-projector.d.ts +0 -65
- package/dist/core/agents/state/heartbeat-projector.d.ts.map +0 -1
- package/dist/core/agents/state/heartbeat-projector.js +0 -527
- package/dist/core/hooks/events/emit.d.ts +0 -31
- package/dist/core/hooks/events/emit.d.ts.map +0 -1
- package/dist/core/hooks/events/emit.js +0 -93
- package/dist/core/hooks/events/rotate.d.ts +0 -43
- package/dist/core/hooks/events/rotate.d.ts.map +0 -1
- package/dist/core/hooks/events/rotate.js +0 -142
- package/dist/core/hooks/events/schema.d.ts +0 -312
- package/dist/core/hooks/events/schema.d.ts.map +0 -1
- package/dist/core/hooks/events/schema.js +0 -12
- package/dist/core/hooks/events/ulid.d.ts +0 -10
- package/dist/core/hooks/events/ulid.d.ts.map +0 -1
- package/dist/core/hooks/events/ulid.js +0 -47
- package/dist/lib/docs-frontmatter-migrate.d.ts +0 -33
- package/dist/lib/docs-frontmatter-migrate.d.ts.map +0 -1
- package/dist/lib/docs-frontmatter-migrate.js +0 -364
- package/src/core/agents/cli-emit.ts +0 -64
- package/src/core/agents/codex-replay.ts +0 -163
- package/src/core/agents/events/consume.ts +0 -254
- package/src/core/agents/events/emit.ts +0 -115
- package/src/core/agents/events/ulid.ts +0 -51
- package/src/core/agents/state/heartbeat-projector.ts +0 -582
- package/src/core/hooks/events/emit.ts +0 -125
- package/src/core/hooks/events/rotate.ts +0 -151
- package/src/core/hooks/events/schema.ts +0 -538
- package/src/core/hooks/events/ulid.ts +0 -51
- package/src/lib/docs-frontmatter-migrate.ts +0 -427
|
@@ -0,0 +1,501 @@
|
|
|
1
|
+
// Diff-aware QA planner: classify a page change against a baseline signature
|
|
2
|
+
// and emit a machine-readable review manifest BEFORE any expensive work runs.
|
|
3
|
+
//
|
|
4
|
+
// The motivating failure is spend without proportionality: a one-word copy
|
|
5
|
+
// edit and a theme rewrite both trigger the same full-page, every-context
|
|
6
|
+
// vision review. This module makes review proportional to the change:
|
|
7
|
+
// - text/data-only edits produce zero vision calls;
|
|
8
|
+
// - a local component change reviews only that component's stable root;
|
|
9
|
+
// - global CSS, unprovable blast radius, or a missing baseline widen to
|
|
10
|
+
// full coverage — ambiguity always widens, never silently downgrades.
|
|
11
|
+
//
|
|
12
|
+
// Everything here is pure data-in/data-out: signatures are captured elsewhere
|
|
13
|
+
// (the browser client), baselines are persisted elsewhere (qa-snapshot.ts),
|
|
14
|
+
// and execution happens elsewhere (the critique engine). Keeping the planner
|
|
15
|
+
// pure means the classification can be reviewed, logged, and overridden
|
|
16
|
+
// before a single model call is made.
|
|
17
|
+
//
|
|
18
|
+
// One deliberate portability boundary: a stylesheet change classifies as
|
|
19
|
+
// `large-structural` here because CSS blast radius is not provable from
|
|
20
|
+
// digests alone. A host that can map component-scoped stylesheets to
|
|
21
|
+
// selectors can downgrade after the fact; the portable layer never does.
|
|
22
|
+
|
|
23
|
+
/** FNV-1a 32-bit over a string, hex-encoded, with a length suffix so the
|
|
24
|
+
* (tiny) collision surface also has to match on length. Used for text and
|
|
25
|
+
* stylesheet digests — a comparison fingerprint, not a security hash. */
|
|
26
|
+
export function fnv1a32(text: string): string {
|
|
27
|
+
let hash = 0x811c9dc5;
|
|
28
|
+
for (let i = 0; i < text.length; i++) {
|
|
29
|
+
hash ^= text.charCodeAt(i);
|
|
30
|
+
hash = Math.imul(hash, 0x01000193);
|
|
31
|
+
}
|
|
32
|
+
return `${(hash >>> 0).toString(16).padStart(8, "0")}-${text.length}`;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** One element's structural fingerprint inside a captured page. */
|
|
36
|
+
export interface QaNodeSignature {
|
|
37
|
+
/** Structural path from body: `body>div:0>table:1>tr:4>td:2` (index among
|
|
38
|
+
* element siblings). Position-sensitive by design — reordering IS a
|
|
39
|
+
* structural change. */
|
|
40
|
+
path: string;
|
|
41
|
+
tag: string;
|
|
42
|
+
/** Canonical attribute string: sorted `name=value` pairs joined with \x1f.
|
|
43
|
+
* Raw (not digested) so a reviewer can see WHICH attribute changed. */
|
|
44
|
+
attrs: string;
|
|
45
|
+
/** Digest of the element's direct text-node content (whitespace-normalized),
|
|
46
|
+
* absent when the element has no direct text. */
|
|
47
|
+
text?: string;
|
|
48
|
+
/** Digest of opaque rendered content whose pixels can change without a DOM
|
|
49
|
+
* structure or attribute change (for example SVG descendants or a canvas
|
|
50
|
+
* bitmap). `unavailable` widens to unknown because text-only cannot be
|
|
51
|
+
* proven without this evidence. */
|
|
52
|
+
visual?: string;
|
|
53
|
+
/** Nearest strict-ancestor stable anchor (unique `#id` or
|
|
54
|
+
* `[data-qa-scope="…"]`), with the anchor element's own path so nested
|
|
55
|
+
* anchors can be deduped to the outermost root. Absent for nodes with no
|
|
56
|
+
* anchored ancestor (e.g. direct children of body on an anchor-free page). */
|
|
57
|
+
anchor?: { selector: string; path: string };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface QaStylesheetSignature {
|
|
61
|
+
/** External sheet href, or `inline:<index>` for a `<style>` block. */
|
|
62
|
+
key: string;
|
|
63
|
+
kind: "external" | "inline";
|
|
64
|
+
/** Content digest, or the literal `"unavailable"` when the sheet's text
|
|
65
|
+
* could not be read (cross-origin without CORS). Unavailable digests widen
|
|
66
|
+
* classification to `unknown` — style stability can't be proven. */
|
|
67
|
+
digest: string;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** A captured page signature: everything the classifier needs, nothing the
|
|
71
|
+
* critique engine does. Produced by the browser client, persisted by the
|
|
72
|
+
* snapshot store. */
|
|
73
|
+
export interface QaSignature {
|
|
74
|
+
url: string;
|
|
75
|
+
/** ISO capture time. */
|
|
76
|
+
capturedAt: string;
|
|
77
|
+
nodes: QaNodeSignature[];
|
|
78
|
+
stylesheets: QaStylesheetSignature[];
|
|
79
|
+
/** True when the capture hit its node cap. A truncated signature cannot
|
|
80
|
+
* prove absence of change — the classifier widens to `unknown`. */
|
|
81
|
+
truncated?: boolean;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export type ChangeClass =
|
|
85
|
+
| "text-data-only"
|
|
86
|
+
| "local-visual"
|
|
87
|
+
| "interaction-state"
|
|
88
|
+
| "large-structural"
|
|
89
|
+
| "unknown";
|
|
90
|
+
|
|
91
|
+
export interface QaScope {
|
|
92
|
+
selector: string;
|
|
93
|
+
reason: string;
|
|
94
|
+
/** How many elements the selector matched at capture time (1 for anchors —
|
|
95
|
+
* uniqueness is verified during capture; explicit selectors carry the
|
|
96
|
+
* caller-counted value). */
|
|
97
|
+
matches: number;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export interface QaClassification {
|
|
101
|
+
/** `interaction-state` is never inferred from signatures — it is declared
|
|
102
|
+
* by explicit state inputs at manifest time. */
|
|
103
|
+
change_class: Exclude<ChangeClass, "interaction-state">;
|
|
104
|
+
reasons: string[];
|
|
105
|
+
/** Paths whose direct text content changed (structure + attrs identical). */
|
|
106
|
+
text_changed_paths: string[];
|
|
107
|
+
/** Paths added, removed, or with changed attributes. */
|
|
108
|
+
structural_changed_paths: string[];
|
|
109
|
+
/** Stylesheet keys whose digest changed, appeared, or disappeared. */
|
|
110
|
+
stylesheets_changed: string[];
|
|
111
|
+
/** Stable scope roots covering every structural change (local-visual only). */
|
|
112
|
+
scopes: QaScope[];
|
|
113
|
+
/** True when baseline and current are indistinguishable. */
|
|
114
|
+
identical: boolean;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export interface ClassifyOptions {
|
|
118
|
+
/** More distinct scope roots than this widens to large-structural: a change
|
|
119
|
+
* that touches many independent regions is a page-level change no matter
|
|
120
|
+
* how well-anchored each region is. Default 4. */
|
|
121
|
+
maxScopes?: number;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const UNAVAILABLE = "unavailable";
|
|
125
|
+
|
|
126
|
+
function diffStylesheets(baseline: QaStylesheetSignature[], current: QaStylesheetSignature[]) {
|
|
127
|
+
const base = new Map(baseline.map((s) => [s.key, s.digest]));
|
|
128
|
+
const cur = new Map(current.map((s) => [s.key, s.digest]));
|
|
129
|
+
const unavailable = [...baseline, ...current].some((s) => s.digest === UNAVAILABLE);
|
|
130
|
+
const changed: string[] = [];
|
|
131
|
+
for (const [key, digest] of cur) {
|
|
132
|
+
const prior = base.get(key);
|
|
133
|
+
if (prior === undefined || prior !== digest) changed.push(key);
|
|
134
|
+
}
|
|
135
|
+
for (const key of base.keys()) {
|
|
136
|
+
if (!cur.has(key)) changed.push(key);
|
|
137
|
+
}
|
|
138
|
+
return { changed: changed.sort(), unavailable };
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Classify current against baseline. Pure: no browser, no filesystem. The
|
|
143
|
+
* bias is stated in the plan and enforced here — ambiguity widens (to
|
|
144
|
+
* `unknown`/`large-structural`), never narrows. A `null` baseline is the
|
|
145
|
+
* "no baseline available" case and is always `unknown`.
|
|
146
|
+
*/
|
|
147
|
+
export function classifySignatures(
|
|
148
|
+
baseline: QaSignature | null,
|
|
149
|
+
current: QaSignature,
|
|
150
|
+
opts: ClassifyOptions = {},
|
|
151
|
+
): QaClassification {
|
|
152
|
+
const maxScopes = opts.maxScopes ?? 4;
|
|
153
|
+
const none: Omit<QaClassification, "change_class" | "reasons"> = {
|
|
154
|
+
text_changed_paths: [],
|
|
155
|
+
structural_changed_paths: [],
|
|
156
|
+
stylesheets_changed: [],
|
|
157
|
+
scopes: [],
|
|
158
|
+
identical: false,
|
|
159
|
+
};
|
|
160
|
+
if (!baseline) {
|
|
161
|
+
return {
|
|
162
|
+
...none,
|
|
163
|
+
change_class: "unknown",
|
|
164
|
+
reasons: ["no baseline available — cannot prove any change class"],
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (baseline.truncated || current.truncated) {
|
|
169
|
+
return {
|
|
170
|
+
...none,
|
|
171
|
+
change_class: "unknown",
|
|
172
|
+
reasons: [
|
|
173
|
+
"signature capture was truncated at its node cap — absence of change cannot be proven",
|
|
174
|
+
],
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const sheets = diffStylesheets(baseline.stylesheets, current.stylesheets);
|
|
179
|
+
if (sheets.unavailable) {
|
|
180
|
+
return {
|
|
181
|
+
...none,
|
|
182
|
+
change_class: "unknown",
|
|
183
|
+
stylesheets_changed: sheets.changed,
|
|
184
|
+
reasons: [
|
|
185
|
+
"stylesheet digest unavailable (cross-origin without CORS) — style stability cannot be proven, DOM equality alone never proves text-only",
|
|
186
|
+
],
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const baseNodes = new Map(baseline.nodes.map((n) => [n.path, n]));
|
|
191
|
+
const curNodes = new Map(current.nodes.map((n) => [n.path, n]));
|
|
192
|
+
const unavailableVisual = [...baseline.nodes, ...current.nodes].find(
|
|
193
|
+
(node) => node.visual === UNAVAILABLE,
|
|
194
|
+
);
|
|
195
|
+
if (unavailableVisual) {
|
|
196
|
+
return {
|
|
197
|
+
...none,
|
|
198
|
+
change_class: "unknown",
|
|
199
|
+
reasons: [
|
|
200
|
+
`visual digest unavailable at ${unavailableVisual.path} — text-only cannot be proven`,
|
|
201
|
+
],
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
const textChanged: string[] = [];
|
|
205
|
+
const structuralChanged = new Map<string, QaNodeSignature>();
|
|
206
|
+
for (const [path, node] of curNodes) {
|
|
207
|
+
const prior = baseNodes.get(path);
|
|
208
|
+
if (!prior) {
|
|
209
|
+
structuralChanged.set(path, node); // added
|
|
210
|
+
} else if (
|
|
211
|
+
prior.tag !== node.tag ||
|
|
212
|
+
prior.attrs !== node.attrs ||
|
|
213
|
+
(prior.visual ?? "") !== (node.visual ?? "")
|
|
214
|
+
) {
|
|
215
|
+
structuralChanged.set(path, node);
|
|
216
|
+
} else if ((prior.text ?? "") !== (node.text ?? "")) {
|
|
217
|
+
textChanged.push(path);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
for (const [path, node] of baseNodes) {
|
|
221
|
+
if (!curNodes.has(path) && !structuralChanged.has(path)) {
|
|
222
|
+
structuralChanged.set(path, node); // removed — anchor comes from baseline side
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (sheets.changed.length > 0) {
|
|
227
|
+
return {
|
|
228
|
+
...none,
|
|
229
|
+
change_class: "large-structural",
|
|
230
|
+
text_changed_paths: textChanged.sort(),
|
|
231
|
+
structural_changed_paths: [...structuralChanged.keys()].sort(),
|
|
232
|
+
stylesheets_changed: sheets.changed,
|
|
233
|
+
reasons: [
|
|
234
|
+
`stylesheet changed (${sheets.changed.join(", ")}) — CSS blast radius is not provable portably, widening to full coverage`,
|
|
235
|
+
],
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (structuralChanged.size === 0) {
|
|
240
|
+
if (textChanged.length === 0) {
|
|
241
|
+
return {
|
|
242
|
+
...none,
|
|
243
|
+
change_class: "text-data-only",
|
|
244
|
+
identical: true,
|
|
245
|
+
reasons: ["no differences detected between baseline and current signatures"],
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
return {
|
|
249
|
+
...none,
|
|
250
|
+
change_class: "text-data-only",
|
|
251
|
+
text_changed_paths: textChanged.sort(),
|
|
252
|
+
reasons: [
|
|
253
|
+
`only direct text content changed (${textChanged.length} node${textChanged.length === 1 ? "" : "s"}); element structure, attributes, and stylesheet digests are unchanged`,
|
|
254
|
+
],
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Structural changes: lift every changed node to its nearest strict-ancestor
|
|
259
|
+
// stable anchor. Any node without one is an unprovable boundary — widen.
|
|
260
|
+
const anchorless: string[] = [];
|
|
261
|
+
const scopeNodes = new Map<string, { path: string; count: number }>();
|
|
262
|
+
for (const [path, node] of structuralChanged) {
|
|
263
|
+
if (!node.anchor) {
|
|
264
|
+
anchorless.push(path);
|
|
265
|
+
continue;
|
|
266
|
+
}
|
|
267
|
+
const existing = scopeNodes.get(node.anchor.selector);
|
|
268
|
+
if (existing) existing.count++;
|
|
269
|
+
else scopeNodes.set(node.anchor.selector, { path: node.anchor.path, count: 1 });
|
|
270
|
+
}
|
|
271
|
+
if (anchorless.length > 0) {
|
|
272
|
+
return {
|
|
273
|
+
...none,
|
|
274
|
+
change_class: "large-structural",
|
|
275
|
+
text_changed_paths: textChanged.sort(),
|
|
276
|
+
structural_changed_paths: [...structuralChanged.keys()].sort(),
|
|
277
|
+
reasons: [
|
|
278
|
+
`${anchorless.length} changed node${anchorless.length === 1 ? "" : "s"} without a stable ancestor (first: ${anchorless.sort()[0]}) — visual impact cannot be proven to stay inside stable selectors`,
|
|
279
|
+
],
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Dedupe nested anchors to the outermost root: reviewing a container once
|
|
284
|
+
// beats one model call per anchored descendant.
|
|
285
|
+
const entries = [...scopeNodes.entries()].sort((a, b) => a[1].path.length - b[1].path.length);
|
|
286
|
+
const roots: Array<[string, { path: string; count: number }]> = [];
|
|
287
|
+
for (const entry of entries) {
|
|
288
|
+
const container = roots.find(([, root]) => entry[1].path.startsWith(`${root.path}>`));
|
|
289
|
+
if (container) container[1].count += entry[1].count;
|
|
290
|
+
else roots.push(entry);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
if (roots.length > maxScopes) {
|
|
294
|
+
return {
|
|
295
|
+
...none,
|
|
296
|
+
change_class: "large-structural",
|
|
297
|
+
text_changed_paths: textChanged.sort(),
|
|
298
|
+
structural_changed_paths: [...structuralChanged.keys()].sort(),
|
|
299
|
+
reasons: [
|
|
300
|
+
`changes span ${roots.length} independent scope roots (limit ${maxScopes}) — a multi-region change is a page-level change`,
|
|
301
|
+
],
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
return {
|
|
306
|
+
change_class: "local-visual",
|
|
307
|
+
identical: false,
|
|
308
|
+
text_changed_paths: textChanged.sort(),
|
|
309
|
+
structural_changed_paths: [...structuralChanged.keys()].sort(),
|
|
310
|
+
stylesheets_changed: [],
|
|
311
|
+
scopes: roots
|
|
312
|
+
.sort((a, b) => a[0].localeCompare(b[0]))
|
|
313
|
+
.map(([selector, root]) => ({
|
|
314
|
+
selector,
|
|
315
|
+
reason: `nearest stable ancestor of ${root.count} changed node${root.count === 1 ? "" : "s"}`,
|
|
316
|
+
matches: 1,
|
|
317
|
+
})),
|
|
318
|
+
reasons: [
|
|
319
|
+
`structural changes contained by ${roots.length} stable scope root${roots.length === 1 ? "" : "s"}`,
|
|
320
|
+
],
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
export interface QaContext {
|
|
325
|
+
viewport: string;
|
|
326
|
+
theme: "light" | "dark";
|
|
327
|
+
state: string;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
export interface QaManifest {
|
|
331
|
+
schema_version: 1;
|
|
332
|
+
change_class: ChangeClass;
|
|
333
|
+
classification_reasons: string[];
|
|
334
|
+
source_revision?: string;
|
|
335
|
+
baseline_revision?: string;
|
|
336
|
+
/** Which resolution-order source produced the baseline:
|
|
337
|
+
* `qa-snapshot:<capturedAt>`, `production-render:<capturedAt>`,
|
|
338
|
+
* `revision-render:<rev>`, or `none`. */
|
|
339
|
+
baseline_source: string;
|
|
340
|
+
scopes: QaScope[];
|
|
341
|
+
contexts: QaContext[];
|
|
342
|
+
checks: {
|
|
343
|
+
deterministic: string[];
|
|
344
|
+
/** Assertions that prove named interaction states behaved correctly. */
|
|
345
|
+
interaction: string[];
|
|
346
|
+
visual: "none" | "scoped" | "full-page";
|
|
347
|
+
};
|
|
348
|
+
concurrency: { headless: number; metered: number };
|
|
349
|
+
reuse: { mode: "none" | "exact-digest" | "band-diff"; cache: boolean };
|
|
350
|
+
/** Provider-call ceiling for the plan, so cost is visible before execution.
|
|
351
|
+
* Full-page tile counts need a rendered page; callers pass an estimate. */
|
|
352
|
+
predicted: { tiles_ceiling: number; model_calls_ceiling: number };
|
|
353
|
+
/** Present when the run cannot produce a trustworthy verdict (e.g. unknown
|
|
354
|
+
* class without permission to widen). An incomplete run is never a pass. */
|
|
355
|
+
incomplete?: { reason: string };
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
export interface ManifestOptions {
|
|
359
|
+
baselineSource: string;
|
|
360
|
+
sourceRevision?: string;
|
|
361
|
+
baselineRevision?: string;
|
|
362
|
+
/** Explicit scope selectors from the producing task — resolution order rung
|
|
363
|
+
* 1; they override lifted anchors entirely. */
|
|
364
|
+
explicitScopes?: QaScope[];
|
|
365
|
+
/** Named interaction states to review (before/after pairs, etc.). Any
|
|
366
|
+
* non-empty list promotes a text/local classification to
|
|
367
|
+
* `interaction-state` and appends one context per state. */
|
|
368
|
+
states?: string[];
|
|
369
|
+
/** Viewports for the full matrix (default ["desktop", "mobile"]). */
|
|
370
|
+
viewports?: string[];
|
|
371
|
+
/** Estimated full-page tile count per context, from the caller's render
|
|
372
|
+
* knowledge (page height / band step, capped). Default 24 (the tile cap). */
|
|
373
|
+
estimatedFullPageTiles?: number;
|
|
374
|
+
concurrency?: { headless: number; metered: number };
|
|
375
|
+
reuse?: { mode: "none" | "exact-digest" | "band-diff"; cache: boolean };
|
|
376
|
+
deterministicChecks?: string[];
|
|
377
|
+
/** Value/behavior assertions paired with explicit interaction states. */
|
|
378
|
+
outcomeAssertions?: string[];
|
|
379
|
+
/** When false (default), an `unknown` classification widens to full
|
|
380
|
+
* large-structural coverage. When true, the manifest instead marks itself
|
|
381
|
+
* incomplete with zero contexts — the caller wants a hard stop. */
|
|
382
|
+
stopOnUnknown?: boolean;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
const DEFAULT_DETERMINISTIC = ["console", "overflow", "truncation", "placeholder"];
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* Turn a classification into an executable review manifest. Pure: rendering,
|
|
389
|
+
* baseline acquisition, and critique execution stay in the caller. The
|
|
390
|
+
* separation is the point — the manifest can be printed by a dry run,
|
|
391
|
+
* reviewed, and overridden before expensive work starts.
|
|
392
|
+
*/
|
|
393
|
+
export function buildQaManifest(
|
|
394
|
+
classification: QaClassification,
|
|
395
|
+
opts: ManifestOptions,
|
|
396
|
+
): QaManifest {
|
|
397
|
+
const viewports = opts.viewports ?? ["desktop", "mobile"];
|
|
398
|
+
const fullPageTiles = opts.estimatedFullPageTiles ?? 24;
|
|
399
|
+
const states = opts.states ?? [];
|
|
400
|
+
const scopes = opts.explicitScopes?.length ? opts.explicitScopes : classification.scopes;
|
|
401
|
+
|
|
402
|
+
let changeClass: ChangeClass = classification.change_class;
|
|
403
|
+
const reasons = [...classification.reasons];
|
|
404
|
+
if (opts.explicitScopes?.length && changeClass === "unknown") {
|
|
405
|
+
// Explicit scope input is resolution-order rung 1: the producing task
|
|
406
|
+
// knows its own blast radius better than a missing baseline does.
|
|
407
|
+
changeClass = "local-visual";
|
|
408
|
+
reasons.push("explicit scope selectors supplied — overriding unknown classification");
|
|
409
|
+
}
|
|
410
|
+
if (
|
|
411
|
+
opts.explicitScopes?.length &&
|
|
412
|
+
changeClass === "large-structural" &&
|
|
413
|
+
classification.stylesheets_changed.length > 0 &&
|
|
414
|
+
classification.structural_changed_paths.length === 0
|
|
415
|
+
) {
|
|
416
|
+
changeClass = "local-visual";
|
|
417
|
+
reasons.push(
|
|
418
|
+
"explicit scope selectors supplied for a stylesheet-only change — host proved the component boundary",
|
|
419
|
+
);
|
|
420
|
+
}
|
|
421
|
+
if (states.length > 0 && (changeClass === "text-data-only" || changeClass === "local-visual")) {
|
|
422
|
+
changeClass = "interaction-state";
|
|
423
|
+
reasons.push(`explicit interaction states requested: ${states.join(", ")}`);
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
let incomplete: { reason: string } | undefined;
|
|
427
|
+
if (classification.change_class === "unknown" && changeClass === "unknown") {
|
|
428
|
+
if (opts.stopOnUnknown) {
|
|
429
|
+
incomplete = { reason: classification.reasons[0] ?? "classification unknown" };
|
|
430
|
+
} else {
|
|
431
|
+
reasons.push("unknown class widened to large-structural coverage");
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
if (
|
|
435
|
+
(changeClass === "local-visual" || changeClass === "interaction-state") &&
|
|
436
|
+
(scopes.length === 0 || scopes.some((scope) => scope.matches < 1))
|
|
437
|
+
) {
|
|
438
|
+
const missing = scopes.find((scope) => scope.matches < 1)?.selector;
|
|
439
|
+
incomplete = {
|
|
440
|
+
reason: missing
|
|
441
|
+
? `scope selector matched no elements: ${missing}`
|
|
442
|
+
: `${changeClass} requires at least one stable scope selector`,
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
const matrix: QaContext[] = viewports.flatMap((viewport) =>
|
|
447
|
+
(["light", "dark"] as const).map((theme) => ({ viewport, theme, state: "default" })),
|
|
448
|
+
);
|
|
449
|
+
let contexts: QaContext[];
|
|
450
|
+
let visual: QaManifest["checks"]["visual"];
|
|
451
|
+
switch (changeClass) {
|
|
452
|
+
case "text-data-only":
|
|
453
|
+
contexts = [];
|
|
454
|
+
visual = "none";
|
|
455
|
+
break;
|
|
456
|
+
case "local-visual":
|
|
457
|
+
contexts = viewports.map((viewport) => ({ viewport, theme: "light", state: "default" }));
|
|
458
|
+
visual = "scoped";
|
|
459
|
+
break;
|
|
460
|
+
case "interaction-state":
|
|
461
|
+
contexts = [
|
|
462
|
+
{ viewport: viewports[0] ?? "desktop", theme: "light", state: "default" },
|
|
463
|
+
...states.map((state) => ({
|
|
464
|
+
viewport: viewports[0] ?? "desktop",
|
|
465
|
+
theme: "light" as const,
|
|
466
|
+
state,
|
|
467
|
+
})),
|
|
468
|
+
];
|
|
469
|
+
visual = "scoped";
|
|
470
|
+
break;
|
|
471
|
+
default:
|
|
472
|
+
contexts = incomplete ? [] : matrix;
|
|
473
|
+
visual = "full-page";
|
|
474
|
+
break;
|
|
475
|
+
}
|
|
476
|
+
if (incomplete) contexts = [];
|
|
477
|
+
|
|
478
|
+
const tilesPerContext =
|
|
479
|
+
visual === "none" ? 0 : visual === "scoped" ? Math.max(1, scopes.length) : fullPageTiles;
|
|
480
|
+
const tilesCeiling = tilesPerContext * contexts.length;
|
|
481
|
+
|
|
482
|
+
return {
|
|
483
|
+
schema_version: 1,
|
|
484
|
+
change_class: changeClass,
|
|
485
|
+
classification_reasons: reasons,
|
|
486
|
+
...(opts.sourceRevision ? { source_revision: opts.sourceRevision } : {}),
|
|
487
|
+
...(opts.baselineRevision ? { baseline_revision: opts.baselineRevision } : {}),
|
|
488
|
+
baseline_source: opts.baselineSource,
|
|
489
|
+
scopes: visual === "none" ? [] : scopes,
|
|
490
|
+
contexts,
|
|
491
|
+
checks: {
|
|
492
|
+
deterministic: opts.deterministicChecks ?? DEFAULT_DETERMINISTIC,
|
|
493
|
+
interaction: opts.outcomeAssertions ?? [],
|
|
494
|
+
visual,
|
|
495
|
+
},
|
|
496
|
+
concurrency: opts.concurrency ?? { headless: 4, metered: 2 },
|
|
497
|
+
reuse: opts.reuse ?? { mode: "none", cache: false },
|
|
498
|
+
predicted: { tiles_ceiling: tilesCeiling, model_calls_ceiling: tilesCeiling },
|
|
499
|
+
...(incomplete ? { incomplete } : {}),
|
|
500
|
+
};
|
|
501
|
+
}
|