@tekyzinc/gsd-t 2.76.10 → 3.10.11
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/CHANGELOG.md +63 -0
- package/README.md +46 -0
- package/bin/gsd-t-unattended-platform.js +381 -0
- package/bin/gsd-t-unattended-safety.js +766 -0
- package/bin/gsd-t-unattended.js +1259 -0
- package/bin/gsd-t.js +14 -3
- package/bin/handoff-lock.js +249 -0
- package/bin/headless-auto-spawn.js +71 -33
- package/commands/gsd-t-help.md +3 -0
- package/commands/gsd-t-resume.md +50 -1
- package/commands/gsd-t-unattended-stop.md +83 -0
- package/commands/gsd-t-unattended-watch.md +290 -0
- package/commands/gsd-t-unattended.md +420 -0
- package/commands/gsd-t-wave.md +1 -1
- package/docs/GSD-T-README.md +17 -0
- package/docs/architecture.md +81 -4
- package/docs/infrastructure.md +104 -0
- package/docs/methodology.md +8 -0
- package/docs/requirements.md +29 -0
- package/docs/unattended-config.md +138 -0
- package/docs/unattended-windows-caveats.md +245 -0
- package/package.json +2 -2
- package/scripts/gsd-t-context-meter.e2e.test.js +1 -1
- package/templates/CLAUDE-global.md +12 -0
package/docs/methodology.md
CHANGED
|
@@ -119,3 +119,11 @@ Between v2.74 and v2.75, GSD-T attempted to cope with context pressure through *
|
|
|
119
119
|
**Structural guarantee.** Because `STOP_THRESHOLD_PCT = 85` and the runway estimator refuses runs that would project past 85%, the runtime's 95% native compact is now structurally unreachable under healthy operation. `halt_type: native-compact` in `.gsd-t/token-metrics.jsonl` is a defect signal — if it appears, the estimator needs re-tuning.
|
|
120
120
|
|
|
121
121
|
**Message content is never logged**: the meter writes only token counts, band names, and error category codes. Never transcript text, never API response bodies, never the API key itself. See `docs/architecture.md` for the full data-flow diagram and `.gsd-t/contracts/context-meter-contract.md` for the schema.
|
|
122
|
+
|
|
123
|
+
## From Runway-Protected Execution to Cross-Session Relay (M36)
|
|
124
|
+
|
|
125
|
+
M34 gave GSD-T a real measurement of how much context window each session had consumed. M35 used that signal to refuse starting new work that would exceed the 85% threshold, auto-spawning a detached headless process instead so the user never had to manually run `/clear`. Both milestones still had a ceiling: the headless continuation was a single shot — it ran one Claude session, and if the milestone wasn't complete when that session exhausted its context, a human had to intervene again to trigger the next continuation. Long-running milestones (multi-day builds, large waves) still required periodic human attention to keep the relay going.
|
|
126
|
+
|
|
127
|
+
M36 (v2.77.10) makes the relay automatic and indefinite. The unattended supervisor (`bin/gsd-t-unattended.js`) is a long-lived OS process, fully detached from any Claude Code terminal session, that drives the relay itself: it spawns a fresh `claude -p "/gsd-t-resume"` worker, waits for it to exit, reads the outcome, and immediately spawns the next worker — repeating until the milestone reaches COMPLETED status or a wall-clock cap is hit. Each worker gets a pristine context window. The `/compact` that inevitably fires in a long session is irrelevant because the *next* session has already started fresh. The supervisor IS the orchestrator of runway handoffs. Safety rails (`bin/gsd-t-unattended-safety.js`) prevent infinite-loop scenarios: gutter detection catches stall patterns, blocker sentinels catch unrecoverable errors, and iteration/hour caps ensure the machine doesn't run forever on a broken state. A cross-platform abstraction layer handles macOS sleep-prevention (`caffeinate`), Linux equivalents, and Windows limitations. From the user's perspective: invoke `/user:gsd-t-unattended`, walk away, and receive a native OS notification when the milestone is done — hours or days later.
|
|
128
|
+
|
|
129
|
+
The in-session watch loop (270-second `ScheduleWakeup` ticks, chosen to stay inside the 5-minute prompt-cache TTL) closes the feedback loop for users who keep a Claude session open. And the `gsd-t-resume` Step 0 auto-reattach means that even a `/clear` or accidental session close is transparent: the next resume detects the live supervisor and silently re-enters the watch loop without any manual step. Taken together, M34 + M35 + M36 form a complete three-layer system: measure the context accurately, refuse to degrade when it runs low, and relay execution automatically across as many fresh sessions as the work requires.
|
package/docs/requirements.md
CHANGED
|
@@ -254,6 +254,15 @@
|
|
|
254
254
|
| REQ-076 | Optimization backlog — detect only, never auto-apply, user promotes or rejects | optimization-backlog | T1–T4 | complete (Wave 4) |
|
|
255
255
|
| REQ-077 | Headless auto-spawn on runway refusal — user never sees a `/clear` prompt | headless-auto-spawn | T1–T5 | complete (Waves 3–4) |
|
|
256
256
|
| REQ-078 | Structural elimination of native compact messages — `halt_type: native-compact` count is 0 during M35 execution | runway-estimator + headless-auto-spawn | T1–T5 (RE), T1–T5 (HAS) | complete (Wave 5) |
|
|
257
|
+
| REQ-079 | `gsd-t unattended` CLI subcommand runs an active milestone to completion unattended on macOS and Linux (24h+ multi-worker relay, detached OS process) | m36-supervisor-core | T1–T5 | complete (M36 Wave 1–2) |
|
|
258
|
+
| REQ-080 | `/user:gsd-t-unattended` slash command launches the supervisor from within a Claude session without blocking the terminal | m36-supervisor-core + m36-watch-loop | T1, T3 | complete (M36 Wave 1–3) |
|
|
259
|
+
| REQ-081 | In-session watch loop ticks every 270s via `ScheduleWakeup` (inside 5-min prompt-cache TTL) to report live supervisor state | m36-watch-loop | T1–T2 | complete (M36 Wave 3) |
|
|
260
|
+
| REQ-082 | `/clear` + `/user:gsd-t-resume` during a live unattended run transparently re-attaches to the watch loop (Step 0 auto-reattach, no user-visible disruption) | m36-watch-loop | T4 | complete (M36 Wave 3) |
|
|
261
|
+
| REQ-083 | Supervisor survives `/compact` and context resets — each worker is a fresh `claude -p` session; context exhaustion is structurally irrelevant | m36-supervisor-core | T1–T5 | complete (M36 Wave 1–2) |
|
|
262
|
+
| REQ-084 | Safety rails prevent infinite loops: gutter detection, blocker sentinels (`BLOCKED_NEEDS_HUMAN`, `DISPATCH_FAILED`), max-hours and max-iterations timeouts | m36-safety-rails | T1–T5 | complete (M36 Wave 2) |
|
|
263
|
+
| REQ-085 | Cross-platform support — macOS (caffeinate sleep-prevention) + Linux (systemd-inhibit or no-op) + Windows (claude.cmd via PATH; sleep-prevention not supported — see docs/unattended-windows-caveats.md) | m36-cross-platform | T1–T5 | complete (M36 Wave 2) |
|
|
264
|
+
| REQ-086 | Handoff-lock primitive (`bin/handoff-lock.js`) eliminates parent/child race in `headless-auto-spawn.js` runway handoffs (M35 gap fix) | m36-m35-gap-fixes | T1–T3 | complete (M36 Wave 2) |
|
|
265
|
+
| REQ-087 | 5 command files no longer emit "Run /clear" STOP — runway-exceeded handoff auto-invokes `autoSpawnHeadless()` seamlessly (M35 gap fix) | m36-m35-gap-fixes | T3 | complete (M36 Wave 3) |
|
|
257
266
|
|
|
258
267
|
**M35 Functional Requirements:**
|
|
259
268
|
- **REQ-069**: `bin/token-budget.js` `getDegradationActions()` must return `{band: 'normal'|'warn'|'stop', pct: number, message: string}` only. No `modelOverride`, no `skipPhases`, no `checkpoint` side-channel.
|
|
@@ -276,6 +285,26 @@
|
|
|
276
285
|
**Orphaned requirements**: None — all M35 REQs mapped to tasks.
|
|
277
286
|
**Unanchored tasks**: None — all 38 M35 tasks trace to REQ-069–REQ-078 or REQ-063–068 (existing requirements that M35 code continues to satisfy).
|
|
278
287
|
|
|
288
|
+
**M36 Functional Requirements:**
|
|
289
|
+
- **REQ-079**: `bin/gsd-t-unattended.js` implements the supervisor relay loop: spawn worker → await exit → post-worker safety check → next iter. State written atomically to `.gsd-t/.unattended/state.json`. Contract: `unattended-supervisor-contract.md` v1.0.0.
|
|
290
|
+
- **REQ-080**: `commands/gsd-t-unattended.md` pre-flights branch + dirty tree, spawns supervisor detached, polls for PID readiness, displays initial watch block, and calls `ScheduleWakeup(270, '/user:gsd-t-unattended-watch')`.
|
|
291
|
+
- **REQ-081**: `commands/gsd-t-unattended-watch.md` implements the watch tick decision tree (§8 of contract): reads PID → liveness probe → reads state.json → reschedule or terminal report.
|
|
292
|
+
- **REQ-082**: `commands/gsd-t-resume.md` Step 0 checks `supervisor.pid` before any other resume logic. If live + non-terminal: skip normal resume, print watch block, call `ScheduleWakeup(270, '/user:gsd-t-unattended-watch')`.
|
|
293
|
+
- **REQ-083**: Supervisor relay architecture ensures each worker gets a fresh context window. No compaction state carries over between workers — only `.gsd-t/` milestone state files.
|
|
294
|
+
- **REQ-084**: `bin/gsd-t-unattended-safety.js` exports: `checkGitBranch`, `checkWorktreeCleanliness`, `validateState`, `checkIterationCap`, `checkWallClockCap`, `detectBlockerSentinel`, `detectGutter`. Called at all 4 supervisor hook points.
|
|
295
|
+
- **REQ-085**: `bin/gsd-t-unattended-platform.js` exports: `spawnSupervisor`, `preventSleep`, `releaseSleep`, `notify`, `resolveClaudePath`. Windows: `preventSleep` is a documented no-op. Windows caveats documented in `docs/unattended-windows-caveats.md`.
|
|
296
|
+
- **REQ-086**: `bin/handoff-lock.js` exports: `acquireLock(dir)`, `releaseLock(dir)`, `isLocked(dir)`. Used in `bin/headless-auto-spawn.js` `autoSpawnHeadless()` to guard the parent-exits-before-child-starts window.
|
|
297
|
+
- **REQ-087**: `commands/gsd-t-execute.md`, `gsd-t-wave.md`, `gsd-t-integrate.md`, `gsd-t-quick.md`, `gsd-t-debug.md` — runway-exceeded path calls `autoSpawnHeadless()` and exits cleanly. No "Run /clear" instruction emitted.
|
|
298
|
+
|
|
299
|
+
**M36 Non-Functional Requirements:**
|
|
300
|
+
- Zero external npm dependencies (all M36 bin/ modules use Node.js built-ins only)
|
|
301
|
+
- Supervisor launch → PID-ready in < 5 seconds (poll timeout in launch command)
|
|
302
|
+
- Worker spawn overhead: < 500ms before `claude -p` subprocess starts
|
|
303
|
+
- Test count: 1146 → 1226 (+80 net new tests across 6 M36 domain test files)
|
|
304
|
+
|
|
305
|
+
**Orphaned requirements**: None — all M36 REQs mapped to tasks.
|
|
306
|
+
**Unanchored tasks**: None — all M36 tasks trace to REQ-079–REQ-087.
|
|
307
|
+
|
|
279
308
|
---
|
|
280
309
|
|
|
281
310
|
## M17: Scan Visual Output — Feature Specification
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# Unattended Supervisor — Configuration File
|
|
2
|
+
|
|
3
|
+
**File**: `.gsd-t/.unattended/config.json` (optional, per-project)
|
|
4
|
+
**Contract reference**: `.gsd-t/contracts/unattended-supervisor-contract.md` §13
|
|
5
|
+
**Loader**: `bin/gsd-t-unattended-safety.js` → `loadConfig(projectDir)`
|
|
6
|
+
**Consumer**: `bin/gsd-t-unattended.js` (supervisor entrypoint)
|
|
7
|
+
|
|
8
|
+
The unattended supervisor reads an optional JSON config file at
|
|
9
|
+
`.gsd-t/.unattended/config.json`. If present, its fields override the
|
|
10
|
+
hardcoded defaults. If absent, the supervisor runs with the defaults below.
|
|
11
|
+
Malformed JSON fails the launch with exit code 2 (preflight-failure) — the
|
|
12
|
+
supervisor never silently falls back on a broken config.
|
|
13
|
+
|
|
14
|
+
## Precedence
|
|
15
|
+
|
|
16
|
+
From highest to lowest:
|
|
17
|
+
|
|
18
|
+
1. **CLI flags** passed to `/user:gsd-t-unattended` (e.g. `--hours=48`)
|
|
19
|
+
2. **Environment variables** (`GSD_T_HOURS`, `GSD_T_MAX_ITERATIONS`, etc.)
|
|
20
|
+
3. **`.gsd-t/.unattended/config.json`** fields
|
|
21
|
+
4. **Hardcoded defaults** in `bin/gsd-t-unattended-safety.js` → `DEFAULTS`
|
|
22
|
+
|
|
23
|
+
A CLI flag always wins. An env var beats the config file. The config file
|
|
24
|
+
beats the built-in defaults. Missing fields fall through to the next level
|
|
25
|
+
individually — a config with only `protectedBranches` still uses the default
|
|
26
|
+
`hours`, `maxIterations`, etc.
|
|
27
|
+
|
|
28
|
+
## Schema
|
|
29
|
+
|
|
30
|
+
```json
|
|
31
|
+
{
|
|
32
|
+
"hours": 24,
|
|
33
|
+
"maxIterations": 200,
|
|
34
|
+
"protectedBranches": ["main", "master", "develop", "trunk", "release/*", "hotfix/*"],
|
|
35
|
+
"dirtyTreeWhitelist": [
|
|
36
|
+
".gsd-t/heartbeat-*.jsonl",
|
|
37
|
+
".gsd-t/.context-meter-state.json",
|
|
38
|
+
".gsd-t/events/*.jsonl",
|
|
39
|
+
".gsd-t/token-metrics.jsonl",
|
|
40
|
+
".gsd-t/token-log.md",
|
|
41
|
+
".gsd-t/.unattended/*",
|
|
42
|
+
".gsd-t/.handoff/*",
|
|
43
|
+
".claude/settings.local.json",
|
|
44
|
+
".claude/settings.local.json.bak*"
|
|
45
|
+
],
|
|
46
|
+
"gutterNoProgressIters": 5,
|
|
47
|
+
"workerTimeoutMs": 3600000
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Field reference
|
|
52
|
+
|
|
53
|
+
| Field | Type | Default | Purpose |
|
|
54
|
+
|---|---|---|---|
|
|
55
|
+
| `hours` | number | `24` | Wall-clock cap in hours. Supervisor exits with code 6 (gutter) once `wallClockElapsedMs >= hours * 3600 * 1000`. |
|
|
56
|
+
| `maxIterations` | integer | `200` | Iteration cap. Supervisor exits with code 6 once `iter >= maxIterations`. |
|
|
57
|
+
| `protectedBranches` | string[] | `["main","master","develop","trunk","release/*","hotfix/*"]` | Branches where the pre-launch guard refuses to spawn. Glob patterns supported (`*`, `**`, `?`). Empty array = no branch protection. |
|
|
58
|
+
| `dirtyTreeWhitelist` | string[] | (see defaults) | Files that can be dirty without triggering the clean-worktree refusal. Glob patterns supported. Non-whitelisted dirty files cause exit code 8. |
|
|
59
|
+
| `gutterNoProgressIters` | integer | `5` | Lookback window for the no-progress gutter detector. Larger = less sensitive. |
|
|
60
|
+
| `workerTimeoutMs` | integer | `3600000` (1h) | Hard wall-clock timeout for a single `claude -p` worker iteration. Exceeding this causes worker SIGTERM + exit code 3. |
|
|
61
|
+
|
|
62
|
+
## Common Overrides
|
|
63
|
+
|
|
64
|
+
### Solo project — commit directly to main
|
|
65
|
+
|
|
66
|
+
For projects where you're the only contributor and main is your working
|
|
67
|
+
branch, disable the protected-branch guard:
|
|
68
|
+
|
|
69
|
+
```json
|
|
70
|
+
{
|
|
71
|
+
"protectedBranches": []
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
The safety rail still runs, but with an empty list nothing matches, so the
|
|
76
|
+
guard always allows. The Destructive Action Guard, blocker sentinels, caps,
|
|
77
|
+
and Red Team are all still active — you're only opting out of one specific
|
|
78
|
+
check.
|
|
79
|
+
|
|
80
|
+
### Long overnight runs
|
|
81
|
+
|
|
82
|
+
Raise the caps for multi-day unattended milestones:
|
|
83
|
+
|
|
84
|
+
```json
|
|
85
|
+
{
|
|
86
|
+
"hours": 72,
|
|
87
|
+
"maxIterations": 600
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Extra-noisy project
|
|
92
|
+
|
|
93
|
+
If your project writes logs or caches outside the default whitelist and you
|
|
94
|
+
don't want to commit or stash them before each run:
|
|
95
|
+
|
|
96
|
+
```json
|
|
97
|
+
{
|
|
98
|
+
"dirtyTreeWhitelist": [
|
|
99
|
+
".gsd-t/heartbeat-*.jsonl",
|
|
100
|
+
".gsd-t/.context-meter-state.json",
|
|
101
|
+
".gsd-t/events/*.jsonl",
|
|
102
|
+
".gsd-t/token-metrics.jsonl",
|
|
103
|
+
".gsd-t/token-log.md",
|
|
104
|
+
".gsd-t/.unattended/*",
|
|
105
|
+
".gsd-t/.handoff/*",
|
|
106
|
+
".claude/settings.local.json",
|
|
107
|
+
"logs/**",
|
|
108
|
+
"tmp/**",
|
|
109
|
+
"*.local.cache"
|
|
110
|
+
]
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Whitelist is a replacement, not an append. If you override it, restate the
|
|
115
|
+
defaults you want to keep.
|
|
116
|
+
|
|
117
|
+
## Validation
|
|
118
|
+
|
|
119
|
+
The loader in `bin/gsd-t-unattended-safety.js` merges field-by-field. Only
|
|
120
|
+
the fields you set are overridden — everything else keeps its default. If
|
|
121
|
+
the file exists but isn't valid JSON, the launcher aborts with:
|
|
122
|
+
|
|
123
|
+
```
|
|
124
|
+
[gsd-t-unattended] preflight-failure: safety-rails: malformed JSON in
|
|
125
|
+
.gsd-t/.unattended/config.json: <parse error>
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
and exits with code 2. The PID file, state file, and run log are never
|
|
129
|
+
written on a preflight failure.
|
|
130
|
+
|
|
131
|
+
## Git
|
|
132
|
+
|
|
133
|
+
`.gsd-t/.unattended/` is in the dirty-tree whitelist, so you can either:
|
|
134
|
+
- **Commit the config** — makes it part of the project's canonical setup
|
|
135
|
+
- **Gitignore the config** — treat it as a per-developer preference
|
|
136
|
+
|
|
137
|
+
Both work. There's no preferred choice — it depends on whether your team
|
|
138
|
+
wants a uniform cap across machines or lets each developer tune their own.
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
# Unattended Supervisor — Windows Caveats (v1.0.0)
|
|
2
|
+
|
|
3
|
+
**Status**: Windows support is **shipping but caveated** in v1.0.0.
|
|
4
|
+
|
|
5
|
+
**Contract reference**: `.gsd-t/contracts/unattended-supervisor-contract.md` v1.0.0
|
|
6
|
+
**Platform module**: `bin/gsd-t-unattended-platform.js`
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 0. Required Software (All Platforms)
|
|
11
|
+
|
|
12
|
+
The launch command (`/user:gsd-t-unattended`) pre-flights required software in
|
|
13
|
+
Step 1e and refuses to spawn if anything is missing. Install these before
|
|
14
|
+
launching:
|
|
15
|
+
|
|
16
|
+
**Required everywhere (hard-fail):**
|
|
17
|
+
|
|
18
|
+
| Tool | Install |
|
|
19
|
+
|---------|---------------------------------------------------------------|
|
|
20
|
+
| node | https://nodejs.org (>= 16) |
|
|
21
|
+
| claude | `npm install -g @anthropic-ai/claude-code` |
|
|
22
|
+
| git | https://git-scm.com/downloads |
|
|
23
|
+
|
|
24
|
+
**macOS — soft warnings (install for best reliability):**
|
|
25
|
+
|
|
26
|
+
| Tool | Purpose | Install |
|
|
27
|
+
|-------------|--------------------------|---------------------|
|
|
28
|
+
| caffeinate | sleep prevention | built-in (Apple) |
|
|
29
|
+
|
|
30
|
+
**Linux — soft warnings:**
|
|
31
|
+
|
|
32
|
+
| Tool | Purpose | Install |
|
|
33
|
+
|---------------------------|-----------------------------|--------------------------------------------|
|
|
34
|
+
| systemd-inhibit OR caffeine | sleep/screen-lock prevention | usually preinstalled; else `sudo apt install caffeine` |
|
|
35
|
+
| notify-send | desktop notifications | `sudo apt install libnotify-bin` |
|
|
36
|
+
|
|
37
|
+
**Windows — soft warnings:**
|
|
38
|
+
|
|
39
|
+
| Tool | Purpose | Install |
|
|
40
|
+
|--------------------|------------------------------|----------------------------------------|
|
|
41
|
+
| PowerShell | sleep prevention (built-in) | ships with Windows |
|
|
42
|
+
| BurntToast | real toast notifications | `Install-Module BurntToast` (PowerShell) |
|
|
43
|
+
|
|
44
|
+
If the pre-flight fails, the launcher prints each missing tool with its
|
|
45
|
+
install instructions and refuses to spawn. Soft warnings are advisory only —
|
|
46
|
+
the supervisor still launches without them, but with degraded resilience.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## 1. Overview
|
|
51
|
+
|
|
52
|
+
The GSD-T unattended supervisor (M36) ships cross-platform. All core supervisor
|
|
53
|
+
mechanics — the watch loop, state-file lifecycle, worker spawning, stop
|
|
54
|
+
sentinel, and safety rails — run unchanged on Windows. The darwin and linux
|
|
55
|
+
code paths are runtime-tested; the win32 code paths are
|
|
56
|
+
**implementation-complete but not runtime-tested on the dev host (macOS)**.
|
|
57
|
+
|
|
58
|
+
Three OS-integration surfaces have known limitations on Windows:
|
|
59
|
+
|
|
60
|
+
1. **Sleep prevention** — no stock `caffeinate` equivalent ships with Windows.
|
|
61
|
+
2. **Notifications** — `msg.exe` is a minimal fire-and-forget shim with real
|
|
62
|
+
delivery restrictions.
|
|
63
|
+
3. **Process detach** — `spawn(..., { detached: true })` behaves differently
|
|
64
|
+
from POSIX and is not a true daemonization primitive.
|
|
65
|
+
|
|
66
|
+
This document covers what works, what doesn't, the Spike C disposition, and
|
|
67
|
+
the recommended usage pattern. Everything below applies to `win32` only;
|
|
68
|
+
darwin and linux are unaffected.
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## 2. Known Gaps
|
|
73
|
+
|
|
74
|
+
### 2.1 Sleep prevention (no-op on win32)
|
|
75
|
+
|
|
76
|
+
`preventSleep(reason)` in `bin/gsd-t-unattended-platform.js` explicitly
|
|
77
|
+
**returns `null` on win32** and writes a one-line notice to stderr:
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
[platform] sleep prevention not implemented on win32 (see docs/unattended-windows-caveats.md)
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Windows has no stock command-line equivalent of macOS `caffeinate`. The
|
|
84
|
+
native API (`SetThreadExecutionState`) requires a C binding, which violates
|
|
85
|
+
the GSD-T zero-external-dependency constraint for `bin/`. `releaseSleep(null)`
|
|
86
|
+
is a safe no-op, so the supervisor still shuts down cleanly.
|
|
87
|
+
|
|
88
|
+
**Consequence**: if a Windows machine is configured to sleep on its default
|
|
89
|
+
power schedule, a long unattended run will pause (or outright fail) when the
|
|
90
|
+
machine sleeps. The supervisor has no way to prevent this.
|
|
91
|
+
|
|
92
|
+
**Workaround (v1)**: the user must configure Windows power settings manually
|
|
93
|
+
to keep the machine awake for the duration of the run. Microsoft's official
|
|
94
|
+
guidance covers both GUI and command-line approaches:
|
|
95
|
+
|
|
96
|
+
- [powercfg command-line options](https://learn.microsoft.com/en-us/windows-hardware/design/device-experiences/powercfg-command-line-options)
|
|
97
|
+
- [Change power plan settings](https://support.microsoft.com/en-us/windows/change-power-mode-for-your-windows-pc-c2aff038-22f9-f46a-8ca1-ba5be2b6a7b9)
|
|
98
|
+
|
|
99
|
+
Useful examples:
|
|
100
|
+
|
|
101
|
+
```powershell
|
|
102
|
+
# Disable sleep while on AC power (requires admin)
|
|
103
|
+
powercfg /change standby-timeout-ac 0
|
|
104
|
+
|
|
105
|
+
# Disable sleep while on battery (requires admin)
|
|
106
|
+
powercfg /change standby-timeout-dc 0
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### 2.2 Notifications (`msg.exe`, interactive-session only)
|
|
110
|
+
|
|
111
|
+
`notify(title, message, level)` in `bin/gsd-t-unattended-platform.js` uses
|
|
112
|
+
`msg.exe * "title: message"` on win32 with `windowsHide: true`. This is a
|
|
113
|
+
deliberate minimal fire-and-forget dependency: `msg.exe` ships with Windows
|
|
114
|
+
and has zero install cost.
|
|
115
|
+
|
|
116
|
+
**Restrictions**:
|
|
117
|
+
|
|
118
|
+
- `msg.exe` only delivers to **interactive Windows sessions**. If the
|
|
119
|
+
supervisor is launched under a Windows Service, a non-interactive ssh
|
|
120
|
+
session, or any other session without a desktop attached, `msg.exe` will
|
|
121
|
+
silently drop the notification (or fail with an access error). The
|
|
122
|
+
supervisor core is unaffected — the `child.on('error', ...)` handler logs
|
|
123
|
+
the failure to stderr and the relay loop continues.
|
|
124
|
+
- `msg.exe` is not a true toast / Action Center notification. It pops a
|
|
125
|
+
blocking message-box dialog into the active session. This is visible and
|
|
126
|
+
audible but is not the modern Windows notification experience.
|
|
127
|
+
|
|
128
|
+
**Recommended v2 enhancement**: integrate a real toast API such as
|
|
129
|
+
[`BurntToast`](https://github.com/Windos/BurntToast) (a PowerShell module).
|
|
130
|
+
`BurntToast` requires an opt-in install, so it will remain behind a capability
|
|
131
|
+
check; stock installs will fall back to `msg.exe`.
|
|
132
|
+
|
|
133
|
+
### 2.3 Process detach (`detached: true` is not full daemonization)
|
|
134
|
+
|
|
135
|
+
`spawnSupervisor({ binPath, args, cwd })` uses
|
|
136
|
+
`spawn('node', [...], { detached: true, stdio: 'ignore', windowsHide: true })`
|
|
137
|
+
followed by `child.unref()`. On **POSIX** (darwin / linux) this makes the
|
|
138
|
+
child a new process-group leader and the supervisor survives the parent
|
|
139
|
+
terminal closing. On **win32** the same options produce a separate process
|
|
140
|
+
tree but do **not** fully detach the child from the launching console:
|
|
141
|
+
|
|
142
|
+
- Closing the launching terminal window may still deliver a console
|
|
143
|
+
`CTRL_CLOSE_EVENT` to the child and terminate the supervisor.
|
|
144
|
+
- Signing out of the user session will terminate the child along with every
|
|
145
|
+
other user process.
|
|
146
|
+
- There is no equivalent of POSIX `setsid()` purely from Node's `spawn`
|
|
147
|
+
options.
|
|
148
|
+
|
|
149
|
+
**Workarounds**:
|
|
150
|
+
|
|
151
|
+
- Use `start /B` via a shell wrapper to launch the supervisor in a fully
|
|
152
|
+
background-detached process on the current session.
|
|
153
|
+
- For truly-outlive-the-session runs, register the supervisor as a **Windows
|
|
154
|
+
Task Scheduler** task. Task Scheduler manages its own process lifetime
|
|
155
|
+
independent of the interactive session.
|
|
156
|
+
- Run inside **WSL2** (see §5) to get POSIX detach semantics end-to-end.
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## 3. Spike C Disposition — Sleep Prevention Alternatives
|
|
161
|
+
|
|
162
|
+
Spike C was an exploratory investigation of Windows-native alternatives to
|
|
163
|
+
`caffeinate`. The question: can we keep the zero-dependency constraint and
|
|
164
|
+
still prevent sleep?
|
|
165
|
+
|
|
166
|
+
Three candidates were evaluated:
|
|
167
|
+
|
|
168
|
+
| Option | Mechanism | Verdict |
|
|
169
|
+
|--------|-----------|---------|
|
|
170
|
+
| `SetThreadExecutionState` Win32 API via `ffi` | Native API, exactly what caffeinate maps to. | **Reject.** Requires `ffi-napi` or equivalent — a C binding and a compiled native dep. Violates the zero-external-dependency constraint for `bin/`. |
|
|
171
|
+
| `powercfg` toggle | CLI that ships with Windows. `powercfg /change standby-timeout-ac 0` before run, restore after. | **Reject.** Requires administrator privileges. Persists across runs if the supervisor crashes mid-run, leaving the machine in a modified power state. Hard to guarantee restoration. |
|
|
172
|
+
| Task Scheduler "wake to run" / wake events | Scheduled task can force the machine to wake at interval. | **Defer.** Best user-space path but adds non-trivial scheduler management code (create task, tear down on exit, handle orphaned tasks). |
|
|
173
|
+
|
|
174
|
+
**Verdict**: **defer to v2.** v1.0.0 ships with the `null`-handle + documentation
|
|
175
|
+
approach described in §2.1. v2 will consider Task Scheduler integration as the
|
|
176
|
+
primary path, since it is the only candidate that is both user-space and
|
|
177
|
+
compatible with the zero-dependency constraint.
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## 4. What Works Today on Windows
|
|
182
|
+
|
|
183
|
+
All of the following run on Windows with no caveats (pending runtime testing
|
|
184
|
+
on a real Windows host; implementation is complete):
|
|
185
|
+
|
|
186
|
+
- **Core supervisor process** — runs to completion, observes the state file,
|
|
187
|
+
dispatches workers, honours the watch-loop cadence, and exits cleanly.
|
|
188
|
+
- **State file lifecycle** — atomic write, lockfile, heartbeat updates, and
|
|
189
|
+
teardown all use Node built-ins and behave identically on win32.
|
|
190
|
+
- **Worker spawning** — `spawnWorker(projectDir, timeoutMs)` uses `claude.cmd`
|
|
191
|
+
via `resolveClaudePath()` with `shell: false` and `windowsHide: true`, which
|
|
192
|
+
avoids the Spike C PowerShell quoting hazard.
|
|
193
|
+
- **Stop sentinel** — sentinel-file detection is filesystem-based and is
|
|
194
|
+
cross-platform by construction.
|
|
195
|
+
- **Safety rails** — `isAlive(pid)` uses Node's `process.kill(pid, 0)`, which
|
|
196
|
+
implements POSIX signal-0 semantics on Windows. Liveness checks, watchdog
|
|
197
|
+
timers, and stuck-worker detection all work unchanged.
|
|
198
|
+
|
|
199
|
+
Exit code table (contract §5), heartbeat contract, and the launch-handshake
|
|
200
|
+
file contract are all platform-agnostic and fully honoured on win32.
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## 5. Recommended Usage Pattern on Windows
|
|
205
|
+
|
|
206
|
+
Given the gaps above, the recommended way to run the unattended supervisor on
|
|
207
|
+
Windows for v1.0.0 is:
|
|
208
|
+
|
|
209
|
+
1. **Run on a desktop that never sleeps.** Configure Windows power settings so
|
|
210
|
+
the machine will not sleep, hibernate, or turn off the display for the
|
|
211
|
+
expected duration of the run. Use `powercfg` or the Settings UI (see §2.1).
|
|
212
|
+
2. **Launch from an interactive PowerShell session** (not a Windows Service,
|
|
213
|
+
not a non-interactive ssh session). This ensures `msg.exe` notifications
|
|
214
|
+
can be delivered and that the supervisor's stderr diagnostics are visible.
|
|
215
|
+
3. **Monitor via the watch-tick command from the same interactive session.**
|
|
216
|
+
Do not close the launching terminal until the supervisor exits — see §2.3
|
|
217
|
+
for why.
|
|
218
|
+
4. **Consider running inside WSL2** instead of native Windows. WSL2 provides a
|
|
219
|
+
full Linux userland where `bin/gsd-t-unattended-platform.js` takes the
|
|
220
|
+
`linux` branch everywhere: `isAlive`, `spawnWorker`, `spawnSupervisor`, and
|
|
221
|
+
`notify` all behave with POSIX semantics end-to-end. The only remaining gap
|
|
222
|
+
in WSL2 is sleep prevention (linux also returns `null` from `preventSleep`
|
|
223
|
+
in v1.0.0), which is still governed by the host Windows machine's power
|
|
224
|
+
settings. WSL2 is currently the closest thing to the full darwin / linux
|
|
225
|
+
feature set on a Windows box.
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## 6. Summary Matrix
|
|
230
|
+
|
|
231
|
+
| Feature | darwin | linux | win32 |
|
|
232
|
+
|--------------------------|-----------|-----------|------------------------------------------------|
|
|
233
|
+
| `resolveClaudePath` | `claude` | `claude` | `claude.cmd` |
|
|
234
|
+
| `isAlive(pid)` | works | works | works (POSIX signal-0 semantics) |
|
|
235
|
+
| `spawnWorker` | works | works | implementation-complete, untested on real host |
|
|
236
|
+
| `spawnSupervisor` detach | full | full | partial — console-close may kill child |
|
|
237
|
+
| `preventSleep` | works | null (v1) | null (v1) — see §2.1 and §3 |
|
|
238
|
+
| `releaseSleep` | works | no-op | no-op |
|
|
239
|
+
| `notify` | works | works | works only in interactive sessions (§2.2) |
|
|
240
|
+
|
|
241
|
+
**v2 roadmap (non-binding)**:
|
|
242
|
+
- Linux: opt-in `systemd-inhibit` for sleep prevention.
|
|
243
|
+
- Windows: Task Scheduler integration for sleep prevention; `BurntToast`
|
|
244
|
+
capability check for real toast notifications; optional Task-Scheduler-based
|
|
245
|
+
daemonization path for true detachment.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tekyzinc/gsd-t",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "GSD-T: Contract-Driven Development for Claude Code —
|
|
3
|
+
"version": "3.10.11",
|
|
4
|
+
"description": "GSD-T: Contract-Driven Development for Claude Code — 61 slash commands with unattended supervisor relay, headless CI/CD mode, graph-powered code analysis, real-time agent dashboard, execution intelligence, task telemetry, doc-ripple enforcement, backlog management, impact analysis, test sync, milestone archival, and PRD generation",
|
|
5
5
|
"author": "Tekyz, Inc.",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|
|
@@ -44,7 +44,7 @@ const os = require("node:os");
|
|
|
44
44
|
|
|
45
45
|
const HOOK_SCRIPT = path.resolve(__dirname, "gsd-t-context-meter.js");
|
|
46
46
|
const INJECTOR = path.resolve(__dirname, "context-meter", "test-injector.js");
|
|
47
|
-
const HARD_TIMEOUT_MS =
|
|
47
|
+
const HARD_TIMEOUT_MS = 12000;
|
|
48
48
|
|
|
49
49
|
/* ──────────────────────────── test fixtures ──────────────────────────── */
|
|
50
50
|
|
|
@@ -68,6 +68,9 @@ PROJECT or FEATURE or SCAN
|
|
|
68
68
|
| `/user:gsd-t-resume` | Restore context, continue |
|
|
69
69
|
| `/user:gsd-t-version-update` | Update GSD-T to latest version |
|
|
70
70
|
| `/user:gsd-t-version-update-all` | Update GSD-T + all registered projects |
|
|
71
|
+
| `/user:gsd-t-unattended` | Launch detached supervisor — runs active milestone to completion with zero human intervention |
|
|
72
|
+
| `/user:gsd-t-unattended-watch` | Watch tick — fires every 270s via ScheduleWakeup, reports supervisor status |
|
|
73
|
+
| `/user:gsd-t-unattended-stop` | Touch stop sentinel — supervisor halts after current worker finishes |
|
|
71
74
|
| `/user:gsd-t-triage-and-merge` | Auto-review, merge, and publish GitHub branches |
|
|
72
75
|
| `/user:gsd-t-audit` | Harness self-audit — analyze cost/benefit of enforcement components |
|
|
73
76
|
| `/user:gsd-t-design-audit` | Compare built screen against Figma design — structured deviation report |
|
|
@@ -398,6 +401,15 @@ KEEP GOING. Only stop for:
|
|
|
398
401
|
3. Milestone completion (checkpoint for user review)
|
|
399
402
|
4. Destructive actions (see Destructive Action Guard above — ALWAYS stop)
|
|
400
403
|
|
|
404
|
+
## Unattended Execution (M36, v3.10.10+)
|
|
405
|
+
|
|
406
|
+
`/user:gsd-t-unattended` launches a detached OS-process supervisor that drives the active milestone to completion over hours or days via a `claude -p` worker relay — each worker in a fresh context window. The interactive Claude session receives a 270-second ScheduleWakeup watch loop (`/user:gsd-t-unattended-watch`) that ticks and prints progress until the supervisor reaches a terminal state.
|
|
407
|
+
|
|
408
|
+
- **Resume re-attach**: `/user:gsd-t-resume` checks for a live `supervisor.pid`; if the supervisor is still running, it skips normal resume and re-starts the watch loop automatically.
|
|
409
|
+
- **Stop**: `/user:gsd-t-unattended-stop` touches `.gsd-t/.unattended/stop`; supervisor halts after the current worker finishes.
|
|
410
|
+
- **Contract**: `.gsd-t/contracts/unattended-supervisor-contract.md` v1.0.0 — authoritative for state schema, exit codes, CLI flags, and platform matrix.
|
|
411
|
+
- **Platform**: macOS and Linux fully supported. Windows supported except sleep-prevention (see `docs/unattended-windows-caveats.md`).
|
|
412
|
+
|
|
401
413
|
## Pre-Commit Gate (MANDATORY)
|
|
402
414
|
|
|
403
415
|
NEVER commit code without running this checklist. This is not optional.
|