@tekyzinc/gsd-t 3.29.10 → 4.0.12

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.
Files changed (112) hide show
  1. package/CHANGELOG.md +176 -0
  2. package/bin/gsd-t-parallel.cjs +64 -13
  3. package/bin/gsd-t-test-data-adapters/file-json-array.cjs +27 -3
  4. package/bin/gsd-t-test-data-adapters/localstorage-key-prefix.cjs +6 -1
  5. package/bin/gsd-t-test-data-adapters/sqlite-table-where.cjs +16 -1
  6. package/bin/gsd-t-test-data-ledger.cjs +1 -0
  7. package/bin/gsd-t.js +48 -376
  8. package/bin/journey-coverage.cjs +6 -3
  9. package/bin/parallel-cli.cjs +13 -1
  10. package/commands/gsd-t-debug.md +47 -533
  11. package/commands/gsd-t-design-decompose.md +24 -497
  12. package/commands/gsd-t-doc-ripple.md +23 -139
  13. package/commands/gsd-t-execute.md +41 -958
  14. package/commands/gsd-t-help.md +0 -2
  15. package/commands/gsd-t-impact.md +26 -295
  16. package/commands/gsd-t-integrate.md +44 -369
  17. package/commands/gsd-t-milestone.md +25 -124
  18. package/commands/gsd-t-partition.md +28 -539
  19. package/commands/gsd-t-plan.md +26 -472
  20. package/commands/gsd-t-prd.md +25 -311
  21. package/commands/gsd-t-quick.md +1 -1
  22. package/commands/gsd-t-resume.md +0 -33
  23. package/commands/gsd-t-verify.md +52 -569
  24. package/commands/gsd-t-wave.md +41 -430
  25. package/package.json +1 -1
  26. package/scripts/gsd-t-calibration-hook.js +3 -1
  27. package/scripts/hooks/pre-commit-journey-coverage +0 -2
  28. package/scripts/hooks/pre-commit-playwright-gate +0 -2
  29. package/templates/CLAUDE-global.md +43 -173
  30. package/templates/CLAUDE-project.md +118 -104
  31. package/templates/prompts/design-verify-subagent.md +3 -0
  32. package/templates/prompts/qa-subagent.md +3 -0
  33. package/templates/prompts/red-team-subagent.md +5 -2
  34. package/templates/workflows/_lib.js +176 -0
  35. package/templates/workflows/gsd-t-debug.workflow.js +86 -0
  36. package/templates/workflows/gsd-t-execute.workflow.js +206 -0
  37. package/templates/workflows/gsd-t-integrate.workflow.js +71 -0
  38. package/templates/workflows/gsd-t-phase.workflow.js +94 -0
  39. package/templates/workflows/gsd-t-quick.workflow.js +72 -0
  40. package/templates/workflows/gsd-t-verify.workflow.js +348 -0
  41. package/templates/workflows/gsd-t-wave.workflow.js +43 -0
  42. package/bin/check-headless-sessions.js +0 -140
  43. package/bin/context-budget-audit.cjs +0 -447
  44. package/bin/context-meter-config.cjs +0 -101
  45. package/bin/context-meter-config.test.cjs +0 -101
  46. package/bin/event-stream.cjs +0 -205
  47. package/bin/gsd-t-benchmark-orchestrator.js +0 -437
  48. package/bin/gsd-t-capture-lint.cjs +0 -440
  49. package/bin/gsd-t-economics.cjs +0 -315
  50. package/bin/gsd-t-in-session-usage.cjs +0 -213
  51. package/bin/gsd-t-orchestrator-config.cjs +0 -161
  52. package/bin/gsd-t-orchestrator-queue.cjs +0 -180
  53. package/bin/gsd-t-orchestrator-recover.cjs +0 -231
  54. package/bin/gsd-t-orchestrator-worker.cjs +0 -219
  55. package/bin/gsd-t-orchestrator.js +0 -535
  56. package/bin/gsd-t-parallel-probe.cjs +0 -132
  57. package/bin/gsd-t-ratelimit-probe-worker.cjs +0 -237
  58. package/bin/gsd-t-ratelimit-probe.cjs +0 -648
  59. package/bin/gsd-t-report-tokens.cjs +0 -549
  60. package/bin/gsd-t-stream-feed-client.cjs +0 -151
  61. package/bin/gsd-t-token-backfill.cjs +0 -366
  62. package/bin/gsd-t-token-capture.cjs +0 -321
  63. package/bin/gsd-t-token-dashboard.cjs +0 -353
  64. package/bin/gsd-t-token-regenerate-log.cjs +0 -129
  65. package/bin/gsd-t-tool-attribution.cjs +0 -377
  66. package/bin/gsd-t-tool-cost.cjs +0 -195
  67. package/bin/gsd-t-transcript-tee.cjs +0 -246
  68. package/bin/gsd-t-unattended-heartbeat.cjs +0 -188
  69. package/bin/gsd-t-unattended-platform.cjs +0 -551
  70. package/bin/gsd-t-unattended-platform.js +0 -381
  71. package/bin/gsd-t-unattended-safety.cjs +0 -773
  72. package/bin/gsd-t-unattended-safety.js +0 -788
  73. package/bin/gsd-t-unattended.cjs +0 -2109
  74. package/bin/gsd-t-unattended.js +0 -1367
  75. package/bin/gsd-t-worker-dispatch.cjs +0 -211
  76. package/bin/handoff-lock.cjs +0 -249
  77. package/bin/handoff-lock.js +0 -249
  78. package/bin/headless-auto-spawn.cjs +0 -711
  79. package/bin/headless-auto-spawn.js +0 -373
  80. package/bin/headless-exit-codes.cjs +0 -67
  81. package/bin/live-activity-report.cjs +0 -615
  82. package/bin/log-tail.cjs +0 -81
  83. package/bin/m44-proof-measure.cjs +0 -285
  84. package/bin/m46-iter-proof.cjs +0 -149
  85. package/bin/m46-worker-proof.cjs +0 -201
  86. package/bin/m55-substrate-proof.cjs +0 -134
  87. package/bin/metrics-rollup.js +0 -200
  88. package/bin/model-windows.cjs +0 -99
  89. package/bin/model-windows.test.cjs +0 -75
  90. package/bin/parallelism-report.cjs +0 -535
  91. package/bin/runway-estimator.cjs +0 -242
  92. package/bin/spawn-plan-derive.cjs +0 -163
  93. package/bin/spawn-plan-status-updater.cjs +0 -292
  94. package/bin/spawn-plan-writer.cjs +0 -204
  95. package/bin/supervisor-pid-fingerprint.cjs +0 -126
  96. package/bin/token-budget.cjs +0 -265
  97. package/bin/unattended-watch-format.cjs +0 -178
  98. package/bin/watch-progress.js +0 -155
  99. package/commands/gsd-t-unattended-stop.md +0 -85
  100. package/commands/gsd-t-unattended-watch.md +0 -465
  101. package/commands/gsd-t-unattended.md +0 -476
  102. package/commands/gsd-t-visualize.md +0 -116
  103. package/scripts/gsd-t-context-meter.e2e.test.js +0 -364
  104. package/scripts/gsd-t-context-meter.js +0 -341
  105. package/scripts/gsd-t-context-meter.test.js +0 -471
  106. package/scripts/gsd-t-dashboard-server.js +0 -1203
  107. package/scripts/gsd-t-post-commit-spawn-plan.sh +0 -86
  108. package/scripts/gsd-t-transcript.html +0 -1821
  109. package/scripts/hooks/gsd-t-conversation-capture.js +0 -439
  110. package/scripts/hooks/gsd-t-in-session-usage-hook.js +0 -84
  111. package/scripts/spawn-plan-fmt-tokens.cjs +0 -80
  112. package/templates/hooks/post-commit-spawn-plan.sh +0 -85
