@givolt/i3-composer-agent 0.0.0-stage → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/plugins/marketplace.json +23 -0
- package/.claude/commands/build.md +44 -0
- package/.claude/commands/code-simplify.md +22 -0
- package/.claude/commands/constraints.md +32 -0
- package/.claude/commands/plan.md +18 -0
- package/.claude/commands/review.md +16 -0
- package/.claude/commands/ship.md +72 -0
- package/.claude/commands/spec.md +17 -0
- package/.claude/commands/test.md +19 -0
- package/.claude/commands/webperf.md +32 -0
- package/.claude-plugin/marketplace.json +27 -0
- package/.claude-plugin/plugin.json +19 -0
- package/.codex-plugin/plugin.json +28 -0
- package/.gemini/commands/build.toml +43 -0
- package/.gemini/commands/code-simplify.toml +22 -0
- package/.gemini/commands/constraints.toml +32 -0
- package/.gemini/commands/planning.toml +18 -0
- package/.gemini/commands/review.toml +16 -0
- package/.gemini/commands/ship.toml +72 -0
- package/.gemini/commands/spec.toml +17 -0
- package/.gemini/commands/test.toml +19 -0
- package/.gemini/commands/webperf.toml +32 -0
- package/CHANGELOG.md +23 -0
- package/LICENSE +21 -0
- package/NOTICE.md +9 -0
- package/README.md +117 -2
- package/agents/code-reviewer.md +102 -0
- package/agents/security-auditor.md +112 -0
- package/agents/test-engineer.md +95 -0
- package/agents/web-performance-auditor.md +184 -0
- package/bin/i3-composer-agent.cjs +122 -0
- package/commands/build.toml +43 -0
- package/commands/code-simplify.toml +22 -0
- package/commands/constraints.toml +32 -0
- package/commands/planning.toml +18 -0
- package/commands/review.toml +16 -0
- package/commands/ship.toml +72 -0
- package/commands/spec.toml +17 -0
- package/commands/test.toml +19 -0
- package/commands/webperf.toml +32 -0
- package/docs/adoption-guide.md +129 -0
- package/docs/advanced-per-agent-configuration.md +70 -0
- package/docs/agents.md +123 -0
- package/docs/antigravity-setup.md +128 -0
- package/docs/codebuddy-setup.md +41 -0
- package/docs/codex-setup.md +34 -0
- package/docs/commandcode-setup.md +69 -0
- package/docs/comparison.md +131 -0
- package/docs/copilot-cli-setup.md +64 -0
- package/docs/copilot-setup.md +162 -0
- package/docs/cursor-setup.md +225 -0
- package/docs/developer-onboarding.md +116 -0
- package/docs/gemini-cli-setup.md +133 -0
- package/docs/getting-started.md +208 -0
- package/docs/opencode-setup.md +259 -0
- package/docs/other-hosts.md +7 -0
- package/docs/skill-anatomy.md +203 -0
- package/docs/windsurf-setup.md +48 -0
- package/evals/README.md +101 -0
- package/evals/cases/api-and-interface-design.json +45 -0
- package/evals/cases/browser-testing-with-devtools.json +44 -0
- package/evals/cases/ci-cd-and-automation.json +45 -0
- package/evals/cases/code-review-and-quality.json +49 -0
- package/evals/cases/code-simplification.json +45 -0
- package/evals/cases/constraint-driven-development.json +79 -0
- package/evals/cases/context-engineering.json +44 -0
- package/evals/cases/debugging-and-error-recovery.json +58 -0
- package/evals/cases/deprecation-and-migration.json +52 -0
- package/evals/cases/documentation-and-adrs.json +44 -0
- package/evals/cases/doubt-driven-development.json +43 -0
- package/evals/cases/frontend-ui-engineering.json +52 -0
- package/evals/cases/git-workflow-and-versioning.json +47 -0
- package/evals/cases/idea-refine.json +43 -0
- package/evals/cases/incremental-implementation.json +57 -0
- package/evals/cases/interview-me.json +42 -0
- package/evals/cases/observability-and-instrumentation.json +44 -0
- package/evals/cases/performance-optimization.json +53 -0
- package/evals/cases/planning-and-task-breakdown.json +45 -0
- package/evals/cases/security-and-hardening.json +53 -0
- package/evals/cases/shipping-and-launch.json +56 -0
- package/evals/cases/source-driven-development.json +44 -0
- package/evals/cases/spec-driven-development.json +72 -0
- package/evals/cases/test-driven-development.json +73 -0
- package/evals/cases/using-agent-skills.json +44 -0
- package/evals/fixtures/api-and-interface-design/service-brief.md +19 -0
- package/evals/fixtures/browser-testing-with-devtools/README.md +5 -0
- package/evals/fixtures/browser-testing-with-devtools/index.html +24 -0
- package/evals/fixtures/browser-testing-with-devtools/server.js +15 -0
- package/evals/fixtures/ci-cd-and-automation/package.json +8 -0
- package/evals/fixtures/ci-cd-and-automation/src/slug.js +3 -0
- package/evals/fixtures/ci-cd-and-automation/test/slug.test.js +9 -0
- package/evals/fixtures/code-review-and-quality/user-search.diff +16 -0
- package/evals/fixtures/code-simplification/config-parser.js +46 -0
- package/evals/fixtures/code-simplification/config-parser.test.js +15 -0
- package/evals/fixtures/context-engineering/context-audit.md +15 -0
- package/evals/fixtures/debugging-and-error-recovery/pagination.js +8 -0
- package/evals/fixtures/debugging-and-error-recovery/pagination.test.js +9 -0
- package/evals/fixtures/debugging-and-error-recovery/time-pressure.md +6 -0
- package/evals/fixtures/deprecation-and-migration/api-inventory.md +9 -0
- package/evals/fixtures/documentation-and-adrs/decision-context.md +16 -0
- package/evals/fixtures/doubt-driven-development/migration-plan.md +19 -0
- package/evals/fixtures/frontend-ui-engineering/Button.tsx +7 -0
- package/evals/fixtures/frontend-ui-engineering/design-system.md +11 -0
- package/evals/fixtures/git-workflow-and-versioning/.eval/working-tree.patch +21 -0
- package/evals/fixtures/git-workflow-and-versioning/app.js +7 -0
- package/evals/fixtures/git-workflow-and-versioning/app.test.js +9 -0
- package/evals/fixtures/incremental-implementation/reports.js +7 -0
- package/evals/fixtures/incremental-implementation/reports.test.js +12 -0
- package/evals/fixtures/incremental-implementation/tasks/plan.md +8 -0
- package/evals/fixtures/incremental-implementation-pressure/draft-export.js +17 -0
- package/evals/fixtures/incremental-implementation-pressure/scenario.md +9 -0
- package/evals/fixtures/observability-and-instrumentation/operations.md +11 -0
- package/evals/fixtures/observability-and-instrumentation/payment-retry.js +14 -0
- package/evals/fixtures/performance-optimization/benchmark.js +15 -0
- package/evals/fixtures/performance-optimization/products.js +14 -0
- package/evals/fixtures/planning-and-task-breakdown/notifications-spec.md +18 -0
- package/evals/fixtures/security-and-hardening/webhook.js +11 -0
- package/evals/fixtures/security-and-hardening/webhook.test.js +13 -0
- package/evals/fixtures/shipping-and-launch/authority-pressure.md +6 -0
- package/evals/fixtures/shipping-and-launch/launch-status.md +11 -0
- package/evals/fixtures/source-driven-development/framework-task.md +10 -0
- package/evals/fixtures/spec-driven-development/billing-brief.md +16 -0
- package/evals/fixtures/spec-driven-development-decomposition/portal-brief.md +22 -0
- package/evals/fixtures/test-driven-development/BUG.md +10 -0
- package/evals/fixtures/test-driven-development/README.md +28 -0
- package/evals/fixtures/test-driven-development/package.json +9 -0
- package/evals/fixtures/test-driven-development/src/split.js +8 -0
- package/evals/fixtures/test-driven-development/test/split.test.js +13 -0
- package/evals/fixtures/test-driven-development-ecosystem/README.md +9 -0
- package/evals/fixtures/test-driven-development-ecosystem/ledger.py +15 -0
- package/evals/fixtures/test-driven-development-ecosystem/test_ledger.py +19 -0
- package/evals/fixtures/using-agent-skills/incident.md +6 -0
- package/evals/plugin/code-review-fires/graders/off-by-one.md +7 -0
- package/evals/plugin/code-review-fires/graders/severity-labels.md +4 -0
- package/evals/plugin/code-review-fires/graders/skill-fired.md +5 -0
- package/evals/plugin/code-review-fires/prompt.md +31 -0
- package/evals/plugin/code-review-stays-quiet/graders/not-fired.md +8 -0
- package/evals/plugin/code-review-stays-quiet/graders/tdd-fired.md +6 -0
- package/evals/plugin/code-review-stays-quiet/prompt.md +8 -0
- package/evals/plugin/code-review-stays-quiet-on-commit-message/graders/not-fired.md +8 -0
- package/evals/plugin/code-review-stays-quiet-on-commit-message/prompt.md +25 -0
- package/evals/skill-impact.md +6 -0
- package/hooks/SDD-CACHE.md +167 -0
- package/hooks/SIMPLIFY-IGNORE.md +91 -0
- package/hooks/sdd-cache-post.sh +135 -0
- package/hooks/sdd-cache-pre.sh +106 -0
- package/hooks/sdd-cache-test.sh +246 -0
- package/hooks/session-start-test.sh +47 -0
- package/hooks/session-start.sh +33 -0
- package/hooks/simplify-ignore-test.sh +476 -0
- package/hooks/simplify-ignore.sh +352 -0
- package/package.json +89 -4
- package/plugin.json +7 -0
- package/rebrand/MAINTENANCE.md +112 -0
- package/rebrand/NOTICE.md +9 -0
- package/rebrand/PR-WORKFLOW.md +34 -0
- package/rebrand/UNIFICATION-SPEC.md +33 -0
- package/rebrand/VALIDATION.md +28 -0
- package/rebrand/VERSIONING.md +32 -0
- package/rebrand/apply.cjs +194 -0
- package/rebrand/brand.json +13 -0
- package/rebrand/catalog.cjs +56 -0
- package/rebrand/fork-patches.json +12 -0
- package/rebrand/overlay/.github/workflows/test-plugin-install.yml +177 -0
- package/rebrand/overlay/CHANGELOG.md +23 -0
- package/rebrand/overlay/bin/i3-composer-agent.cjs +122 -0
- package/rebrand/overlay/scripts/validate-brand.cjs +44 -0
- package/rebrand/overlay/tests/bundle.test.cjs +85 -0
- package/rebrand/package.template.json +82 -0
- package/rebrand/rebrand.sh +4 -0
- package/rebrand/record-upstream.cjs +37 -0
- package/rebrand/templates/README.md +86 -0
- package/rebrand/templates/codebuddy-setup.md +41 -0
- package/rebrand/templates/codex-setup.md +34 -0
- package/rebrand/tests/pipeline.test.cjs +185 -0
- package/rebrand/upstream.json +171 -0
- package/references/accessibility-checklist.md +160 -0
- package/references/definition-of-done.md +67 -0
- package/references/observability-checklist.md +92 -0
- package/references/orchestration-patterns.md +370 -0
- package/references/performance-checklist.md +236 -0
- package/references/security-checklist.md +248 -0
- package/references/testing-patterns.md +235 -0
- package/scripts/floor-guard-reference-test.js +291 -0
- package/scripts/lib/skill-lint-test.js +650 -0
- package/scripts/lib/skill-lint.js +584 -0
- package/scripts/run-evals-test.js +623 -0
- package/scripts/run-evals.js +638 -0
- package/scripts/validate-artifact-paths-test.js +179 -0
- package/scripts/validate-artifact-paths.js +128 -0
- package/scripts/validate-brand.cjs +44 -0
- package/scripts/validate-commands-test.js +216 -0
- package/scripts/validate-commands.js +222 -0
- package/scripts/validate-reference-links-test.js +495 -0
- package/scripts/validate-reference-links.js +187 -0
- package/scripts/validate-skills.js +69 -0
- package/scripts/validate-versions-test.js +32 -0
- package/scripts/validate-versions.js +35 -0
- package/skills/api-and-interface-design/SKILL.md +367 -0
- package/skills/browser-testing-with-devtools/SKILL.md +317 -0
- package/skills/ci-cd-and-automation/SKILL.md +390 -0
- package/skills/code-review-and-quality/SKILL.md +398 -0
- package/skills/code-simplification/SKILL.md +331 -0
- package/skills/constraint-driven-development/SKILL.md +311 -0
- package/skills/constraint-driven-development/references/floor-guard.md +182 -0
- package/skills/context-engineering/SKILL.md +353 -0
- package/skills/debugging-and-error-recovery/SKILL.md +300 -0
- package/skills/deprecation-and-migration/SKILL.md +247 -0
- package/skills/documentation-and-adrs/SKILL.md +288 -0
- package/skills/doubt-driven-development/SKILL.md +243 -0
- package/skills/frontend-ui-engineering/SKILL.md +340 -0
- package/skills/git-workflow-and-versioning/SKILL.md +355 -0
- package/skills/idea-refine/SKILL.md +178 -0
- package/skills/idea-refine/examples.md +238 -0
- package/skills/idea-refine/frameworks.md +99 -0
- package/skills/idea-refine/refinement-criteria.md +113 -0
- package/skills/idea-refine/scripts/idea-refine.sh +15 -0
- package/skills/incremental-implementation/SKILL.md +249 -0
- package/skills/interview-me/SKILL.md +235 -0
- package/skills/observability-and-instrumentation/SKILL.md +238 -0
- package/skills/performance-optimization/SKILL.md +267 -0
- package/skills/performance-optimization/references/optimization-patterns.md +250 -0
- package/skills/planning-and-task-breakdown/SKILL.md +257 -0
- package/skills/security-and-hardening/SKILL.md +216 -0
- package/skills/security-and-hardening/references/hardening-patterns.md +324 -0
- package/skills/shipping-and-launch/SKILL.md +330 -0
- package/skills/source-driven-development/SKILL.md +216 -0
- package/skills/spec-driven-development/SKILL.md +259 -0
- package/skills/test-driven-development/SKILL.md +398 -0
- package/skills/using-agent-skills/SKILL.md +192 -0
- package/tests/bundle.test.cjs +85 -0
|
@@ -0,0 +1,476 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# simplify-ignore-test.sh — Tests for the simplify-ignore hook
|
|
3
|
+
#
|
|
4
|
+
# Exercises filter_file by extracting function definitions from the hook.
|
|
5
|
+
# Run: bash hooks/simplify-ignore-test.sh
|
|
6
|
+
|
|
7
|
+
set -euo pipefail
|
|
8
|
+
|
|
9
|
+
PASS=0 FAIL=0
|
|
10
|
+
TMPDIR=$(mktemp -d)
|
|
11
|
+
trap 'rm -rf "$TMPDIR"' EXIT
|
|
12
|
+
|
|
13
|
+
export CACHE="$TMPDIR/cache"
|
|
14
|
+
mkdir -p "$CACHE"
|
|
15
|
+
|
|
16
|
+
# Extract function definitions we need
|
|
17
|
+
hash_cmd() {
|
|
18
|
+
if command -v shasum >/dev/null 2>&1; then shasum
|
|
19
|
+
elif command -v sha1sum >/dev/null 2>&1; then sha1sum
|
|
20
|
+
else printf '%s\n' "error: missing shasum or sha1sum" >&2; exit 1; fi
|
|
21
|
+
}
|
|
22
|
+
file_id() { printf '%s' "$1" | hash_cmd | cut -c1-16; }
|
|
23
|
+
block_hash() { printf '%s' "$1" | hash_cmd | cut -c1-8; }
|
|
24
|
+
escape_glob() {
|
|
25
|
+
local s="$1"
|
|
26
|
+
s="${s//\\/\\\\}"
|
|
27
|
+
s="${s//\*/\\*}"
|
|
28
|
+
s="${s//\?/\\?}"
|
|
29
|
+
s="${s//\[/\\[}"
|
|
30
|
+
printf '%s' "$s"
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
# Extract filter_file from the hook script (line 59 "filter_file()" to line 142 closing brace)
|
|
34
|
+
eval "$(sed -n '/^filter_file()/,/^}/p' hooks/simplify-ignore.sh)"
|
|
35
|
+
|
|
36
|
+
assert_eq() {
|
|
37
|
+
local label="$1" expected="$2" actual="$3"
|
|
38
|
+
if [ "$expected" = "$actual" ]; then
|
|
39
|
+
PASS=$((PASS + 1))
|
|
40
|
+
printf ' PASS: %s\n' "$label"
|
|
41
|
+
else
|
|
42
|
+
FAIL=$((FAIL + 1))
|
|
43
|
+
printf ' FAIL: %s\n' "$label" >&2
|
|
44
|
+
printf ' expected: %s\n' "$(printf '%s' "$expected" | cat -v)" >&2
|
|
45
|
+
printf ' actual: %s\n' "$(printf '%s' "$actual" | cat -v)" >&2
|
|
46
|
+
fi
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
# ── Test 1: Single-line block produces exactly one placeholder ────────────
|
|
50
|
+
printf 'Test 1: Single-line block (start+end on same line)\n'
|
|
51
|
+
rm -f "$CACHE"/*
|
|
52
|
+
|
|
53
|
+
SRC="$TMPDIR/single-line.js"
|
|
54
|
+
DEST="$TMPDIR/single-line-filtered.js"
|
|
55
|
+
cat > "$SRC" <<'EOF'
|
|
56
|
+
const a = 1;
|
|
57
|
+
/* simplify-ignore-start */ const secret = 42; /* simplify-ignore-end */
|
|
58
|
+
const b = 2;
|
|
59
|
+
EOF
|
|
60
|
+
|
|
61
|
+
FID="test_single"
|
|
62
|
+
filter_file "$SRC" "$DEST" "$FID"
|
|
63
|
+
|
|
64
|
+
placeholder_count=$(grep -c 'BLOCK_' "$DEST")
|
|
65
|
+
assert_eq "exactly one placeholder line" "1" "$placeholder_count"
|
|
66
|
+
assert_eq "line before block preserved" "1" "$(grep -c 'const a = 1' "$DEST")"
|
|
67
|
+
assert_eq "line after block preserved" "1" "$(grep -c 'const b = 2' "$DEST")"
|
|
68
|
+
|
|
69
|
+
block_files=$(ls "$CACHE/${FID}".block.* 2>/dev/null | wc -l | tr -d ' ')
|
|
70
|
+
assert_eq "one block file in cache" "1" "$block_files"
|
|
71
|
+
|
|
72
|
+
block_content=$(cat "$CACHE/${FID}".block.*)
|
|
73
|
+
assert_eq "block content matches" \
|
|
74
|
+
"/* simplify-ignore-start */ const secret = 42; /* simplify-ignore-end */" \
|
|
75
|
+
"$block_content"
|
|
76
|
+
|
|
77
|
+
# ── Test 2: Multi-line block ─────────────────────────────────────────────
|
|
78
|
+
printf '\nTest 2: Multi-line block\n'
|
|
79
|
+
rm -f "$CACHE"/*
|
|
80
|
+
|
|
81
|
+
SRC="$TMPDIR/multi-line.js"
|
|
82
|
+
DEST="$TMPDIR/multi-line-filtered.js"
|
|
83
|
+
cat > "$SRC" <<'EOF'
|
|
84
|
+
const a = 1;
|
|
85
|
+
// simplify-ignore-start
|
|
86
|
+
const secret1 = 42;
|
|
87
|
+
const secret2 = 99;
|
|
88
|
+
// simplify-ignore-end
|
|
89
|
+
const b = 2;
|
|
90
|
+
EOF
|
|
91
|
+
|
|
92
|
+
FID="test_multi"
|
|
93
|
+
filter_file "$SRC" "$DEST" "$FID"
|
|
94
|
+
|
|
95
|
+
placeholder_count=$(grep -c 'BLOCK_' "$DEST")
|
|
96
|
+
assert_eq "exactly one placeholder for multi-line block" "1" "$placeholder_count"
|
|
97
|
+
|
|
98
|
+
output_lines=$(wc -l < "$DEST" | tr -d ' ')
|
|
99
|
+
assert_eq "output has 3 lines (before + placeholder + after)" "3" "$output_lines"
|
|
100
|
+
|
|
101
|
+
# ── Test 3: Multiple blocks in one file ──────────────────────────────────
|
|
102
|
+
printf '\nTest 3: Multiple blocks in one file\n'
|
|
103
|
+
rm -f "$CACHE"/*
|
|
104
|
+
|
|
105
|
+
SRC="$TMPDIR/multi-block.js"
|
|
106
|
+
DEST="$TMPDIR/multi-block-filtered.js"
|
|
107
|
+
cat > "$SRC" <<'EOF'
|
|
108
|
+
line1
|
|
109
|
+
// simplify-ignore-start
|
|
110
|
+
blockA
|
|
111
|
+
// simplify-ignore-end
|
|
112
|
+
line2
|
|
113
|
+
// simplify-ignore-start
|
|
114
|
+
blockB
|
|
115
|
+
// simplify-ignore-end
|
|
116
|
+
line3
|
|
117
|
+
EOF
|
|
118
|
+
|
|
119
|
+
FID="test_multiblock"
|
|
120
|
+
filter_file "$SRC" "$DEST" "$FID"
|
|
121
|
+
|
|
122
|
+
placeholder_count=$(grep -c 'BLOCK_' "$DEST")
|
|
123
|
+
assert_eq "two placeholders for two blocks" "2" "$placeholder_count"
|
|
124
|
+
|
|
125
|
+
block_files=$(ls "$CACHE/${FID}".block.* 2>/dev/null | wc -l | tr -d ' ')
|
|
126
|
+
assert_eq "two block files in cache" "2" "$block_files"
|
|
127
|
+
|
|
128
|
+
# ── Test 4: Reason string preserved ──────────────────────────────────────
|
|
129
|
+
printf '\nTest 4: Reason string in placeholder\n'
|
|
130
|
+
rm -f "$CACHE"/*
|
|
131
|
+
|
|
132
|
+
SRC="$TMPDIR/reason.js"
|
|
133
|
+
DEST="$TMPDIR/reason-filtered.js"
|
|
134
|
+
cat > "$SRC" <<'EOF'
|
|
135
|
+
// simplify-ignore-start: perf-critical
|
|
136
|
+
hot_loop();
|
|
137
|
+
// simplify-ignore-end
|
|
138
|
+
EOF
|
|
139
|
+
|
|
140
|
+
FID="test_reason"
|
|
141
|
+
filter_file "$SRC" "$DEST" "$FID"
|
|
142
|
+
|
|
143
|
+
assert_eq "placeholder includes reason" "1" "$(grep -c 'perf-critical' "$DEST")"
|
|
144
|
+
|
|
145
|
+
reason_files=$(ls "$CACHE/${FID}".reason.* 2>/dev/null | wc -l | tr -d ' ')
|
|
146
|
+
assert_eq "reason file saved" "1" "$reason_files"
|
|
147
|
+
assert_eq "reason content" "perf-critical" "$(cat "$CACHE/${FID}".reason.*)"
|
|
148
|
+
|
|
149
|
+
# ── Test 5: Trailing newline preservation ────────────────────────────────
|
|
150
|
+
printf '\nTest 5: Trailing newline preservation\n'
|
|
151
|
+
rm -f "$CACHE"/*
|
|
152
|
+
|
|
153
|
+
SRC="$TMPDIR/no-trailing-nl.js"
|
|
154
|
+
DEST="$TMPDIR/no-trailing-nl-filtered.js"
|
|
155
|
+
printf 'line1\n// simplify-ignore-start\nsecret\n// simplify-ignore-end' > "$SRC"
|
|
156
|
+
|
|
157
|
+
FID="test_trail"
|
|
158
|
+
filter_file "$SRC" "$DEST" "$FID"
|
|
159
|
+
|
|
160
|
+
# Source has no trailing newline; dest should also have no trailing newline
|
|
161
|
+
src_has_nl=$(tail -c 1 "$SRC" | wc -l | tr -d ' ')
|
|
162
|
+
dest_has_nl=$(tail -c 1 "$DEST" | wc -l | tr -d ' ')
|
|
163
|
+
assert_eq "dest preserves no-trailing-newline from source" "$src_has_nl" "$dest_has_nl"
|
|
164
|
+
|
|
165
|
+
# ── Test 6: No blocks → return 1 ────────────────────────────────────────
|
|
166
|
+
printf '\nTest 6: No blocks returns 1\n'
|
|
167
|
+
rm -f "$CACHE"/*
|
|
168
|
+
|
|
169
|
+
SRC="$TMPDIR/no-blocks.js"
|
|
170
|
+
DEST="$TMPDIR/no-blocks-filtered.js"
|
|
171
|
+
cat > "$SRC" <<'EOF'
|
|
172
|
+
const a = 1;
|
|
173
|
+
const b = 2;
|
|
174
|
+
EOF
|
|
175
|
+
|
|
176
|
+
FID="test_noblocks"
|
|
177
|
+
rc=0
|
|
178
|
+
filter_file "$SRC" "$DEST" "$FID" || rc=$?
|
|
179
|
+
assert_eq "returns 1 when no blocks found" "1" "$rc"
|
|
180
|
+
|
|
181
|
+
# ── Test 7: Unclosed block emits warning and flushes ─────────────────────
|
|
182
|
+
printf '\nTest 7: Unclosed block\n'
|
|
183
|
+
rm -f "$CACHE"/*
|
|
184
|
+
|
|
185
|
+
SRC="$TMPDIR/unclosed.js"
|
|
186
|
+
DEST="$TMPDIR/unclosed-filtered.js"
|
|
187
|
+
cat > "$SRC" <<'EOF'
|
|
188
|
+
line1
|
|
189
|
+
// simplify-ignore-start
|
|
190
|
+
orphan code
|
|
191
|
+
EOF
|
|
192
|
+
|
|
193
|
+
FID="test_unclosed"
|
|
194
|
+
stderr_out=$(filter_file "$SRC" "$DEST" "$FID" 2>&1) || true
|
|
195
|
+
assert_eq "warning emitted for unclosed block" "1" "$(printf '%s' "$stderr_out" | grep -c 'unclosed')"
|
|
196
|
+
assert_eq "orphan code flushed to output" "1" "$(grep -c 'orphan code' "$DEST")"
|
|
197
|
+
|
|
198
|
+
# ── Test 8: Single-line block with reason ────────────────────────────────
|
|
199
|
+
printf '\nTest 8: Single-line block with reason\n'
|
|
200
|
+
rm -f "$CACHE"/*
|
|
201
|
+
|
|
202
|
+
SRC="$TMPDIR/single-reason.js"
|
|
203
|
+
DEST="$TMPDIR/single-reason-filtered.js"
|
|
204
|
+
cat > "$SRC" <<'EOF'
|
|
205
|
+
before
|
|
206
|
+
/* simplify-ignore-start: hot-path */ x = compute(); /* simplify-ignore-end */
|
|
207
|
+
after
|
|
208
|
+
EOF
|
|
209
|
+
|
|
210
|
+
FID="test_single_reason"
|
|
211
|
+
filter_file "$SRC" "$DEST" "$FID"
|
|
212
|
+
|
|
213
|
+
placeholder_count=$(grep -c 'BLOCK_' "$DEST")
|
|
214
|
+
assert_eq "exactly one placeholder for single-line+reason" "1" "$placeholder_count"
|
|
215
|
+
assert_eq "reason in placeholder" "1" "$(grep -c 'hot-path' "$DEST")"
|
|
216
|
+
|
|
217
|
+
# ── Test 9: HTML comment syntax ──────────────────────────────────────────
|
|
218
|
+
printf '\nTest 9: HTML comment syntax\n'
|
|
219
|
+
rm -f "$CACHE"/*
|
|
220
|
+
|
|
221
|
+
SRC="$TMPDIR/html.html"
|
|
222
|
+
DEST="$TMPDIR/html-filtered.html"
|
|
223
|
+
cat > "$SRC" <<'EOF'
|
|
224
|
+
<div>
|
|
225
|
+
<!-- simplify-ignore-start -->
|
|
226
|
+
<secret-component />
|
|
227
|
+
<!-- simplify-ignore-end -->
|
|
228
|
+
</div>
|
|
229
|
+
EOF
|
|
230
|
+
|
|
231
|
+
FID="test_html"
|
|
232
|
+
filter_file "$SRC" "$DEST" "$FID"
|
|
233
|
+
|
|
234
|
+
placeholder_count=$(grep -c 'BLOCK_' "$DEST")
|
|
235
|
+
assert_eq "HTML block replaced" "1" "$placeholder_count"
|
|
236
|
+
assert_eq "HTML suffix preserved" "1" "$(grep -c '\-\->' "$DEST")"
|
|
237
|
+
|
|
238
|
+
# ── Test 10: JSON parsing error warning ──────────────────────────────────
|
|
239
|
+
printf '\nTest 10: Malformed JSON input produces warning\n'
|
|
240
|
+
|
|
241
|
+
# Without jq the hook's guard exits before parsing input. Assert whichever
|
|
242
|
+
# branch this machine can exercise (same pattern as session-start-test.sh).
|
|
243
|
+
warning_out=$(echo 'NOT_JSON{{{' | bash hooks/simplify-ignore.sh 2>&1) || true
|
|
244
|
+
if command -v jq >/dev/null 2>&1; then
|
|
245
|
+
assert_eq "warning on bad JSON" "1" "$(printf '%s' "$warning_out" | grep -c 'Warning.*failed to parse')"
|
|
246
|
+
else
|
|
247
|
+
assert_eq "missing-jq guard surfaced" "1" "$(printf '%s' "$warning_out" | grep -c 'error: missing jq')"
|
|
248
|
+
fi
|
|
249
|
+
|
|
250
|
+
# ── Test 11: Stop keeps a change made outside Edit|Write ─────────────────
|
|
251
|
+
printf '\nTest 11: Stop keeps a Bash write made after the last Edit\n'
|
|
252
|
+
|
|
253
|
+
if ! command -v jq >/dev/null 2>&1; then
|
|
254
|
+
printf ' SKIP: full lifecycle needs jq (the hook exits at its jq guard)\n'
|
|
255
|
+
else
|
|
256
|
+
PROJ="$TMPDIR/proj"
|
|
257
|
+
rm -rf "$PROJ"
|
|
258
|
+
mkdir -p "$PROJ/.claude"
|
|
259
|
+
TARGET="$PROJ/app.js"
|
|
260
|
+
cat > "$TARGET" <<'EOF'
|
|
261
|
+
const editable = 1;
|
|
262
|
+
/* simplify-ignore-start: perf-critical */
|
|
263
|
+
const protectedValue = 42;
|
|
264
|
+
/* simplify-ignore-end */
|
|
265
|
+
EOF
|
|
266
|
+
|
|
267
|
+
hook_event() { printf '%s' "$1" | CLAUDE_PROJECT_DIR="$PROJ" bash hooks/simplify-ignore.sh; }
|
|
268
|
+
read_event=$(printf '{"tool_name":"Read","tool_input":{"file_path":"%s"}}' "$TARGET")
|
|
269
|
+
edit_event=$(printf '{"tool_name":"Edit","tool_input":{"file_path":"%s"}}' "$TARGET")
|
|
270
|
+
|
|
271
|
+
# PreToolUse Read → block hidden behind a placeholder, backup taken
|
|
272
|
+
hook_event "$read_event"
|
|
273
|
+
assert_eq "protected block hidden after Read" "1" "$(grep -c 'BLOCK_' "$TARGET")"
|
|
274
|
+
assert_eq "protected content off disk after Read" "0" "$(grep -c 'protectedValue' "$TARGET")"
|
|
275
|
+
|
|
276
|
+
# Model edits the filtered file → PostToolUse Edit refreshes the backup
|
|
277
|
+
printf 'const added = 3;\n' >> "$TARGET"
|
|
278
|
+
hook_event "$edit_event"
|
|
279
|
+
|
|
280
|
+
# A later write through Bash — no Edit or Write event follows it
|
|
281
|
+
sed 's/const editable = 1;/const editable = 2;/' "$TARGET" > "$TMPDIR/bash-write.js"
|
|
282
|
+
cat "$TMPDIR/bash-write.js" > "$TARGET"
|
|
283
|
+
|
|
284
|
+
# Stop
|
|
285
|
+
hook_event '{}'
|
|
286
|
+
|
|
287
|
+
assert_eq "Bash write survives Stop" "1" "$(grep -c 'const editable = 2;' "$TARGET")"
|
|
288
|
+
assert_eq "stale backup value not restored" "0" "$(grep -c 'const editable = 1;' "$TARGET")"
|
|
289
|
+
assert_eq "edit made through Edit survives Stop" "1" "$(grep -c 'const added = 3;' "$TARGET")"
|
|
290
|
+
assert_eq "protected block back on disk" "1" "$(grep -c 'const protectedValue = 42;' "$TARGET")"
|
|
291
|
+
assert_eq "no placeholder left after Stop" "0" "$(grep -c 'BLOCK_' "$TARGET")"
|
|
292
|
+
fi
|
|
293
|
+
|
|
294
|
+
# ── Test 12: Stop fallback keeps the rewrite in the cache ───────────────
|
|
295
|
+
printf '\nTest 12: Wholesale rewrite is kept in the cache before the backup restore\n'
|
|
296
|
+
|
|
297
|
+
if ! command -v jq >/dev/null 2>&1; then
|
|
298
|
+
printf ' SKIP: full lifecycle needs jq (the hook exits at its jq guard)\n'
|
|
299
|
+
else
|
|
300
|
+
PROJ="$TMPDIR/proj-rewrite"
|
|
301
|
+
rm -rf "$PROJ"
|
|
302
|
+
mkdir -p "$PROJ/.claude"
|
|
303
|
+
TARGET="$PROJ/app.js"
|
|
304
|
+
cat > "$TARGET" <<'EOF'
|
|
305
|
+
const editable = 1;
|
|
306
|
+
/* simplify-ignore-start: perf-critical */
|
|
307
|
+
const protectedValue = 42;
|
|
308
|
+
/* simplify-ignore-end */
|
|
309
|
+
EOF
|
|
310
|
+
|
|
311
|
+
hook_event() { printf '%s' "$1" | CLAUDE_PROJECT_DIR="$PROJ" bash hooks/simplify-ignore.sh; }
|
|
312
|
+
read_event=$(printf '{"tool_name":"Read","tool_input":{"file_path":"%s"}}' "$TARGET")
|
|
313
|
+
|
|
314
|
+
hook_event "$read_event"
|
|
315
|
+
assert_eq "protected block hidden after Read" "1" "$(grep -c 'BLOCK_' "$TARGET")"
|
|
316
|
+
|
|
317
|
+
# Wholesale rewrite — every placeholder is gone, so Stop has nothing to expand
|
|
318
|
+
printf 'const rewritten = 7;\n' > "$TARGET"
|
|
319
|
+
|
|
320
|
+
stop_out=$(hook_event '{}' 2>&1) || true
|
|
321
|
+
|
|
322
|
+
PROJ_CACHE="$PROJ/.claude/.simplify-ignore-cache"
|
|
323
|
+
RECOVERED="$PROJ_CACHE/$(file_id "$TARGET").recovered"
|
|
324
|
+
|
|
325
|
+
assert_eq "backup restored over the rewrite" "1" "$(grep -c 'const protectedValue = 42;' "$TARGET")"
|
|
326
|
+
assert_eq "rewrite kept in cache" "1" "$([ -f "$RECOVERED" ] && echo 1 || echo 0)"
|
|
327
|
+
assert_eq "cached rewrite has the rewritten content" "const rewritten = 7;" "$(cat "$RECOVERED")"
|
|
328
|
+
assert_eq "warning names the restored file" "1" \
|
|
329
|
+
"$(printf '%s' "$stop_out" | grep -c -F "$TARGET")"
|
|
330
|
+
assert_eq "warning names the cached rewrite" "1" \
|
|
331
|
+
"$(printf '%s' "$stop_out" | grep -c -F "$RECOVERED")"
|
|
332
|
+
fi
|
|
333
|
+
|
|
334
|
+
# ── Test 13: Read → direct write with no event → Stop ───────────────────
|
|
335
|
+
printf '\nTest 13: A write with no Edit or Write event survives Stop\n'
|
|
336
|
+
|
|
337
|
+
if ! command -v jq >/dev/null 2>&1; then
|
|
338
|
+
printf ' SKIP: full lifecycle needs jq (the hook exits at its jq guard)\n'
|
|
339
|
+
else
|
|
340
|
+
PROJ="$TMPDIR/proj-noevent"
|
|
341
|
+
rm -rf "$PROJ"
|
|
342
|
+
mkdir -p "$PROJ/.claude"
|
|
343
|
+
TARGET="$PROJ/app.js"
|
|
344
|
+
cat > "$TARGET" <<'EOF'
|
|
345
|
+
const editable = 1;
|
|
346
|
+
/* simplify-ignore-start: perf-critical */
|
|
347
|
+
const protectedValue = 42;
|
|
348
|
+
/* simplify-ignore-end */
|
|
349
|
+
EOF
|
|
350
|
+
|
|
351
|
+
hook_event() { printf '%s' "$1" | CLAUDE_PROJECT_DIR="$PROJ" bash hooks/simplify-ignore.sh; }
|
|
352
|
+
read_event=$(printf '{"tool_name":"Read","tool_input":{"file_path":"%s"}}' "$TARGET")
|
|
353
|
+
|
|
354
|
+
# Read → placeholder on disk, backup taken
|
|
355
|
+
hook_event "$read_event"
|
|
356
|
+
|
|
357
|
+
# Direct write, no Edit or Write event follows it
|
|
358
|
+
sed 's/const editable = 1;/const editable = 9;/' "$TARGET" > "$TMPDIR/noevent-write.js"
|
|
359
|
+
cat "$TMPDIR/noevent-write.js" > "$TARGET"
|
|
360
|
+
|
|
361
|
+
# Stop
|
|
362
|
+
hook_event '{}'
|
|
363
|
+
|
|
364
|
+
assert_eq "write with no event survives Stop" "1" "$(grep -c 'const editable = 9;' "$TARGET")"
|
|
365
|
+
assert_eq "stale backup value not restored" "0" "$(grep -c 'const editable = 1;' "$TARGET")"
|
|
366
|
+
assert_eq "protected block back on disk" "1" "$(grep -c 'const protectedValue = 42;' "$TARGET")"
|
|
367
|
+
assert_eq "no placeholder left after Stop" "0" "$(grep -c 'BLOCK_' "$TARGET")"
|
|
368
|
+
fi
|
|
369
|
+
|
|
370
|
+
# ── Tests 14-16: full-lifecycle round-trip fidelity ──────────────────────
|
|
371
|
+
# Run the hook end-to-end (Read → [Edit] → Stop) against an isolated
|
|
372
|
+
# CLAUDE_PROJECT_DIR and assert the original bytes are recovered exactly.
|
|
373
|
+
# These exercise the expand/restore half of the hook, which the
|
|
374
|
+
# function-extraction tests above cannot reach.
|
|
375
|
+
|
|
376
|
+
if command -v jq >/dev/null 2>&1; then
|
|
377
|
+
|
|
378
|
+
rt_hook_event() {
|
|
379
|
+
# rt_hook_event <project_dir> <tool_name|""> <file_path|"">
|
|
380
|
+
local proj="$1" tool="$2" fp="$3" input
|
|
381
|
+
if [ -n "$tool" ]; then
|
|
382
|
+
input=$(jq -n --arg t "$tool" --arg fp "$fp" \
|
|
383
|
+
'{tool_name:$t, tool_input:{file_path:$fp}}')
|
|
384
|
+
else
|
|
385
|
+
input='{}'
|
|
386
|
+
fi
|
|
387
|
+
printf '%s' "$input" | CLAUDE_PROJECT_DIR="$proj" bash hooks/simplify-ignore.sh
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
# ── Test 14: Read → Stop restores the file byte-identically ──────────────
|
|
391
|
+
printf '\nTest 14: Round-trip Read → Stop (byte fidelity)\n'
|
|
392
|
+
PROJ="$TMPDIR/rt14"; mkdir -p "$PROJ"
|
|
393
|
+
RT="$PROJ/roundtrip.js"
|
|
394
|
+
cat > "$RT" <<'EOF'
|
|
395
|
+
const a = `template ${literal}`;
|
|
396
|
+
// simplify-ignore-start: perf-critical
|
|
397
|
+
const secret = "glob*chars? [and] \\backslashes";
|
|
398
|
+
if (a && b) { mask = flags & 0xff; } // ampersands must survive bash 5.2 patsub_replacement
|
|
399
|
+
hot_loop($HOME);
|
|
400
|
+
// simplify-ignore-end
|
|
401
|
+
middle line
|
|
402
|
+
/* simplify-ignore-start */ const inline = 1; /* simplify-ignore-end */
|
|
403
|
+
const b = 2;
|
|
404
|
+
EOF
|
|
405
|
+
cp "$RT" "$PROJ/roundtrip.orig"
|
|
406
|
+
|
|
407
|
+
rt_hook_event "$PROJ" "Read" "$RT"
|
|
408
|
+
assert_eq "blocks hidden on disk after Read" "2" "$(grep -c 'BLOCK_' "$RT")"
|
|
409
|
+
assert_eq "secret absent from disk after Read" "0" "$(grep -c 'secret' "$RT")"
|
|
410
|
+
|
|
411
|
+
rt_hook_event "$PROJ" "" ""
|
|
412
|
+
if cmp -s "$RT" "$PROJ/roundtrip.orig"; then
|
|
413
|
+
assert_eq "Stop restores original bytes" "identical" "identical"
|
|
414
|
+
else
|
|
415
|
+
assert_eq "Stop restores original bytes" "identical" "$(cmp "$RT" "$PROJ/roundtrip.orig" 2>&1 | head -1)"
|
|
416
|
+
fi
|
|
417
|
+
|
|
418
|
+
# ── Test 15: Round-trip preserves missing trailing newline ────────────────
|
|
419
|
+
printf '\nTest 15: Round-trip with no trailing newline\n'
|
|
420
|
+
PROJ="$TMPDIR/rt15"; mkdir -p "$PROJ"
|
|
421
|
+
RT="$PROJ/nonewline.js"
|
|
422
|
+
printf 'top\n// simplify-ignore-start\nhidden\n// simplify-ignore-end\nbottom' > "$RT"
|
|
423
|
+
cp "$RT" "$PROJ/nonewline.orig"
|
|
424
|
+
|
|
425
|
+
rt_hook_event "$PROJ" "Read" "$RT"
|
|
426
|
+
assert_eq "block hidden" "1" "$(grep -c 'BLOCK_' "$RT")"
|
|
427
|
+
rt_hook_event "$PROJ" "" ""
|
|
428
|
+
if cmp -s "$RT" "$PROJ/nonewline.orig"; then
|
|
429
|
+
assert_eq "no-trailing-newline file restored byte-identically" "identical" "identical"
|
|
430
|
+
else
|
|
431
|
+
assert_eq "no-trailing-newline file restored byte-identically" "identical" "differs"
|
|
432
|
+
fi
|
|
433
|
+
|
|
434
|
+
# ── Test 16: Read → model edit → Edit event → Stop keeps the edit ────────
|
|
435
|
+
printf '\nTest 16: Round-trip with an edit during the session\n'
|
|
436
|
+
PROJ="$TMPDIR/rt16"; mkdir -p "$PROJ"
|
|
437
|
+
RT="$PROJ/edited.js"
|
|
438
|
+
cat > "$RT" <<'EOF'
|
|
439
|
+
const a = 1;
|
|
440
|
+
// simplify-ignore-start
|
|
441
|
+
const secret = 42;
|
|
442
|
+
// simplify-ignore-end
|
|
443
|
+
const b = 2;
|
|
444
|
+
EOF
|
|
445
|
+
cp "$RT" "$PROJ/edited.orig"
|
|
446
|
+
|
|
447
|
+
rt_hook_event "$PROJ" "Read" "$RT"
|
|
448
|
+
# Simulate the model editing the filtered file: append a new line.
|
|
449
|
+
printf '%s\n' "const added = true;" >> "$RT"
|
|
450
|
+
rt_hook_event "$PROJ" "Edit" "$RT"
|
|
451
|
+
|
|
452
|
+
assert_eq "disk still placeholdered after Edit" "1" "$(grep -c 'BLOCK_' "$RT")"
|
|
453
|
+
assert_eq "secret still absent from disk after Edit" "0" "$(grep -c 'secret' "$RT")"
|
|
454
|
+
assert_eq "added line survives re-filter" "1" "$(grep -c 'const added' "$RT")"
|
|
455
|
+
BAK=$(ls "$PROJ/.claude/.simplify-ignore-cache"/*.bak 2>/dev/null | head -1)
|
|
456
|
+
assert_eq "backup holds real content" "1" "$(grep -c 'const secret = 42' "${BAK:-/dev/null}")"
|
|
457
|
+
assert_eq "backup holds the edit" "1" "$(grep -c 'const added' "${BAK:-/dev/null}")"
|
|
458
|
+
|
|
459
|
+
rt_hook_event "$PROJ" "" ""
|
|
460
|
+
EXPECTED="$PROJ/edited.expected"
|
|
461
|
+
cp "$PROJ/edited.orig" "$EXPECTED"
|
|
462
|
+
printf '%s\n' "const added = true;" >> "$EXPECTED"
|
|
463
|
+
if cmp -s "$RT" "$EXPECTED"; then
|
|
464
|
+
assert_eq "Stop restores original + edit byte-identically" "identical" "identical"
|
|
465
|
+
else
|
|
466
|
+
assert_eq "Stop restores original + edit byte-identically" "identical" "differs"
|
|
467
|
+
fi
|
|
468
|
+
|
|
469
|
+
else
|
|
470
|
+
printf '\nTests 14-16 skipped: jq not available (hook no-ops without it)\n'
|
|
471
|
+
fi
|
|
472
|
+
|
|
473
|
+
# ── Summary ──────────────────────────────────────────────────────────────
|
|
474
|
+
printf '\n══════════════════════════════════════════\n'
|
|
475
|
+
printf 'Results: %d passed, %d failed\n' "$PASS" "$FAIL"
|
|
476
|
+
[ "$FAIL" -eq 0 ] && exit 0 || exit 1
|