When GSD hits a blocking decision point (AskUserQuestion, next action prompt),
external watchers have no way to detect it. Users monitoring multiple auto
sessions must visually check each terminal.
Added:
- state signal-waiting: writes .planning/WAITING.json (or .gsd/WAITING.json)
with type, question, options, timestamp, and phase info
- state signal-resume: removes WAITING.json when user answers
Signal file format:
{ status, type, question, options[], since, phase }
External tools can watch for this file via fswatch, polling, or inotify.
Complements the existing remote-questions extension (Slack/Discord).
Fixes #1034
This commit is contained in:
@@ -15,6 +15,8 @@
|
||||
* state get [section] Get STATE.md content or section
|
||||
* state patch --field val ... Batch update STATE.md fields
|
||||
* state begin-phase --phase N --name S --plans C Update STATE.md for new phase start
|
||||
* state signal-waiting --type T --question Q --options "A|B" --phase P Write WAITING.json signal
|
||||
* state signal-resume Remove WAITING.json signal
|
||||
* resolve-model <agent-type> Get model for agent based on profile
|
||||
* find-phase <phase> Find phase directory by number
|
||||
* commit <message> [--files f1 f2] Commit planning docs
|
||||
@@ -255,6 +257,21 @@ async function main() {
|
||||
plansIdx !== -1 ? parseInt(args[plansIdx + 1], 10) : null,
|
||||
raw
|
||||
);
|
||||
} else if (subcommand === 'signal-waiting') {
|
||||
const typeIdx = args.indexOf('--type');
|
||||
const qIdx = args.indexOf('--question');
|
||||
const optIdx = args.indexOf('--options');
|
||||
const phaseIdx = args.indexOf('--phase');
|
||||
state.cmdSignalWaiting(
|
||||
cwd,
|
||||
typeIdx !== -1 ? args[typeIdx + 1] : null,
|
||||
qIdx !== -1 ? args[qIdx + 1] : null,
|
||||
optIdx !== -1 ? args[optIdx + 1] : null,
|
||||
phaseIdx !== -1 ? args[phaseIdx + 1] : null,
|
||||
raw
|
||||
);
|
||||
} else if (subcommand === 'signal-resume') {
|
||||
state.cmdSignalResume(cwd, raw);
|
||||
} else {
|
||||
state.cmdStateLoad(cwd, raw);
|
||||
}
|
||||
|
||||
@@ -778,6 +778,53 @@ function cmdStateBeginPhase(cwd, phaseNumber, phaseName, planCount, raw) {
|
||||
output({ updated, phase: phaseNumber, phase_name: phaseName || null, plan_count: planCount || null }, raw, updated.length > 0 ? 'true' : 'false');
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a WAITING.json signal file when GSD hits a decision point.
|
||||
* External watchers (fswatch, polling, orchestrators) can detect this.
|
||||
* File is written to .planning/WAITING.json (or .gsd/WAITING.json if .gsd exists).
|
||||
* Fixes #1034.
|
||||
*/
|
||||
function cmdSignalWaiting(cwd, type, question, options, phase, raw) {
|
||||
const gsdDir = fs.existsSync(path.join(cwd, '.gsd')) ? path.join(cwd, '.gsd') : path.join(cwd, '.planning');
|
||||
const waitingPath = path.join(gsdDir, 'WAITING.json');
|
||||
|
||||
const signal = {
|
||||
status: 'waiting',
|
||||
type: type || 'decision_point',
|
||||
question: question || null,
|
||||
options: options ? options.split('|').map(o => o.trim()) : [],
|
||||
since: new Date().toISOString(),
|
||||
phase: phase || null,
|
||||
};
|
||||
|
||||
try {
|
||||
fs.mkdirSync(gsdDir, { recursive: true });
|
||||
fs.writeFileSync(waitingPath, JSON.stringify(signal, null, 2), 'utf-8');
|
||||
output({ signaled: true, path: waitingPath }, raw, 'true');
|
||||
} catch (e) {
|
||||
output({ signaled: false, error: e.message }, raw, 'false');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the WAITING.json signal file when user answers and agent resumes.
|
||||
*/
|
||||
function cmdSignalResume(cwd, raw) {
|
||||
const paths = [
|
||||
path.join(cwd, '.gsd', 'WAITING.json'),
|
||||
path.join(cwd, '.planning', 'WAITING.json'),
|
||||
];
|
||||
|
||||
let removed = false;
|
||||
for (const p of paths) {
|
||||
if (fs.existsSync(p)) {
|
||||
try { fs.unlinkSync(p); removed = true; } catch {}
|
||||
}
|
||||
}
|
||||
|
||||
output({ resumed: true, removed }, raw, removed ? 'true' : 'false');
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
stateExtractField,
|
||||
stateReplaceField,
|
||||
@@ -796,4 +843,6 @@ module.exports = {
|
||||
cmdStateSnapshot,
|
||||
cmdStateJson,
|
||||
cmdStateBeginPhase,
|
||||
cmdSignalWaiting,
|
||||
cmdSignalResume,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user