@@ -1,178 +0,0 @@
1
- /**
2
- * bin/unattended-watch-format.cjs
3
- *
4
- * Pure formatter for the unattended watch-tick activity block (M38 ES).
5
- * Given an array of events (as returned by event-stream.readSinceCursor) and
6
- * supervisor state, render the human-scannable output per
7
- * `.gsd-t/contracts/unattended-event-stream-contract.md` §4.
8
- *
9
- * Kept separate from the watch command so it can be unit-tested (ES-T3) and
10
- * so the command itself stays a thin shell wrapper.
11
- */
12
-
13
- "use strict";
14
-
15
- function _groupByIter(events) {
16
- const groups = new Map();
17
- for (const ev of events) {
18
- if (!ev || typeof ev !== "object") continue;
19
- const iter = Number.isFinite(ev.iter) ? ev.iter : 0;
20
- if (!groups.has(iter)) groups.set(iter, []);
21
- groups.get(iter).push(ev);
22
- }
23
- return [...groups.entries()].sort((a, b) => a[0] - b[0]);
24
- }
25
-
26
- function _fmtElapsed(startedAt, now) {
27
- if (!startedAt) return "";
28
- const t = Date.parse(startedAt);
29
- if (!Number.isFinite(t)) return "";
30
- const ms = (now || Date.now()) - t;
31
- const m = Math.floor(ms / 60000);
32
- if (m < 60) return `+${m}m elapsed`;
33
- const h = Math.floor(m / 60);
34
- return `+${h}h${m % 60}m elapsed`;
35
- }
36
-
37
- function _fmtDuration(s) {
38
- if (!Number.isFinite(s) || s < 0) return "";
39
- if (s < 60) return `${s}s`;
40
- const m = Math.floor(s / 60);
41
- return `${m}m ${s % 60}s`;
42
- }
43
-
44
- function _formatIteration(iter, evs) {
45
- const taskStart = evs.find((e) => e.type === "task_start");
46
- const taskComplete = evs.find((e) => e.type === "task_complete");
47
- const fileChanges = evs.filter((e) => e.type === "file_changed");
48
- const testResults = evs.filter((e) => e.type === "test_result");
49
- const verdicts = evs.filter((e) => e.type === "subagent_verdict");
50
- const errors = evs.filter((e) => e.type === "error");
51
- const retries = evs.filter((e) => e.type === "retry");
52
-
53
- const lines = [];
54
- if (taskStart) {
55
- const wave = taskStart.wave ? ` (wave ${taskStart.wave})` : "";
56
- const task = taskStart.task || "(unnamed)";
57
- lines.push(` ▶ task: ${task}${wave}`);
58
- }
59
- if (fileChanges.length > 0) {
60
- const paths = fileChanges.map((e) => e.path || "?").filter(Boolean);
61
- const shown = paths.slice(0, 5).join(", ");
62
- const extra = paths.length > 5 ? ` … and ${paths.length - 5} more` : "";
63
- lines.push(` 📝 ${paths.length} file${paths.length === 1 ? "" : "s"} modified (${shown}${extra})`);
64
- }
65
- for (const tr of testResults) {
66
- const suite = tr.suite || "?";
67
- const pass = Number.isFinite(tr.pass) ? tr.pass : 0;
68
- const total = Number.isFinite(tr.total) ? tr.total : 0;
69
- const mark = (tr.fail || 0) > 0 ? "❌" : "✅";
70
- lines.push(` ${mark} test_result: ${suite} ${pass}/${total} pass`);
71
- }
72
- for (const v of verdicts) {
73
- const agent = v.agent || "?";
74
- const verdict = v.verdict || "?";
75
- const findings = Number.isFinite(v.findings_count) ? ` (${v.findings_count} findings)` : "";
76
- const mark = verdict === "pass" || verdict === "grudging_pass" ? "✅" : "❌";
77
- lines.push(` ${mark} subagent_verdict: ${agent} ${verdict}${findings}`);
78
- }
79
- for (const er of errors) {
80
- lines.push(` ❌ error: ${er.error || "(unknown)"}${er.recoverable ? " [recoverable]" : ""}`);
81
- }
82
- for (const r of retries) {
83
- lines.push(` 🔁 retry: attempt ${r.attempt || iter} — ${r.reason || "?"}`);
84
- }
85
- if (taskComplete) {
86
- const dur = _fmtDuration(taskComplete.duration_s);
87
- const verdict = taskComplete.verdict || "?";
88
- lines.push(` ⏱ duration: ${dur} · verdict: ${verdict}`);
89
- }
90
- return lines;
91
- }
92
-
93
- /**
94
- * Format an activity block for the watch tick.
95
- *
96
- * @param {object} args
97
- * @param {object[]} args.events — events since last cursor (may be empty)
98
- * @param {object} args.state — supervisor state.json contents
99
- * @param {number} [args.now] — override for Date.now() (tests)
100
- * @returns {string}
101
- */
102
- function _renderWatchProgressTree(args) {
103
- // M39 D2 — best-effort watch-progress tree appended below the formatter
104
- // output. Banner preserved verbatim; returns "" on any failure so callers
105
- // never see a tree when state is missing/unavailable.
106
- try {
107
- const wp = require("./watch-progress.js");
108
- const stateDir = (args && args.stateDir) || ".gsd-t/.watch-state";
109
- const current = args && args.currentAgent ? args.currentAgent : null;
110
- const tree = wp.buildTree(stateDir);
111
- return wp.renderTree(tree, { currentAgent: current }) || "";
112
- } catch (_) {
113
- return "";
114
- }
115
- }
116
-
117
- function formatWatchTick(args) {
118
- const events = Array.isArray(args && args.events) ? args.events : [];
119
- const state = (args && args.state) || {};
120
- const now = args && Number.isFinite(args.now) ? args.now : Date.now();
121
-
122
- const elapsed = _fmtElapsed(state.startedAt, now);
123
- const iter = Number.isFinite(state.iter) ? state.iter : 0;
124
- const header = `[unattended supervisor — iter ${iter}${elapsed ? `, ${elapsed}` : ""}]`;
125
-
126
- let body;
127
- if (events.length === 0) {
128
- body = `${header} (no new activity since last tick)`;
129
- } else {
130
- const groups = _groupByIter(events);
131
- const blocks = [];
132
- for (const [groupIter, evs] of groups) {
133
- const groupHeader = groups.length > 1 ? `[iter ${groupIter}]` : header;
134
- const bodyLines = _formatIteration(groupIter, evs);
135
- blocks.push([groupHeader, ...bodyLines].join("\n"));
136
- }
137
- body = groups.length > 1 ? `${header}\n${blocks.join("\n")}` : blocks[0];
138
- }
139
-
140
- // M39 D2 — watch-progress tree below the existing formatter output.
141
- // Banner preserved verbatim; tree appended only when caller opts in via
142
- // `args.withWatchProgress = true`. Default-off preserves backward
143
- // compatibility with existing snapshot-style callers (tests).
144
- if (!(args && args.withWatchProgress === true)) return body;
145
- const tree = _renderWatchProgressTree({
146
- stateDir: args && args.stateDir,
147
- currentAgent: args && (args.currentAgent || state.sessionId),
148
- });
149
- return tree ? `${body}\n${tree}` : body;
150
- }
151
-
152
- /**
153
- * Terminal-status block when supervisor reached `done`/`failed`/`stopped`/`crashed`.
154
- * Returns null if status is not terminal.
155
- */
156
- function formatTerminalBlock(state) {
157
- if (!state || typeof state !== "object") return null;
158
- const s = state.status;
159
- if (s === "done") {
160
- return `🎉 Unattended supervisor COMPLETED the milestone (${state.milestone || "?"}, iter ${state.iter || 0}).`;
161
- }
162
- if (s === "failed") {
163
- return `❌ Unattended supervisor HALTED — status=failed (last exit ${state.lastExit ?? "?"}, iter ${state.iter || 0}).`;
164
- }
165
- if (s === "stopped") {
166
- return `🛑 Unattended supervisor STOPPED by user (iter ${state.iter || 0}).`;
167
- }
168
- if (s === "crashed") {
169
- return `💥 Unattended supervisor CRASHED (iter ${state.iter || 0}).`;
170
- }
171
- return null;
172
- }
173
-
174
- module.exports = {
175
- formatWatchTick,
176
- formatTerminalBlock,
177
- _internal: { _groupByIter, _formatIteration, _fmtElapsed, _fmtDuration },
178
- };
@@ -1,155 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * bin/watch-progress.js — GSD-T Watch-Progress Tree Builder + Renderer
4
- *
5
- * Reads `.gsd-t/.watch-state/*.json` state files written by
6
- * `scripts/gsd-t-watch-state.js` and reconstructs the agent workflow tree
7
- * via `parent_agent_id` lineage. Renders a task-list with ✅/🔄/⬜ markers
8
- * below every `--watch` surface (banner preserved intact).
9
- *
10
- * Contract: `.gsd-t/contracts/watch-progress-contract.md` v1.0.0
11
- * Owner: D2 (M39 `d2-progress-watch`)
12
- * Zero external deps.
13
- */
14
-
15
- "use strict";
16
-
17
- const fs = require("fs");
18
- const path = require("path");
19
-
20
- const STALE_MS = 24 * 60 * 60 * 1000; // 24h
21
-
22
- const MARKERS = {
23
- done: "✅",
24
- in_progress: "🔄",
25
- pending: "⬜",
26
- skipped: "➡️",
27
- failed: "❌",
28
- };
29
-
30
- function _readAll(stateDir) {
31
- if (!stateDir || !fs.existsSync(stateDir)) return [];
32
- let entries;
33
- try {
34
- entries = fs.readdirSync(stateDir);
35
- } catch (_) {
36
- return [];
37
- }
38
- const records = [];
39
- for (const f of entries) {
40
- if (!f.endsWith(".json")) continue;
41
- try {
42
- const raw = fs.readFileSync(path.join(stateDir, f), "utf8");
43
- const rec = JSON.parse(raw);
44
- if (rec && typeof rec === "object" && typeof rec.agent_id === "string") {
45
- records.push(rec);
46
- }
47
- } catch (_) { /* skip malformed */ }
48
- }
49
- return records;
50
- }
51
-
52
- function _isStale(record, now) {
53
- if (!record.completed_at) return false;
54
- const t = Date.parse(record.completed_at);
55
- if (!Number.isFinite(t)) return false;
56
- return (now - t) > STALE_MS;
57
- }
58
-
59
- function buildTree(stateDir, options) {
60
- const now = options && Number.isFinite(options.now) ? options.now : Date.now();
61
- const records = _readAll(stateDir).filter((r) => !_isStale(r, now));
62
- const index = new Map();
63
- for (const r of records) index.set(r.agent_id, { record: r, children: [] });
64
- const roots = [];
65
- const orphans = [];
66
- for (const r of records) {
67
- const node = index.get(r.agent_id);
68
- const parentId = r.parent_agent_id;
69
- if (parentId === null || parentId === undefined) {
70
- roots.push(node);
71
- } else if (index.has(parentId)) {
72
- index.get(parentId).children.push(node);
73
- } else {
74
- orphans.push(node);
75
- }
76
- }
77
- return { roots, orphans };
78
- }
79
-
80
- function _marker(status) {
81
- return MARKERS[status] || MARKERS.pending;
82
- }
83
-
84
- function _countDone(node) {
85
- let count = 0;
86
- const s = node.record.status;
87
- if (s === "done" || s === "skipped") count = 1;
88
- for (const c of node.children) count += _countDone(c);
89
- return count;
90
- }
91
-
92
- function _flattenIds(node, acc) {
93
- acc.push(node.record.agent_id);
94
- for (const c of node.children) _flattenIds(c, acc);
95
- return acc;
96
- }
97
-
98
- function _containsAgent(node, agentId) {
99
- if (!agentId) return false;
100
- return _flattenIds(node, []).includes(agentId);
101
- }
102
-
103
- function _pickCurrent(tree) {
104
- let pick = null;
105
- let latest = -Infinity;
106
- const walk = (node) => {
107
- const r = node.record;
108
- if (r.status === "in_progress" && r.started_at) {
109
- const t = Date.parse(r.started_at);
110
- if (Number.isFinite(t) && t > latest) { latest = t; pick = r.agent_id; }
111
- }
112
- for (const c of node.children) walk(c);
113
- };
114
- for (const root of tree.roots) walk(root);
115
- return pick;
116
- }
117
-
118
- function _renderExpanded(node, depth, lines) {
119
- const indent = " ".repeat(depth);
120
- const r = node.record;
121
- lines.push(`${indent}${_marker(r.status)} ${r.step_label || r.command || r.agent_id}`);
122
- for (const c of node.children) _renderExpanded(c, depth + 1, lines);
123
- }
124
-
125
- function _renderCollapsed(node, depth, lines) {
126
- const indent = " ".repeat(depth);
127
- const r = node.record;
128
- const doneCount = _countDone(node);
129
- const label = r.step_label || r.command || r.agent_id;
130
- lines.push(`${indent}${_marker(r.status)} ${label} (${doneCount} tasks done)`);
131
- }
132
-
133
- function renderTree(tree, options) {
134
- if (!tree || (tree.roots.length === 0 && tree.orphans.length === 0)) return "";
135
- const opts = options || {};
136
- const currentAgent = opts.currentAgent || _pickCurrent(tree);
137
- const lines = [];
138
- for (const root of tree.roots) {
139
- if (_containsAgent(root, currentAgent)) _renderExpanded(root, 0, lines);
140
- else _renderCollapsed(root, 0, lines);
141
- }
142
- if (tree.orphans.length > 0) {
143
- lines.push("⬜ (orphan subtree — parent state missing)");
144
- for (const o of tree.orphans) _renderExpanded(o, 1, lines);
145
- }
146
- return lines.join("\n");
147
- }
148
-
149
- module.exports = { buildTree, renderTree, MARKERS, STALE_MS, _pickCurrent };
150
-
151
- if (require.main === module) {
152
- const stateDir = process.argv[2] || path.join(".gsd-t", ".watch-state");
153
- const out = renderTree(buildTree(stateDir));
154
- if (out) process.stdout.write(out + "\n");
155
- }
@@ -1,85 +0,0 @@
1
- # GSD-T: Unattended Stop — Signal Supervisor to Halt
2
-
3
- **Model**: haiku (trivial sentinel toucher — no reasoning needed)
4
-
5
- You are signaling the unattended supervisor to halt cleanly between worker iterations by writing the stop sentinel file at `.gsd-t/.unattended/stop`. This is a fire-and-forget command: no PID kill, no wait, no confirmation prompt.
6
-
7
- See `unattended-supervisor-contract.md` §10 (Stop Mechanism) for the full handshake.
8
-
9
- ## Step 1: Check Supervisor State Directory Exists
10
-
11
- Run via Bash:
12
-
13
- ```bash
14
- if [ ! -d ".gsd-t/.unattended" ]; then
15
- echo "No supervisor state directory — nothing to stop."
16
- exit 0
17
- fi
18
- ```
19
-
20
- If the directory does not exist, exit 0 (not an error — there is simply nothing to signal).
21
-
22
- ## Step 2: Check Supervisor PID File Exists
23
-
24
- Run via Bash:
25
-
26
- ```bash
27
- if [ ! -f ".gsd-t/.unattended/supervisor.pid" ]; then
28
- echo "No supervisor running in this project (no PID file at .gsd-t/.unattended/supervisor.pid)."
29
- exit 0
30
- fi
31
- ```
32
-
33
- If the PID file is missing, the supervisor has already finalized cleanly. Exit 0 without writing the sentinel.
34
-
35
- ## Step 3: Read Current Session Snapshot
36
-
37
- Run via Bash to grab the session ID and current iteration from `state.json` (best-effort — tolerate missing or partial state):
38
-
39
- ```bash
40
- node -e "
41
- try {
42
- const s = JSON.parse(require('fs').readFileSync('.gsd-t/.unattended/state.json', 'utf8'));
43
- console.log('SESSION=' + (s.sessionId || 'unknown'));
44
- console.log('ITER=' + (s.iter ?? 'unknown'));
45
- console.log('STATUS=' + (s.status || 'unknown'));
46
- } catch (e) {
47
- console.log('SESSION=unknown');
48
- console.log('ITER=unknown');
49
- console.log('STATUS=unknown');
50
- }
51
- "
52
- ```
53
-
54
- ## Step 4: Write the Stop Sentinel
55
-
56
- Write `.gsd-t/.unattended/stop` containing the current ISO timestamp as the body (for diagnostics — the supervisor only checks for the file's existence, not its contents):
57
-
58
- ```bash
59
- node -e "require('fs').writeFileSync('.gsd-t/.unattended/stop', new Date().toISOString())"
60
- ```
61
-
62
- This is race-free, terminal-close-safe, and language-agnostic (per contract §10).
63
-
64
- ## Step 5: Print Confirmation
65
-
66
- Output the confirmation block:
67
-
68
- ```
69
- 🛑 Stop sentinel written. Supervisor will halt after the current worker finishes (up to ~5 min).
70
-
71
- Session: {SESSION from Step 3}
72
- Iter: {ITER from Step 3}
73
- Status: {STATUS from Step 3}
74
-
75
- The current worker runs to completion. Stop is honored at the next pre-worker checkpoint.
76
- The watch loop (if running) will detect status=stopped on its next tick and stop itself.
77
- If a watch tick fires before the supervisor processes the sentinel, it may reschedule once
78
- more — this is expected. It will catch the terminal status on the following tick.
79
- ```
80
-
81
- ## Step 6: Return Immediately
82
-
83
- Do NOT wait for the supervisor to acknowledge. Do NOT poll state.json. Do NOT call ScheduleWakeup. The supervisor will finalize state.json with `status=stopped` on its next iteration check — that's the watch loop's job to observe, not this command's.
84
-
85
- $ARGUMENTS