@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,159 @@
|
|
|
1
|
+
import { estimateTokens } from "./carry.js";
|
|
2
|
+
import { currentCycle } from "./harness.js";
|
|
3
|
+
import { withoutGuidanceNotices } from "../tool-execution/guidance-notices.js";
|
|
4
|
+
import { isFreeflowInstruction } from "../tool-execution/skill-reads.js";
|
|
5
|
+
/**
|
|
6
|
+
* The result index: this cycle's larger tool results, each with an id the agent can carry by. Ids number tool results
|
|
7
|
+
* in branch order (r1, r2, ...), so they stay stable while the branch grows, and a result from an earlier cycle still
|
|
8
|
+
* resolves because its entry stays stored after compaction.
|
|
9
|
+
*/
|
|
10
|
+
const SIZE_FLOOR = 500;
|
|
11
|
+
const MAX_ROWS = 40;
|
|
12
|
+
/**
|
|
13
|
+
* The most tokens the rendered index can take: 40 rows of at most about 140 characters (an 80-character label plus
|
|
14
|
+
* id, tool, size and carried note) and a heading. Below the warning by more than this, the index cannot reach it.
|
|
15
|
+
*/
|
|
16
|
+
export const INDEX_TOKEN_BOUND = 2_000;
|
|
17
|
+
/** Freeflow's own control calls: no evidence to carry, as routing's evidence selection also excludes them. */
|
|
18
|
+
const CONTROL_TOOLS = new Set([
|
|
19
|
+
"delegate_work",
|
|
20
|
+
"return_work",
|
|
21
|
+
"select_evidence",
|
|
22
|
+
"routing_unit",
|
|
23
|
+
"compact_context",
|
|
24
|
+
// The same tools' names before Task 003's rename, still in sessions saved earlier.
|
|
25
|
+
"freeflow_delegate",
|
|
26
|
+
"freeflow_return",
|
|
27
|
+
"freeflow_project",
|
|
28
|
+
"freeflow_unit",
|
|
29
|
+
"freeflow_compact",
|
|
30
|
+
]);
|
|
31
|
+
/** A result's text without the guidance notices that joined it. */
|
|
32
|
+
const resultText = (message) =>
|
|
33
|
+
withoutGuidanceNotices(
|
|
34
|
+
(message?.content ?? [])
|
|
35
|
+
.map((part) => (part?.type === "text" ? part.text : part?.type === "image" ? "[image]" : ""))
|
|
36
|
+
.join(""),
|
|
37
|
+
);
|
|
38
|
+
function label(name, input) {
|
|
39
|
+
const firstLine = (text) =>
|
|
40
|
+
text
|
|
41
|
+
.split("\n")
|
|
42
|
+
.map((line) => line.trim())
|
|
43
|
+
.find(Boolean) ?? "";
|
|
44
|
+
const value =
|
|
45
|
+
typeof input?.command === "string"
|
|
46
|
+
? input.command
|
|
47
|
+
: typeof input?.path === "string"
|
|
48
|
+
? input.path
|
|
49
|
+
: typeof input?.url === "string"
|
|
50
|
+
? input.url
|
|
51
|
+
: typeof input?.code === "string"
|
|
52
|
+
? `script: ${firstLine(input.code)}`
|
|
53
|
+
: Array.isArray(input?.queries)
|
|
54
|
+
? input.queries.join("; ")
|
|
55
|
+
: typeof input?.query === "string"
|
|
56
|
+
? input.query
|
|
57
|
+
: name;
|
|
58
|
+
const line = firstLine(String(value));
|
|
59
|
+
return line.length > 80 ? `${line.slice(0, 77)}...` : line;
|
|
60
|
+
}
|
|
61
|
+
/** Every tool result on the branch with its id, oldest first. */
|
|
62
|
+
function allResults(branch) {
|
|
63
|
+
const calls = new Map();
|
|
64
|
+
const results = [];
|
|
65
|
+
for (const entry of branch) {
|
|
66
|
+
const message = entry?.type === "message" ? entry.message : undefined;
|
|
67
|
+
if (message?.role === "assistant")
|
|
68
|
+
for (const block of message.content ?? [])
|
|
69
|
+
if (block?.type === "toolCall") calls.set(block.id, { name: block.name, input: block.arguments });
|
|
70
|
+
if (message?.role !== "toolResult") continue;
|
|
71
|
+
const call = calls.get(message.toolCallId);
|
|
72
|
+
const text = resultText(message);
|
|
73
|
+
const tool = call?.name ?? message.toolName ?? "tool";
|
|
74
|
+
results.push({
|
|
75
|
+
id: `r${results.length + 1}`,
|
|
76
|
+
tool,
|
|
77
|
+
label: label(tool, call?.input),
|
|
78
|
+
tokens: estimateTokens(text),
|
|
79
|
+
text,
|
|
80
|
+
...firstLineOf(tool, call?.input, message),
|
|
81
|
+
entry,
|
|
82
|
+
input: call?.input,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
return results;
|
|
86
|
+
}
|
|
87
|
+
/** A text read of a file starts at its offset (Pi's read is 1-based); an image or failed read has no lines. */
|
|
88
|
+
function firstLineOf(tool, input, message) {
|
|
89
|
+
if (tool !== "read" || typeof input?.path !== "string" || message?.isError) return {};
|
|
90
|
+
if ((message?.content ?? []).some((part) => part?.type === "image")) return {};
|
|
91
|
+
return { firstLine: Number.isInteger(input?.offset) && input.offset > 0 ? input.offset : 1 };
|
|
92
|
+
}
|
|
93
|
+
/** The first line of the read result in a session entry, for a result carried by routing ref. */
|
|
94
|
+
export function resultFirstLine(branch, entryId) {
|
|
95
|
+
return allResults(branch).find((result) => result.entry?.id === entryId)?.firstLine;
|
|
96
|
+
}
|
|
97
|
+
export function resolveResult(branch, id) {
|
|
98
|
+
const found = allResults(branch).find((result) => result.id === id);
|
|
99
|
+
if (!found) return undefined;
|
|
100
|
+
const { entry: _entry, input: _input, ...result } = found;
|
|
101
|
+
return result;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* The tool results of the work in progress, newest first: the current assignment's under Cognitive Routing (by
|
|
105
|
+
* routing ref), otherwise this cycle's (by r-id). Freeflow's control calls and reads of its own instructions are left
|
|
106
|
+
* out: they are how the agent works, not what it worked on.
|
|
107
|
+
*/
|
|
108
|
+
export function scopeResults(branch, assignment) {
|
|
109
|
+
const cycle = new Set(currentCycle(branch));
|
|
110
|
+
return allResults(branch)
|
|
111
|
+
.filter((result) => (assignment ? assignment.entryIds.has(result.entry.id) : cycle.has(result.entry)))
|
|
112
|
+
.filter((result) => !CONTROL_TOOLS.has(result.tool) && !isFreeflowInstruction(result.tool, result.input))
|
|
113
|
+
.reverse()
|
|
114
|
+
.map(({ entry, input, ...result }) => ({
|
|
115
|
+
...result,
|
|
116
|
+
id: assignment ? `ctx:${entry.id}` : result.id,
|
|
117
|
+
entryId: entry.id,
|
|
118
|
+
...(typeof input?.path === "string" ? { path: input.path } : {}),
|
|
119
|
+
}));
|
|
120
|
+
}
|
|
121
|
+
/** This cycle's results above the size floor, newest first, then results the last Freeflow compaction carried. */
|
|
122
|
+
export function resultIndex(branch) {
|
|
123
|
+
const cycle = new Set(currentCycle(branch));
|
|
124
|
+
const results = allResults(branch);
|
|
125
|
+
const rows = results
|
|
126
|
+
.filter(
|
|
127
|
+
(result) =>
|
|
128
|
+
cycle.has(result.entry) &&
|
|
129
|
+
result.tokens >= SIZE_FLOOR &&
|
|
130
|
+
!CONTROL_TOOLS.has(result.tool) &&
|
|
131
|
+
!isFreeflowInstruction(result.tool, result.input),
|
|
132
|
+
)
|
|
133
|
+
.reverse()
|
|
134
|
+
.map(({ id, tool, label, tokens }) => ({ id, tool, label, tokens }));
|
|
135
|
+
const latest = [...branch].reverse().find((entry) => entry?.type === "compaction" && entry.details?.freeflow);
|
|
136
|
+
for (const item of latest?.details?.freeflow?.carried ?? []) {
|
|
137
|
+
if (item?.kind !== "result" || rows.some((row) => row.id === item.ref)) continue;
|
|
138
|
+
const result = results.find((each) => each.id === item.ref);
|
|
139
|
+
if (result)
|
|
140
|
+
rows.push({
|
|
141
|
+
id: result.id,
|
|
142
|
+
tool: result.tool,
|
|
143
|
+
label: result.label,
|
|
144
|
+
tokens: result.tokens,
|
|
145
|
+
firstCycle: item.firstCycle,
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
return rows.slice(0, MAX_ROWS);
|
|
149
|
+
}
|
|
150
|
+
export function renderIndex(rows) {
|
|
151
|
+
if (!rows.length) return "No tool results large enough to list; carry files by path.";
|
|
152
|
+
return [
|
|
153
|
+
"Results you can carry by id:",
|
|
154
|
+
...rows.map(
|
|
155
|
+
(row) =>
|
|
156
|
+
`- ${row.id} ${row.tool} ${row.label} ~${row.tokens} tokens${row.firstCycle ? ` (carried since cycle ${row.firstCycle})` : ""}`,
|
|
157
|
+
),
|
|
158
|
+
].join("\n");
|
|
159
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* When compaction is due. Pi compacts on its own once context passes the window minus its reserve, and stays as the
|
|
3
|
+
* fallback for a full context. Freeflow says "compact now" 25k tokens before that, leaving room to prepare after a
|
|
4
|
+
* safe point, and warns earlier still: at 70% of the window, and at least 20k tokens before "compact now", so the
|
|
5
|
+
* agent has room to reach a safe point first.
|
|
6
|
+
*/
|
|
7
|
+
export const DEFAULT_RESERVE_TOKENS = 16_384;
|
|
8
|
+
const WARNING_SHARE = 0.7;
|
|
9
|
+
const WARNING_LEAD = 20_000;
|
|
10
|
+
const COMPACT_NOW_HEADROOM = 25_000;
|
|
11
|
+
/** Pi's effective reserve for a model: its per-model override, else the ordinary setting, else Pi's default. */
|
|
12
|
+
export function reserveTokens(settings, model) {
|
|
13
|
+
const compaction = settings?.compaction ?? {};
|
|
14
|
+
const override = model ? compaction.modelOverrides?.[`${model.provider}/${model.id}`] : undefined;
|
|
15
|
+
const value = override?.reserveTokens ?? compaction.reserveTokens;
|
|
16
|
+
return Number.isSafeInteger(value) && value >= 0 ? value : DEFAULT_RESERVE_TOKENS;
|
|
17
|
+
}
|
|
18
|
+
export function thresholds(window, reserve) {
|
|
19
|
+
const trigger = Math.max(0, window - reserve);
|
|
20
|
+
const compactNow = Math.max(0, trigger - COMPACT_NOW_HEADROOM);
|
|
21
|
+
return {
|
|
22
|
+
window,
|
|
23
|
+
trigger,
|
|
24
|
+
warning: Math.max(0, Math.min(Math.floor(window * WARNING_SHARE), compactNow - WARNING_LEAD)),
|
|
25
|
+
compactNow,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/** The strictest thresholds across models that may receive the full history (the active model and routing workers). */
|
|
29
|
+
export function strictest(models, settings) {
|
|
30
|
+
const all = models
|
|
31
|
+
.filter((model) => typeof model?.contextWindow === "number" && model.contextWindow > 0)
|
|
32
|
+
.map((model) => thresholds(model.contextWindow, reserveTokens(settings, model)));
|
|
33
|
+
if (!all.length) return undefined;
|
|
34
|
+
return all.reduce((a, b) => (b.warning < a.warning ? b : a));
|
|
35
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
export const COMPACT_CONTEXT = "compact_context";
|
|
2
|
+
const DESCRIPTION =
|
|
3
|
+
"Compact the conversation into a new cycle. Use only when Freeflow says compaction is due or the user asks, and read the compaction skill first. Pass your summary and what to carry; compaction happens at the end of this turn, and the run continues from the summary, the carried context and a recovery message.";
|
|
4
|
+
/** Registered once, declared only while Freeflow compaction is effective (see applyCompactionTools). */
|
|
5
|
+
export function registerCompactionTool(pi, controller) {
|
|
6
|
+
pi.registerTool({
|
|
7
|
+
name: COMPACT_CONTEXT,
|
|
8
|
+
label: "Compact",
|
|
9
|
+
description: DESCRIPTION,
|
|
10
|
+
parameters: {
|
|
11
|
+
type: "object",
|
|
12
|
+
additionalProperties: false,
|
|
13
|
+
properties: {
|
|
14
|
+
summary: {
|
|
15
|
+
type: "string",
|
|
16
|
+
description:
|
|
17
|
+
"The next cycle's working state, for a reader with none of this conversation. The compaction skill says what it must keep.",
|
|
18
|
+
},
|
|
19
|
+
carry: {
|
|
20
|
+
type: "array",
|
|
21
|
+
description:
|
|
22
|
+
"What to carry into the next cycle, within the budget the notice gives: files by path (read fresh at compaction, optional line ranges) and tool results by id from the notice's index.",
|
|
23
|
+
items: {
|
|
24
|
+
type: "object",
|
|
25
|
+
additionalProperties: false,
|
|
26
|
+
properties: {
|
|
27
|
+
file: { type: "string" },
|
|
28
|
+
lines: { type: "array", items: { type: "integer" }, description: "[first, last], 1-based" },
|
|
29
|
+
result: {
|
|
30
|
+
type: "string",
|
|
31
|
+
description:
|
|
32
|
+
"A tool result: its routing ref (such as ctx:1a2b3c4d) when Cognitive Routing is on, otherwise its id from the notice's list (such as r12)",
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
required: ["summary"],
|
|
39
|
+
},
|
|
40
|
+
// Callable from codemode scripts as well: agents that look for tools there first concluded, when it was missing,
|
|
41
|
+
// that they could not compact. The compaction still happens at the end of the turn, after the script returns.
|
|
42
|
+
exposure: "direct",
|
|
43
|
+
defaultActive: false,
|
|
44
|
+
executionMode: "sequential",
|
|
45
|
+
async execute(_id, params, _signal, _update, ctx) {
|
|
46
|
+
return { content: [{ type: "text", text: await controller.request(params, ctx) }] };
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
/** Declare or withdraw compact_context when compaction's effective state changes, keeping other tools in place. */
|
|
51
|
+
export function applyCompactionTools(pi, effective) {
|
|
52
|
+
if (typeof pi.getActiveTools !== "function" || typeof pi.setActiveTools !== "function") return;
|
|
53
|
+
const current = pi.getActiveTools();
|
|
54
|
+
const present = current.includes(COMPACT_CONTEXT);
|
|
55
|
+
if (effective && !present) pi.setActiveTools([...current, COMPACT_CONTEXT]);
|
|
56
|
+
if (!effective && present) pi.setActiveTools(current.filter((name) => name !== COMPACT_CONTEXT));
|
|
57
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// Keyed by the reader and its getBranch function, so a reader whose source is swapped is walked again.
|
|
2
|
+
const cache = new WeakMap();
|
|
3
|
+
export function cachedBranch(reader) {
|
|
4
|
+
if (!reader?.getBranch) return [];
|
|
5
|
+
// Without a leaf id the branch cannot be keyed; fall back to Pi's walk.
|
|
6
|
+
if (!reader.getLeafId) return reader.getBranch();
|
|
7
|
+
const leaf = reader.getLeafId();
|
|
8
|
+
const hit = cache.get(reader);
|
|
9
|
+
if (hit && hit.leaf === leaf && hit.source === reader.getBranch) return hit.branch;
|
|
10
|
+
const branch = Object.freeze([...reader.getBranch()]);
|
|
11
|
+
cache.set(reader, { leaf, source: reader.getBranch, branch });
|
|
12
|
+
return branch;
|
|
13
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
const isObject = (value) => !!value && typeof value === "object" && !Array.isArray(value);
|
|
2
|
+
/** Deterministic JSON: object keys sorted, undefined properties omitted, so equal values serialize equally. */
|
|
3
|
+
export function canonical(value) {
|
|
4
|
+
if (Array.isArray(value)) return `[${value.map(canonical).join(",")}]`;
|
|
5
|
+
if (isObject(value))
|
|
6
|
+
return `{${Object.keys(value)
|
|
7
|
+
.filter((k) => value[k] !== undefined)
|
|
8
|
+
.sort()
|
|
9
|
+
.map((k) => `${JSON.stringify(k)}:${canonical(value[k])}`)
|
|
10
|
+
.join(",")}}`;
|
|
11
|
+
return JSON.stringify(value) ?? "null";
|
|
12
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { fileURLToPath } from "node:url";
|
|
2
|
+
/**
|
|
3
|
+
* Freeflow's fixed command and skill surface: the commands it registers, the skills it lists to the model, and where
|
|
4
|
+
* their files live.
|
|
5
|
+
*/
|
|
6
|
+
export const WORKFLOW_COMMANDS = [
|
|
7
|
+
{ command: "discuss-work", skill: "discuss-work" },
|
|
8
|
+
{ command: "track-work", skill: "track-work" },
|
|
9
|
+
{ command: "write-docs", skill: "write-docs" },
|
|
10
|
+
{ command: "execute-work", skill: "execute-work" },
|
|
11
|
+
{ command: "verify-work", skill: "verify-work" },
|
|
12
|
+
{ command: "review-work", skill: "review-work" },
|
|
13
|
+
{ command: "deliver-work", skill: "deliver-work" },
|
|
14
|
+
];
|
|
15
|
+
export const CONTRIBUTOR_COMMANDS = ["setup-freeflow", "write-skill", "evaluate-behavior"];
|
|
16
|
+
/**
|
|
17
|
+
* Every portable skill Freeflow ships, by directory name. The canonical list: validation scripts and tests compare the
|
|
18
|
+
* skills directory, the package and the coverage matrix against it instead of a fixed count.
|
|
19
|
+
*/
|
|
20
|
+
export const FREEFLOW_MODEL_SKILL_NAMES = [
|
|
21
|
+
"deliver-work",
|
|
22
|
+
"discuss-work",
|
|
23
|
+
"evaluate-behavior",
|
|
24
|
+
"execute-work",
|
|
25
|
+
"review-work",
|
|
26
|
+
"setup-freeflow",
|
|
27
|
+
"track-work",
|
|
28
|
+
"verify-work",
|
|
29
|
+
"write-docs",
|
|
30
|
+
"write-skill",
|
|
31
|
+
];
|
|
32
|
+
export const STABLE_FREEFLOW_SURFACE = Object.freeze({
|
|
33
|
+
enabled: true,
|
|
34
|
+
cognitiveRouting: { effective: true },
|
|
35
|
+
toolExecution: { effective: true },
|
|
36
|
+
compaction: { effective: true },
|
|
37
|
+
taskMemory: { effective: true },
|
|
38
|
+
messaging: { effective: true },
|
|
39
|
+
});
|
|
40
|
+
export function freeflowSkillPath(skillName) {
|
|
41
|
+
return fileURLToPath(new URL(`../../../skills/${skillName}/SKILL.md`, import.meta.url));
|
|
42
|
+
}
|
|
43
|
+
export function freeflowCapabilitySkillPath(skillName) {
|
|
44
|
+
return fileURLToPath(new URL(`../../../capabilities/${skillName}/SKILL.md`, import.meta.url));
|
|
45
|
+
}
|
|
46
|
+
export function freeflowModelSkillPaths(capabilityState = undefined) {
|
|
47
|
+
// A skill the user turned off is not loaded (config-validation.ts SWITCHABLE_SKILLS).
|
|
48
|
+
const off = capabilityState?.skills?.off ?? [];
|
|
49
|
+
const paths = FREEFLOW_MODEL_SKILL_NAMES.filter((skillName) => !off.includes(skillName)).map((skillName) =>
|
|
50
|
+
freeflowSkillPath(skillName),
|
|
51
|
+
);
|
|
52
|
+
if (capabilityState?.cognitiveRouting?.effective === true)
|
|
53
|
+
paths.push(freeflowCapabilitySkillPath("cognitive-routing"));
|
|
54
|
+
if (capabilityState?.compaction?.effective === true) paths.push(freeflowCapabilitySkillPath("compaction"));
|
|
55
|
+
if (capabilityState?.taskMemory?.effective === true) paths.push(freeflowCapabilitySkillPath("task-memory"));
|
|
56
|
+
if (capabilityState?.messaging?.effective === true) paths.push(freeflowCapabilitySkillPath("messaging"));
|
|
57
|
+
return paths;
|
|
58
|
+
}
|
|
59
|
+
export function skillPrompt(skill, args) {
|
|
60
|
+
const trimmed = args?.trim();
|
|
61
|
+
return trimmed ? `/skill:${skill}\n\n${trimmed}` : `/skill:${skill}`;
|
|
62
|
+
}
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import { validateCompactionConfig } from "../compaction/config.js";
|
|
2
|
+
import { validateTaskMemoryConfig } from "../task-memory/config.js";
|
|
3
|
+
import { validateMessagingConfig } from "../messaging/config.js";
|
|
4
|
+
import { validateToolExecutionConfig } from "../tool-execution/config.js";
|
|
5
|
+
import { FREEFLOW_MODEL_SKILL_NAMES } from "./catalog.js";
|
|
6
|
+
/**
|
|
7
|
+
* Whether a Freeflow config file is valid: one answer for Pi and for the session-start hooks of the other hosts, which
|
|
8
|
+
* import the built file. Also how the settings every host reads, `prompts`, `review` and `skills`, layer. Keep this module and its
|
|
9
|
+
* imports free of Pi packages; the hooks run in plain Node.
|
|
10
|
+
*/
|
|
11
|
+
function isRecord(value) {
|
|
12
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
13
|
+
}
|
|
14
|
+
/** The runtime prompts Freeflow delivers on every host, each on unless a config turns it off. */
|
|
15
|
+
export const RUNTIME_PROMPTS = ["core", "interactionContract", "workingMethod"];
|
|
16
|
+
/** The keys `prompts` accepts: a master switch for all three, and one switch per prompt. */
|
|
17
|
+
export const PROMPTS_KEYS = ["enabled", ...RUNTIME_PROMPTS];
|
|
18
|
+
/** A section's master switch (`prompts.enabled`, `skills.enabled`) for two valid layers; on unless a config turns it off. */
|
|
19
|
+
export function sectionEnabled(repository, local, section) {
|
|
20
|
+
const layer = (config) => (isRecord(config?.[section]) ? config[section] : {});
|
|
21
|
+
return (layer(local).enabled ?? layer(repository).enabled ?? true) === true;
|
|
22
|
+
}
|
|
23
|
+
function validatePromptsConfig(value) {
|
|
24
|
+
if (!isRecord(value)) return "prompts must be an object";
|
|
25
|
+
const unknown = Object.keys(value).find((key) => !PROMPTS_KEYS.includes(key));
|
|
26
|
+
if (unknown) return `prompts has unsupported key: ${unknown}`;
|
|
27
|
+
for (const key of PROMPTS_KEYS)
|
|
28
|
+
if (value[key] !== undefined && typeof value[key] !== "boolean") return `prompts.${key} must be a boolean`;
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* The prompts Freeflow delivers for two valid config layers: the personal layer overrides the repository's, and the
|
|
33
|
+
* master switch off turns all three off.
|
|
34
|
+
*/
|
|
35
|
+
export function selectedRuntimePrompts(repository, local) {
|
|
36
|
+
const layer = (config) => (isRecord(config?.prompts) ? config.prompts : {});
|
|
37
|
+
const [shared, personal] = [layer(repository), layer(local)];
|
|
38
|
+
const master = sectionEnabled(repository, local, "prompts");
|
|
39
|
+
const selection = {};
|
|
40
|
+
for (const key of RUNTIME_PROMPTS) selection[key] = master && (personal[key] ?? shared[key] ?? true) === true;
|
|
41
|
+
return selection;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* The skills a user can turn off. Setup Freeflow always stays, so a user can repair a configuration; the capability
|
|
45
|
+
* skills follow their capability's switch. On Pi an off skill is not loaded; other hosts load plugin skills themselves,
|
|
46
|
+
* so there the Runtime State only tells the agent not to use it.
|
|
47
|
+
*/
|
|
48
|
+
export const SWITCHABLE_SKILLS = FREEFLOW_MODEL_SKILL_NAMES.filter((name) => name !== "setup-freeflow").sort();
|
|
49
|
+
/** The keys `skills` accepts: a master switch for every switchable skill, and one switch per skill. */
|
|
50
|
+
export const SKILLS_KEYS = ["enabled", ...SWITCHABLE_SKILLS];
|
|
51
|
+
function validateSkillsConfig(value) {
|
|
52
|
+
if (!isRecord(value)) return "skills must be an object";
|
|
53
|
+
const unknown = Object.keys(value).find((key) => !SKILLS_KEYS.includes(key));
|
|
54
|
+
if (unknown) return `skills has unsupported key: ${unknown}; use ${SKILLS_KEYS.join(", ")}`;
|
|
55
|
+
for (const [key, on] of Object.entries(value)) if (typeof on !== "boolean") return `skills.${key} must be a boolean`;
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* The skills turned off for two valid config layers: the personal layer overrides the repository's, skill by skill,
|
|
60
|
+
* and the master switch off turns every switchable skill off.
|
|
61
|
+
*/
|
|
62
|
+
export function skillsOff(repository, local) {
|
|
63
|
+
const layer = (config) => (isRecord(config?.skills) ? config.skills : {});
|
|
64
|
+
const [shared, personal] = [layer(repository), layer(local)];
|
|
65
|
+
if (!sectionEnabled(repository, local, "skills")) return [...SWITCHABLE_SKILLS];
|
|
66
|
+
return SWITCHABLE_SKILLS.filter((name) => (personal[name] ?? shared[name] ?? true) === false);
|
|
67
|
+
}
|
|
68
|
+
/** The Runtime State line for skills the user turned off; none while every skill is on. */
|
|
69
|
+
export function skillsStateLine(off) {
|
|
70
|
+
return off?.length ? `Skills off: ${off.map((name) => `\`${name}\``).join(", ")}; do not open or follow them.` : null;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* How Review Work reviews finished work. Without the key it runs `auto`, its own risk gate; `off` and `always` are the
|
|
74
|
+
* user's choice for every task, and `model` names the model a reviewer runs on. `auto` is accepted so a personal file
|
|
75
|
+
* can return a shared `off` or `always` to the default.
|
|
76
|
+
*/
|
|
77
|
+
export const REVIEW_MODES = ["auto", "off", "always"];
|
|
78
|
+
export const REVIEW_KEYS = ["mode", "model"];
|
|
79
|
+
function validateReviewConfig(value) {
|
|
80
|
+
if (!isRecord(value)) return "review must be an object";
|
|
81
|
+
const unknown = Object.keys(value).find((key) => !REVIEW_KEYS.includes(key));
|
|
82
|
+
if (unknown) return `review has unsupported key: ${unknown}`;
|
|
83
|
+
if (value.mode !== undefined && !REVIEW_MODES.includes(value.mode))
|
|
84
|
+
return `review.mode must be one of ${REVIEW_MODES.join(", ")}`;
|
|
85
|
+
// The model is shown to the agent in the Runtime State, so it must fit on one line in a code span.
|
|
86
|
+
if (
|
|
87
|
+
value.model !== undefined &&
|
|
88
|
+
(typeof value.model !== "string" || !value.model.trim() || /[\p{Cc}`]/u.test(value.model))
|
|
89
|
+
)
|
|
90
|
+
return "review.model must be a non-empty model name on one line";
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
/** Review settings for two valid config layers: the personal layer overrides the repository's, field by field. */
|
|
94
|
+
export function resolveReviewSettings(repository, local) {
|
|
95
|
+
const layer = (config) => (isRecord(config?.review) ? config.review : {});
|
|
96
|
+
const [shared, personal] = [layer(repository), layer(local)];
|
|
97
|
+
const mode = personal.mode ?? shared.mode ?? "auto";
|
|
98
|
+
const model = personal.model ?? shared.model;
|
|
99
|
+
return model === undefined ? { mode } : { mode, model };
|
|
100
|
+
}
|
|
101
|
+
/** The Runtime State line for the user's review choice; none for the default, `auto` with no model. */
|
|
102
|
+
export function reviewStateLine(review) {
|
|
103
|
+
if (!review || (review.mode === "auto" && review.model === undefined)) return null;
|
|
104
|
+
return `Review: \`${review.mode}\`${review.model === undefined ? "" : `, reviewer model \`${review.model}\``}`;
|
|
105
|
+
}
|
|
106
|
+
function removedContextConfigError(value, filePath) {
|
|
107
|
+
const removedKeys = ["contextVirtualization", "conversationHistory"].filter((key) =>
|
|
108
|
+
Object.prototype.hasOwnProperty.call(value, key),
|
|
109
|
+
);
|
|
110
|
+
return removedKeys.length > 0
|
|
111
|
+
? `Removed Freeflow context setting(s) in ${filePath}: ${removedKeys.join(", ")}. Delete those keys before using Freeflow.`
|
|
112
|
+
: null;
|
|
113
|
+
}
|
|
114
|
+
function validateCoreConfigFields(value) {
|
|
115
|
+
if (value.enabled !== undefined && typeof value.enabled !== "boolean") {
|
|
116
|
+
return "enabled must be a boolean";
|
|
117
|
+
}
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
/** The top-level keys Freeflow acts on; the settings test checks that every key under them has a settings row. */
|
|
121
|
+
export const CONFIG_SECTIONS = [
|
|
122
|
+
"enabled",
|
|
123
|
+
"cognitiveRouting",
|
|
124
|
+
"toolExecution",
|
|
125
|
+
"compaction",
|
|
126
|
+
"taskMemory",
|
|
127
|
+
"messaging",
|
|
128
|
+
"prompts",
|
|
129
|
+
"review",
|
|
130
|
+
"skills",
|
|
131
|
+
];
|
|
132
|
+
// outputRouter, observedRouting, and scriptTransform belong to retired features; they are accepted and ignored so
|
|
133
|
+
// existing configs keep loading.
|
|
134
|
+
const RETIRED_SECTIONS = ["outputRouter", "observedRouting", "scriptTransform"];
|
|
135
|
+
export function validateRepositoryConfig(value) {
|
|
136
|
+
if (!isRecord(value)) {
|
|
137
|
+
return "config must be a JSON object";
|
|
138
|
+
}
|
|
139
|
+
const removedContextError = removedContextConfigError(value, ".freeflow/config.json");
|
|
140
|
+
if (removedContextError) return removedContextError;
|
|
141
|
+
const allowedKeys = new Set([...CONFIG_SECTIONS, ...RETIRED_SECTIONS]);
|
|
142
|
+
for (const key of Object.keys(value)) {
|
|
143
|
+
if (!allowedKeys.has(key)) {
|
|
144
|
+
return `unsupported top-level config key: ${key}`;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
const coreError = validateCoreConfigFields(value);
|
|
148
|
+
if (coreError) return coreError;
|
|
149
|
+
for (const key of ["outputRouter", "observedRouting", "scriptTransform"]) {
|
|
150
|
+
if (value[key] !== undefined && !isRecord(value[key])) {
|
|
151
|
+
return `${key} must be an object`;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
if (value.toolExecution !== undefined) {
|
|
155
|
+
const error = validateToolExecutionConfig(value.toolExecution);
|
|
156
|
+
if (error) return error;
|
|
157
|
+
}
|
|
158
|
+
if (value.prompts !== undefined) {
|
|
159
|
+
const error = validatePromptsConfig(value.prompts);
|
|
160
|
+
if (error) return error;
|
|
161
|
+
}
|
|
162
|
+
if (value.compaction !== undefined) {
|
|
163
|
+
const error = validateCompactionConfig(value.compaction);
|
|
164
|
+
if (error) return error;
|
|
165
|
+
}
|
|
166
|
+
if (value.taskMemory !== undefined) {
|
|
167
|
+
const error = validateTaskMemoryConfig(value.taskMemory);
|
|
168
|
+
if (error) return error;
|
|
169
|
+
}
|
|
170
|
+
if (value.messaging !== undefined) {
|
|
171
|
+
const error = validateMessagingConfig(value.messaging);
|
|
172
|
+
if (error) return error;
|
|
173
|
+
}
|
|
174
|
+
if (value.skills !== undefined) {
|
|
175
|
+
const error = validateSkillsConfig(value.skills);
|
|
176
|
+
if (error) return error;
|
|
177
|
+
}
|
|
178
|
+
if (value.review !== undefined) return validateReviewConfig(value.review);
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
export function validateLocalConfig(value) {
|
|
182
|
+
if (!isRecord(value)) {
|
|
183
|
+
return "local config must be a JSON object";
|
|
184
|
+
}
|
|
185
|
+
const removedContextError = removedContextConfigError(value, ".freeflow/local.json");
|
|
186
|
+
if (removedContextError) return removedContextError;
|
|
187
|
+
// processing belongs to a retired feature; it is accepted and ignored so existing local configs keep loading.
|
|
188
|
+
const allowedKeys = new Set([
|
|
189
|
+
"enabled",
|
|
190
|
+
"processing",
|
|
191
|
+
"cognitiveRouting",
|
|
192
|
+
"toolExecution",
|
|
193
|
+
"compaction",
|
|
194
|
+
"taskMemory",
|
|
195
|
+
"messaging",
|
|
196
|
+
"prompts",
|
|
197
|
+
"review",
|
|
198
|
+
"skills",
|
|
199
|
+
]);
|
|
200
|
+
for (const key of Object.keys(value)) {
|
|
201
|
+
if (!allowedKeys.has(key)) {
|
|
202
|
+
return `unsupported top-level local config key: ${key}`;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
const coreError = validateCoreConfigFields(value);
|
|
206
|
+
if (coreError) return coreError;
|
|
207
|
+
if (value.toolExecution !== undefined) {
|
|
208
|
+
const error = validateToolExecutionConfig(value.toolExecution);
|
|
209
|
+
if (error) return error;
|
|
210
|
+
}
|
|
211
|
+
if (value.prompts !== undefined) {
|
|
212
|
+
const error = validatePromptsConfig(value.prompts);
|
|
213
|
+
if (error) return error;
|
|
214
|
+
}
|
|
215
|
+
if (value.compaction !== undefined) {
|
|
216
|
+
const error = validateCompactionConfig(value.compaction);
|
|
217
|
+
if (error) return error;
|
|
218
|
+
}
|
|
219
|
+
if (value.taskMemory !== undefined) {
|
|
220
|
+
const error = validateTaskMemoryConfig(value.taskMemory);
|
|
221
|
+
if (error) return error;
|
|
222
|
+
}
|
|
223
|
+
if (value.messaging !== undefined) {
|
|
224
|
+
const error = validateMessagingConfig(value.messaging);
|
|
225
|
+
if (error) return error;
|
|
226
|
+
}
|
|
227
|
+
if (value.skills !== undefined) {
|
|
228
|
+
const error = validateSkillsConfig(value.skills);
|
|
229
|
+
if (error) return error;
|
|
230
|
+
}
|
|
231
|
+
if (value.review !== undefined) return validateReviewConfig(value.review);
|
|
232
|
+
return null;
|
|
233
|
+
}
|