@hassangameryt/freeflow 0.7.3 → 0.9.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/.agents/plugins/marketplace.json +2 -2
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +2 -2
- package/.codex-plugin/plugin.json +3 -3
- package/.cursor-plugin/plugin.json +1 -1
- package/NOTICE +14 -0
- package/README.md +101 -159
- package/capabilities/cognitive-routing/SKILL.md +47 -210
- package/capabilities/cognitive-routing/references/coordinator.md +163 -0
- package/capabilities/cognitive-routing/references/worker.md +38 -0
- package/capabilities/compaction/SKILL.md +49 -0
- package/capabilities/compaction/references/summary-format.md +250 -0
- package/capabilities/messaging/SKILL.md +49 -0
- package/capabilities/task-memory/SKILL.md +87 -0
- package/command-surface.json +8 -52
- package/gemini-extension.json +1 -1
- package/hooks/claude/hooks.json +13 -3
- package/hooks/codex/hooks.json +2 -1
- package/hooks/shared/runtime-context.mjs +73 -83
- package/licenses/Apache-2.0.txt +55 -0
- package/package.json +42 -12
- package/pi-extension/README.md +41 -0
- package/pi-extension/dist/ask-user/ask.js +108 -0
- package/pi-extension/dist/ask-user/form.js +250 -0
- package/pi-extension/dist/ask-user/questions.js +66 -0
- package/pi-extension/dist/ask-user/tool.js +124 -0
- package/pi-extension/dist/cognitive-routing/assembler.js +417 -0
- package/pi-extension/dist/cognitive-routing/bootstrap.js +90 -0
- package/pi-extension/dist/{cognitive-routing-v2 → cognitive-routing}/config.js +8 -6
- package/pi-extension/dist/cognitive-routing/economics.js +45 -0
- package/pi-extension/dist/cognitive-routing/event-schema.js +388 -0
- package/pi-extension/dist/{session-sources/events.js → cognitive-routing/event-store.js} +107 -41
- package/pi-extension/dist/cognitive-routing/gate.js +256 -0
- package/pi-extension/dist/cognitive-routing/handlers.js +901 -0
- package/pi-extension/dist/cognitive-routing/handoffs.js +350 -0
- package/pi-extension/dist/cognitive-routing/model-control.js +476 -0
- package/pi-extension/dist/cognitive-routing/projection.js +520 -0
- package/pi-extension/dist/cognitive-routing/provenance.js +83 -0
- package/pi-extension/dist/{cognitive-routing-v2 → cognitive-routing}/render.js +15 -15
- package/pi-extension/dist/cognitive-routing/runtime.js +398 -0
- package/pi-extension/dist/{cognitive-routing-v2 → cognitive-routing}/schemas.js +47 -11
- package/pi-extension/dist/cognitive-routing/session.js +223 -0
- package/pi-extension/dist/{session-sources → cognitive-routing}/sources.js +126 -87
- package/pi-extension/dist/{cognitive-routing-v2 → cognitive-routing}/state.js +55 -386
- package/pi-extension/dist/cognitive-routing/status.js +81 -0
- package/pi-extension/dist/cognitive-routing/tools.js +74 -0
- package/pi-extension/dist/{cognitive-routing-v2 → cognitive-routing}/types.js +14 -11
- package/pi-extension/dist/compaction/carry.js +205 -0
- package/pi-extension/dist/compaction/config.js +24 -0
- package/pi-extension/dist/compaction/controller.js +494 -0
- package/pi-extension/dist/compaction/harness.js +93 -0
- package/pi-extension/dist/compaction/results.js +159 -0
- package/pi-extension/dist/compaction/thresholds.js +35 -0
- package/pi-extension/dist/compaction/tool.js +57 -0
- package/pi-extension/dist/host/branch.js +13 -0
- package/pi-extension/dist/host/canonical.js +12 -0
- package/pi-extension/dist/host/catalog.js +62 -0
- package/pi-extension/dist/host/config-validation.js +233 -0
- package/pi-extension/dist/host/config.js +361 -0
- package/pi-extension/dist/host/inbound.js +142 -0
- package/pi-extension/dist/host/projection-tags.js +60 -0
- package/pi-extension/dist/host/prompts.js +93 -0
- package/pi-extension/dist/{session-sources → host}/read-only-session.js +117 -1
- package/pi-extension/dist/{runtime → host}/request-history.js +125 -39
- package/pi-extension/dist/host/rows.js +25 -0
- package/pi-extension/dist/host/runtime-state.js +204 -0
- package/pi-extension/dist/host/section-keeper.js +85 -0
- package/pi-extension/dist/host/settings/freeflow-command.js +2323 -0
- package/pi-extension/dist/{settings/settings-tui.js → host/settings/settings-view.js} +205 -73
- package/pi-extension/dist/host/staging.js +28 -0
- package/pi-extension/dist/host/status.js +115 -0
- package/pi-extension/dist/index.js +1004 -188
- package/pi-extension/dist/messaging/config.js +27 -0
- package/pi-extension/dist/messaging/messaging.js +398 -0
- package/pi-extension/dist/messaging/registry.js +57 -0
- package/pi-extension/dist/messaging/render.js +90 -0
- package/pi-extension/dist/messaging/tools.js +109 -0
- package/pi-extension/dist/messaging/transport.js +101 -0
- package/pi-extension/dist/provider-support/cache/anchor.js +21 -0
- package/pi-extension/dist/provider-support/cache/anthropic.js +102 -0
- package/pi-extension/dist/provider-support/cache/health.js +73 -0
- package/pi-extension/dist/provider-support/cache/index.js +58 -0
- package/pi-extension/dist/provider-support/cache/keepalive.js +222 -0
- package/pi-extension/dist/provider-support/cache/monitor.js +17 -0
- package/pi-extension/dist/provider-support/cache/openai-responses.js +48 -0
- package/pi-extension/dist/provider-support/effort.js +13 -0
- package/pi-extension/dist/provider-support/index.js +44 -3
- package/pi-extension/dist/provider-support/{astra → openai}/adapter.js +46 -29
- package/pi-extension/dist/provider-support/{astra → openai}/history.js +10 -8
- package/pi-extension/dist/provider-support/{astra → openai}/index.js +8 -4
- package/pi-extension/dist/provider-support/{astra → openai}/session-state.js +29 -38
- package/pi-extension/dist/provider-support/routes.js +17 -0
- package/pi-extension/dist/task-memory/config.js +49 -0
- package/pi-extension/dist/task-memory/registry.js +119 -0
- package/pi-extension/dist/task-memory/render.js +107 -0
- package/pi-extension/dist/task-memory/runtime.js +994 -0
- package/pi-extension/dist/task-memory/tool.js +233 -0
- package/pi-extension/dist/tool-execution/apply-patch/grammar.js +23 -0
- package/pi-extension/dist/tool-execution/apply-patch/match.js +38 -0
- package/pi-extension/dist/tool-execution/apply-patch/parser.js +177 -0
- package/pi-extension/dist/tool-execution/apply-patch/plan.js +201 -0
- package/pi-extension/dist/tool-execution/apply-patch/tool.js +84 -0
- package/pi-extension/dist/tool-execution/background.js +430 -0
- package/pi-extension/dist/tool-execution/bash-guard.js +23 -0
- package/pi-extension/dist/tool-execution/config.js +33 -0
- package/pi-extension/dist/tool-execution/edit-messages.js +120 -0
- package/pi-extension/dist/tool-execution/file-state.js +138 -0
- package/pi-extension/dist/tool-execution/file-tracking.js +163 -0
- package/pi-extension/dist/tool-execution/guidance-notices.js +124 -0
- package/pi-extension/dist/tool-execution/prompt.js +54 -0
- package/pi-extension/dist/tool-execution/skill-reads.js +143 -0
- package/pi-extension/dist/tool-execution/tools.js +16 -0
- package/pi-extension/freeflow/README.md +9 -0
- package/runtime/prompts/cognitive-routing.md +4 -4
- package/runtime/prompts/core.md +29 -72
- package/runtime/prompts/interaction-contract.md +18 -8
- package/runtime/prompts/tool-execution.md +25 -0
- package/runtime/prompts/working-method.md +25 -0
- package/skills/deliver-work/SKILL.md +76 -0
- package/skills/deliver-work/references/branch-closeout.md +134 -0
- package/skills/deliver-work/references/commit.md +83 -0
- package/skills/deliver-work/references/launch.md +94 -0
- package/skills/deliver-work/references/release.md +85 -0
- package/skills/deliver-work/scripts/commit-state.mjs +139 -0
- package/skills/deliver-work/scripts/delivery-state.mjs +107 -0
- package/skills/deliver-work/scripts/lib/git-state.mjs +178 -0
- package/skills/deliver-work/scripts/push-route.mjs +122 -0
- package/skills/deliver-work/scripts/release-preflight.mjs +177 -0
- package/skills/discuss-work/SKILL.md +148 -0
- package/skills/{discuss → discuss-work}/references/discussion-continuity.md +13 -50
- package/skills/discuss-work/references/learning-action.md +36 -0
- package/skills/discuss-work/scripts/choices.mjs +101 -0
- package/skills/discuss-work/scripts/lib/choices.mjs +159 -0
- package/skills/evaluate-behavior/SKILL.md +107 -0
- package/skills/evaluate-behavior/references/authoring.md +381 -0
- package/skills/evaluate-behavior/references/coding-tasks.md +145 -0
- package/skills/evaluate-behavior/references/conversations-pipelines-judges.md +177 -0
- package/skills/evaluate-behavior/references/design-and-measurement.md +273 -0
- package/skills/evaluate-behavior/references/running-and-evidence.md +245 -0
- package/skills/evaluate-behavior/scripts/claude-guard.mjs +76 -0
- package/skills/evaluate-behavior/scripts/guard-rules.mjs +309 -0
- package/skills/evaluate-behavior/scripts/lib/agreement.mjs +90 -0
- package/skills/evaluate-behavior/scripts/lib/arms.mjs +55 -0
- package/skills/evaluate-behavior/scripts/lib/budget.mjs +87 -0
- package/skills/evaluate-behavior/scripts/lib/build-source.mjs +287 -0
- package/skills/evaluate-behavior/scripts/lib/clear.mjs +74 -0
- package/skills/evaluate-behavior/scripts/lib/container.mjs +395 -0
- package/skills/evaluate-behavior/scripts/lib/decision.mjs +418 -0
- package/skills/evaluate-behavior/scripts/lib/definitions.mjs +1072 -0
- package/skills/evaluate-behavior/scripts/lib/freeflow.mjs +103 -0
- package/skills/evaluate-behavior/scripts/lib/grade-command.mjs +591 -0
- package/skills/evaluate-behavior/scripts/lib/grade-comparison.mjs +90 -0
- package/skills/{evaluate-skill → evaluate-behavior}/scripts/lib/grade-interaction.mjs +19 -18
- package/skills/{evaluate-skill → evaluate-behavior}/scripts/lib/grade-support.mjs +32 -5
- package/skills/{evaluate-skill → evaluate-behavior}/scripts/lib/grade-workspace.mjs +28 -12
- package/skills/evaluate-behavior/scripts/lib/grade.mjs +101 -0
- package/skills/evaluate-behavior/scripts/lib/hooks.mjs +98 -0
- package/skills/evaluate-behavior/scripts/lib/hosts/claude-code/confinement.mjs +196 -0
- package/skills/evaluate-behavior/scripts/lib/hosts/claude-code/constraints.mjs +111 -0
- package/skills/evaluate-behavior/scripts/lib/hosts/claude-code/index.mjs +48 -0
- package/skills/evaluate-behavior/scripts/lib/hosts/claude-code/isolation.mjs +74 -0
- package/skills/evaluate-behavior/scripts/lib/hosts/claude-code/launch.mjs +123 -0
- package/skills/evaluate-behavior/scripts/lib/hosts/claude-code/model-call.mjs +73 -0
- package/skills/evaluate-behavior/scripts/lib/hosts/claude-code/recorder.mjs +178 -0
- package/skills/evaluate-behavior/scripts/lib/hosts/claude-code/session.mjs +494 -0
- package/skills/evaluate-behavior/scripts/lib/hosts/claude-code/skills.mjs +81 -0
- package/skills/evaluate-behavior/scripts/lib/hosts/index.mjs +31 -0
- package/skills/evaluate-behavior/scripts/lib/hosts/names.mjs +3 -0
- package/skills/evaluate-behavior/scripts/lib/hosts/pi/confinement.mjs +173 -0
- package/skills/evaluate-behavior/scripts/lib/hosts/pi/host.mjs +148 -0
- package/skills/evaluate-behavior/scripts/lib/hosts/pi/index.mjs +70 -0
- package/skills/evaluate-behavior/scripts/lib/hosts/pi/isolation.mjs +81 -0
- package/skills/evaluate-behavior/scripts/lib/hosts/pi/model-call.mjs +79 -0
- package/skills/evaluate-behavior/scripts/lib/hosts/pi/process.mjs +241 -0
- package/skills/{evaluate-skill/scripts/lib → evaluate-behavior/scripts/lib/hosts/pi}/rpc.mjs +144 -26
- package/skills/evaluate-behavior/scripts/lib/identity.mjs +82 -0
- package/skills/evaluate-behavior/scripts/lib/judge.mjs +688 -0
- package/skills/evaluate-behavior/scripts/lib/metrics.mjs +332 -0
- package/skills/evaluate-behavior/scripts/lib/model-call.mjs +17 -0
- package/skills/evaluate-behavior/scripts/lib/participants.mjs +616 -0
- package/skills/{evaluate-skill → evaluate-behavior}/scripts/lib/process.mjs +22 -0
- package/skills/evaluate-behavior/scripts/lib/queue.mjs +54 -0
- package/skills/evaluate-behavior/scripts/lib/reference.mjs +343 -0
- package/skills/evaluate-behavior/scripts/lib/reuse.mjs +277 -0
- package/skills/evaluate-behavior/scripts/lib/review.mjs +933 -0
- package/skills/evaluate-behavior/scripts/lib/runner.mjs +732 -0
- package/skills/{evaluate-skill → evaluate-behavior}/scripts/lib/sandbox.mjs +121 -14
- package/skills/evaluate-behavior/scripts/lib/scan-shell.mjs +457 -0
- package/skills/evaluate-behavior/scripts/lib/scan.mjs +479 -0
- package/skills/evaluate-behavior/scripts/lib/seal.mjs +91 -0
- package/skills/evaluate-behavior/scripts/lib/shell.mjs +560 -0
- package/skills/evaluate-behavior/scripts/lib/source-override.mjs +64 -0
- package/skills/evaluate-behavior/scripts/lib/subject-file.mjs +88 -0
- package/skills/{evaluate-skill/scripts/lib/pi.mjs → evaluate-behavior/scripts/lib/subject.mjs} +239 -262
- package/skills/evaluate-behavior/scripts/lib/task-copy.mjs +124 -0
- package/skills/evaluate-behavior/scripts/lib/trials.mjs +524 -0
- package/skills/evaluate-behavior/scripts/lib/validity.mjs +68 -0
- package/skills/evaluate-behavior/scripts/lib/view-html.mjs +454 -0
- package/skills/{evaluate-skill → evaluate-behavior}/scripts/lib/view.mjs +218 -11
- package/skills/evaluate-behavior/scripts/pi-command-tool.mjs +159 -0
- package/skills/evaluate-behavior/scripts/pi-container-route.mjs +23 -0
- package/skills/evaluate-behavior/scripts/pi-guard.mjs +77 -0
- package/skills/evaluate-behavior/scripts/pi-login-refresh.mjs +31 -0
- package/skills/evaluate-behavior/scripts/skill-eval.mjs +586 -0
- package/skills/execute-work/SKILL.md +96 -72
- package/skills/execute-work/references/code-practices.md +27 -49
- package/skills/execute-work/references/design.md +271 -0
- package/skills/execute-work/references/diagnose.md +117 -0
- package/skills/execute-work/references/migration.md +108 -0
- package/skills/execute-work/references/simplify.md +65 -0
- package/skills/execute-work/scripts/self-review.mjs +422 -0
- package/skills/execute-work/scripts/touch-map.mjs +290 -0
- package/skills/review-work/SKILL.md +94 -64
- package/skills/review-work/references/adjudication.md +94 -0
- package/skills/review-work/references/artifact.md +198 -0
- package/skills/review-work/references/evals-and-judges.md +66 -0
- package/skills/review-work/references/work.md +177 -0
- package/skills/review-work/scripts/check-brief.mjs +128 -0
- package/skills/review-work/scripts/review-packet.mjs +233 -0
- package/skills/setup-freeflow/SKILL.md +69 -16
- package/skills/track-work/SKILL.md +135 -151
- package/skills/track-work/references/handoff.md +190 -0
- package/skills/track-work/references/projects.md +51 -0
- package/skills/track-work/references/working-record-format.md +201 -344
- package/skills/track-work/scripts/lib/document.mjs +79 -19
- package/skills/track-work/scripts/lib/format.mjs +18 -1
- package/skills/track-work/scripts/lib/recover.mjs +254 -0
- package/skills/track-work/scripts/lib/registry.mjs +656 -0
- package/skills/track-work/scripts/lib/search.mjs +40 -0
- package/skills/track-work/scripts/lib/store.mjs +53 -21
- package/skills/track-work/scripts/lib/transitions.mjs +79 -4
- package/skills/track-work/scripts/lib/views.mjs +50 -1
- package/skills/track-work/scripts/working-record.mjs +263 -22
- package/skills/verify-work/SKILL.md +64 -47
- package/skills/verify-work/references/feature-map.md +120 -0
- package/skills/verify-work/references/runtime-evidence.md +203 -0
- package/skills/verify-work/references/test-design.md +27 -6
- package/skills/verify-work/scripts/test-changes.mjs +246 -0
- package/skills/write-docs/SKILL.md +171 -0
- package/skills/write-docs/references/documentation-shapes.md +184 -0
- package/skills/write-docs/references/spec-and-plan-shapes.md +308 -0
- package/skills/write-docs/scripts/artifact-check.mjs +148 -0
- package/skills/write-docs/scripts/docs-check.mjs +229 -0
- package/skills/write-docs/scripts/plan-lint.mjs +123 -0
- package/skills/write-skill/SKILL.md +165 -165
- package/skills/write-skill/references/activation-and-wording.md +143 -0
- package/skills/write-skill/references/placement-and-dependencies.md +154 -0
- package/skills/write-skill/scripts/lib/compare.mjs +701 -0
- package/skills/write-skill/scripts/lib/similarity.mjs +56 -0
- package/skills/write-skill/scripts/lib/skill-author.mjs +197 -3
- package/skills/write-skill/scripts/skill-author.mjs +67 -8
- package/capabilities/context-virtualization/SKILL.md +0 -103
- package/capabilities/conversation-history/SKILL.md +0 -53
- package/hooks/tests/check-host-adapters.test.mjs +0 -82
- package/hooks/tests/check-runtime-context-hook.sh +0 -212
- package/pi-extension/dist/cognitive-routing-v2/projection.js +0 -330
- package/pi-extension/dist/cognitive-routing-v2/runtime.js +0 -2181
- package/pi-extension/dist/cognitive-routing-v2/tools.js +0 -60
- package/pi-extension/dist/context-virtualization/commands.js +0 -89
- package/pi-extension/dist/context-virtualization/projector.js +0 -42
- package/pi-extension/dist/context-virtualization/runtime.js +0 -378
- package/pi-extension/dist/context-virtualization/state.js +0 -57
- package/pi-extension/dist/context-virtualization/types.js +0 -10
- package/pi-extension/dist/conversation-history/passages.js +0 -66
- package/pi-extension/dist/conversation-history/ranking.js +0 -105
- package/pi-extension/dist/conversation-history/runtime.js +0 -226
- package/pi-extension/dist/conversation-history/search.js +0 -56
- package/pi-extension/dist/conversation-history/types.js +0 -1
- package/pi-extension/dist/freeflow-context/resolver.js +0 -120
- package/pi-extension/dist/freeflow-context/runtime.js +0 -80
- package/pi-extension/dist/freeflow-context/source-projector.js +0 -95
- package/pi-extension/dist/freeflow-context/tool.js +0 -314
- package/pi-extension/dist/freeflow-context/types.js +0 -12
- package/pi-extension/dist/freeflow-context/visibility.js +0 -28
- package/pi-extension/dist/integrations/mcp-config.js +0 -29
- package/pi-extension/dist/runtime/runtime-context.js +0 -754
- package/pi-extension/dist/runtime/runtime-identity.js +0 -5
- package/pi-extension/dist/session-sources/provenance.js +0 -32
- package/pi-extension/dist/settings/settings-ui.js +0 -1360
- package/pi-extension/dist/ui/text-component.js +0 -57
- package/pi-extension/src/cognitive-routing-v2/budget.ts +0 -42
- package/pi-extension/src/cognitive-routing-v2/config.ts +0 -173
- package/pi-extension/src/cognitive-routing-v2/projection.ts +0 -375
- package/pi-extension/src/cognitive-routing-v2/render.ts +0 -277
- package/pi-extension/src/cognitive-routing-v2/runtime.ts +0 -2241
- package/pi-extension/src/cognitive-routing-v2/schemas.ts +0 -180
- package/pi-extension/src/cognitive-routing-v2/state.ts +0 -839
- package/pi-extension/src/cognitive-routing-v2/tools.ts +0 -62
- package/pi-extension/src/cognitive-routing-v2/types.ts +0 -254
- package/pi-extension/src/context-virtualization/commands.ts +0 -111
- package/pi-extension/src/context-virtualization/projector.ts +0 -62
- package/pi-extension/src/context-virtualization/runtime.ts +0 -428
- package/pi-extension/src/context-virtualization/state.ts +0 -79
- package/pi-extension/src/context-virtualization/types.ts +0 -92
- package/pi-extension/src/conversation-history/passages.ts +0 -81
- package/pi-extension/src/conversation-history/ranking.ts +0 -155
- package/pi-extension/src/conversation-history/runtime.ts +0 -250
- package/pi-extension/src/conversation-history/search.ts +0 -79
- package/pi-extension/src/conversation-history/types.ts +0 -31
- package/pi-extension/src/freeflow-context/resolver.ts +0 -139
- package/pi-extension/src/freeflow-context/runtime.ts +0 -100
- package/pi-extension/src/freeflow-context/source-projector.ts +0 -106
- package/pi-extension/src/freeflow-context/tool.ts +0 -366
- package/pi-extension/src/freeflow-context/types.ts +0 -70
- package/pi-extension/src/freeflow-context/visibility.ts +0 -53
- package/pi-extension/src/index.ts +0 -390
- package/pi-extension/src/integrations/mcp-config.ts +0 -32
- package/pi-extension/src/provider-support/astra/adapter.ts +0 -108
- package/pi-extension/src/provider-support/astra/history.ts +0 -145
- package/pi-extension/src/provider-support/astra/index.ts +0 -12
- package/pi-extension/src/provider-support/astra/session-state.ts +0 -113
- package/pi-extension/src/provider-support/index.ts +0 -5
- package/pi-extension/src/runtime/request-history.ts +0 -243
- package/pi-extension/src/runtime/runtime-context.ts +0 -860
- package/pi-extension/src/runtime/runtime-identity.ts +0 -8
- package/pi-extension/src/session-sources/events.ts +0 -230
- package/pi-extension/src/session-sources/provenance.ts +0 -39
- package/pi-extension/src/session-sources/read-only-session.ts +0 -170
- package/pi-extension/src/session-sources/sources.ts +0 -334
- package/pi-extension/src/settings/settings-tui.ts +0 -501
- package/pi-extension/src/settings/settings-ui.ts +0 -1652
- package/pi-extension/src/ui/text-component.ts +0 -66
- package/pi-extension/tests/cache-reuse/history.test.js +0 -117
- package/pi-extension/tests/cache-reuse/native.test.js +0 -91
- package/pi-extension/tests/cache-reuse/settings.test.js +0 -211
- package/pi-extension/tests/cognitive-routing-v2/communication.test.js +0 -577
- package/pi-extension/tests/cognitive-routing-v2/compaction-input.test.js +0 -183
- package/pi-extension/tests/cognitive-routing-v2/delegation.test.js +0 -557
- package/pi-extension/tests/cognitive-routing-v2/native.test.js +0 -474
- package/pi-extension/tests/cognitive-routing-v2/performance.test.js +0 -87
- package/pi-extension/tests/cognitive-routing-v2/persistence.test.js +0 -300
- package/pi-extension/tests/cognitive-routing-v2/projection.test.js +0 -241
- package/pi-extension/tests/cognitive-routing-v2/recovery.test.js +0 -1034
- package/pi-extension/tests/cognitive-routing-v2/render.test.js +0 -244
- package/pi-extension/tests/cognitive-routing-v2/runtime.test.js +0 -423
- package/pi-extension/tests/cognitive-routing-v2/stabilization.test.js +0 -521
- package/pi-extension/tests/cognitive-routing-v2/state.test.js +0 -586
- package/pi-extension/tests/context-virtualization/extension.test.js +0 -775
- package/pi-extension/tests/context-virtualization/projector.test.js +0 -110
- package/pi-extension/tests/context-virtualization/runtime.test.js +0 -230
- package/pi-extension/tests/conversation-history/runtime.test.js +0 -98
- package/pi-extension/tests/conversation-history/search.test.js +0 -97
- package/pi-extension/tests/fixtures/pi-host.js +0 -4
- package/pi-extension/tests/fixtures/routing-native.js +0 -191
- package/pi-extension/tests/integration/mode-free-core.test.js +0 -220
- package/pi-extension/tests/integration/pi-extension.test.js +0 -1447
- package/pi-extension/tests/integration/prompt-architecture.test.js +0 -447
- package/pi-extension/tests/integration/unaffected-regressions.test.js +0 -478
- package/pi-extension/tests/provider-support/astra-boundaries.test.js +0 -75
- package/pi-extension/tests/provider-support/astra.test.js +0 -306
- package/pi-extension/tests/provider-support/cli.test.js +0 -92
- package/pi-extension/tests/provider-support/native.test.js +0 -183
- package/pi-extension/tests/settings/settings-tui.test.js +0 -243
- package/pi-extension/tsconfig.json +0 -16
- package/plugin.json +0 -33
- package/runtime/prompts/context-virtualization.md +0 -3
- package/runtime/prompts/conversation-history.md +0 -3
- package/skills/action-selection/SKILL.md +0 -100
- package/skills/action-selection/references/trajectory-stalls.md +0 -71
- package/skills/bypass/SKILL.md +0 -153
- package/skills/commit-work/SKILL.md +0 -145
- package/skills/commit-work/references/git-state-edges.md +0 -94
- package/skills/commit-work/references/simple-push.md +0 -92
- package/skills/commit-work/references/staging-decisions.md +0 -106
- package/skills/decision-gate/SKILL.md +0 -106
- package/skills/design-for-depth/SKILL.md +0 -117
- package/skills/design-for-depth/references/design-pressure-signals.md +0 -182
- package/skills/design-for-depth/references/implementation-decisions.md +0 -76
- package/skills/design-for-depth/references/interface-design-loop.md +0 -136
- package/skills/design-for-depth/references/module-and-dependency-design.md +0 -147
- package/skills/design-for-depth/references/software-design-philosophy.md +0 -202
- package/skills/design-for-depth/references/state-and-failure-boundaries.md +0 -136
- package/skills/diagnose-failure/SKILL.md +0 -125
- package/skills/diagnose-failure/references/diagnostic-loop-catalog.md +0 -48
- package/skills/diagnose-failure/references/flaky-and-performance-diagnosis.md +0 -51
- package/skills/discuss/SKILL.md +0 -116
- package/skills/evaluate-skill/SKILL.md +0 -219
- package/skills/evaluate-skill/references/evaluation-definition-schema.md +0 -385
- package/skills/evaluate-skill/references/evaluation-design.md +0 -112
- package/skills/evaluate-skill/references/execution-and-evidence.md +0 -90
- package/skills/evaluate-skill/references/review-and-revision.md +0 -92
- package/skills/evaluate-skill/scripts/lib/definitions.mjs +0 -407
- package/skills/evaluate-skill/scripts/lib/grade-comparison.mjs +0 -60
- package/skills/evaluate-skill/scripts/lib/grade.mjs +0 -64
- package/skills/evaluate-skill/scripts/lib/runner.mjs +0 -368
- package/skills/evaluate-skill/scripts/pi-guard.mjs +0 -164
- package/skills/evaluate-skill/scripts/skill-eval.mjs +0 -102
- package/skills/execute-work/references/execute-work-edges.md +0 -68
- package/skills/finish-branch/SKILL.md +0 -117
- package/skills/finish-branch/references/integration-options.md +0 -80
- package/skills/handoff/SKILL.md +0 -82
- package/skills/handoff/references/handoff-templates.md +0 -150
- package/skills/launch-work/SKILL.md +0 -116
- package/skills/launch-work/references/launch-readiness.md +0 -85
- package/skills/migration-work/SKILL.md +0 -115
- package/skills/migration-work/references/migration-lifecycle.md +0 -82
- package/skills/release-work/SKILL.md +0 -118
- package/skills/release-work/references/release-evidence.md +0 -78
- package/skills/review-artifact/SKILL.md +0 -142
- package/skills/review-artifact/references/adjudicate-artifact-review.md +0 -101
- package/skills/review-artifact/references/independent-artifact-reviewer-contract.md +0 -159
- package/skills/review-work/references/adjudicate-work-review.md +0 -97
- package/skills/review-work/references/independent-work-reviewer-contract.md +0 -139
- package/skills/review-work/references/security-risk-lens.md +0 -69
- package/skills/setup-freeflow/references/activation-contract.md +0 -109
- package/skills/setup-freeflow/references/host-setup.md +0 -67
- package/skills/simplify-code/SKILL.md +0 -85
- package/skills/simplify-code/references/simplification-patterns.md +0 -70
- package/skills/verify-work/references/browser-runtime-evidence.md +0 -55
- package/skills/verify-work/references/integration-evidence.md +0 -47
- package/skills/verify-work/references/performance-evidence.md +0 -57
- package/skills/workflow/SKILL.md +0 -127
- package/skills/workflow/references/domain-skill-composition.md +0 -43
- package/skills/write-plan/SKILL.md +0 -92
- package/skills/write-plan/references/plan-shapes.md +0 -156
- package/skills/write-skill/references/activation-boundaries.md +0 -104
- package/skills/write-skill/references/agent-first-instructions.md +0 -121
- package/skills/write-skill/references/progressive-disclosure.md +0 -127
- package/skills/write-skill/references/skill-dependency-graphs.md +0 -190
- package/skills/write-spec/SKILL.md +0 -92
- package/skills/write-spec/references/artifact-standards.md +0 -86
- package/skills/write-spec/references/decision-records.md +0 -78
- package/skills/write-spec/references/spec-shapes.md +0 -143
- /package/pi-extension/dist/{cognitive-routing-v2 → cognitive-routing}/budget.js +0 -0
- /package/skills/{evaluate-skill → evaluate-behavior}/scripts/lib/evidence.mjs +0 -0
- /package/skills/{evaluate-skill → evaluate-behavior}/scripts/pi-observer.mjs +0 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// The validity gate: a subject run the host reported complete is graded only when it shows a model actually ran.
|
|
2
|
+
// A login that failed, a provider that answered nothing, or a host that exited cleanly without calling the model
|
|
3
|
+
// would otherwise be graded like real behavior: every check fails, or an "absent" check passes, and the run counts
|
|
4
|
+
// in a comparison. Such a run becomes `invalid` with its reasons, before any grader runs; it is never a fail, never
|
|
5
|
+
// counted in a comparison or decision, and it stops a pilot. An unclean host exit is already `infrastructure-failed`.
|
|
6
|
+
//
|
|
7
|
+
// Cost is not the signal: a model with no configured price reports zero cost for real work. Tokens are: every real
|
|
8
|
+
// model call has input and output tokens, so a run whose usage totals zero tokens did not reach a model. A provider
|
|
9
|
+
// that reports no token usage at all cannot be told apart from one that never answered, so its runs are invalid too.
|
|
10
|
+
//
|
|
11
|
+
// Tool use is not required. A model that answers in one turn without tools, such as a description run whose target
|
|
12
|
+
// did not activate, or a subject that declines the task, is behavior to grade, not a hollow run. A run must leave an
|
|
13
|
+
// answer or written work: one that only read and ended silently has nothing to grade.
|
|
14
|
+
|
|
15
|
+
/** The run's assistant messages, from its transcript (every host records them there). */
|
|
16
|
+
function assistantMessages(run) {
|
|
17
|
+
return (Array.isArray(run.transcript) ? run.transcript : []).filter((message) => message?.role === "assistant");
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function totalTokens(usage) {
|
|
21
|
+
if (usage === null || typeof usage !== "object") return 0;
|
|
22
|
+
return ["input", "output", "cacheRead", "cacheWrite"].reduce(
|
|
23
|
+
(total, key) => total + (Number.isFinite(usage[key]) ? usage[key] : 0),
|
|
24
|
+
0,
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function answered(run) {
|
|
29
|
+
if (typeof run.response === "string" && run.response.trim() !== "") return true;
|
|
30
|
+
return (Array.isArray(run.turns) ? run.turns : []).some(
|
|
31
|
+
(turn) => typeof turn?.response === "string" && turn.response.trim() !== "",
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function wroteSomething(run) {
|
|
36
|
+
const changes = run.effects?.changes;
|
|
37
|
+
return ["created", "modified", "deleted"].some((key) => Array.isArray(changes?.[key]) && changes[key].length > 0);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Why a run the host reported complete is not valid evidence, as a list of reasons; empty when it is valid. Only a
|
|
42
|
+
* `complete` run is checked: every other state already says why it is not graded.
|
|
43
|
+
*
|
|
44
|
+
* @param {any} run
|
|
45
|
+
* @returns {string[]}
|
|
46
|
+
*/
|
|
47
|
+
export function validityProblems(run) {
|
|
48
|
+
if (run?.state !== "complete") return [];
|
|
49
|
+
const problems = [];
|
|
50
|
+
if (assistantMessages(run).length === 0) problems.push("no model turn: the host recorded no assistant message");
|
|
51
|
+
if (totalTokens(run.usage) === 0) {
|
|
52
|
+
problems.push("no tokens: the run's usage totals zero tokens, so no model call is shown to have happened");
|
|
53
|
+
}
|
|
54
|
+
if (!answered(run) && !wroteSomething(run)) problems.push("no answer and nothing written in the workspace");
|
|
55
|
+
return problems;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Marks a hollow complete run `invalid` in place, keeping everything it recorded; returns whether it did. The
|
|
60
|
+
* reasons are in `error.reasons`, and `error.kind` is `validity`.
|
|
61
|
+
*/
|
|
62
|
+
export function applyValidityGate(run) {
|
|
63
|
+
const problems = validityProblems(run);
|
|
64
|
+
if (problems.length === 0) return false;
|
|
65
|
+
run.state = "invalid";
|
|
66
|
+
run.error = { kind: "validity", message: `not valid evidence: ${problems.join("; ")}`, reasons: problems };
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
import { readFile, stat, writeFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
|
|
4
|
+
import { storedArms } from "./arms.mjs";
|
|
5
|
+
import { claimSummary, trialCounts, verdictText } from "./decision.mjs";
|
|
6
|
+
import { readSubjectFile, skippedNote } from "./subject-file.mjs";
|
|
7
|
+
import { resolveResult } from "./view.mjs";
|
|
8
|
+
|
|
9
|
+
// Run content (responses, changed files, tool arguments) can be large or hostile; every value passes through esc().
|
|
10
|
+
const CONTENT_CAP = 20000;
|
|
11
|
+
const VALUE_CAP = 500;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Writes one self-contained HTML page for a stored result or aggregate: inline CSS, no scripts, no network.
|
|
15
|
+
* Returns the absolute path written. Selectors are refused because the page always covers the whole result.
|
|
16
|
+
*/
|
|
17
|
+
export async function writeHtml(
|
|
18
|
+
target,
|
|
19
|
+
file,
|
|
20
|
+
{ root = process.cwd(), selectors = { group: null, variant: null }, results = null } = {},
|
|
21
|
+
) {
|
|
22
|
+
if (selectors.group !== null || selectors.variant !== null) {
|
|
23
|
+
throw new Error("view --html renders the whole result; drop --group and --variant");
|
|
24
|
+
}
|
|
25
|
+
const html = await renderHtml(target, { root, results });
|
|
26
|
+
const destination = path.resolve(root, file);
|
|
27
|
+
await writeFile(destination, html);
|
|
28
|
+
return destination;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export async function renderHtml(target, { root = process.cwd(), results = null } = {}) {
|
|
32
|
+
const resultDirectory = await resolveResult(target, root, results);
|
|
33
|
+
const aggregate = await readOptionalJson(path.join(resultDirectory, "aggregate.json"));
|
|
34
|
+
if (aggregate !== null) {
|
|
35
|
+
const parts = [
|
|
36
|
+
claimSection(aggregate),
|
|
37
|
+
decisionBlock(aggregate),
|
|
38
|
+
...(Array.isArray(aggregate.groups) ? aggregate.groups : []).map(metricsGroupBlock),
|
|
39
|
+
`<p class="meta">Aggregate ${esc(aggregate.id)} · state ${esc(aggregate.state)} · trials ${esc(trialCounts(aggregate))}</p>`,
|
|
40
|
+
];
|
|
41
|
+
for (const trial of aggregate.trials) {
|
|
42
|
+
parts.push(`<section class="trial"><h2>Trial ${esc(trial.id)} [${esc(trial.state)}]</h2>`);
|
|
43
|
+
try {
|
|
44
|
+
// An aggregate's trials are stored beside it.
|
|
45
|
+
const trialDirectory = await resolveResult(trial.id, root, path.dirname(resultDirectory));
|
|
46
|
+
const summary = await readJson(path.join(trialDirectory, "summary.json"), `trial ${trial.id} summary`);
|
|
47
|
+
parts.push(await resultBody(trialDirectory, summary));
|
|
48
|
+
} catch (error) {
|
|
49
|
+
parts.push(
|
|
50
|
+
`<p class="missing">Trial result unavailable: ${esc(error instanceof Error ? error.message : String(error))}</p>`,
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
parts.push("</section>");
|
|
54
|
+
}
|
|
55
|
+
return page(`Aggregate ${aggregate.id}`, parts.join("\n"));
|
|
56
|
+
}
|
|
57
|
+
const summary = await readJson(path.join(resultDirectory, "summary.json"), "result summary");
|
|
58
|
+
return page(`Result ${summary.id}`, await resultBody(resultDirectory, summary));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async function resultBody(resultDirectory, summary) {
|
|
62
|
+
const parts = [`<p class="meta">Result ${esc(summary.id)} · state ${esc(summary.state)}</p>`];
|
|
63
|
+
for (const group of Array.isArray(summary.groups) ? summary.groups : []) {
|
|
64
|
+
parts.push(await groupSection(resultDirectory, group));
|
|
65
|
+
}
|
|
66
|
+
return parts.join("\n");
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async function groupSection(resultDirectory, group) {
|
|
70
|
+
const groupDirectory = path.join(resultDirectory, "groups", group.id);
|
|
71
|
+
const definition = await readJson(path.join(groupDirectory, "definition.json"), `definition for ${group.id}`);
|
|
72
|
+
const grade = await readJson(
|
|
73
|
+
path.join(groupDirectory, group.artifacts?.grade ?? "deterministic-grade.json"),
|
|
74
|
+
`grade for ${group.id}`,
|
|
75
|
+
);
|
|
76
|
+
const parts = [
|
|
77
|
+
`<section class="group"><h2>Group ${esc(group.id)} [${esc(group.state)}] <span class="muted">type=${esc(definition.type)}</span></h2>`,
|
|
78
|
+
promptBlock(definition),
|
|
79
|
+
];
|
|
80
|
+
const reviewQuestions = Array.isArray(definition.review_questions) ? definition.review_questions : [];
|
|
81
|
+
if (reviewQuestions.length > 0) {
|
|
82
|
+
parts.push(
|
|
83
|
+
`<h3>Review questions</h3><ul>${reviewQuestions.map((question) => `<li>${esc(question)}</li>`).join("")}</ul>`,
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
for (const arm of storedArms(group, definition)) {
|
|
87
|
+
parts.push(await armSection(groupDirectory, arm, grade));
|
|
88
|
+
}
|
|
89
|
+
const advisory = await readOptionalJson(path.join(groupDirectory, "semantic-grade.json"));
|
|
90
|
+
if (advisory !== null) parts.push(advisoryBlock(advisory));
|
|
91
|
+
parts.push("</section>");
|
|
92
|
+
return parts.join("\n");
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function promptBlock(definition) {
|
|
96
|
+
if (typeof definition.input?.prompt === "string") {
|
|
97
|
+
return `<h3>Prompt</h3><pre>${esc(definition.input.prompt)}</pre>`;
|
|
98
|
+
}
|
|
99
|
+
const turns = Array.isArray(definition.input?.turns) ? definition.input.turns : [];
|
|
100
|
+
return turns.map((turn, index) => `<h3>Turn ${index + 1} prompt</h3><pre>${esc(turn)}</pre>`).join("\n");
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async function armSection(groupDirectory, arm, grade) {
|
|
104
|
+
const variantDirectory = path.join(groupDirectory, arm);
|
|
105
|
+
const run = await readJson(path.join(variantDirectory, "run.json"), `${arm} run`);
|
|
106
|
+
const parts = [`<article class="arm"><h3>${esc(arm)} <span class="muted">[${esc(run.state)}]</span></h3>`];
|
|
107
|
+
|
|
108
|
+
const finalFile = path.resolve(
|
|
109
|
+
variantDirectory,
|
|
110
|
+
typeof run.artifacts?.final === "string" ? run.artifacts.final : "final.md",
|
|
111
|
+
);
|
|
112
|
+
const finalText = await readText(finalFile);
|
|
113
|
+
parts.push(
|
|
114
|
+
`<h4>Final response</h4>${finalText === null ? '<p class="missing">No final response recorded.</p>' : preBlock(finalText)}`,
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
parts.push(await changedFilesBlock(run, variantDirectory));
|
|
118
|
+
parts.push(toolCallsBlock(run));
|
|
119
|
+
parts.push(checksBlock(grade, arm));
|
|
120
|
+
if (run.metrics && typeof run.metrics === "object") parts.push(metricsBlock(run.metrics));
|
|
121
|
+
const judged = await readOptionalJson(path.join(variantDirectory, "judged-grade.json"));
|
|
122
|
+
if (judged !== null) parts.push(judgedBlock(judged));
|
|
123
|
+
|
|
124
|
+
parts.push("</article>");
|
|
125
|
+
return parts.join("\n");
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
async function changedFilesBlock(run, variantDirectory) {
|
|
129
|
+
const changes = run.effects?.changes;
|
|
130
|
+
if (!changes) return "";
|
|
131
|
+
const workspace = typeof run.workspace === "string" ? path.resolve(variantDirectory, run.workspace) : null;
|
|
132
|
+
const entries = [];
|
|
133
|
+
for (const kind of ["created", "modified", "deleted"]) {
|
|
134
|
+
for (const relative of Array.isArray(changes[kind]) ? changes[kind] : []) {
|
|
135
|
+
entries.push(await changedFileEntry(kind, String(relative), workspace));
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
if (entries.length === 0) return "<h4>Changed files</h4><p>None.</p>";
|
|
139
|
+
return `<h4>Changed files</h4>${entries.join("\n")}`;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
async function changedFileEntry(kind, relative, workspace) {
|
|
143
|
+
const label = `${esc(kind)} ${esc(relative)}`;
|
|
144
|
+
if (kind === "deleted")
|
|
145
|
+
return `<details><summary>${label}</summary><p class="missing">Deleted; no content.</p></details>`;
|
|
146
|
+
if (workspace === null)
|
|
147
|
+
return `<details><summary>${label}</summary><p class="missing">Content unavailable.</p></details>`;
|
|
148
|
+
const file = path.resolve(workspace, relative);
|
|
149
|
+
if (!file.startsWith(`${workspace}${path.sep}`)) {
|
|
150
|
+
return `<details><summary>${label}</summary><p class="missing">Path leaves the workspace; not shown.</p></details>`;
|
|
151
|
+
}
|
|
152
|
+
// Never through a link the run made, and only a regular file inside the workspace, read to a bound.
|
|
153
|
+
const read = await readSubjectFile(workspace, relative, { limit: CONTENT_CAP * 4 });
|
|
154
|
+
if (read.skipped !== undefined) {
|
|
155
|
+
const why =
|
|
156
|
+
read.skipped === "missing" || read.skipped === "binary" ? "Content unavailable." : `${skippedNote(read)}.`;
|
|
157
|
+
return `<details><summary>${label}</summary><p class="missing">${esc(why)}</p></details>`;
|
|
158
|
+
}
|
|
159
|
+
const { text } = read;
|
|
160
|
+
const cut = read.truncated || text.length > CONTENT_CAP;
|
|
161
|
+
const shown = text.length > CONTENT_CAP ? text.slice(0, CONTENT_CAP) : text;
|
|
162
|
+
const of = read.truncated ? `${read.size} bytes` : `${text.length} characters`;
|
|
163
|
+
const note = cut ? `<p class="missing">Cut at ${CONTENT_CAP} of ${of}.</p>` : "";
|
|
164
|
+
return `<details><summary>${label}</summary>${preBlock(shown)}${note}</details>`;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function toolCallsBlock(run) {
|
|
168
|
+
const calls = Array.isArray(run.turns)
|
|
169
|
+
? run.turns.flatMap((turn) => (turn.toolActivity ?? []).map((entry) => ({ turn: turn.turn, entry })))
|
|
170
|
+
: (run.toolActivity ?? []).map((entry) => ({ turn: null, entry }));
|
|
171
|
+
if (calls.length === 0) return "<h4>Tool calls</h4><p>None.</p>";
|
|
172
|
+
const rows = calls.map(({ turn, entry }) => {
|
|
173
|
+
const where = turn === null ? "" : `turn ${esc(turn)} · `;
|
|
174
|
+
const failed = entry.isError === true ? ' <span class="fail">error</span>' : "";
|
|
175
|
+
return `<li>${where}<code>${esc(entry.toolName ?? "unknown")}</code>${failed} <code>${esc(compact(entry.args))}</code></li>`;
|
|
176
|
+
});
|
|
177
|
+
return `<h4>Tool calls</h4><ol>${rows.join("")}</ol>`;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function checksBlock(grade, arm) {
|
|
181
|
+
const checks = Array.isArray(grade.checks) ? grade.checks.filter((check) => check.variant === arm) : [];
|
|
182
|
+
if (checks.length === 0) return "<h4>Deterministic checks</h4><p>None for this arm.</p>";
|
|
183
|
+
const rows = checks.map(
|
|
184
|
+
(check) =>
|
|
185
|
+
`<tr><td>${esc(check.id)}</td><td>${esc(check.kind)}</td><td class="${check.state === "pass" ? "pass" : check.state === "fail" ? "fail" : ""}">${esc(check.state)}</td><td><code>${esc(compact(check.expected))}</code></td><td><code>${esc(compact(check.observed))}</code></td></tr>`,
|
|
186
|
+
);
|
|
187
|
+
return `<h4>Deterministic checks</h4><table><thead><tr><th>id</th><th>kind</th><th>state</th><th>expected</th><th>observed</th></tr></thead><tbody>${rows.join("")}</tbody></table>`;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function metricsBlock(metrics) {
|
|
191
|
+
const rows = Object.entries(metrics).map(
|
|
192
|
+
([name, value]) => `<tr><td>${esc(name)}</td><td><code>${esc(compact(value))}</code></td></tr>`,
|
|
193
|
+
);
|
|
194
|
+
return `<h4>Metrics</h4><table><tbody>${rows.join("")}</tbody></table>`;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// The judged-grade.json shape is written by review.mjs (rubric judging) and read by judge.mjs (judgedLines).
|
|
198
|
+
function judgedBlock(judged) {
|
|
199
|
+
const dimensions = Array.isArray(judged.rubric?.dimensions) ? judged.rubric.dimensions : [];
|
|
200
|
+
const combined = Array.isArray(judged.answers) ? judged.answers : [];
|
|
201
|
+
const judges = Array.isArray(judged.judges) ? judged.judges : [];
|
|
202
|
+
const gaps = Array.isArray(judged.contractGaps) ? judged.contractGaps : [];
|
|
203
|
+
const parts = [
|
|
204
|
+
`<h4>Judged evidence <span class="muted">(judged, not deterministic grades)</span></h4>`,
|
|
205
|
+
`<p class="meta">state ${esc(judged.state)} · combine ${esc(judged.combine ?? "majority")} · truncated ${esc(judged.truncated ?? 0)}</p>`,
|
|
206
|
+
gaps.length === 0
|
|
207
|
+
? "<p>Contract gaps: none</p>"
|
|
208
|
+
: `<p class="fail">Contract gaps: ${gaps.map((gap) => esc(gap)).join("; ")}</p>`,
|
|
209
|
+
];
|
|
210
|
+
for (const dimension of dimensions) {
|
|
211
|
+
const result = combined.find((entry) => entry.dimension === dimension.id);
|
|
212
|
+
const rows = judges.map((judge) => {
|
|
213
|
+
const answer = (judge.answers ?? []).find((entry) => entry.dimension === dimension.id);
|
|
214
|
+
return `<tr><td>${esc(judgeLabel(judge))}<br><span class="muted">family ${esc(judge.familyRelation ?? "unknown")} · ${esc(judge.state)}</span></td><td>${esc(answer?.answer ?? "-")}</td><td>${esc(answer?.evidence ?? "-")}</td><td>${calibrationCell(judge.calibration, dimension.id)}</td></tr>`;
|
|
215
|
+
});
|
|
216
|
+
const votes = Array.isArray(result?.votes) ? result.votes.map((vote) => esc(vote)).join(", ") : "-";
|
|
217
|
+
rows.push(
|
|
218
|
+
`<tr><th>combined</th><td>${esc(result?.answer ?? "-")}</td><td>votes ${votes || "-"}</td><td></td></tr>`,
|
|
219
|
+
);
|
|
220
|
+
parts.push(
|
|
221
|
+
`<h5>${esc(dimension.id)} <span class="muted">${esc(dimension.question ?? "")}</span></h5>`,
|
|
222
|
+
`<table><thead><tr><th>judge</th><th>answer</th><th>evidence</th><th>calibration</th></tr></thead><tbody>${rows.join("")}</tbody></table>`,
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
for (const judge of judges) {
|
|
226
|
+
for (const error of judge.errors ?? []) parts.push(`<p class="fail">${esc(judgeLabel(judge))}: ${esc(error)}</p>`);
|
|
227
|
+
}
|
|
228
|
+
return parts.join("\n");
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function judgeLabel(judge) {
|
|
232
|
+
return `${judge.model ?? "unknown"}${judge.thinking ? ` (${judge.thinking})` : ""}`;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function calibrationCell(calibration, dimensionId) {
|
|
236
|
+
if (calibration?.state !== "checked") return "not checked";
|
|
237
|
+
const measured = calibration.dimensions?.[dimensionId];
|
|
238
|
+
const kappa = measured ? `kappa ${fmt(measured.kappa)} over ${esc(measured.items ?? "-")} item(s)` : "no kappa";
|
|
239
|
+
return `agreement ${fmt(calibration.agreement)} over ${esc(calibration.runs ?? 0)} labelled run(s); ${kappa}; checked ${esc(calibration.checkedAt ?? "-")}`;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// The advisory pairwise review (semantic-grade.json). Its answers are not canonical evidence.
|
|
243
|
+
function advisoryBlock(review) {
|
|
244
|
+
const labels = review.labels && typeof review.labels === "object" ? review.labels : {};
|
|
245
|
+
const names = Object.keys(labels);
|
|
246
|
+
const arms = names.map((label) => labels[label]);
|
|
247
|
+
const answers = Array.isArray(review.answers) ? review.answers : [];
|
|
248
|
+
const rows = answers.map(
|
|
249
|
+
(answer, index) =>
|
|
250
|
+
`<tr><td>${index + 1}. ${esc(answer.question ?? "")}</td>${arms.map((arm) => `<td>${esc(answer[arm] ?? "-")}</td>`).join("")}<td>${esc(answer.rationale ?? "")}</td></tr>`,
|
|
251
|
+
);
|
|
252
|
+
const parts = [
|
|
253
|
+
`<section class="advisory"><h3>Advisory pairwise review <span class="muted">(advisory, not canonical evidence)</span></h3>`,
|
|
254
|
+
`<p class="meta">state ${esc(review.state)} · model ${esc(review.model ?? "unknown")}${review.thinking ? ` (${esc(review.thinking)})` : ""} · judge family ${esc(review.judge?.family ?? "unknown")} · subject ${esc(review.subject?.familyRelation ?? "unknown")}</p>`,
|
|
255
|
+
`<p class="meta">Labels: ${names.map((label) => `${esc(label)} = ${esc(labels[label])}`).join(", ") || "none"}</p>`,
|
|
256
|
+
`<table><thead><tr><th>question</th>${arms.map((arm) => `<th>${esc(arm)}</th>`).join("")}<th>rationale</th></tr></thead><tbody>${rows.join("")}</tbody></table>`,
|
|
257
|
+
];
|
|
258
|
+
const agreement = review.swap?.agreement;
|
|
259
|
+
if (agreement) {
|
|
260
|
+
const perArm = agreement.arms
|
|
261
|
+
? ` · per arm ${Object.entries(agreement.arms)
|
|
262
|
+
.map(([arm, counts]) => `${esc(arm)} ${esc(counts.agreed)}/${esc(counts.questions)}`)
|
|
263
|
+
.join(", ")}`
|
|
264
|
+
: "";
|
|
265
|
+
parts.push(`<p>Order swap agreed on ${esc(agreement.agreed)}/${esc(agreement.questions)}${perArm}</p>`);
|
|
266
|
+
} else if (review.swap === undefined) {
|
|
267
|
+
parts.push(`<p class="missing">Order not swapped.</p>`);
|
|
268
|
+
}
|
|
269
|
+
for (const gap of Array.isArray(review.contractGaps) ? review.contractGaps : []) {
|
|
270
|
+
parts.push(`<p class="fail">Contract gap: ${esc(gap)}</p>`);
|
|
271
|
+
}
|
|
272
|
+
for (const error of Array.isArray(review.errors) ? review.errors : []) {
|
|
273
|
+
parts.push(`<p class="fail">Error: ${esc(error)}</p>`);
|
|
274
|
+
}
|
|
275
|
+
parts.push("</section>");
|
|
276
|
+
return parts.join("\n");
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// The aggregate's decision: the rule, the split, the sign test p and the verdict.
|
|
280
|
+
function decisionBlock(aggregate) {
|
|
281
|
+
const decision = aggregate.decision;
|
|
282
|
+
if (!decision || typeof decision !== "object" || !decision.rule) return "";
|
|
283
|
+
const rule = decision.rule;
|
|
284
|
+
const measure = Object.entries(rule.measure ?? {})
|
|
285
|
+
.map(([kind, name]) => `${kind} ${name}`)
|
|
286
|
+
.join(", ");
|
|
287
|
+
const rows = [
|
|
288
|
+
["measure", measure],
|
|
289
|
+
["direction", `${rule.direction} is better`],
|
|
290
|
+
["arms", `${decision.arm} against ${decision.reference}`],
|
|
291
|
+
["method", `${rule.method} (alpha ${fmt(rule.alpha)}, min cases ${rule.min_cases})`],
|
|
292
|
+
...(rule.trials ? [["trials", `${rule.trials.initial}..${rule.trials.max} step ${rule.trials.step}`]] : []),
|
|
293
|
+
["rule sha256", decision.ruleSha256],
|
|
294
|
+
["split (better / worse / ties)", `${decision.better} / ${decision.worse} / ${decision.ties}`],
|
|
295
|
+
["decided / excluded", `${decision.decided} / ${decision.excluded}`],
|
|
296
|
+
["p (sign test)", Number.isFinite(decision.p) ? String(Number(decision.p.toPrecision(4))) : "-"],
|
|
297
|
+
["verdict", verdictText(decision.verdict)],
|
|
298
|
+
["claim", claimSummary(aggregate)?.reached ?? "none"],
|
|
299
|
+
];
|
|
300
|
+
const cases = Array.isArray(decision.cases) ? decision.cases : [];
|
|
301
|
+
const caseRows = cases.map(
|
|
302
|
+
(entry) =>
|
|
303
|
+
`<tr><td>${esc(entry.id)}</td><td>${esc(entry.trials ?? "-")}</td><td>${esc(entry.sign ?? "-")}</td><td>${esc(entry.reason ?? "")}</td><td><code>${esc(compact(entry.arms))}</code></td></tr>`,
|
|
304
|
+
);
|
|
305
|
+
return [
|
|
306
|
+
`<section class="decision"><h2>Decision</h2>`,
|
|
307
|
+
`<table><tbody>${rows.map(([name, value]) => `<tr><th>${esc(name)}</th><td>${esc(value)}</td></tr>`).join("")}</tbody></table>`,
|
|
308
|
+
`<h4>Cases</h4><table><thead><tr><th>case</th><th>trials</th><th>sign</th><th>reason</th><th>arms</th></tr></thead><tbody>${caseRows.join("")}</tbody></table>`,
|
|
309
|
+
"</section>",
|
|
310
|
+
].join("\n");
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// The per-group metrics section of an aggregate: per arm medians, and paired differences against the reference.
|
|
314
|
+
function metricsGroupBlock(group) {
|
|
315
|
+
const section = group?.metrics;
|
|
316
|
+
if (!section || typeof section !== "object") return "";
|
|
317
|
+
const head = `<section class="metrics"><h3>Metrics: ${esc(group.id)}</h3>`;
|
|
318
|
+
if (typeof section.error === "string") return `${head}<p class="fail">${esc(section.error)}</p></section>`;
|
|
319
|
+
const arms = Object.entries(section.arms ?? {});
|
|
320
|
+
const names = [...new Set(arms.flatMap(([, metrics]) => Object.keys(metrics ?? {})))].filter((name) =>
|
|
321
|
+
arms.some(([, metrics]) => (metrics?.[name]?.count ?? 0) > 0),
|
|
322
|
+
);
|
|
323
|
+
const rows = names.map(
|
|
324
|
+
(name) =>
|
|
325
|
+
`<tr><td>${esc(name)}</td>${arms
|
|
326
|
+
.map(([, metrics]) => {
|
|
327
|
+
const summary = metrics?.[name];
|
|
328
|
+
return `<td>median ${fmt(summary?.median)} · mean ${fmt(summary?.mean)} · n ${esc(summary?.count ?? 0)}</td>`;
|
|
329
|
+
})
|
|
330
|
+
.join("")}</tr>`,
|
|
331
|
+
);
|
|
332
|
+
const diffRows = [];
|
|
333
|
+
for (const [arm, byName] of Object.entries(section.differences ?? {})) {
|
|
334
|
+
for (const name of names) {
|
|
335
|
+
const difference = byName?.[name];
|
|
336
|
+
if (!difference || difference.pairs === 0) continue;
|
|
337
|
+
diffRows.push(
|
|
338
|
+
`<tr><td>${esc(name)}</td><td>${esc(arm)} − ${esc(section.reference)}</td><td>mean ${fmt(difference.mean)} · median ${fmt(difference.median)} · pairs ${esc(difference.pairs)}</td></tr>`,
|
|
339
|
+
);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
const parts = [head];
|
|
343
|
+
parts.push(
|
|
344
|
+
`<table><thead><tr><th>metric</th>${arms.map(([arm]) => `<th>${esc(arm)}</th>`).join("")}</tr></thead><tbody>${rows.join("")}</tbody></table>`,
|
|
345
|
+
);
|
|
346
|
+
if (diffRows.length > 0) {
|
|
347
|
+
parts.push(
|
|
348
|
+
`<h4>Paired differences</h4><table><thead><tr><th>metric</th><th>comparison</th><th>difference</th></tr></thead><tbody>${diffRows.join("")}</tbody></table>`,
|
|
349
|
+
);
|
|
350
|
+
}
|
|
351
|
+
parts.push("</section>");
|
|
352
|
+
return parts.join("\n");
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
function fmt(value) {
|
|
356
|
+
if (value === null || value === undefined) return "-";
|
|
357
|
+
if (typeof value === "number") return Number.isFinite(value) ? String(Number(value.toFixed(3))) : "-";
|
|
358
|
+
return esc(value);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// Worded by decision.mjs, as in the text view, so a decision's verdict is never shown as "none".
|
|
362
|
+
function claimSection(aggregate) {
|
|
363
|
+
const summary = claimSummary(aggregate);
|
|
364
|
+
if (summary === null) return "";
|
|
365
|
+
return `<section class="claim"><h2>Claim</h2><p>${esc(summary.reached)}</p><p class="muted">${esc(summary.detail)}</p></section>`;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
function preBlock(text) {
|
|
369
|
+
const value = String(text);
|
|
370
|
+
const cut = value.length > CONTENT_CAP;
|
|
371
|
+
return `<pre>${esc(cut ? value.slice(0, CONTENT_CAP) : value)}</pre>${cut ? `<p class="missing">Cut at ${CONTENT_CAP} of ${value.length} characters.</p>` : ""}`;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
function compact(value) {
|
|
375
|
+
if (value === undefined) return "-";
|
|
376
|
+
const text = typeof value === "string" ? value : (JSON.stringify(value) ?? "-");
|
|
377
|
+
return text.length > VALUE_CAP ? `${text.slice(0, VALUE_CAP)}... (cut at ${VALUE_CAP} of ${text.length})` : text;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
function esc(value) {
|
|
381
|
+
return String(value)
|
|
382
|
+
.replace(/&/g, "&")
|
|
383
|
+
.replace(/</g, "<")
|
|
384
|
+
.replace(/>/g, ">")
|
|
385
|
+
.replace(/"/g, """)
|
|
386
|
+
.replace(/'/g, "'");
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
function page(title, body) {
|
|
390
|
+
return `<!doctype html>
|
|
391
|
+
<html lang="en">
|
|
392
|
+
<head>
|
|
393
|
+
<meta charset="utf-8">
|
|
394
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
395
|
+
<title>${esc(title)}</title>
|
|
396
|
+
<style>
|
|
397
|
+
:root { color-scheme: light dark; --bg: #ffffff; --fg: #1d1f23; --muted: #5c6370; --border: #d8dce3; --code: #f5f6f8; --pass: #1a7f37; --fail: #cf222e; }
|
|
398
|
+
@media (prefers-color-scheme: dark) {
|
|
399
|
+
:root:not([data-theme="light"]) { --bg: #0f1115; --fg: #e6e8eb; --muted: #9aa3ad; --border: #2c313a; --code: #171a20; --pass: #3fb950; --fail: #ff7b72; }
|
|
400
|
+
}
|
|
401
|
+
:root[data-theme="dark"] { --bg: #0f1115; --fg: #e6e8eb; --muted: #9aa3ad; --border: #2c313a; --code: #171a20; --pass: #3fb950; --fail: #ff7b72; }
|
|
402
|
+
body { margin: 0; background: var(--bg); color: var(--fg); font: 15px/1.5 system-ui, -apple-system, "Segoe UI", sans-serif; }
|
|
403
|
+
main { max-width: 960px; margin: 0 auto; padding: 16px; }
|
|
404
|
+
h1 { font-size: 20px; }
|
|
405
|
+
h2 { font-size: 18px; margin: 0 0 8px; }
|
|
406
|
+
h3 { font-size: 16px; margin: 16px 0 6px; }
|
|
407
|
+
h4 { font-size: 14px; margin: 14px 0 4px; }
|
|
408
|
+
h5 { font-size: 14px; margin: 12px 0 4px; }
|
|
409
|
+
section, article { border-top: 1px solid var(--border); padding-top: 8px; margin-top: 16px; }
|
|
410
|
+
.muted, .meta { color: var(--muted); font-size: 13px; }
|
|
411
|
+
.claim { border-top: 0; }
|
|
412
|
+
pre { background: var(--code); border: 1px solid var(--border); border-radius: 6px; padding: 8px; font-size: 13px; white-space: pre-wrap; overflow-wrap: anywhere; margin: 6px 0; }
|
|
413
|
+
code { font-size: 13px; overflow-wrap: anywhere; }
|
|
414
|
+
table { width: 100%; border-collapse: collapse; font-size: 13px; }
|
|
415
|
+
th, td { border-bottom: 1px solid var(--border); padding: 4px 6px; text-align: left; vertical-align: top; overflow-wrap: anywhere; }
|
|
416
|
+
details { margin: 6px 0; }
|
|
417
|
+
summary { cursor: pointer; font-family: ui-monospace, Menlo, monospace; font-size: 13px; overflow-wrap: anywhere; }
|
|
418
|
+
.pass { color: var(--pass); }
|
|
419
|
+
.fail { color: var(--fail); }
|
|
420
|
+
.missing { color: var(--muted); font-style: italic; }
|
|
421
|
+
</style>
|
|
422
|
+
</head>
|
|
423
|
+
<body>
|
|
424
|
+
<main>
|
|
425
|
+
${body}
|
|
426
|
+
</main>
|
|
427
|
+
</body>
|
|
428
|
+
</html>
|
|
429
|
+
`;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
async function readText(file) {
|
|
433
|
+
if (!(await stat(file).catch(() => null))) return null;
|
|
434
|
+
return readFile(file, "utf8");
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
async function readOptionalJson(file) {
|
|
438
|
+
if (!(await stat(file).catch(() => null))) return null;
|
|
439
|
+
return readJson(file, path.basename(file));
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
async function readJson(file, label) {
|
|
443
|
+
let contents;
|
|
444
|
+
try {
|
|
445
|
+
contents = await readFile(file, "utf8");
|
|
446
|
+
} catch {
|
|
447
|
+
throw new Error(`Cannot read ${label}: ${file}`);
|
|
448
|
+
}
|
|
449
|
+
try {
|
|
450
|
+
return JSON.parse(contents);
|
|
451
|
+
} catch {
|
|
452
|
+
throw new Error(`${label} is not valid JSON: ${file}`);
|
|
453
|
+
}
|
|
454
|
+
}
|