Skip to content

Commit 0fd5eea

Browse files
committed
feat: Add end-of-day session cleanup as MCP tool
- Create tools/mcp-server/src/handlers/end-of-day.ts handler - Register end_of_day_session_cleanup MCP tool in MCP server - Expose modes: report (default), commit, push with confirmation gating - Return structured check results: 4X4.md, CHANGELOG.md, MEMORY.md, build validation - Include git state reporting: branch, modified files, untracked files - Support dryRun, force, skipValidation flags for automation - Update MCP server version to 0.9.0 - Update tools/mcp-server/README.md with tool documentation - Update tools/mcp-server/package.json version and description - Update main CHANGELOG.md with MCP tool entry
1 parent 550037e commit 0fd5eea

9 files changed

Lines changed: 402 additions & 33 deletions

File tree

4X4.md

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
---
22
client: Hypercart Dev Tools
33
repo: https://github.com/Hypercart-Dev-Tools/AI-DDTK
4-
last_edit: 2026-03-24
5-
week_of: 2026-03-24
4+
last_edit: 2026-04-05
5+
week_of: 2026-04-05
66
source_pr_number: n/a
7-
sprint: Playwright Auth helper (pw-auth)
7+
sprint: Core tooling hardening and experimental promotion
88

99
---
1010

@@ -16,17 +16,17 @@ A simple, actionable framework to prioritize and track engineering tasks. Focus
1616
# About the Current Project
1717
AI-DDTK (AI Driven Development ToolKit) is a central, install-once toolkit used across WordPress projects to standardize AI agent guidance, security practices, and developer workflows (e.g., WPCC scanning, runtime perf profiling, AJAX endpoint testing).
1818

19-
This week’s focus is adding passwordless Playwright auth for WP admin (`pw-auth`) to enable AI agents to drive headless browser automation without hardcoded credentials.
19+
This week’s focus is shipping core tooling improvements (.wpcignore, servers-audit promotion) and reducing the gap between experimental tooling and mainline.
2020

2121
---
2222

2323
## 1. Strategic Backlog
2424
**Maximum of 4 items. Focus on long-term goals and impactful improvements.**
2525

26-
1. - [ ] Ship native `.wpcignore` support in WPCC (reduce recursive scans; unblock repo-wide scanning)
26+
1. - [x] Ship native `.wpcignore` support in WPCC (reduce recursive scans; unblock repo-wide scanning)
2727
2. - [x] Weekly UX audit now automated via CI ([recipe](recipes/weekly-ux-audit.md)) — version drift, doc parity, and link checks run every Monday; failures create GitHub issues
2828
3. - [ ] Prove the experimental crash-loop workflow on 2-3 projects before promoting it beyond `experimental/`
29-
4. - [ ] Continue release hygiene improvements (consistent SemVer sections, lightweight summaries)
29+
4. - [x] Release hygiene: CHANGELOG restructured (no Unreleased, maintainer rules, consistent SemVer blocks)
3030

3131
---
3232

