@hassangameryt/freeflow 0.4.0 → 0.6.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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +2 -1
- package/.codex-plugin/plugin.json +2 -1
- package/README.md +150 -155
- package/capabilities/cognitive-routing/SKILL.md +229 -0
- package/capabilities/context-virtualization/SKILL.md +103 -0
- package/capabilities/conversation-history/SKILL.md +53 -0
- package/command-surface.json +17 -13
- package/hooks/freeflow-runtime-context.mjs +393 -159
- package/hooks/hooks.json +26 -1
- package/hooks/tests/check-runtime-context-hook.sh +223 -54
- package/package.json +25 -16
- package/pi-extension/dist/cognitive-routing/commands.js +96 -0
- package/pi-extension/dist/cognitive-routing/config.js +236 -0
- package/pi-extension/dist/cognitive-routing/controller.js +862 -0
- package/pi-extension/dist/cognitive-routing/history.js +439 -0
- package/pi-extension/dist/cognitive-routing/host.js +126 -0
- package/pi-extension/dist/cognitive-routing/runtime.js +43 -0
- package/pi-extension/dist/cognitive-routing/tool.js +211 -0
- package/pi-extension/dist/cognitive-routing/types.js +6 -0
- package/pi-extension/dist/context-virtualization/commands.js +89 -0
- package/pi-extension/dist/context-virtualization/projector.js +42 -0
- package/pi-extension/dist/context-virtualization/runtime.js +356 -0
- package/pi-extension/dist/context-virtualization/state.js +57 -0
- package/pi-extension/dist/context-virtualization/types.js +10 -0
- package/pi-extension/dist/conversation-history/passages.js +66 -0
- package/pi-extension/dist/conversation-history/ranking.js +105 -0
- package/pi-extension/dist/conversation-history/runtime.js +226 -0
- package/pi-extension/dist/conversation-history/search.js +56 -0
- package/pi-extension/dist/conversation-history/types.js +1 -0
- package/pi-extension/dist/freeflow-context/resolver.js +120 -0
- package/pi-extension/dist/freeflow-context/runtime.js +80 -0
- package/pi-extension/dist/freeflow-context/source-projector.js +95 -0
- package/pi-extension/dist/freeflow-context/tool.js +308 -0
- package/pi-extension/dist/freeflow-context/types.js +12 -0
- package/pi-extension/dist/freeflow-context/visibility.js +28 -0
- package/pi-extension/dist/index.js +516 -98
- package/pi-extension/dist/runtime/runtime-context.js +318 -271
- package/pi-extension/dist/runtime/runtime-identity.js +5 -0
- package/pi-extension/dist/settings/settings-tui.js +78 -0
- package/pi-extension/dist/settings/settings-ui.js +593 -563
- package/pi-extension/dist/ui/text-component.js +57 -0
- package/pi-extension/src/cognitive-routing/commands.ts +119 -0
- package/pi-extension/src/cognitive-routing/config.ts +307 -0
- package/pi-extension/src/cognitive-routing/controller.ts +1118 -0
- package/pi-extension/src/cognitive-routing/history.ts +638 -0
- package/pi-extension/src/cognitive-routing/host.ts +172 -0
- package/pi-extension/src/cognitive-routing/runtime.ts +57 -0
- package/pi-extension/src/cognitive-routing/tool.ts +272 -0
- package/pi-extension/src/cognitive-routing/types.ts +89 -0
- package/pi-extension/src/context-virtualization/commands.ts +111 -0
- package/pi-extension/src/context-virtualization/projector.ts +62 -0
- package/pi-extension/src/context-virtualization/runtime.ts +406 -0
- package/pi-extension/src/context-virtualization/state.ts +79 -0
- package/pi-extension/src/context-virtualization/types.ts +92 -0
- package/pi-extension/src/conversation-history/passages.ts +81 -0
- package/pi-extension/src/conversation-history/ranking.ts +155 -0
- package/pi-extension/src/conversation-history/runtime.ts +250 -0
- package/pi-extension/src/conversation-history/search.ts +79 -0
- package/pi-extension/src/conversation-history/types.ts +31 -0
- package/pi-extension/src/freeflow-context/resolver.ts +139 -0
- package/pi-extension/src/freeflow-context/runtime.ts +100 -0
- package/pi-extension/src/freeflow-context/source-projector.ts +106 -0
- package/pi-extension/src/freeflow-context/tool.ts +360 -0
- package/pi-extension/src/freeflow-context/types.ts +70 -0
- package/pi-extension/src/freeflow-context/visibility.ts +53 -0
- package/pi-extension/src/index.ts +553 -101
- package/pi-extension/src/runtime/runtime-context.ts +339 -281
- package/pi-extension/src/runtime/runtime-identity.ts +8 -0
- package/pi-extension/src/settings/settings-tui.ts +93 -0
- package/pi-extension/src/settings/settings-ui.ts +700 -613
- package/pi-extension/src/ui/text-component.ts +66 -0
- package/pi-extension/tests/cognitive-routing/commands.test.js +134 -0
- package/pi-extension/tests/cognitive-routing/controller.test.js +1099 -0
- package/pi-extension/tests/cognitive-routing/extension-lifecycle.test.js +1071 -0
- package/pi-extension/tests/cognitive-routing/history.test.js +274 -0
- package/pi-extension/tests/cognitive-routing/host-fixture.js +4 -0
- package/pi-extension/tests/cognitive-routing/host-identity.test.js +63 -0
- package/pi-extension/tests/cognitive-routing/profile-resolution.test.js +236 -0
- package/pi-extension/tests/cognitive-routing/tool.test.js +230 -0
- package/pi-extension/tests/context-virtualization/extension.test.js +749 -0
- package/pi-extension/tests/context-virtualization/projector.test.js +110 -0
- package/pi-extension/tests/context-virtualization/runtime.test.js +216 -0
- package/pi-extension/tests/conversation-history/runtime.test.js +98 -0
- package/pi-extension/tests/conversation-history/search.test.js +97 -0
- package/pi-extension/tests/integration/pi-extension.test.js +928 -2047
- package/pi-extension/tests/integration/prompt-architecture.test.js +305 -0
- package/runtime/prompts/cognitive-routing.md +9 -0
- package/runtime/prompts/context-virtualization.md +3 -0
- package/runtime/prompts/conversation-history.md +3 -0
- package/runtime/prompts/core.md +13 -0
- package/runtime/prompts/interaction-contract.md +7 -0
- package/runtime/prompts/skills.md +65 -0
- package/skills/action-selection/SKILL.md +91 -0
- package/skills/bypass/SKILL.md +3 -2
- package/skills/commit-work/SKILL.md +1 -1
- package/skills/commit-work/references/staging-decisions.md +1 -1
- package/skills/decision-gate/SKILL.md +1 -1
- package/skills/design-for-depth/SKILL.md +14 -33
- package/skills/design-for-depth/references/design-pressure-signals.md +1 -1
- package/skills/design-for-depth/references/interface-design-loop.md +1 -1
- package/skills/design-for-depth/references/software-design-philosophy.md +1 -1
- package/skills/diagnose-failure/SKILL.md +20 -14
- package/skills/diagnose-failure/references/diagnostic-loop-catalog.md +1 -3
- package/skills/diagnose-failure/references/{flaky-and-performance.md → flaky-and-performance-diagnosis.md} +1 -1
- package/skills/discuss/SKILL.md +34 -22
- package/skills/discuss/references/discussion-continuity.md +71 -0
- package/skills/evaluate-skill/SKILL.md +5 -5
- package/skills/evaluate-skill/references/{definition-schema.md → evaluation-definition-schema.md} +42 -2
- package/skills/evaluate-skill/references/execution-and-evidence.md +8 -3
- package/skills/evaluate-skill/scripts/lib/definitions.mjs +114 -3
- package/skills/evaluate-skill/scripts/lib/grade-interaction.mjs +156 -1
- package/skills/evaluate-skill/scripts/lib/grade.mjs +9 -1
- package/skills/evaluate-skill/scripts/lib/pi.mjs +147 -32
- package/skills/evaluate-skill/scripts/lib/rpc.mjs +4 -4
- package/skills/evaluate-skill/scripts/lib/runner.mjs +36 -14
- package/skills/evaluate-skill/scripts/lib/sandbox.mjs +92 -0
- package/skills/evaluate-skill/scripts/pi-guard.mjs +1 -1
- package/skills/evaluate-skill/scripts/pi-observer.mjs +66 -0
- package/skills/evaluate-skill/scripts/skill-eval.mjs +6 -5
- package/skills/execute-work/SKILL.md +18 -15
- package/skills/execute-work/references/code-practices.md +1 -1
- package/skills/execute-work/references/execute-work-edges.md +42 -0
- package/skills/finish-branch/SKILL.md +2 -2
- package/skills/finish-branch/references/integration-options.md +1 -1
- package/skills/handoff/SKILL.md +3 -3
- package/skills/launch-work/SKILL.md +1 -1
- package/skills/launch-work/references/launch-readiness.md +2 -2
- package/skills/migration-work/SKILL.md +2 -2
- package/skills/migration-work/references/migration-lifecycle.md +1 -1
- package/skills/mode-contract/SKILL.md +32 -10
- package/skills/release-work/SKILL.md +1 -1
- package/skills/release-work/references/release-evidence.md +1 -1
- package/skills/review-artifact/SKILL.md +28 -26
- package/skills/review-work/SKILL.md +28 -26
- package/skills/review-work/references/{reviewer-prompt.md → independent-work-reviewer-contract.md} +1 -1
- package/skills/review-work/references/security-risk-lens.md +1 -1
- package/skills/setup-freeflow/SKILL.md +6 -10
- package/skills/setup-freeflow/references/activation-contract.md +5 -10
- package/skills/setup-freeflow/references/host-setup.md +3 -7
- package/skills/simplify-code/SKILL.md +1 -1
- package/skills/simplify-code/references/simplification-patterns.md +1 -1
- package/skills/tdd/SKILL.md +18 -38
- package/skills/tdd/references/test-design.md +2 -2
- package/skills/track-work/SKILL.md +362 -58
- package/skills/track-work/scripts/lib/codec.mjs +570 -0
- package/skills/track-work/scripts/lib/commands.mjs +568 -0
- package/skills/track-work/scripts/lib/contract.mjs +303 -0
- package/skills/track-work/scripts/lib/model.mjs +506 -0
- package/skills/track-work/scripts/lib/operations.mjs +965 -0
- package/skills/track-work/scripts/lib/record-store.mjs +264 -0
- package/skills/track-work/scripts/lib/result.mjs +37 -0
- package/skills/track-work/scripts/lib/rewrites.mjs +740 -0
- package/skills/track-work/scripts/lib/schema.mjs +277 -0
- package/skills/track-work/scripts/lib/source-inventory.mjs +162 -0
- package/skills/track-work/scripts/lib/views.mjs +443 -0
- package/skills/track-work/scripts/lib/workspace.mjs +134 -0
- package/skills/track-work/scripts/working-record.mjs +122 -0
- package/skills/verify-work/SKILL.md +14 -2
- package/skills/verify-work/references/browser-runtime-evidence.md +1 -1
- package/skills/verify-work/references/integration-evidence.md +1 -1
- package/skills/verify-work/references/performance-evidence.md +1 -1
- package/skills/workflow/SKILL.md +105 -53
- package/skills/workflow/references/domain-skill-composition.md +22 -42
- package/skills/write-plan/SKILL.md +1 -1
- package/skills/write-skill/SKILL.md +3 -2
- package/skills/write-skill/references/progressive-disclosure.md +17 -3
- package/pi-extension/dist/output-router/host-producer-identification.js +0 -232
- package/pi-extension/dist/output-router/native-safety-net.js +0 -216
- package/pi-extension/dist/output-router/observed-tool-routing.js +0 -122
- package/pi-extension/dist/output-router/renderers.js +0 -1023
- package/pi-extension/dist/output-router/router-tools.js +0 -554
- package/pi-extension/dist/output-router/schemas.js +0 -383
- package/pi-extension/dist/output-router/status.js +0 -744
- package/pi-extension/dist/output-router/utils.js +0 -502
- package/pi-extension/src/output-router/host-producer-identification.ts +0 -256
- package/pi-extension/src/output-router/native-safety-net.ts +0 -248
- package/pi-extension/src/output-router/observed-tool-routing.ts +0 -134
- package/pi-extension/src/output-router/renderers.ts +0 -1108
- package/pi-extension/src/output-router/router-tools.ts +0 -579
- package/pi-extension/src/output-router/schemas.ts +0 -387
- package/pi-extension/src/output-router/status.ts +0 -791
- package/pi-extension/src/output-router/utils.ts +0 -554
- package/pi-extension/tests/output-router/observed-producers.test.js +0 -132
- package/pi-extension/tests/output-router/search.test.js +0 -722
- package/router/dist/benchmarks/benchmark-harness.d.ts +0 -35
- package/router/dist/benchmarks/benchmark-harness.js +0 -92
- package/router/dist/benchmarks/benchmarks.d.ts +0 -109
- package/router/dist/benchmarks/benchmarks.js +0 -979
- package/router/dist/benchmarks/codex-qa-benchmarks.d.ts +0 -95
- package/router/dist/benchmarks/codex-qa-benchmarks.js +0 -500
- package/router/dist/benchmarks/command-benchmarks.d.ts +0 -143
- package/router/dist/benchmarks/command-benchmarks.js +0 -698
- package/router/dist/benchmarks/context-mode-normalized-benchmarks.d.ts +0 -82
- package/router/dist/benchmarks/context-mode-normalized-benchmarks.js +0 -773
- package/router/dist/benchmarks/context-mode-real-deep-benchmark.d.ts +0 -132
- package/router/dist/benchmarks/context-mode-real-deep-benchmark.js +0 -1380
- package/router/dist/benchmarks/context-saving-baseline.d.ts +0 -60
- package/router/dist/benchmarks/context-saving-baseline.js +0 -470
- package/router/dist/benchmarks/index-benchmarks.d.ts +0 -103
- package/router/dist/benchmarks/index-benchmarks.js +0 -862
- package/router/dist/benchmarks/storage-policy-benchmarks.d.ts +0 -101
- package/router/dist/benchmarks/storage-policy-benchmarks.js +0 -618
- package/router/dist/benchmarks/vault-index-benchmarks.d.ts +0 -56
- package/router/dist/benchmarks/vault-index-benchmarks.js +0 -322
- package/router/dist/config/config.d.ts +0 -103
- package/router/dist/config/config.js +0 -632
- package/router/dist/config/router-contract.d.ts +0 -10
- package/router/dist/config/router-contract.js +0 -54
- package/router/dist/config/schema.d.ts +0 -27
- package/router/dist/config/schema.js +0 -648
- package/router/dist/config/types.d.ts +0 -573
- package/router/dist/config/types.js +0 -41
- package/router/dist/evidence/bounded-evidence.d.ts +0 -40
- package/router/dist/evidence/bounded-evidence.js +0 -323
- package/router/dist/evidence/evidence-range-selector.d.ts +0 -24
- package/router/dist/evidence/evidence-range-selector.js +0 -232
- package/router/dist/evidence/evidence-search.d.ts +0 -27
- package/router/dist/evidence/evidence-search.js +0 -490
- package/router/dist/evidence/evidence.d.ts +0 -38
- package/router/dist/evidence/evidence.js +0 -200
- package/router/dist/evidence/failure-contracts.d.ts +0 -37
- package/router/dist/evidence/failure-contracts.js +0 -166
- package/router/dist/evidence/line-ranges.d.ts +0 -24
- package/router/dist/evidence/line-ranges.js +0 -22
- package/router/dist/experiments/local-index.d.ts +0 -64
- package/router/dist/experiments/local-index.js +0 -581
- package/router/dist/index.d.ts +0 -30
- package/router/dist/index.js +0 -32
- package/router/dist/local/local-traversal.d.ts +0 -18
- package/router/dist/local/local-traversal.js +0 -334
- package/router/dist/processing/engine.d.ts +0 -132
- package/router/dist/processing/engine.js +0 -533
- package/router/dist/processing/reducers.d.ts +0 -280
- package/router/dist/processing/reducers.js +0 -1673
- package/router/dist/processing/renderers.d.ts +0 -31
- package/router/dist/processing/renderers.js +0 -195
- package/router/dist/processing/scripts.d.ts +0 -91
- package/router/dist/processing/scripts.js +0 -386
- package/router/dist/repo/repo-traversal.d.ts +0 -18
- package/router/dist/repo/repo-traversal.js +0 -245
- package/router/dist/routing/observed-reducers.d.ts +0 -41
- package/router/dist/routing/observed-reducers.js +0 -661
- package/router/dist/routing/observed-routing.d.ts +0 -26
- package/router/dist/routing/observed-routing.js +0 -378
- package/router/dist/routing/parsers.d.ts +0 -16
- package/router/dist/routing/parsers.js +0 -521
- package/router/dist/routing/run-filters.d.ts +0 -60
- package/router/dist/routing/run-filters.js +0 -238
- package/router/dist/routing/run-reducers.d.ts +0 -49
- package/router/dist/routing/run-reducers.js +0 -122
- package/router/dist/sandbox/adapter-roots.d.ts +0 -46
- package/router/dist/sandbox/adapter-roots.js +0 -66
- package/router/dist/sandbox/eryx-python-adapter.d.ts +0 -13
- package/router/dist/sandbox/eryx-python-adapter.js +0 -868
- package/router/dist/sandbox/jq-wasm-adapter.d.ts +0 -9
- package/router/dist/sandbox/jq-wasm-adapter.js +0 -429
- package/router/dist/sandbox/quickjs-wasi-adapter.d.ts +0 -13
- package/router/dist/sandbox/quickjs-wasi-adapter.js +0 -384
- package/router/dist/sandbox/script-sandbox.d.ts +0 -134
- package/router/dist/sandbox/script-sandbox.js +0 -337
- package/router/dist/setup/script-transform-adapters.d.ts +0 -32
- package/router/dist/setup/script-transform-adapters.js +0 -278
- package/router/dist/tools/batch.d.ts +0 -33
- package/router/dist/tools/batch.js +0 -586
- package/router/dist/tools/run.d.ts +0 -62
- package/router/dist/tools/run.js +0 -1304
- package/router/dist/tools/search.d.ts +0 -66
- package/router/dist/tools/search.js +0 -1364
- package/router/dist/transform/engine.d.ts +0 -168
- package/router/dist/transform/engine.js +0 -2072
- package/router/dist/vault/vault-index.d.ts +0 -125
- package/router/dist/vault/vault-index.js +0 -416
- package/router/dist/vault/vault.d.ts +0 -138
- package/router/dist/vault/vault.js +0 -630
- package/runtime/interaction-contract.md +0 -16
- package/skills/discuss/references/checkpoints.md +0 -66
- package/skills/execute-work/references/execution-loop.md +0 -77
- package/skills/output-router/SKILL.md +0 -206
- package/skills/output-router/references/safety-policy.md +0 -40
- package/skills/setup-freeflow/references/output-router-setup.md +0 -110
- package/skills/track-work/references/working-record-schema.md +0 -378
- package/skills/workflow/references/workflow-loop.md +0 -92
- /package/skills/handoff/references/{templates.md → handoff-templates.md} +0 -0
- /package/skills/review-artifact/references/{reviewer-prompt.md → independent-artifact-reviewer-contract.md} +0 -0
package/hooks/hooks.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"description": "Load Freeflow runtime context
|
|
2
|
+
"description": "Load Freeflow runtime context and manage session mode.",
|
|
3
3
|
"hooks": {
|
|
4
4
|
"SessionStart": [
|
|
5
5
|
{
|
|
@@ -13,6 +13,31 @@
|
|
|
13
13
|
}
|
|
14
14
|
]
|
|
15
15
|
}
|
|
16
|
+
],
|
|
17
|
+
"UserPromptSubmit": [
|
|
18
|
+
{
|
|
19
|
+
"hooks": [
|
|
20
|
+
{
|
|
21
|
+
"type": "command",
|
|
22
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT:-${PLUGIN_ROOT}}/hooks/freeflow-runtime-context.mjs\" UserPromptSubmit",
|
|
23
|
+
"timeout": 5,
|
|
24
|
+
"statusMessage": "Checking Freeflow mode"
|
|
25
|
+
}
|
|
26
|
+
]
|
|
27
|
+
}
|
|
28
|
+
],
|
|
29
|
+
"SessionEnd": [
|
|
30
|
+
{
|
|
31
|
+
"matcher": "clear",
|
|
32
|
+
"hooks": [
|
|
33
|
+
{
|
|
34
|
+
"type": "command",
|
|
35
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT:-${PLUGIN_ROOT}}/hooks/freeflow-runtime-context.mjs\" SessionEnd",
|
|
36
|
+
"timeout": 3,
|
|
37
|
+
"statusMessage": "Preserving Freeflow mode"
|
|
38
|
+
}
|
|
39
|
+
]
|
|
40
|
+
}
|
|
16
41
|
]
|
|
17
42
|
}
|
|
18
43
|
}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
set -euo pipefail
|
|
3
3
|
|
|
4
|
-
ROOT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")/../.." && pwd)"
|
|
4
|
+
ROOT_DIR="$(CDPATH='' cd -- "$(dirname -- "$0")/../.." && pwd)"
|
|
5
5
|
HOOK_PATH="$ROOT_DIR/hooks/freeflow-runtime-context.mjs"
|
|
6
6
|
HOOKS_JSON="$ROOT_DIR/hooks/hooks.json"
|
|
7
|
-
|
|
7
|
+
CORE_PROMPT="$ROOT_DIR/runtime/prompts/core.md"
|
|
8
|
+
INTERACTION_PROMPT="$ROOT_DIR/runtime/prompts/interaction-contract.md"
|
|
9
|
+
SKILLS_PROMPT="$ROOT_DIR/runtime/prompts/skills.md"
|
|
8
10
|
|
|
9
11
|
fail() {
|
|
10
12
|
echo "runtime-context hook check failed: $*" >&2
|
|
@@ -29,18 +31,20 @@ assert_not_contains() {
|
|
|
29
31
|
|
|
30
32
|
[[ -f "$HOOK_PATH" ]] || fail "missing hook script"
|
|
31
33
|
[[ -f "$HOOKS_JSON" ]] || fail "missing hooks manifest"
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
[[ -n "$workflow_owner_line" ]] || fail "canonical Workflow owner sentinel missing"
|
|
36
|
-
[[ -n "$workflow_self_review_line" ]] || fail "canonical Workflow self-review sentinel missing"
|
|
34
|
+
for prompt_file in "$CORE_PROMPT" "$INTERACTION_PROMPT" "$SKILLS_PROMPT"; do
|
|
35
|
+
[[ -f "$prompt_file" ]] || fail "missing runtime prompt fragment: $prompt_file"
|
|
36
|
+
done
|
|
37
37
|
node --check "$HOOK_PATH"
|
|
38
38
|
node -e '
|
|
39
39
|
const fs = require("fs");
|
|
40
40
|
const hooks = JSON.parse(fs.readFileSync(process.argv[1], "utf8")).hooks || {};
|
|
41
41
|
if (!Array.isArray(hooks.SessionStart) || hooks.SessionStart.length === 0) process.exit(1);
|
|
42
42
|
if (hooks.SessionStart[0]?.matcher !== "startup|resume|clear|compact") process.exit(1);
|
|
43
|
-
|
|
43
|
+
if (!Array.isArray(hooks.UserPromptSubmit) || hooks.UserPromptSubmit.length !== 1) process.exit(1);
|
|
44
|
+
if (hooks.UserPromptSubmit[0]?.matcher != null) process.exit(1);
|
|
45
|
+
if (!Array.isArray(hooks.SessionEnd) || hooks.SessionEnd.length !== 1) process.exit(1);
|
|
46
|
+
if (hooks.SessionEnd[0]?.matcher !== "clear") process.exit(1);
|
|
47
|
+
' "$HOOKS_JSON" || fail "hooks.json does not register the expected non-overlapping runtime events"
|
|
44
48
|
|
|
45
49
|
tmp_dir="$(mktemp -d)"
|
|
46
50
|
trap 'rm -rf "$tmp_dir"' EXIT
|
|
@@ -57,45 +61,207 @@ user_prompt_output="$(printf '{"cwd":"%s","model":"gpt-5"}\n' "$tmp_dir" | node
|
|
|
57
61
|
[[ -z "$user_prompt_output" ]] || fail "UserPromptSubmit should not duplicate session-start runtime context"
|
|
58
62
|
|
|
59
63
|
for expected in \
|
|
60
|
-
"
|
|
61
|
-
|
|
62
|
-
"
|
|
64
|
+
'"hookEventName":"SessionStart"' \
|
|
65
|
+
"# Freeflow Stable Guidance" \
|
|
66
|
+
"## Mode" \
|
|
67
|
+
"## Shared Terms" \
|
|
68
|
+
"## Three Nested Loops" \
|
|
69
|
+
"## Workflow Cue" \
|
|
70
|
+
"## Action Selection Cue" \
|
|
71
|
+
"## Supported Exit" \
|
|
63
72
|
"# Freeflow Interaction Contract" \
|
|
64
|
-
"
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
"$workflow_owner_line" \
|
|
68
|
-
"$workflow_self_review_line" \
|
|
69
|
-
'Current Freeflow default mode: `workflow`.' \
|
|
73
|
+
"Treat questions, criticism, examples, hypotheses, and tentative ideas as" \
|
|
74
|
+
'Configured default: `workflow` (repository)' \
|
|
75
|
+
'Effective mode: `workflow` (configured default, active)' \
|
|
70
76
|
'Interaction Contract: enabled' \
|
|
71
|
-
'Skills: enabled'
|
|
72
|
-
'Output router: disabled'; do
|
|
77
|
+
'Skills: enabled'; do
|
|
73
78
|
assert_contains "$codex_output" "$expected" "Codex config-only context"
|
|
74
79
|
done
|
|
80
|
+
assert_not_contains "$codex_output" "Output Router" "Codex host context"
|
|
81
|
+
assert_not_contains "$codex_output" "Output router:" "Codex host context"
|
|
82
|
+
|
|
83
|
+
# The Pi-only capability key is tolerated by shared host validators but is not
|
|
84
|
+
# injected into Codex or Claude runtime context.
|
|
85
|
+
cognitive_dir="$(mktemp -d)"
|
|
86
|
+
mkdir -p "$cognitive_dir/.freeflow"
|
|
87
|
+
printf '{"defaultMode":"workflow","cognitiveRouting":{"enabled":true,"profiles":{"standard":{"provider":"faux","model":"standard","thinkingLevel":"high"},"reasoning":{"provider":"faux","model":"reasoning","thinkingLevel":"max"}}}}\n' >"$cognitive_dir/.freeflow/config.json"
|
|
88
|
+
cognitive_output="$(printf '{"cwd":"%s","model":"gpt-5"}\n' "$cognitive_dir" | node "$HOOK_PATH" SessionStart)"
|
|
89
|
+
assert_contains "$cognitive_output" "# Freeflow Stable Guidance" "Pi-only capability tolerance"
|
|
90
|
+
assert_not_contains "$cognitive_output" "Cognitive Routing" "non-Pi capability isolation"
|
|
91
|
+
rm -rf "$cognitive_dir"
|
|
75
92
|
for excluded_heading in \
|
|
76
93
|
"# Freeflow Runtime Kernel" \
|
|
77
94
|
"## Freeflow Runtime Priority" \
|
|
78
95
|
"## Loaded Mode Contract Skill" \
|
|
79
96
|
"## Loaded Workflow Skill" \
|
|
80
97
|
"## Loaded Decision Gate Skill" \
|
|
98
|
+
"# Freeflow Workflow Bootstrap" \
|
|
81
99
|
"## Discovery-light" \
|
|
82
100
|
"## Loaded Output Router Skill"; do
|
|
83
101
|
assert_not_contains "$codex_output" "$excluded_heading" "default context"
|
|
84
102
|
done
|
|
85
|
-
|
|
86
|
-
[[ "$
|
|
103
|
+
skills_prompt_count="$(grep -Fo '## Shared Terms' <<<"$codex_output" | wc -l | tr -d ' ')"
|
|
104
|
+
[[ "$skills_prompt_count" == "1" ]] || fail "Codex SessionStart should load the Skills prompt exactly once"
|
|
87
105
|
assert_not_contains "$codex_output" "## Conversation Mode Boundary" "workflow context"
|
|
88
106
|
assert_not_contains "$codex_output" "## Strict Workflow Overlay" "workflow context"
|
|
89
107
|
|
|
90
108
|
claude_output="$(printf '{"hook_event_name":"SessionStart","source":"startup","cwd":"%s"}\n' "$tmp_dir" | node "$HOOK_PATH" SessionStart)"
|
|
91
109
|
assert_contains "$claude_output" '"hookEventName":"SessionStart"' "Claude wrapper"
|
|
92
110
|
assert_contains "$claude_output" "# Freeflow Interaction Contract" "Claude config-only context"
|
|
93
|
-
assert_contains "$claude_output" "
|
|
94
|
-
|
|
111
|
+
assert_contains "$claude_output" "## Shared Terms" "Claude skills context"
|
|
112
|
+
assert_not_contains "$claude_output" "# Freeflow Workflow Bootstrap" "Claude first-turn context"
|
|
113
|
+
assert_contains "$claude_output" "Treat questions, criticism, examples, hypotheses, and tentative ideas as" "Claude config-only context"
|
|
114
|
+
|
|
115
|
+
# Session mode changes are host-managed state: they apply before the same model request,
|
|
116
|
+
# survive lifecycle restoration, remain isolated by session id, and never edit repo config.
|
|
117
|
+
session_data_dir="$(mktemp -d)"
|
|
118
|
+
session_id="session/with unsafe path characters"
|
|
119
|
+
config_before="$(shasum -a 256 "$tmp_dir/.freeflow/config.json" | awk '{print $1}')"
|
|
120
|
+
mode_change_output="$(printf '{"hook_event_name":"UserPromptSubmit","session_id":"%s","cwd":"%s","prompt":"Switch to conversation mode."}\n' "$session_id" "$tmp_dir" | PLUGIN_DATA="$session_data_dir" node "$HOOK_PATH" UserPromptSubmit)"
|
|
121
|
+
assert_contains "$mode_change_output" '"hookEventName":"UserPromptSubmit"' "same-turn mode change wrapper"
|
|
122
|
+
assert_contains "$mode_change_output" '# Freeflow Runtime State' "same-turn mode change"
|
|
123
|
+
assert_contains "$mode_change_output" 'Session override: `conversation`' "same-turn mode change"
|
|
124
|
+
assert_contains "$mode_change_output" 'Effective mode: `conversation` (session override, active)' "same-turn mode change"
|
|
125
|
+
assert_not_contains "$mode_change_output" "# Freeflow Mode Update" "same-turn mode change"
|
|
126
|
+
assert_not_contains "$mode_change_output" "## Conversation Mode Boundary" "same-turn mode change"
|
|
127
|
+
assert_not_contains "$mode_change_output" "Do not call write, edit, or mutating tools" "same-turn mode change"
|
|
128
|
+
|
|
129
|
+
restored_mode_output="$(printf '{"hook_event_name":"SessionStart","source":"compact","session_id":"%s","cwd":"%s","model":"gpt-5"}\n' "$session_id" "$tmp_dir" | PLUGIN_DATA="$session_data_dir" node "$HOOK_PATH" SessionStart)"
|
|
130
|
+
assert_contains "$restored_mode_output" 'Configured default: `workflow` (repository)' "restored session mode"
|
|
131
|
+
assert_contains "$restored_mode_output" 'Session override: `conversation`' "restored session mode"
|
|
132
|
+
assert_contains "$restored_mode_output" 'Effective mode: `conversation` (session override, active)' "restored session mode"
|
|
133
|
+
|
|
134
|
+
other_session_output="$(printf '{"hook_event_name":"SessionStart","source":"resume","session_id":"other-session","cwd":"%s","model":"gpt-5"}\n' "$tmp_dir" | PLUGIN_DATA="$session_data_dir" node "$HOOK_PATH" SessionStart)"
|
|
135
|
+
assert_contains "$other_session_output" 'Session override: none' "session mode isolation"
|
|
136
|
+
assert_contains "$other_session_output" 'Effective mode: `workflow` (configured default, active)' "session mode isolation"
|
|
137
|
+
|
|
138
|
+
ordinary_prompt_output="$(printf '{"hook_event_name":"UserPromptSubmit","session_id":"%s","cwd":"%s","prompt":"Please explain this function."}\n' "$session_id" "$tmp_dir" | PLUGIN_DATA="$session_data_dir" node "$HOOK_PATH" UserPromptSubmit)"
|
|
139
|
+
[[ -z "$ordinary_prompt_output" ]] || fail "ordinary prompts should not duplicate runtime context"
|
|
140
|
+
question_prompt_output="$(printf '{"hook_event_name":"UserPromptSubmit","session_id":"%s","cwd":"%s","prompt":"Should we switch to strict-workflow mode?"}\n' "$session_id" "$tmp_dir" | PLUGIN_DATA="$session_data_dir" node "$HOOK_PATH" UserPromptSubmit)"
|
|
141
|
+
[[ -z "$question_prompt_output" ]] || fail "mode questions should not mutate session state"
|
|
142
|
+
hypothetical_prompt_output="$(printf '{"hook_event_name":"UserPromptSubmit","session_id":"%s","cwd":"%s","prompt":"Suppose the mode were workflow."}\n' "$session_id" "$tmp_dir" | PLUGIN_DATA="$session_data_dir" node "$HOOK_PATH" UserPromptSubmit)"
|
|
143
|
+
[[ -z "$hypothetical_prompt_output" ]] || fail "mode hypotheticals should not mutate session state"
|
|
144
|
+
default_prompt_output="$(printf '{"hook_event_name":"UserPromptSubmit","session_id":"%s","cwd":"%s","prompt":"Change the default mode to strict-workflow."}\n' "$session_id" "$tmp_dir" | PLUGIN_DATA="$session_data_dir" node "$HOOK_PATH" UserPromptSubmit)"
|
|
145
|
+
[[ -z "$default_prompt_output" ]] || fail "default-mode requests should remain agent-routed configuration decisions"
|
|
146
|
+
|
|
147
|
+
native_change_output="$(printf '{"hook_event_name":"UserPromptSubmit","session_id":"%s","cwd":"%s","prompt":"$mode-contract strict-workflow"}\n' "$session_id" "$tmp_dir" | PLUGIN_DATA="$session_data_dir" node "$HOOK_PATH" UserPromptSubmit)"
|
|
148
|
+
assert_contains "$native_change_output" '# Freeflow Runtime State' "Codex native skill mode control"
|
|
149
|
+
assert_contains "$native_change_output" 'Session override: `strict-workflow`' "Codex native skill mode control"
|
|
150
|
+
assert_not_contains "$native_change_output" "# Freeflow Mode Update" "Codex native skill mode control"
|
|
151
|
+
assert_not_contains "$native_change_output" "## Strict Workflow Overlay" "Codex native skill mode control"
|
|
152
|
+
|
|
153
|
+
claude_data_dir="$(mktemp -d)"
|
|
154
|
+
claude_mode_output="$(printf '{"hook_event_name":"UserPromptSubmit","session_id":"claude-session","cwd":"%s","prompt":"/freeflow:mode-contract conversation"}\n' "$tmp_dir" | CLAUDE_PLUGIN_DATA="$claude_data_dir" node "$HOOK_PATH" UserPromptSubmit)"
|
|
155
|
+
assert_contains "$claude_mode_output" '"hookEventName":"UserPromptSubmit"' "Claude native skill mode control"
|
|
156
|
+
assert_contains "$claude_mode_output" 'Session override: `conversation`' "Claude native skill mode control"
|
|
157
|
+
claude_restored_output="$(printf '{"hook_event_name":"SessionStart","source":"resume","session_id":"claude-session","cwd":"%s"}\n' "$tmp_dir" | CLAUDE_PLUGIN_DATA="$claude_data_dir" node "$HOOK_PATH" SessionStart)"
|
|
158
|
+
assert_contains "$claude_restored_output" 'Effective mode: `conversation` (session override, active)' "Claude restored session mode"
|
|
159
|
+
|
|
160
|
+
# Claude /clear ends one session and starts another. SessionEnd transfers only the
|
|
161
|
+
# active override for this host process/workspace, and SessionStart consumes it exactly once.
|
|
162
|
+
claude_clear_end_output="$(printf '{"hook_event_name":"SessionEnd","reason":"clear","session_id":"claude-session","cwd":"%s"}\n' "$tmp_dir" | CLAUDE_PLUGIN_DATA="$claude_data_dir" CLAUDE_PID="claude-process-a" node "$HOOK_PATH" SessionEnd)"
|
|
163
|
+
[[ -z "$claude_clear_end_output" ]] || fail "SessionEnd clear should not emit model context"
|
|
164
|
+
claude_clear_output="$(printf '{"hook_event_name":"SessionStart","source":"clear","session_id":"claude-session-after-clear","cwd":"%s"}\n' "$tmp_dir" | CLAUDE_PLUGIN_DATA="$claude_data_dir" CLAUDE_PID="claude-process-a" node "$HOOK_PATH" SessionStart)"
|
|
165
|
+
assert_contains "$claude_clear_output" 'Session override: `conversation`' "Claude clear session transfer"
|
|
166
|
+
assert_contains "$claude_clear_output" 'Effective mode: `conversation` (session override, active)' "Claude clear session transfer"
|
|
167
|
+
claude_unrelated_output="$(printf '{"hook_event_name":"SessionStart","source":"startup","session_id":"claude-unrelated-session","cwd":"%s"}\n' "$tmp_dir" | CLAUDE_PLUGIN_DATA="$claude_data_dir" node "$HOOK_PATH" SessionStart)"
|
|
168
|
+
assert_contains "$claude_unrelated_output" 'Session override: none' "Claude clear transfer isolation"
|
|
169
|
+
claude_second_clear_output="$(printf '{"hook_event_name":"SessionStart","source":"clear","session_id":"claude-second-clear","cwd":"%s"}\n' "$tmp_dir" | CLAUDE_PLUGIN_DATA="$claude_data_dir" node "$HOOK_PATH" SessionStart)"
|
|
170
|
+
assert_contains "$claude_second_clear_output" 'Session override: none' "Claude clear transfer one-shot consumption"
|
|
171
|
+
|
|
172
|
+
# A stale clear handoff is consumed without applying it.
|
|
173
|
+
claude_stale_mode_output="$(printf '{"hook_event_name":"UserPromptSubmit","session_id":"claude-stale-source","cwd":"%s","prompt":"Switch to strict-workflow mode."}\n' "$tmp_dir" | CLAUDE_PLUGIN_DATA="$claude_data_dir" node "$HOOK_PATH" UserPromptSubmit)"
|
|
174
|
+
assert_contains "$claude_stale_mode_output" 'Session override: `strict-workflow`' "Claude stale clear setup"
|
|
175
|
+
printf '{"hook_event_name":"SessionEnd","reason":"clear","session_id":"claude-stale-source","cwd":"%s"}\n' "$tmp_dir" | CLAUDE_PLUGIN_DATA="$claude_data_dir" CLAUDE_PID="claude-process-stale" node "$HOOK_PATH" SessionEnd >/dev/null
|
|
176
|
+
clear_transfer_file="$(find "$claude_data_dir/session-modes/claude-clear" -type f -name '*.json' -print -quit)"
|
|
177
|
+
node - "$clear_transfer_file" <<'NODE'
|
|
178
|
+
const fs = require("fs");
|
|
179
|
+
const path = process.argv[2];
|
|
180
|
+
const state = JSON.parse(fs.readFileSync(path, "utf8"));
|
|
181
|
+
state.createdAt = new Date(Date.now() - 120000).toISOString();
|
|
182
|
+
fs.writeFileSync(path, `${JSON.stringify(state)}\n`);
|
|
183
|
+
NODE
|
|
184
|
+
claude_stale_clear_output="$(printf '{"hook_event_name":"SessionStart","source":"clear","session_id":"claude-stale-target","cwd":"%s"}\n' "$tmp_dir" | CLAUDE_PLUGIN_DATA="$claude_data_dir" CLAUDE_PID="claude-process-stale" node "$HOOK_PATH" SessionStart)"
|
|
185
|
+
assert_contains "$claude_stale_clear_output" 'Session override: none' "Claude stale clear transfer"
|
|
186
|
+
[[ ! -e "$clear_transfer_file" ]] || fail "stale Claude clear transfer should be consumed"
|
|
187
|
+
|
|
188
|
+
# Malformed plugin-owned transfer content fails closed without suppressing the
|
|
189
|
+
# normal SessionStart context and is consumed rather than retried forever.
|
|
190
|
+
printf '{"hook_event_name":"SessionEnd","reason":"clear","session_id":"claude-stale-source","cwd":"%s"}\n' "$tmp_dir" | CLAUDE_PLUGIN_DATA="$claude_data_dir" CLAUDE_PID="claude-process-malformed" node "$HOOK_PATH" SessionEnd >/dev/null
|
|
191
|
+
malformed_transfer_file="$(find "$claude_data_dir/session-modes/claude-clear" -type f -name '*.json' -print -quit)"
|
|
192
|
+
printf 'null\n' >"$malformed_transfer_file"
|
|
193
|
+
claude_malformed_clear_output="$(printf '{"hook_event_name":"SessionStart","source":"clear","session_id":"claude-malformed-target","cwd":"%s"}\n' "$tmp_dir" | CLAUDE_PLUGIN_DATA="$claude_data_dir" CLAUDE_PID="claude-process-malformed" node "$HOOK_PATH" SessionStart)"
|
|
194
|
+
assert_contains "$claude_malformed_clear_output" '# Freeflow Stable Guidance' "Claude malformed clear transfer"
|
|
195
|
+
assert_contains "$claude_malformed_clear_output" 'Session override: none' "Claude malformed clear transfer"
|
|
196
|
+
[[ ! -e "$malformed_transfer_file" ]] || fail "malformed Claude clear transfer should be consumed"
|
|
197
|
+
|
|
198
|
+
# Overlapping clears in one workspace remain isolated by the host process ID.
|
|
199
|
+
printf '{"hook_event_name":"UserPromptSubmit","session_id":"claude-overlap-a","cwd":"%s","prompt":"Switch to conversation mode."}\n' "$tmp_dir" | CLAUDE_PLUGIN_DATA="$claude_data_dir" node "$HOOK_PATH" UserPromptSubmit >/dev/null
|
|
200
|
+
printf '{"hook_event_name":"UserPromptSubmit","session_id":"claude-overlap-b","cwd":"%s","prompt":"Switch to strict-workflow mode."}\n' "$tmp_dir" | CLAUDE_PLUGIN_DATA="$claude_data_dir" node "$HOOK_PATH" UserPromptSubmit >/dev/null
|
|
201
|
+
printf '{"hook_event_name":"SessionEnd","reason":"clear","session_id":"claude-overlap-a","cwd":"%s"}\n' "$tmp_dir" | CLAUDE_PLUGIN_DATA="$claude_data_dir" CLAUDE_PID="claude-process-overlap-a" node "$HOOK_PATH" SessionEnd >/dev/null
|
|
202
|
+
printf '{"hook_event_name":"SessionEnd","reason":"clear","session_id":"claude-overlap-b","cwd":"%s"}\n' "$tmp_dir" | CLAUDE_PLUGIN_DATA="$claude_data_dir" CLAUDE_PID="claude-process-overlap-b" node "$HOOK_PATH" SessionEnd >/dev/null
|
|
203
|
+
claude_overlap_b_output="$(printf '{"hook_event_name":"SessionStart","source":"clear","session_id":"claude-overlap-b-new","cwd":"%s"}\n' "$tmp_dir" | CLAUDE_PLUGIN_DATA="$claude_data_dir" CLAUDE_PID="claude-process-overlap-b" node "$HOOK_PATH" SessionStart)"
|
|
204
|
+
assert_contains "$claude_overlap_b_output" 'Session override: `strict-workflow`' "Claude overlapping clear B"
|
|
205
|
+
claude_overlap_a_output="$(printf '{"hook_event_name":"SessionStart","source":"clear","session_id":"claude-overlap-a-new","cwd":"%s"}\n' "$tmp_dir" | CLAUDE_PLUGIN_DATA="$claude_data_dir" CLAUDE_PID="claude-process-overlap-a" node "$HOOK_PATH" SessionStart)"
|
|
206
|
+
assert_contains "$claude_overlap_a_output" 'Session override: `conversation`' "Claude overlapping clear A"
|
|
207
|
+
|
|
208
|
+
# A no-override clear removes any stale transfer for the same process/workspace.
|
|
209
|
+
printf '{"hook_event_name":"SessionEnd","reason":"clear","session_id":"claude-no-override","cwd":"%s"}\n' "$tmp_dir" | CLAUDE_PLUGIN_DATA="$claude_data_dir" CLAUDE_PID="claude-process-overlap-a" node "$HOOK_PATH" SessionEnd >/dev/null
|
|
210
|
+
claude_no_override_clear_output="$(printf '{"hook_event_name":"SessionStart","source":"clear","session_id":"claude-no-override-new","cwd":"%s"}\n' "$tmp_dir" | CLAUDE_PLUGIN_DATA="$claude_data_dir" CLAUDE_PID="claude-process-overlap-a" node "$HOOK_PATH" SessionStart)"
|
|
211
|
+
assert_contains "$claude_no_override_clear_output" 'Session override: none' "Claude no-override clear"
|
|
212
|
+
|
|
213
|
+
# Transfer consumption claims the handoff atomically: two concurrent starts can
|
|
214
|
+
# never both receive the same override.
|
|
215
|
+
printf '{"hook_event_name":"SessionEnd","reason":"clear","session_id":"claude-overlap-b-new","cwd":"%s"}\n' "$tmp_dir" | CLAUDE_PLUGIN_DATA="$claude_data_dir" CLAUDE_PID="claude-process-race" node "$HOOK_PATH" SessionEnd >/dev/null
|
|
216
|
+
race_output_a="$(mktemp)"
|
|
217
|
+
race_output_b="$(mktemp)"
|
|
218
|
+
printf '{"hook_event_name":"SessionStart","source":"clear","session_id":"claude-race-a","cwd":"%s"}\n' "$tmp_dir" | CLAUDE_PLUGIN_DATA="$claude_data_dir" CLAUDE_PID="claude-process-race" node "$HOOK_PATH" SessionStart >"$race_output_a" &
|
|
219
|
+
race_pid_a=$!
|
|
220
|
+
printf '{"hook_event_name":"SessionStart","source":"clear","session_id":"claude-race-b","cwd":"%s"}\n' "$tmp_dir" | CLAUDE_PLUGIN_DATA="$claude_data_dir" CLAUDE_PID="claude-process-race" node "$HOOK_PATH" SessionStart >"$race_output_b" &
|
|
221
|
+
race_pid_b=$!
|
|
222
|
+
wait "$race_pid_a" "$race_pid_b"
|
|
223
|
+
race_override_count="$(grep -Fh 'Session override: `strict-workflow`' "$race_output_a" "$race_output_b" | wc -l | tr -d ' ')"
|
|
224
|
+
[[ "$race_override_count" == "1" ]] || fail "Claude clear transfer should have exactly one concurrent consumer"
|
|
225
|
+
rm -f "$race_output_a" "$race_output_b"
|
|
226
|
+
|
|
227
|
+
# Codex currently reports SessionEnd reason=other, so it must never stage a
|
|
228
|
+
# Claude-style clear handoff.
|
|
229
|
+
codex_clear_data_dir="$(mktemp -d)"
|
|
230
|
+
printf '{"hook_event_name":"UserPromptSubmit","session_id":"codex-source","cwd":"%s","prompt":"Switch to conversation mode."}\n' "$tmp_dir" | PLUGIN_DATA="$codex_clear_data_dir" node "$HOOK_PATH" UserPromptSubmit >/dev/null
|
|
231
|
+
printf '{"hook_event_name":"SessionEnd","reason":"other","session_id":"codex-source","cwd":"%s"}\n' "$tmp_dir" | PLUGIN_DATA="$codex_clear_data_dir" node "$HOOK_PATH" SessionEnd >/dev/null
|
|
232
|
+
if [[ -d "$codex_clear_data_dir/session-modes/claude-clear" ]]; then
|
|
233
|
+
fail "Codex SessionEnd should not stage Claude clear state"
|
|
234
|
+
fi
|
|
235
|
+
rm -rf "$codex_clear_data_dir" "$claude_data_dir"
|
|
236
|
+
|
|
237
|
+
reset_output="$(printf '{"hook_event_name":"UserPromptSubmit","session_id":"%s","cwd":"%s","prompt":"Reset the session mode."}\n' "$session_id" "$tmp_dir" | PLUGIN_DATA="$session_data_dir" node "$HOOK_PATH" UserPromptSubmit)"
|
|
238
|
+
assert_contains "$reset_output" 'Session override: cleared' "session mode reset"
|
|
239
|
+
assert_contains "$reset_output" 'Effective mode: `workflow` (configured default, active)' "session mode reset"
|
|
240
|
+
config_after="$(shasum -a 256 "$tmp_dir/.freeflow/config.json" | awk '{print $1}')"
|
|
241
|
+
[[ "$config_before" == "$config_after" ]] || fail "session mode controls modified repository config"
|
|
242
|
+
if find "$session_data_dir" -type f -print | grep -Fq "$session_id"; then
|
|
243
|
+
fail "raw session id leaked into the session-state path"
|
|
244
|
+
fi
|
|
245
|
+
rm -rf "$session_data_dir"
|
|
95
246
|
|
|
96
247
|
for source in startup resume clear compact; do
|
|
97
|
-
|
|
98
|
-
|
|
248
|
+
codex_event_output="$(printf '{"hook_event_name":"SessionStart","source":"%s","cwd":"%s","model":"gpt-5"}\n' "$source" "$tmp_dir" | node "$HOOK_PATH" SessionStart)"
|
|
249
|
+
claude_event_output="$(printf '{"hook_event_name":"SessionStart","source":"%s","cwd":"%s"}\n' "$source" "$tmp_dir" | node "$HOOK_PATH" SessionStart)"
|
|
250
|
+
for host in codex claude; do
|
|
251
|
+
if [[ "$host" == "codex" ]]; then
|
|
252
|
+
event_output="$codex_event_output"
|
|
253
|
+
else
|
|
254
|
+
event_output="$claude_event_output"
|
|
255
|
+
assert_contains "$event_output" '"hookEventName":"SessionStart"' "Claude $source wrapper"
|
|
256
|
+
fi
|
|
257
|
+
assert_contains "$event_output" "# Freeflow Interaction Contract" "$host $source SessionStart context"
|
|
258
|
+
assert_contains "$event_output" "## Shared Terms" "$host $source SessionStart context"
|
|
259
|
+
contract_count="$(grep -Fo '# Freeflow Interaction Contract' <<<"$event_output" | wc -l | tr -d ' ')"
|
|
260
|
+
skills_count="$(grep -Fo '## Shared Terms' <<<"$event_output" | wc -l | tr -d ' ')"
|
|
261
|
+
[[ "$contract_count" == "1" ]] || fail "$host $source SessionStart should load the Interaction Contract exactly once"
|
|
262
|
+
[[ "$skills_count" == "1" ]] || fail "$host $source SessionStart should load the Skills prompt exactly once"
|
|
263
|
+
assert_not_contains "$event_output" "# Freeflow Workflow Bootstrap" "$host $source SessionStart context"
|
|
264
|
+
done
|
|
99
265
|
done
|
|
100
266
|
|
|
101
267
|
# Repo-owned host instructions are neither required for activation nor modified by the read-only hook.
|
|
@@ -124,23 +290,23 @@ mkdir -p "$local_dir/.freeflow"
|
|
|
124
290
|
printf '{"defaultMode":"workflow"}\n' >"$local_dir/.freeflow/config.json"
|
|
125
291
|
printf '{"defaultMode":"strict-workflow"}\n' >"$local_dir/.freeflow/local.json"
|
|
126
292
|
local_output="$(printf '{"cwd":"%s","model":"gpt-5"}\n' "$local_dir" | node "$HOOK_PATH" SessionStart)"
|
|
127
|
-
assert_contains "$local_output" '
|
|
128
|
-
assert_contains "$local_output" '
|
|
129
|
-
|
|
130
|
-
|
|
293
|
+
assert_contains "$local_output" 'Configured default: `strict-workflow` (personal)' "local default override"
|
|
294
|
+
assert_contains "$local_output" 'Effective mode: `strict-workflow` (configured default, active)' "local default source"
|
|
295
|
+
assert_not_contains "$local_output" "## Strict Workflow Overlay" "local strict overlay"
|
|
296
|
+
assert_not_contains "$local_output" "security, privacy, billing, data loss, migrations, public interfaces" "local strict overlay"
|
|
131
297
|
assert_contains "$local_output" "# Freeflow Interaction Contract" "local default override"
|
|
132
|
-
assert_contains "$local_output" "
|
|
298
|
+
assert_contains "$local_output" "## Shared Terms" "local default override"
|
|
133
299
|
rm -rf "$local_dir"
|
|
134
300
|
|
|
135
301
|
local_interaction_dir="$(mktemp -d)"
|
|
136
302
|
mkdir -p "$local_interaction_dir/.freeflow"
|
|
137
|
-
printf '{"defaultMode":"workflow"}\n' >
|
|
138
|
-
printf '{"interactionContract":false}\n' >
|
|
303
|
+
printf '{"defaultMode":"workflow"}\n' >"$local_interaction_dir/.freeflow/config.json"
|
|
304
|
+
printf '{"interactionContract":false}\n' >"$local_interaction_dir/.freeflow/local.json"
|
|
139
305
|
local_interaction_output="$(printf '{"cwd":"%s","model":"gpt-5"}\n' "$local_interaction_dir" | node "$HOOK_PATH" SessionStart)"
|
|
140
306
|
assert_contains "$local_interaction_output" 'Interaction Contract: disabled' "independent local interaction override"
|
|
141
307
|
assert_contains "$local_interaction_output" 'Skills: enabled' "independent local interaction override"
|
|
142
308
|
assert_not_contains "$local_interaction_output" "# Freeflow Interaction Contract" "independent local interaction override"
|
|
143
|
-
assert_contains "$local_interaction_output" "
|
|
309
|
+
assert_contains "$local_interaction_output" "## Shared Terms" "independent local interaction override"
|
|
144
310
|
rm -rf "$local_interaction_dir"
|
|
145
311
|
|
|
146
312
|
local_skills_dir="$(mktemp -d)"
|
|
@@ -148,10 +314,11 @@ mkdir -p "$local_skills_dir/.freeflow"
|
|
|
148
314
|
printf '{"defaultMode":"workflow"}\n' >"$local_skills_dir/.freeflow/config.json"
|
|
149
315
|
printf '{"defaultMode":"conversation","interactionContract":false,"skills":{"enabled":false}}\n' >"$local_skills_dir/.freeflow/local.json"
|
|
150
316
|
local_skills_output="$(printf '{"cwd":"%s","model":"gpt-5"}\n' "$local_skills_dir" | node "$HOOK_PATH" SessionStart)"
|
|
151
|
-
assert_contains "$local_skills_output" 'Resolved
|
|
317
|
+
assert_contains "$local_skills_output" 'Resolved mode: `conversation` (dormant because Skills are disabled)' "local dormant mode"
|
|
152
318
|
assert_contains "$local_skills_output" 'Interaction Contract: disabled' "local interaction override"
|
|
153
319
|
assert_contains "$local_skills_output" 'Skills: disabled' "local skills override"
|
|
154
320
|
assert_not_contains "$local_skills_output" "# Freeflow Interaction Contract" "local interaction override"
|
|
321
|
+
assert_not_contains "$local_skills_output" "# Freeflow Mode Update" "local skills override"
|
|
155
322
|
assert_not_contains "$local_skills_output" "# Freeflow Workflow Bootstrap" "local skills override"
|
|
156
323
|
rm -rf "$local_skills_dir"
|
|
157
324
|
|
|
@@ -168,56 +335,58 @@ mkdir -p "$local_disabled_dir/.freeflow"
|
|
|
168
335
|
printf '{"enabled":true,"defaultMode":"workflow"}\n' >"$local_disabled_dir/.freeflow/config.json"
|
|
169
336
|
printf '{"enabled":false,"processing":{"unsafeUnsandboxed":{"enabled":true}}}\n' >"$local_disabled_dir/.freeflow/local.json"
|
|
170
337
|
local_disabled_output="$(printf '{"cwd":"%s","model":"gpt-5"}\n' "$local_disabled_dir" | node "$HOOK_PATH" SessionStart)"
|
|
171
|
-
|
|
172
|
-
assert_contains "$local_disabled_output" "effective \`enabled\` is false from local" "local master source"
|
|
173
|
-
assert_not_contains "$local_disabled_output" "# Freeflow Interaction Contract" "local master override"
|
|
338
|
+
[[ -z "$local_disabled_output" ]] || fail "local master override should suppress hook prompt delivery"
|
|
174
339
|
rm -rf "$local_disabled_dir"
|
|
175
340
|
|
|
176
341
|
disabled_dir="$(mktemp -d)"
|
|
177
342
|
mkdir -p "$disabled_dir/.freeflow"
|
|
178
343
|
printf '{"enabled":false,"defaultMode":"workflow"}\n' >"$disabled_dir/.freeflow/config.json"
|
|
179
344
|
disabled_output="$(printf '{"cwd":"%s","model":"gpt-5"}\n' "$disabled_dir" | node "$HOOK_PATH" SessionStart)"
|
|
180
|
-
|
|
181
|
-
assert_not_contains "$disabled_output" "# Freeflow Runtime Kernel" "disabled context"
|
|
345
|
+
[[ -z "$disabled_output" ]] || fail "disabled Freeflow should suppress hook prompt delivery"
|
|
182
346
|
rm -rf "$disabled_dir"
|
|
183
347
|
|
|
184
348
|
router_dir="$(mktemp -d)"
|
|
185
349
|
mkdir -p "$router_dir/.freeflow"
|
|
186
350
|
printf '{"defaultMode":"workflow","skills":{"enabled":false},"outputRouter":{"enabled":true}}\n' >"$router_dir/.freeflow/config.json"
|
|
187
351
|
router_output="$(printf '{"cwd":"%s","model":"gpt-5"}\n' "$router_dir" | node "$HOOK_PATH" SessionStart)"
|
|
188
|
-
assert_contains "$router_output" "Skills: disabled" "router
|
|
189
|
-
assert_contains "$router_output" "
|
|
190
|
-
|
|
191
|
-
assert_not_contains "$router_output" "
|
|
352
|
+
assert_contains "$router_output" "Skills: disabled" "Codex context with legacy router config"
|
|
353
|
+
assert_contains "$router_output" "# Freeflow Interaction Contract" "Codex context with legacy router config"
|
|
354
|
+
assert_not_contains "$router_output" "# Freeflow Workflow Bootstrap" "Codex context with disabled skills"
|
|
355
|
+
assert_not_contains "$router_output" "Output Router" "Codex context with legacy router config"
|
|
356
|
+
assert_not_contains "$router_output" "Output router:" "Codex context with legacy router config"
|
|
192
357
|
rm -rf "$router_dir"
|
|
193
358
|
|
|
194
359
|
all_dir="$(mktemp -d)"
|
|
195
360
|
mkdir -p "$all_dir/.freeflow"
|
|
196
361
|
printf '{"defaultMode":"strict-workflow","outputRouter":{"enabled":true}}\n' >"$all_dir/.freeflow/config.json"
|
|
197
362
|
all_output="$(printf '{"cwd":"%s","model":"gpt-5"}\n' "$all_dir" | node "$HOOK_PATH" SessionStart)"
|
|
198
|
-
assert_contains "$all_output" "# Freeflow Interaction Contract" "
|
|
199
|
-
assert_contains "$all_output" "##
|
|
200
|
-
|
|
201
|
-
|
|
363
|
+
assert_contains "$all_output" "# Freeflow Interaction Contract" "Codex strict context"
|
|
364
|
+
assert_contains "$all_output" "## Shared Terms" "Codex strict context"
|
|
365
|
+
assert_not_contains "$all_output" "Output Router" "Codex strict context"
|
|
366
|
+
assert_not_contains "$all_output" "Output router:" "Codex strict context"
|
|
367
|
+
assert_contains "$all_output" 'Effective mode: `strict-workflow` (configured default, active)' "Codex strict context"
|
|
368
|
+
assert_not_contains "$all_output" "## Strict Workflow Overlay" "all-capabilities strict overlay"
|
|
202
369
|
rm -rf "$all_dir"
|
|
203
370
|
|
|
204
371
|
conversation_dir="$(mktemp -d)"
|
|
205
372
|
mkdir -p "$conversation_dir/.freeflow"
|
|
206
373
|
printf '{"defaultMode":"conversation"}\n' >"$conversation_dir/.freeflow/config.json"
|
|
207
374
|
conversation_output="$(printf '{"cwd":"%s","model":"gpt-5"}\n' "$conversation_dir" | node "$HOOK_PATH" SessionStart)"
|
|
208
|
-
assert_contains "$conversation_output" '
|
|
209
|
-
assert_contains "$conversation_output" '`conversation
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
375
|
+
assert_contains "$conversation_output" 'Configured default: `conversation` (repository)' "conversation context"
|
|
376
|
+
assert_contains "$conversation_output" 'Effective mode: `conversation` (configured default, active)' "conversation context"
|
|
377
|
+
assert_not_contains "$conversation_output" "## Conversation Mode Boundary" "conversation overlay"
|
|
378
|
+
assert_not_contains "$conversation_output" "Do not call write, edit, or mutating tools" "conversation overlay"
|
|
379
|
+
assert_not_contains "$conversation_output" "an execution skill does not override this boundary" "conversation overlay"
|
|
213
380
|
rm -rf "$conversation_dir"
|
|
214
381
|
|
|
215
382
|
observed_dir="$(mktemp -d)"
|
|
216
383
|
mkdir -p "$observed_dir/.freeflow"
|
|
217
384
|
printf '{"defaultMode":"workflow","outputRouter":{"enabled":true,"observedRouting":{"enabled":true}},"scriptTransform":{"enabled":false}}\n' >"$observed_dir/.freeflow/config.json"
|
|
218
385
|
observed_output="$(printf '{"cwd":"%s","model":"gpt-5"}\n' "$observed_dir" | node "$HOOK_PATH" SessionStart)"
|
|
219
|
-
assert_contains "$observed_output" "# Freeflow Interaction Contract" "observed-routing config"
|
|
220
|
-
assert_contains "$observed_output" "##
|
|
386
|
+
assert_contains "$observed_output" "# Freeflow Interaction Contract" "Codex context with observed-routing config"
|
|
387
|
+
assert_contains "$observed_output" "## Shared Terms" "Codex context with observed-routing config"
|
|
388
|
+
assert_not_contains "$observed_output" "Output Router" "Codex context with observed-routing config"
|
|
389
|
+
assert_not_contains "$observed_output" "Output router:" "Codex context with observed-routing config"
|
|
221
390
|
rm -rf "$observed_dir"
|
|
222
391
|
|
|
223
392
|
echo "runtime-context hook checks passed"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hassangameryt/freeflow",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Feedback-based control system for coding agents.",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -18,24 +18,33 @@
|
|
|
18
18
|
"scripts": {
|
|
19
19
|
"format": "prettier --write .",
|
|
20
20
|
"format:check": "prettier --check .",
|
|
21
|
-
"format:router-dist": "prettier --write router/dist",
|
|
22
21
|
"format:pi-extension-dist": "prettier --write pi-extension/dist",
|
|
23
|
-
"build:router": "tsc -p router/tsconfig.json && npm run format:router-dist",
|
|
24
22
|
"build:pi-extension": "tsc -p pi-extension/tsconfig.json && npm run format:pi-extension-dist",
|
|
25
|
-
"build": "npm run build:
|
|
23
|
+
"build": "npm run build:pi-extension",
|
|
24
|
+
"typecheck": "tsc -p pi-extension/tsconfig.json --noEmit",
|
|
25
|
+
"check": "npm run typecheck && npm run check:source && npm run check:changelog && npm run check:release-workflow && npm run check:docs && npm run format:check && npm run check:release-version && npm run check:commands && npm run check:activation && npm run check:runtime && npm run check:package",
|
|
26
|
+
"check:source": "node scripts/validation/check-source-files.mjs",
|
|
27
|
+
"check:changelog": "node scripts/validation/check-changelog.mjs --structure",
|
|
28
|
+
"check:release-workflow": "node scripts/validation/check-release-workflow.mjs",
|
|
29
|
+
"check:docs": "node scripts/validation/check-docs.mjs",
|
|
30
|
+
"check:release-version": "node scripts/validation/check-release-version.mjs",
|
|
31
|
+
"check:commands": "scripts/validation/audit-command-surface.sh",
|
|
32
|
+
"check:activation": "scripts/validation/check-activation-contract.sh",
|
|
33
|
+
"check:runtime": "hooks/tests/check-runtime-context-hook.sh",
|
|
34
|
+
"check:package": "node scripts/validation/check-package.mjs",
|
|
35
|
+
"check:release-metadata": "scripts/validation/validate-release-metadata.sh --mode prepublish",
|
|
26
36
|
"test:pi-extension": "npm run build && node --test $(find pi-extension/tests -name '*.test.js' | sort)",
|
|
27
|
-
"test:router": "npm run build:router && node --test $(find router/tests -name '*.test.js' | sort)",
|
|
28
37
|
"test:skill-author": "node --test $(find .skill-eval/write-skill/tests -name '*.test.mjs' | sort)",
|
|
29
38
|
"test:skill-eval": "node --test $(find .skill-eval/evaluate-skill/tests -name '*.test.mjs' | sort)",
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
+
"test:track-work": "node --test .skill-eval/track-work/tests/*.test.mjs",
|
|
40
|
+
"test:freeflow-snapshot": "node --test scripts/freeflow-snapshot.test.mjs",
|
|
41
|
+
"test:release-utils": "node --test scripts/release-utils.test.mjs",
|
|
42
|
+
"test:changelog": "node --test scripts/validation/check-changelog.test.mjs",
|
|
43
|
+
"test:release-workflow": "node --test scripts/validation/check-release-workflow.test.mjs",
|
|
44
|
+
"test:docs": "node --test scripts/validation/check-docs.test.mjs",
|
|
45
|
+
"release:prepare": "node scripts/release.mjs",
|
|
46
|
+
"release:notes": "node scripts/release-notes.mjs",
|
|
47
|
+
"snapshot:refresh": "node scripts/freeflow-snapshot.mjs"
|
|
39
48
|
},
|
|
40
49
|
"keywords": [
|
|
41
50
|
"pi-package",
|
|
@@ -66,11 +75,11 @@
|
|
|
66
75
|
"LICENSE",
|
|
67
76
|
"README.md",
|
|
68
77
|
"assets/**",
|
|
78
|
+
"capabilities/**",
|
|
79
|
+
"runtime/**",
|
|
69
80
|
"command-surface.json",
|
|
70
81
|
"hooks/**",
|
|
71
82
|
"pi-extension/**",
|
|
72
|
-
"router/dist/**",
|
|
73
|
-
"runtime/**",
|
|
74
83
|
"skills/**"
|
|
75
84
|
],
|
|
76
85
|
"peerDependencies": {
|