`
+block on regeneration (only `CLAUDE.md`, no other files are touched).
diff --git a/.claude/skills/hooks-daemon/report.md b/.claude/skills/hooks-daemon/report.md
index f0ab48ae..e6042738 100644
--- a/.claude/skills/hooks-daemon/report.md
+++ b/.claude/skills/hooks-daemon/report.md
@@ -109,9 +109,9 @@ Write a single markdown file with this structure:
## Timeline
-| Time | Event | Source |
-|------|-------|--------|
-| ... | ... | daemon log / transcript / git |
+| Time | Event | Source |
+| ---- | ----- | ----------------------------- |
+| ... | ... | daemon log / transcript / git |
{Chronological table of events leading up to, during, and after the issue.}
@@ -148,6 +148,7 @@ Write a single markdown file with this structure:
## Analysis
{Detailed analysis of what went wrong:
+
- What was the immediate cause?
- What was the root cause?
- Were there contributing factors?
diff --git a/.claude/skills/hooks-daemon/scripts/health-check.sh b/.claude/skills/hooks-daemon/scripts/health-check.sh
index 2675a892..91daf46e 100755
--- a/.claude/skills/hooks-daemon/scripts/health-check.sh
+++ b/.claude/skills/hooks-daemon/scripts/health-check.sh
@@ -112,6 +112,21 @@ else
fi
# === SELF-BOOTSTRAP END ===
+# Plan 00122 BUG 4: make any non-zero exit honest. Under `set -euo pipefail` an
+# unguarded failure (e.g. sourcing _resolve-venv.sh when venv resolution dies)
+# would otherwise terminate the script with NO output, leaving the operator
+# nothing to act on (observed on macOS). This trap prints the script, exit
+# code, and failing line on a non-zero exit; it stays silent on success.
+_health_check_exit_trap() {
+ local rc=$?
+ if [ "$rc" -ne 0 ]; then
+ echo "" >&2
+ echo "❌ health-check.sh aborted (exit $rc) at line ${BASH_LINENO[0]:-unknown}." >&2
+ echo " Re-run with 'bash -x \"$0\"' for a full trace, or check the daemon logs." >&2
+ fi
+}
+trap _health_check_exit_trap EXIT
+
# Detect project root
PROJECT_ROOT="$(pwd)"
while [ "$PROJECT_ROOT" != "/" ]; do
diff --git a/.claude/skills/hooks-daemon/scripts/install.sh b/.claude/skills/hooks-daemon/scripts/install.sh
index c9a64dee..7044cf4f 100755
--- a/.claude/skills/hooks-daemon/scripts/install.sh
+++ b/.claude/skills/hooks-daemon/scripts/install.sh
@@ -96,16 +96,48 @@ export HOOKS_DAEMON_PYTHON="$FOUND_PY"
echo "Using Python: $FOUND_PY"
echo ""
+# Plan 00122 BUG 3: an install counts as "already installed" only if it is
+# HEALTHY — a venv python exists AND the daemon package imports. A bare
+# directory check treated a broken/partial install (dir present, no working
+# venv) as complete, so the documented `/hooks-daemon install` could not repair
+# it (only `--force` could, which re-clones from scratch). Returns 0 when
+# healthy, non-zero otherwise. Probe output goes to a temp file (never
+# /dev/null) so failures stay inspectable.
+_installation_is_healthy() {
+ local dir="$1"
+ local py probe_out
+ probe_out="$(mktemp)"
+ # canonical-resolver-exempt: this is the skill bootstrap, which runs
+ # standalone in a client project BEFORE the daemon source tree (and
+ # scripts/lib/resolve_venv.sh) exists. This is a lightweight health probe,
+ # not venv resolution for use, so it globs directly.
+ for py in "$dir"/untracked/venv-*/bin/python "$dir"/untracked/venv/bin/python; do
+ if [ -x "$py" ] && "$py" -c "import claude_code_hooks_daemon" > "$probe_out" 2> "$probe_out"; then
+ rm -f "$probe_out"
+ return 0
+ fi
+ done
+ rm -f "$probe_out"
+ return 1
+}
+
# Check if already installed
if [ -d "$DAEMON_DIR" ] && [ "$FORCE_FLAG" != "--force" ]; then
- echo "Daemon is already installed at: $DAEMON_DIR"
- echo ""
- echo "To upgrade to a new version:"
- echo " /hooks-daemon upgrade"
+ if _installation_is_healthy "$DAEMON_DIR"; then
+ echo "Daemon is already installed at: $DAEMON_DIR"
+ echo ""
+ echo "To upgrade to a new version:"
+ echo " /hooks-daemon upgrade"
+ echo ""
+ echo "To force reinstall:"
+ echo " /hooks-daemon install --force"
+ exit 0
+ fi
+ echo "Daemon directory exists at: $DAEMON_DIR"
+ echo "but the installation looks broken (venv missing or package not importable)."
+ echo "Repairing now (equivalent to --force)..."
echo ""
- echo "To force reinstall:"
- echo " /hooks-daemon install --force"
- exit 0
+ FORCE_FLAG="--force"
fi
# Download installer to temp file (never pipe curl to shell — we block that pattern)
diff --git a/.claude/skills/hooks-daemon/scripts/upgrade.sh b/.claude/skills/hooks-daemon/scripts/upgrade.sh
index 11db8200..2170ef8a 100755
--- a/.claude/skills/hooks-daemon/scripts/upgrade.sh
+++ b/.claude/skills/hooks-daemon/scripts/upgrade.sh
@@ -19,9 +19,9 @@
set -euo pipefail
if [ "${1:-}" = "--help" ] || [ "${1:-}" = "-h" ]; then
- echo "Usage: upgrade.sh [VERSION]"
- echo " VERSION Target git tag (default: latest). See HOOKS_DAEMON_UPGRADE_REF"
- echo " and HOOKS_DAEMON_UPGRADE_BASE_URL for fetch overrides."
+ printf '%s\n' "Usage: upgrade.sh [VERSION]" \
+ " VERSION Target git tag (default: latest). See HOOKS_DAEMON_UPGRADE_REF" \
+ " and HOOKS_DAEMON_UPGRADE_BASE_URL for fetch overrides."
exit 0
fi
@@ -41,8 +41,11 @@ URL="$BASE_URL/$REF/scripts/upgrade.sh"
TMP="$(mktemp)"
if ! curl -fsSL --max-time 30 -o "$TMP" "$URL"; then
- echo "Error: failed to fetch upgrade.sh from $URL" >&2
rm -f "$TMP"
+ # Plan 00114 F4: make the offline/network failure actionable instead of a
+ # dead end. The installed daemon already ships a working Layer 1 upgrade.sh.
+ # A single printf keeps the shim under its thin-shim line budget.
+ printf 'Error: failed to fetch upgrade.sh from %s\nRecovery: run the installed daemon Layer 1 directly:\n bash "%s/.claude/hooks-daemon/scripts/upgrade.sh" --project-root "%s"\nor pin a reachable ref: HOOKS_DAEMON_UPGRADE_REF=v3.16.0 bash "%s"\n' "$URL" "$PROJECT_ROOT" "$PROJECT_ROOT" "$0" >&2
exit 1
fi
chmod +x "$TMP"
diff --git a/.claude/skills/hooks-daemon/upgrade.md b/.claude/skills/hooks-daemon/upgrade.md
index 8755d34e..deef2a93 100644
--- a/.claude/skills/hooks-daemon/upgrade.md
+++ b/.claude/skills/hooks-daemon/upgrade.md
@@ -24,7 +24,64 @@ Upgrade the Claude Code Hooks Daemon and commit the result atomically.
$PYTHON -m claude_code_hooks_daemon.daemon.cli status
```
-4. **Stage daemon-owned paths ONLY** with explicit `git add` — other
+4. **Reconcile project docs with truth-changes** (skip on `--force`
+ reinstall, where `from_version == to_version`). Some statements that were
+ true about working in this project may have changed across the upgrade.
+ Load the truth-changes for the range you just crossed:
+
+ ```bash
+ $PYTHON -m claude_code_hooks_daemon.daemon.cli check-truth-changes \
+ --from ${from_version} --to ${to_version}
+ ```
+
+ Exit code `0` means nothing to do — skip to the next step. Exit code `1`
+ means there are `was → now` entries to reconcile. For **each** entry:
+
+ - **Semantically** search the PROJECT'S OWN docs for the `was` statement —
+ `CLAUDE/`, `docs/`, `README*`, `AGENTS*`, and any project instruction
+ files. It is a natural-language statement, not a literal string; match on
+ meaning.
+ - **NEVER** edit anything under `.claude/hooks-daemon/` — that is the
+ upstream daemon clone and is overwritten on upgrade.
+ - If `now` is present: update the project's doc to assert the `now` truth
+ instead. Minimal edits — change only the stale statement.
+ - If `now` is empty / "remove all reference": delete the stale guidance. Remove
+ only the specific statement; if it is embedded in a larger section, ask
+ before removing the whole section.
+ - If a doc does not assert the `was` truth, there is nothing to do for it
+ (the step is idempotent — re-running is a no-op).
+
+ Stage and commit any project-doc edits **separately** from the daemon
+ upgrade commit below (they touch project files, not daemon-owned paths). You
+ can re-run `check-truth-changes` any time to re-reconcile.
+
+5. **Surface newly-available / recommended config options** (skip on `--force`
+ reinstall, where `from_version == to_version`). Some releases add opt-in
+ protections or flip a default; this step reports what is now available or
+ recommended for the range you crossed so a new feature never ships dormant:
+
+ ```bash
+ $PYTHON -m claude_code_hooks_daemon.daemon.cli check-config-migrations \
+ --from ${from_version} --to ${to_version}
+ ```
+
+ Exit code `0` means nothing to surface — skip to the next step. Exit code `1`
+ means there are suggestions. Read them:
+
+ - Anything under **🆕 Recommended — enable these** is a feature the daemon
+ recommends turning on. The output shows the key, the recommended value, and
+ your current value. To adopt one, set that key/value in
+ `.claude/hooks-daemon.yaml`.
+ - If a recommendation carries a migration **Note** (e.g. "migrate existing
+ memory into tracked docs first"), perform that migration **before**
+ enabling — follow any referenced post-upgrade task.
+ - Items under **💡 New Options Available** are informational; adopt if useful.
+
+ This is advisory — enabling is your choice; the daemon never edits your config
+ for you. Stage and commit any `.claude/hooks-daemon.yaml` edits separately
+ from the daemon upgrade commit below.
+
+6. **Stage daemon-owned paths ONLY** with explicit `git add` — other
working-tree changes are not part of this commit. Never `git add .`:
```bash
@@ -33,7 +90,7 @@ Upgrade the Claude Code Hooks Daemon and commit the result atomically.
.claude/settings.json
```
-5. **Commit** with the metadata block in the body:
+7. **Commit** with the metadata block in the body:
```
hooks daemon upgrade: ${from_version} → ${to_version}
diff --git a/.claude/skills/planning/SKILL.md b/.claude/skills/planning/SKILL.md
index 2206fe0d..6ee1c857 100644
--- a/.claude/skills/planning/SKILL.md
+++ b/.claude/skills/planning/SKILL.md
@@ -33,6 +33,7 @@ find CLAUDE/Plan -maxdepth 2 -type d -name '[0-9]*' | grep -oP '/\K\d{3}(?=-)' |
See @CLAUDE/PlanWorkflow.md for full template.
Key sections:
+
- Overview
- Goals / Non-Goals
- Tasks (with checkboxes and status icons)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index bc24ab37..0c3e758d 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -24,7 +24,7 @@ jobs:
- name: Setup Node.js
uses: actions/setup-node@v4
with:
- node-version: '18'
+ node-version: '22'
cache: 'npm'
- name: Install dependencies
@@ -35,6 +35,18 @@ jobs:
env:
VITE_CONTACT_FORM_URL: ${{ vars.VITE_CONTACT_FORM_URL }}
+ # QA runs after build, not before: ts-qa's Playwright phase serves the real
+ # dist/ output (via `npm run preview`) rather than a mocked/dev server, so the
+ # build has to exist first. Everything else in the pipeline (lint/type-check/
+ # unit tests) doesn't depend on dist/ but there's no cost to running it after -
+ # GITHUB_ACTIONS=true puts ts-qa in read-only mode automatically (check-only,
+ # never auto-fixes/commits in CI).
+ - name: Install Playwright browsers
+ run: npx playwright install --with-deps chromium
+
+ - name: Run QA pipeline
+ run: npx ts-qa
+
- name: Upload Pages artifact
if: github.ref == 'refs/heads/main'
uses: actions/upload-pages-artifact@v3
@@ -54,4 +66,4 @@ jobs:
steps:
- name: Deploy to GitHub Pages
id: deployment
- uses: actions/deploy-pages@v4
\ No newline at end of file
+ uses: actions/deploy-pages@v4
diff --git a/.gitignore b/.gitignore
index e94cdb5c..ba917b15 100644
--- a/.gitignore
+++ b/.gitignore
@@ -33,9 +33,21 @@ npm-debug.log*
# Claude Code Hooks Daemon
.claude/hooks-daemon/
+# Git worktrees (isolated agent branches)
+.claude/worktrees
+
+# Claude Code Hooks Daemon - scheduled task lock file
+.claude/scheduled_tasks.lock
+
# ClaudeMdInjector backup (session artifact, never commit)
.CLAUDE.md.pre-inject
# Python bytecode caches (project-handlers)
__pycache__/
*.pyc
+
+# Playwright
+test-results/
+playwright-report/
+blob-report/
+playwright/.cache/
diff --git a/.prettierignore b/.prettierignore
new file mode 100644
index 00000000..2a15d2fd
--- /dev/null
+++ b/.prettierignore
@@ -0,0 +1,11 @@
+dist
+dist-server
+node_modules
+code-snippets
+untracked
+ARCHIVE
+var
+.claude
+cloudflare-workers
+package-lock.json
+src/data/snippets.ts
diff --git a/ARCHIVE/README.md b/ARCHIVE/README.md
index aec96c11..1b10b430 100644
--- a/ARCHIVE/README.md
+++ b/ARCHIVE/README.md
@@ -37,6 +37,7 @@ This directory contains the complete legacy build system for the LTS Commerce st
## Why Archived?
The site is being migrated to React/TypeScript for:
+
- **Type safety**: Zero runtime type errors
- **Component reusability**: Reduce duplication
- **Better DX**: TypeScript + ESLint + modern tooling
@@ -45,6 +46,7 @@ The site is being migrated to React/TypeScript for:
## Technology Comparison
### Legacy (Archived)
+
```
EJS Templates → Custom Preprocessing → Vite → Static HTML
- ✅ Simple, no framework overhead
@@ -54,6 +56,7 @@ EJS Templates → Custom Preprocessing → Vite → Static HTML
```
### New (React)
+
```
React Components → TypeScript → Vite → Static HTML (SSG)
- ✅ Type-safe throughout
@@ -69,6 +72,7 @@ All articles and content from `private_html/articles/` are being migrated to the
## Reference
This archive remains for:
+
- **Content reference**: When migrating articles
- **Design reference**: Reviewing layout decisions
- **Build reference**: Understanding previous approach
@@ -82,18 +86,21 @@ This archive remains for:
## How to Use This Archive
### Extract Article Content
+
```bash
# Articles are in ARCHIVE/private_html/articles/
ls ARCHIVE/private_html/articles/
```
### View Original Styles
+
```bash
# CSS files in ARCHIVE/private_html/css/
cat ARCHIVE/private_html/css/main.css
```
### Review Build Scripts
+
```bash
# Build utilities in ARCHIVE/scripts/
cat ARCHIVE/scripts/process-ejs.js
@@ -104,6 +111,7 @@ cat ARCHIVE/scripts/process-ejs.js
⚠️ **This system is archived and should NOT be used for new development.**
All new work follows:
+
- React/TypeScript architecture
- react-site-skeleton patterns
- PlanWorkflow system
diff --git a/ARCHIVE/private_html/articles/CLAUDE.md b/ARCHIVE/private_html/articles/CLAUDE.md
index 72a20a0f..7d22a9d1 100644
--- a/ARCHIVE/private_html/articles/CLAUDE.md
+++ b/ARCHIVE/private_html/articles/CLAUDE.md
@@ -18,6 +18,7 @@ This guide provides instructions for creating high-quality technical articles fo
### Research Requirements
Before writing ANY technical content:
+
1. **Check current version** - Visit npm, GitHub releases, official docs
2. **Verify features** - Confirm features exist in the current version
3. **Read recent updates** - Check blog posts from the last 3-6 months
@@ -27,6 +28,7 @@ Before writing ANY technical content:
### Research Tools
Use these tools for EVERY article:
+
- `WebSearch` - Find current documentation and recent articles
- `WebFetch` - Read official docs, GitHub pages, and release notes
- Cross-reference multiple sources
@@ -45,6 +47,7 @@ cp private_html/articles/php-magic-constants-maintainable-logging.ejs private_ht
```
The `_TEMPLATE-ARTICLE.ejs` includes:
+
- Complete structure with comments explaining each section
- Code snippet examples with proper directory path usage
- Extensive linking examples
@@ -73,6 +76,7 @@ The `_TEMPLATE-ARTICLE.ejs` includes:
**ALWAYS use the snippet injection system for ALL code examples, no matter how small.**
Embedding code directly in EJS templates causes catastrophic rendering failures:
+
- Unescaped HTML characters (`<`, `>`, `&`, `` tags on a new line
**Examples of what to put in separate snippet files**:
+
- ✅ Complete class definitions
- ✅ Function examples (even single functions)
- ✅ Configuration file excerpts
@@ -97,26 +102,33 @@ Embedding code directly in EJS templates causes catastrophic rendering failures:
**Code Examples Requirements - Audience-Dependent**:
### Developer-Focused Technical Articles
+
**MANDATORY** - Include examples in ALL of these languages **IN THIS ORDER**:
+
1. **Pseudocode** (`.txt` files) - Conceptual explanation first
-2. **PHP** (`.php` files) - Current 8.4 syntax and best practices
+2. **PHP** (`.php` files) - Current 8.4 syntax and best practices
3. **TypeScript** (`.ts` files) - Modern Node.js/TypeScript examples
4. **Ansible** (`.yml` files) - Infrastructure automation playbooks
5. **Bash** (`.sh` files) - Shell scripting with error handling
### Executive/Strategic Articles (C-level, Business Focus)
+
**OPTIONAL** - Code examples should be:
+
- **Minimal or none** - Focus on business concepts, ROI, strategic value
- **High-level conceptual** - If code is needed, use simple pseudocode or architecture diagrams
- **Business-relevant** - Only include code that directly supports business decision-making
### Mixed Technical/Business Articles
+
**SELECTIVE** - Include code examples that:
+
- **Support business points** - Code serves to illustrate business concepts
- **1-3 languages maximum** - Choose most relevant to the business context
- **Focus on outcomes** - Emphasize results rather than implementation details
**Directory Structure Example**:
+
```
code-snippets/
├── defensive-programming-principles/
@@ -133,11 +145,13 @@ code-snippets/
```
**Pseudocode File Extension Rule**:
+
- **ALWAYS use `.txt` extension** for pseudocode files to clearly indicate they are conceptual, not real Python code
- Use `language-python` for syntax highlighting, but content must be language-agnostic pseudocode
- Examples: `CLASS UserService`, `METHOD validate() -> boolean`, `IF condition THEN action`
**Article Template Usage**:
+
```html
{{SNIPPET:article-slug/concept-pseudocode.txt}}
@@ -153,11 +167,13 @@ code-snippets/
```
**Critical Rules**:
+
- **Closing tags MUST be on a new line**: If they're on the same line as the last line of code (especially comments), they'll be treated as part of the code
- **Use full directory paths**: Always include the article directory name in snippet references
- **Match directory names**: Code snippet directory should match article slug (kebab-case)
**HTML Escaping**: The build process automatically escapes HTML entities in code snippets:
+
- `<` becomes `<`
- `>` becomes `>`
- `&` becomes `&`
@@ -200,12 +216,14 @@ git push origin main # Triggers auto-deployment
- **Current information** - Check that linked resources are up-to-date
**CRITICAL**: Training data is often months or years out of date. For example:
+
- Framework versions change frequently (e.g., oclif v4 released June 2024)
- Best practices evolve rapidly
- Tool features are added monthly
- Security recommendations change
Always use WebSearch and WebFetch to verify:
+
- Current version numbers
- Latest features and updates
- Recent breaking changes
@@ -215,6 +233,7 @@ Always use WebSearch and WebFetch to verify:
### Research Process Example
**BAD** (using training knowledge):
+
```
"The latest version includes new features like..."
"This framework recently added support for..."
@@ -222,6 +241,7 @@ Always use WebSearch and WebFetch to verify:
```
**GOOD** (after research):
+
```
"Version X.Y.Z (released [exact date from GitHub]) includes..."
"According to npm, the current version published [days] ago is..."
@@ -231,73 +251,124 @@ Always use WebSearch and WebFetch to verify:
Examples of well-linked content:
**Basic linking**:
+
```html
- Oclif is an
- open-source framework for building command-line interfaces in
- Node.js and
- TypeScript.
+ Oclif is an open-source framework
+ for building command-line interfaces in
+ Node.js and
+ TypeScript.
```
**Language feature linking (MANDATORY)**:
+
```html
- PHP 8.4 introduces property hooks
- and asymmetric visibility.
- Final classes
- prevent inheritance, encouraging composition over inheritance.
+ PHP 8.4 introduces
+ property hooks
+ and
+ asymmetric visibility.
+ Final classes
+ prevent inheritance, encouraging composition over inheritance.
- TypeScript's union types
- and branded types
- provide stronger type safety than traditional approaches.
+ TypeScript's
+ union types
+ and
+ branded types
+ provide stronger type safety than traditional approaches.
```
**Comprehensive linking**:
+
```html
- PHP has converged around PSR-11 Container Interface,
- with most frameworks implementing compatible containers. TypeScript? It's the Wild West.
+ PHP has converged around
+ PSR-11 Container Interface, with most frameworks implementing compatible containers. TypeScript? It's the Wild West.
-
+
```
**Even inline code elements can be linked**:
+
```html
- In PHP, you might use final to prevent inheritance
+ In PHP, you might use
+ final
+ to prevent inheritance
```
### 2. Content Structure
#### Opening Section
-- **Lead paragraph** in ``
+
+- **Lead paragraph** in `
`
- Hook the reader with the problem being solved
- Establish credibility and scope
#### Body Sections
+
- Use `` tags for major topics
- Hierarchical headings: `` for main sections, `` for subsections
- One idea per paragraph
- Use lists for multiple related points
#### Code Examples
+
- Always use appropriate language classes: `language-php`, `language-javascript`, etc.
- Provide context before code blocks
- Keep examples practical and runnable
- Comment complex sections
#### Conclusion
+
- Summarize key takeaways
- Provide actionable next steps
- Avoid generic endings
@@ -305,12 +376,14 @@ Examples of well-linked content:
### 3. Writing Style
#### Technical Accuracy
+
- **No fabrication** - Never invent case studies or metrics
- **Practical focus** - Real-world applications over theory
- **Honest assessment** - Include limitations and drawbacks
- **Balanced perspective** - Pros AND cons for tools/approaches
#### Tone and Voice
+
- **Professional** but approachable
- **Confident** without being arrogant
- **Instructive** rather than prescriptive
@@ -325,6 +398,7 @@ Examples of well-linked content:
- **NO "in conclusion"** - just conclude
#### Formatting Standards
+
- **Links**: All external links must include `target="_blank" rel="noopener"`
- **Emphasis**: Use `` for important terms, not just bold
- **Lists**: Use `