@@ -35,30 +35,30 @@ This week’s focus is adding passwordless Playwright auth for WP admin (`pw-aut
3535

3636
> **Tip:** If your team frequently handles urgent issues, consider reserving 1-2 slots for hotfixes. Otherwise, use all 4 slots for planned work.
3737
38-
- [x] Refactor bin/pw-auth to improve maintainability by externalizing embedded helper scripts (Phase 1).
39-
40-
- [ ] Formalize Valet clone-lab as an optional recipe (macOS-only) with clear guardrails and no core-toolset promotion
38+
- [x] Implement `.wpcignore` support in WPCC `check-performance.sh` (gitignore-style file filtering)
39+
- [x] Promote `servers-audit.sh` and `servers-preflight.sh` from `experimental/` to `tools/`
40+
- [x] VS Code extension v0.2.0 — dynamic MCP server discovery with file watchers
41+
- [ ] Prove crash-loop workflow on 2-3 real projects
4142

4243
---
4344

4445
## 3. Previous Week
4546
**Review completed, deferred, or blocked tasks from the prior week.**
4647

47-
- [x] Validate the tmux workflow end-to-end on a machine where `tmux` is installed (v1.0.7)
48-
- [x] Move the theme crash-loop workflow into `experimental/theme-crash-loop.sh` (v1.0.7)
49-
- [x] Standardize crash-loop artifacts under the target project `/temp` folder and add optional `--tmux` mode (v1.0.7)
50-
- [x] Update README.md, CHANGELOG.md, and the dashboard for the experimental workflow (v1.0.7)
48+
- [x] Refactor bin/pw-auth to improve maintainability by externalizing embedded helper scripts
49+
- [x] Formalize Valet clone-lab as an optional recipe (macOS-only) with guardrails
50+
- [x] `project.sh` v1.5 — secrets scanner, scrub command, filename normalization, robustness fixes
51+
- [x] `servers-audit.sh` — Launchd plist parsing, KeepAlive conflict detection, expanded TLD coverage
5152

5253
---
5354

5455
## 4. Recent Lessons Learned
5556
**Capture insights to improve processes and avoid repeating mistakes.**
5657

57-
1. Externalizing embedded helper scripts (e.g., from bash into separate `.js` files) is a low-risk, high-reward first step in a larger refactor. It immediately improves syntax highlighting, linting, and code isolation without changing the core logic.
58-
2. Unit tests that mock shell execution are good for verifying a script's *interface* (arguments, output), but they don't confirm the script's *functionality*. End-to-end testing, even via a simple manual `doctor` command, is necessary to ensure the refactored script still works.
59-
3. A well-built `doctor` command in a CLI tool is an invaluable asset for both development and testing, providing a quick way to verify environment-dependent functionality.
60-
4. Never use `eval` with user-controlled strings in shell scripts — bash arrays with `"${arr[@]}"` invocation are safer and just as flexible.
61-
5. `.mjs` files run as ESM — `require()` is CJS-only. Use `.js` extension for scripts that need `require()`.
58+
1. Dropping the `[Unreleased]` CHANGELOG section eliminated friction without losing signal — at current velocity, versioned blocks on commit are more useful than a batched unreleased bucket.
59+
2. Experimental scripts that receive 4+ consecutive hardening commits are no longer experimental — promote them to reduce confusion about maturity.
60+
3. The VS Code extension's real value is zero-config workspace onboarding (MCP server auto-discovery), not wrapping terminal commands with UI chrome.
61+
4. `.wpcignore` should have shipped much earlier — the placeholder file existed but was never wired in, leaving WPCC unable to do repo-wide scans without false positives from `tools/`, `temp/`, etc.
6262

6363
---
6464

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
1919
- **Native `.wpcignore` support in WPCC**`check-performance.sh` now loads gitignore-style patterns from a `.wpcignore` file and filters the PHP file list before scanning. Auto-detects `.wpcignore` in the scan target directory or current working directory. Supports directory patterns (`tools/`), extension globs (`*.min.js`), and literal substring matches. New flags: `--wpcignore-file <path>` for explicit file, `--no-wpcignore` to disable. Unblocks repo-wide scanning without false positives from embedded tools, temp files, and vendor directories.
2020
- **VS Code extension dynamic MCP discovery (v0.2.0)** — the extension's MCP server definition provider now merges configs from 5 layers (static AI-DDTK fallback, workspace `.mcp.json`, `.vscode/mcp.json`, `.mcp.local.json`, `temp/mcp/local-snippets/*.json`) with file watchers for live re-discovery. Site-specific WP MCP Adapter servers are automatically provided to all VS Code MCP clients without manual wiring or restart.
2121
- **`experimental/end-of-day.sh` — solo developer session cleanup script** — automated script for end-of-work synchronization. Checks 4X4.md, CHANGELOG.md, and MEMORY.md freshness; archives session-scoped MEMORY.md to `PROJECT/1-INBOX/MEMORY-<timestamp>.md` for clean sessions. Supports `--commit` (with confirmation), `--push` (implies commit, with confirmation), `--force` (skip prompts for automation), `--dry-run`, and agent hook integration for orchestration. Default mode reports findings only; opt-in flags enable commit/push. Includes build validation (PHP syntax check) and structured event emission for agent coordination.
22+
- **MCP tool: `end_of_day_session_cleanup`** — expose end-of-day.sh as a typed MCP tool (v0.9.0). Agents can call `end_of_day_session_cleanup` with `mode` (report/commit/push), `dryRun`, `force`, `skipValidation` flags. Returns structured check results (4X4.md, CHANGELOG.md, MEMORY.md, build validation), git state (branch, modified files, untracked), and command exit code. Enables VS Code agents to orchestrate session cleanup without shell escaping.
2223

2324
### Changed
2425
- **`servers-audit.sh` and `servers-preflight.sh` promoted to `tools/`** — moved from `experimental/` to `tools/` alongside `servers.md` template. These scripts have received 4+ consecutive hardening releases (Launchd plist parsing, KeepAlive detection, expanded TLD coverage, Valet site discovery) and are no longer experimental. Internal path references (`$SCRIPT_DIR`) are relative and required no changes. CLI-REFERENCE.md updated with new sections for both scripts.

docs/CLI-REFERENCE.md

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# AI-DDTK CLI Reference
22

3-
Complete command reference for all AI-DDTK tools: `pw-auth`, `wpcc`, `local-wp`, `wp-ajax-test`, `aiddtk-tmux`, `tools/valet-site-copy.sh`.
3+
Complete command reference for all AI-DDTK tools: `pw-auth`, `wpcc`, `local-wp`, `wp-ajax-test`, `aiddtk-tmux`, `tools/valet-site-copy.sh`, `tools/servers-audit.sh`, `tools/servers-preflight.sh`.
44

55
**Last Updated:** 2026-03-22
66
**Version:** 1.0.0
@@ -240,6 +240,8 @@ wpcc [options] [paths...]
240240
- `--baseline <path>` — Use custom baseline file (default: `.hcc-baseline`)
241241
- `--ignore-baseline` — Ignore baseline file even if present
242242
- `--enable-clone-detection` — Enable function clone detection
243+
- `--wpcignore-file <path>` — Use custom `.wpcignore` file (default: auto-detect in scan dir or cwd)
244+
- `--no-wpcignore` — Disable `.wpcignore` file loading
243245
- `--help` — Show help message
244246

245247
**Examples:**
@@ -264,6 +266,12 @@ wpcc --severity-config ./custom-severity.json
264266

265267
# Verbose output with all matches
266268
wpcc --verbose --context-lines 5
269+
270+
# Repo-wide scan using .wpcignore to skip tools/, temp/, etc.
271+
wpcc --paths .
272+
273+
# Scan without .wpcignore filtering
274+
wpcc --paths . --no-wpcignore
267275
```
268276

269277
**Output:**
@@ -287,6 +295,32 @@ wpcc --features
287295

288296
---
289297

298+
#### `.wpcignore` File
299+
300+
Place a `.wpcignore` file in the scan target directory (or current working directory) to exclude paths from scanning. Uses gitignore-style patterns:
301+
302+
```
303+
# Directories (trailing slash)
304+
tools/
305+
temp/
306+
vendor/
307+
node_modules/
308+
309+
# Extension globs
310+
*.min.js
311+
*.min.css
312+
313+
# Literal substring
314+
some-legacy-file.php
315+
```
316+
317+
**Auto-detection order:**
318+
1. `<scan-dir>/.wpcignore` (if `--paths` points to a directory)
319+
2. `./.wpcignore` (current working directory)
320+
3. `--wpcignore-file <path>` overrides auto-detection
321+
322+
---
323+
290324
## local-wp
291325

292326
**Purpose:** WP-CLI wrapper for Local by Flywheel sites.
@@ -596,6 +630,43 @@ tools/valet-site-copy.sh teardown clone-test-01 --yes
596630

597631
---
598632

633+
## servers-audit.sh
634+
635+
**Purpose:** Capture a baseline snapshot of your local development environment — running services, ports, hostnames, DNS config, and Launchd service states — for diffing when things break.
636+
637+
**Location:** `~/bin/ai-ddtk/tools/servers-audit.sh`
638+
639+
```bash
640+
# Full audit to file
641+
tools/servers-audit.sh --output ~/bin/servers-audit.md
642+
643+
# Focus on hostname checks
644+
tools/servers-audit.sh --output ~/bin/servers-audit.md --focus hostname
645+
646+
# Diff against previous snapshot
647+
tools/servers-audit.sh --output /tmp/servers-now.md --previous-snapshot ~/bin/servers-audit.md
648+
```
649+
650+
Writes machine-readable artifacts under `temp/servers-audit/<run-id>/`.
651+
652+
---
653+
654+
## servers-preflight.sh
655+
656+
**Purpose:** Interactive pre-check for adding new local development domains — validates that hostnames, ports, and DNS entries won't conflict with existing Local WP sites, Valet links, or Homebrew services.
657+
658+
**Location:** `~/bin/ai-ddtk/tools/servers-preflight.sh`
659+
660+
```bash
661+
# Check if a domain is safe to add
662+
tools/servers-preflight.sh check-domain mysite.local
663+
664+
# JSON output for agent consumption
665+
tools/servers-preflight.sh check-domain mysite.local --json
666+
```
667+
668+
---
669+
599670
## Exit Codes
600671

601672
| Code | Meaning |

tools/mcp-server/README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
# AI-DDTK MCP Server
22

3-
> Version: 0.7.0
3+
> Version: 0.9.0
44
5-
Unified MCP server for AI-DDTK. Exposes LocalWP, WPCC, `pw-auth`, `wp-ajax-test`, tmux, and Query Monitor workflows as typed **Tools**, **Resources**, and **Prompts** — compatible with Claude Code, GitHub Copilot, Cline, Augment Code, Cursor, Claude Desktop, and any MCP-capable client.
5+
Unified MCP server for AI-DDTK. Exposes LocalWP, WPCC, `pw-auth`, `wp-ajax-test`, tmux, Query Monitor, and end-of-day session cleanup workflows as typed **Tools**, **Resources**, and **Prompts** — compatible with Claude Code, GitHub Copilot, Cline, Augment Code, Cursor, Claude Desktop, and any MCP-capable client.
66

77
## Quick Start
88

@@ -55,6 +55,7 @@ npm run mcp:http
5555
| AJAX | `wp_ajax_test` | Test `admin-ajax.php` endpoints with structured inputs |
5656
| tmux | `tmux_start`, `tmux_send`, `tmux_capture`, `tmux_stop`, `tmux_list`, `tmux_status` | Run resilient long-lived commands and inspect output |
5757
| Query Monitor | `qm_profile_page`, `qm_slow_queries`, `qm_duplicate_queries` | Profile pages, find slow queries, detect N+1 patterns |
58+
| Session cleanup | `end_of_day_session_cleanup` | Automated solo dev session cleanup: sync 4X4.md/CHANGELOG.md/MEMORY.md, optionally commit and push with confirmation |
5859

5960
## Resources
6061

tools/mcp-server/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "ai-ddtk-mcp",
3-
"version": "0.6.3",
4-
"description": "AI-DDTK MCP server for LocalWP, pw-auth, wp-ajax-test, tmux, and WPCC tools/resources",
3+
"version": "0.9.0",
4+
"description": "AI-DDTK MCP server for LocalWP, pw-auth, wp-ajax-test, tmux, WPCC, Query Monitor, and end-of-day session cleanup workflows",
55
"type": "module",
66
"main": "dist/src/index.js",
77
"bin": {
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
import path from "node:path";
2+
import { ExecFileTextError, execFileText, type ExecFileText, type ExecResult } from "../utils/exec.js";
3+
4+
const DEFAULT_TIMEOUT_MS = 30_000;
5+
6+
export type EndOfDayMode = "report" | "commit" | "push";
7+
8+
export type EndOfDayCheckResult = Record<string, unknown> & {
9+
check: string;
10+
status: "ok" | "missing" | "stale" | "dirty" | "error";
11+
message: string;
12+
};
13+
14+
export type EndOfDayResult = Record<string, unknown> & {
15+
mode: EndOfDayMode;
16+
dryRun: boolean;
17+
force: boolean;
18+
checks: EndOfDayCheckResult[];
19+
gitBranch: string;
20+
gitState: "clean" | "dirty";
21+
modifiedFiles: number;
22+
untrackedFiles: number;
23+
stdout: string;
24+
stderr: string;
25+
exitCode: number;
26+
};
27+
28+
export interface EndOfDayHandlerDeps {
29+
repoRoot: string;
30+
timeoutMs?: number;
31+
execRunner?: ExecFileText;
32+
}
33+
34+
export function createEndOfDayHandlers(deps: EndOfDayHandlerDeps) {
35+
const { repoRoot, timeoutMs = DEFAULT_TIMEOUT_MS, execRunner = execFileText } = deps;
36+
const scriptPath = path.join(repoRoot, "experimental/end-of-day.sh");
37+
38+
async function runEndOfDay(options: {
39+
mode?: EndOfDayMode;
40+
dryRun?: boolean;
41+
force?: boolean;
42+
skipValidation?: boolean;
43+
}): Promise<EndOfDayResult> {
44+
const { mode = "report", dryRun = false, force = false, skipValidation = false } = options;
45+
46+
const args: string[] = [];
47+
48+
if (mode === "commit") {
49+
args.push("--commit");
50+
} else if (mode === "push") {
51+
args.push("--push");
52+
}
53+
54+
if (force) {
55+
args.push("--force");
56+
}
57+
58+
if (dryRun) {
59+
args.push("--dry-run");
60+
}
61+
62+
if (skipValidation) {
63+
args.push("--no-validate");
64+
}
65+
66+
try {
67+
const result = await execRunner("bash", [scriptPath, ...args], {
68+
cwd: repoRoot,
69+
timeoutMs,
70+
});
71+
72+
// Parse stdout for check results and git state
73+
const lines = result.stdout.split("\n");
74+
const checks: EndOfDayCheckResult[] = [];
75+
let gitBranch = "unknown";
76+
let gitState: "clean" | "dirty" = "clean";
77+
let modifiedFiles = 0;
78+
let untrackedFiles = 0;
79+
80+
for (const line of lines) {
81+
if (line.includes("4X4.md")) {
82+
checks.push({
83+
check: "4X4.md",
84+
status: line.includes("✓") ? "ok" : line.includes("⚠") ? "stale" : "error",
85+
message: line,
86+
});
87+
} else if (line.includes("CHANGELOG.md")) {
88+
checks.push({
89+
check: "CHANGELOG.md",
90+
status: line.includes("✓") ? "ok" : line.includes("⚠") ? "stale" : "error",
91+
message: line,
92+
});
93+
} else if (line.includes("MEMORY.md")) {
94+
checks.push({
95+
check: "MEMORY.md",
96+
status: line.includes("archived") ? "ok" : "ok",
97+
message: line,
98+
});
99+
} else if (line.includes("Build validation")) {
100+
checks.push({
101+
check: "build",
102+
status: line.includes("✓") ? "ok" : "error",
103+
message: line,
104+
});
105+
} else if (line.includes("Branch:")) {
106+
const match = line.match(/Branch:\s+(\S+)/);
107+
if (match) gitBranch = match[1];
108+
} else if (line.includes("Git state:")) {
109+
if (line.includes("clean")) {
110+
gitState = "clean";
111+
} else {
112+
gitState = "dirty";
113+
const modMatch = line.match(/(\d+)\s+modified/);
114+
const untMatch = line.match(/(\d+)\s+untracked/);
115+
if (modMatch) modifiedFiles = parseInt(modMatch[1], 10);
116+
if (untMatch) untrackedFiles = parseInt(untMatch[1], 10);
117+
}
118+
}
119+
}
120+
121+
return {
122+
mode,
123+
dryRun,
124+
force,
125+
checks: checks.length > 0 ? checks : [{ check: "session", status: "ok", message: "Session check complete" }],
126+
gitBranch,
127+
gitState,
128+
modifiedFiles,
129+
untrackedFiles,
130+
stdout: result.stdout,
131+
stderr: result.stderr,
132+
exitCode: result.exitCode,
133+
};
134+
} catch (error) {
135+
if (error instanceof ExecFileTextError) {
136+
return {
137+
mode,
138+
dryRun,
139+
force,
140+
checks: [
141+
{
142+
check: "script",
143+
status: "error",
144+
message: error.message,
145+
},
146+
],
147+
gitBranch: "unknown",
148+
gitState: "clean",
149+
modifiedFiles: 0,
150+
untrackedFiles: 0,
151+
stdout: error.stdout || "",
152+
stderr: error.stderr || error.message,
153+
exitCode: error.exitCode || 2,
154+
};
155+
}
156+
throw error;
157+
}
158+
}
159+
160+
return { runEndOfDay };
161+
}
162+

0 commit comments

Comments
 (0)