declare-cc 0.4.3 → 0.4.8
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/bin/install.js +21 -2
- package/commands/declare/actions.md +8 -3
- package/commands/declare/execute.md +17 -14
- package/commands/declare/future.md +23 -3
- package/commands/declare/milestones.md +7 -2
- package/dist/declare-tools.cjs +258 -2
- package/dist/public/app.js +1382 -0
- package/dist/public/index.html +700 -0
- package/package.json +1 -1
package/bin/install.js
CHANGED
|
@@ -1465,8 +1465,9 @@ function install(isGlobal, runtime = 'claude') {
|
|
|
1465
1465
|
console.log(` ${green}✓${reset} Installed workflows/`);
|
|
1466
1466
|
}
|
|
1467
1467
|
|
|
1468
|
-
// Copy dashboard static files (
|
|
1469
|
-
|
|
1468
|
+
// Copy dashboard static files (dist/public/) → .claude/server/public/
|
|
1469
|
+
// dist/public/ ships in the npm package (built by esbuild.config.js)
|
|
1470
|
+
const publicSrc = path.join(src, 'dist', 'public');
|
|
1470
1471
|
if (fs.existsSync(publicSrc)) {
|
|
1471
1472
|
const publicDest = path.join(targetDir, 'server', 'public');
|
|
1472
1473
|
fs.mkdirSync(publicDest, { recursive: true });
|
|
@@ -1563,6 +1564,9 @@ function install(isGlobal, runtime = 'claude') {
|
|
|
1563
1564
|
const updateCheckCommand = isGlobal
|
|
1564
1565
|
? buildHookCommand(targetDir, 'declare-check-update.js')
|
|
1565
1566
|
: 'node ' + dirName + '/hooks/declare-check-update.js';
|
|
1567
|
+
const activityCommand = isGlobal
|
|
1568
|
+
? buildHookCommand(targetDir, 'declare-activity.js')
|
|
1569
|
+
: 'node ' + dirName + '/hooks/declare-activity.js';
|
|
1566
1570
|
|
|
1567
1571
|
// Enable experimental agents for Gemini CLI (required for custom sub-agents)
|
|
1568
1572
|
if (isGemini) {
|
|
@@ -1599,6 +1603,21 @@ function install(isGlobal, runtime = 'claude') {
|
|
|
1599
1603
|
});
|
|
1600
1604
|
console.log(` ${green}✓${reset} Configured update check hook`);
|
|
1601
1605
|
}
|
|
1606
|
+
|
|
1607
|
+
// Configure PreToolUse + PostToolUse hooks for activity feed (Claude Code only)
|
|
1608
|
+
if (!isOpencode && !isGemini) {
|
|
1609
|
+
if (!settings.hooks.PreToolUse) settings.hooks.PreToolUse = [];
|
|
1610
|
+
if (!settings.hooks.PostToolUse) settings.hooks.PostToolUse = [];
|
|
1611
|
+
|
|
1612
|
+
const hasActivityPre = settings.hooks.PreToolUse.some(e =>
|
|
1613
|
+
e.hooks && e.hooks.some(h => h.command && h.command.includes('declare-activity'))
|
|
1614
|
+
);
|
|
1615
|
+
if (!hasActivityPre) {
|
|
1616
|
+
settings.hooks.PreToolUse.push({ hooks: [{ type: 'command', command: activityCommand }] });
|
|
1617
|
+
settings.hooks.PostToolUse.push({ hooks: [{ type: 'command', command: activityCommand }] });
|
|
1618
|
+
console.log(` ${green}✓${reset} Configured activity feed hooks`);
|
|
1619
|
+
}
|
|
1620
|
+
}
|
|
1602
1621
|
}
|
|
1603
1622
|
|
|
1604
1623
|
// Write file manifest for future modification detection
|
|
@@ -95,11 +95,16 @@ After all milestones processed:
|
|
|
95
95
|
node dist/declare-tools.cjs load-graph
|
|
96
96
|
```
|
|
97
97
|
|
|
98
|
-
2.
|
|
99
|
-
|
|
98
|
+
2. Start the dashboard if not already running:
|
|
99
|
+
```bash
|
|
100
|
+
curl -sf http://localhost:3847/api/graph -o /dev/null || (node dist/declare-tools.cjs serve --port 3847 > /tmp/declare-dashboard.log 2>&1 & sleep 1 && open http://localhost:3847 2>/dev/null || true)
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
3. Show summary: milestones processed, plans created, total actions derived.
|
|
104
|
+
4. Suggest the next step clearly:
|
|
100
105
|
|
|
101
106
|
```
|
|
102
|
-
Actions
|
|
107
|
+
Actions and edges are live in the dashboard → http://localhost:3847
|
|
103
108
|
|
|
104
109
|
/declare:plan M-XX — research + planner + checker loop → EXEC-PLAN files
|
|
105
110
|
/declare:execute M-XX — once plans exist, execute with wave scheduling
|
|
@@ -188,25 +188,28 @@ If `--confirm` flag was set, pause after successful verification:
|
|
|
188
188
|
- "Wave N complete and verified. Proceed to Wave N+1? (yes/no)"
|
|
189
189
|
- Wait for user confirmation before continuing.
|
|
190
190
|
|
|
191
|
-
**3e.
|
|
191
|
+
**3e. Propagate statuses after each wave:**
|
|
192
192
|
|
|
193
|
-
After successful wave verification, update
|
|
193
|
+
After successful wave verification, run sync-status to update PLAN.md, MILESTONES.md, and FUTURE.md atomically. This keeps the dashboard live as waves complete:
|
|
194
194
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
195
|
+
```bash
|
|
196
|
+
node dist/declare-tools.cjs sync-status
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Do not manually edit PLAN.md or MILESTONES.md — sync-status handles all of it correctly.
|
|
200
|
+
|
|
201
|
+
**Step 4: After all waves complete, propagate statuses.**
|
|
199
202
|
|
|
200
|
-
|
|
203
|
+
Run sync-status to propagate action → milestone → declaration completion automatically:
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
node dist/declare-tools.cjs sync-status
|
|
207
|
+
```
|
|
201
208
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
2. Find the row for M-XX in the milestones table.
|
|
205
|
-
3. Change its Status from PENDING or ACTIVE to DONE.
|
|
206
|
-
4. Write the updated MILESTONES.md back.
|
|
207
|
-
5. Display: "Milestone M-XX marked as DONE (pending verification)."
|
|
209
|
+
Parse the result. It will show which actions, milestones, and declarations were marked DONE.
|
|
210
|
+
Display: "Status propagated — [summary from sync-status result]."
|
|
208
211
|
|
|
209
|
-
Proceed to Step 5. Do NOT display a completion banner yet
|
|
212
|
+
Proceed to Step 5. Do NOT display a completion banner yet — that happens in Step 8 after verification.
|
|
210
213
|
|
|
211
214
|
**Step 5: Milestone truth verification.**
|
|
212
215
|
|
|
@@ -44,9 +44,29 @@ node dist/declare-tools.cjs add-declaration --title "Short Title" --statement "F
|
|
|
44
44
|
|
|
45
45
|
Parse the JSON output to confirm the declaration was created and note its assigned ID (e.g., D-01).
|
|
46
46
|
|
|
47
|
-
**Step 5:
|
|
47
|
+
**Step 5: Launch dashboard and show summary.**
|
|
48
48
|
|
|
49
49
|
After all declarations are captured:
|
|
50
50
|
|
|
51
|
-
1.
|
|
52
|
-
|
|
51
|
+
1. Start the dashboard server (if not already running):
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
node dist/declare-tools.cjs serve --port 3847 > /tmp/declare-dashboard.log 2>&1 &
|
|
55
|
+
sleep 1 && curl -sf http://localhost:3847/api/graph -o /dev/null && echo "RUNNING" || echo "FAILED"
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
If RUNNING, open it:
|
|
59
|
+
```bash
|
|
60
|
+
open http://localhost:3847 2>/dev/null || true
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
2. List all declarations with their IDs and statements.
|
|
64
|
+
|
|
65
|
+
3. Suggest next step:
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
Your declarations are live in the dashboard → http://localhost:3847
|
|
69
|
+
The graph updates every 5 seconds as you add milestones and actions.
|
|
70
|
+
|
|
71
|
+
Run /declare:milestones to work backward from these declarations.
|
|
72
|
+
```
|
|
@@ -77,5 +77,10 @@ After all declarations processed:
|
|
|
77
77
|
node dist/declare-tools.cjs load-graph
|
|
78
78
|
```
|
|
79
79
|
|
|
80
|
-
2.
|
|
81
|
-
|
|
80
|
+
2. Start the dashboard if not already running (dashboard updates live when files change):
|
|
81
|
+
```bash
|
|
82
|
+
curl -sf http://localhost:3847/api/graph -o /dev/null || (node dist/declare-tools.cjs serve --port 3847 > /tmp/declare-dashboard.log 2>&1 & sleep 1 && open http://localhost:3847 2>/dev/null || true)
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
3. Show summary: declarations processed, milestones derived.
|
|
86
|
+
4. Suggest: "Milestones are live in the dashboard → http://localhost:3847 — Run `/declare:actions` to derive action plans."
|
package/dist/declare-tools.cjs
CHANGED
|
@@ -1329,7 +1329,7 @@ var require_help = __commonJS({
|
|
|
1329
1329
|
usage: "/declare:help"
|
|
1330
1330
|
}
|
|
1331
1331
|
],
|
|
1332
|
-
version: "0.4.
|
|
1332
|
+
version: "0.4.7"
|
|
1333
1333
|
};
|
|
1334
1334
|
}
|
|
1335
1335
|
module2.exports = { runHelp: runHelp2 };
|
|
@@ -3096,6 +3096,167 @@ var require_sync_status = __commonJS({
|
|
|
3096
3096
|
}
|
|
3097
3097
|
});
|
|
3098
3098
|
|
|
3099
|
+
// src/commands/get-exec-plan.js
|
|
3100
|
+
var require_get_exec_plan = __commonJS({
|
|
3101
|
+
"src/commands/get-exec-plan.js"(exports2, module2) {
|
|
3102
|
+
"use strict";
|
|
3103
|
+
var { existsSync, readFileSync, readdirSync } = require("node:fs");
|
|
3104
|
+
var { join } = require("node:path");
|
|
3105
|
+
var { parseFlag } = require_parse_args();
|
|
3106
|
+
var { buildDagFromDisk } = require_build_dag();
|
|
3107
|
+
var { findMilestoneFolder } = require_milestone_folders();
|
|
3108
|
+
function parseFrontmatter(fmText) {
|
|
3109
|
+
const result = {};
|
|
3110
|
+
const lines = fmText.split("\n");
|
|
3111
|
+
let i = 0;
|
|
3112
|
+
while (i < lines.length) {
|
|
3113
|
+
const line = lines[i];
|
|
3114
|
+
const keyMatch = line.match(/^(\w[\w_]*):\s*(.*)/);
|
|
3115
|
+
if (!keyMatch) {
|
|
3116
|
+
i++;
|
|
3117
|
+
continue;
|
|
3118
|
+
}
|
|
3119
|
+
const [, key, rest] = keyMatch;
|
|
3120
|
+
if (rest.trim() === "") {
|
|
3121
|
+
const children = [];
|
|
3122
|
+
i++;
|
|
3123
|
+
while (i < lines.length && (lines[i].startsWith(" ") || lines[i].trim() === "")) {
|
|
3124
|
+
const child = lines[i];
|
|
3125
|
+
const listItem = child.match(/^\s+-\s+(.*)/);
|
|
3126
|
+
const nestedKey = child.match(/^\s+(\w[\w_]*):\s*(.*)/);
|
|
3127
|
+
if (listItem) {
|
|
3128
|
+
children.push({ type: "item", value: listItem[1].replace(/^["']|["']$/g, "") });
|
|
3129
|
+
} else if (nestedKey) {
|
|
3130
|
+
children.push({ type: "key", key: nestedKey[1], value: nestedKey[2] });
|
|
3131
|
+
}
|
|
3132
|
+
i++;
|
|
3133
|
+
}
|
|
3134
|
+
if (children.length > 0 && children[0].type === "item") {
|
|
3135
|
+
result[key] = children.map((c) => c.value);
|
|
3136
|
+
} else if (children.length > 0 && children[0].type === "key") {
|
|
3137
|
+
result[key] = {};
|
|
3138
|
+
let subKey = null;
|
|
3139
|
+
let subItems = [];
|
|
3140
|
+
for (const c of children) {
|
|
3141
|
+
if (c.type === "key") {
|
|
3142
|
+
if (subKey) result[key][subKey] = subItems;
|
|
3143
|
+
subKey = c.key;
|
|
3144
|
+
subItems = c.value.trim() ? [c.value.replace(/^["']|["']$/g, "")] : [];
|
|
3145
|
+
} else if (c.type === "item") {
|
|
3146
|
+
subItems.push(c.value);
|
|
3147
|
+
}
|
|
3148
|
+
}
|
|
3149
|
+
if (subKey) result[key][subKey] = subItems;
|
|
3150
|
+
}
|
|
3151
|
+
} else {
|
|
3152
|
+
result[key] = rest.trim().replace(/^["']|["']$/g, "");
|
|
3153
|
+
i++;
|
|
3154
|
+
}
|
|
3155
|
+
}
|
|
3156
|
+
return result;
|
|
3157
|
+
}
|
|
3158
|
+
function extractTag(content, tag) {
|
|
3159
|
+
const re = new RegExp(`<${tag}[^>]*>([\\s\\S]*?)<\\/${tag}>`, "i");
|
|
3160
|
+
const m = content.match(re);
|
|
3161
|
+
return m ? m[1].trim() : null;
|
|
3162
|
+
}
|
|
3163
|
+
function parseTasks(tasksContent) {
|
|
3164
|
+
const tasks = [];
|
|
3165
|
+
const taskRe = /<task([^>]*)>([\s\S]*?)<\/task>/gi;
|
|
3166
|
+
let m;
|
|
3167
|
+
while ((m = taskRe.exec(tasksContent)) !== null) {
|
|
3168
|
+
const attrs = m[1];
|
|
3169
|
+
const body = m[2];
|
|
3170
|
+
const typeMatch = attrs.match(/type="([^"]+)"/);
|
|
3171
|
+
const taskType = typeMatch ? typeMatch[1] : "auto";
|
|
3172
|
+
tasks.push({
|
|
3173
|
+
type: taskType,
|
|
3174
|
+
name: extractTag(body, "name") || "",
|
|
3175
|
+
action: extractTag(body, "action"),
|
|
3176
|
+
verify: extractTag(body, "verify"),
|
|
3177
|
+
done: extractTag(body, "done"),
|
|
3178
|
+
howToVerify: extractTag(body, "how-to-verify"),
|
|
3179
|
+
resumeSignal: extractTag(body, "resume-signal"),
|
|
3180
|
+
whatBuilt: extractTag(body, "what-built")
|
|
3181
|
+
});
|
|
3182
|
+
}
|
|
3183
|
+
return tasks;
|
|
3184
|
+
}
|
|
3185
|
+
function findExecPlan(milestoneFolder, actionId) {
|
|
3186
|
+
if (!existsSync(milestoneFolder)) return null;
|
|
3187
|
+
const entries = readdirSync(milestoneFolder);
|
|
3188
|
+
const match = entries.find(
|
|
3189
|
+
(f) => f.toUpperCase().startsWith(actionId.toUpperCase() + "-EXEC-PLAN") || f.toUpperCase().startsWith("EXEC-PLAN-" + actionId.replace(/^A-/, ""))
|
|
3190
|
+
);
|
|
3191
|
+
return match ? join(milestoneFolder, match) : null;
|
|
3192
|
+
}
|
|
3193
|
+
function runGetExecPlan2(cwd, args) {
|
|
3194
|
+
const actionId = parseFlag(args, "action");
|
|
3195
|
+
if (!actionId) {
|
|
3196
|
+
return { error: "Missing --action flag. Usage: get-exec-plan --action A-XX" };
|
|
3197
|
+
}
|
|
3198
|
+
const graphResult = buildDagFromDisk(cwd);
|
|
3199
|
+
if ("error" in graphResult) return graphResult;
|
|
3200
|
+
const { dag } = graphResult;
|
|
3201
|
+
const action = dag.getNode(actionId);
|
|
3202
|
+
if (!action) return { error: `Action not found: ${actionId}` };
|
|
3203
|
+
const upstreamMilestones = dag.getUpstream(actionId).filter((n) => n.type === "milestone");
|
|
3204
|
+
if (upstreamMilestones.length === 0) return { error: `No milestone found for action ${actionId}` };
|
|
3205
|
+
const milestone = upstreamMilestones[0];
|
|
3206
|
+
const planningDir = join(cwd, ".planning");
|
|
3207
|
+
const milestoneFolder = findMilestoneFolder(planningDir, milestone.id);
|
|
3208
|
+
if (!milestoneFolder) {
|
|
3209
|
+
return { error: `Milestone folder not found for ${milestone.id}` };
|
|
3210
|
+
}
|
|
3211
|
+
const execPlanPath = findExecPlan(milestoneFolder, actionId);
|
|
3212
|
+
if (!execPlanPath) {
|
|
3213
|
+
return {
|
|
3214
|
+
actionId,
|
|
3215
|
+
actionTitle: action.title,
|
|
3216
|
+
status: action.status,
|
|
3217
|
+
milestoneId: milestone.id,
|
|
3218
|
+
milestoneTitle: milestone.title,
|
|
3219
|
+
execPlan: null,
|
|
3220
|
+
summaryExists: false
|
|
3221
|
+
};
|
|
3222
|
+
}
|
|
3223
|
+
const raw = readFileSync(execPlanPath, "utf-8");
|
|
3224
|
+
const fmMatch = raw.match(/^---\n([\s\S]*?)\n---/);
|
|
3225
|
+
const frontmatter = fmMatch ? parseFrontmatter(fmMatch[1]) : {};
|
|
3226
|
+
const objective = extractTag(raw, "objective");
|
|
3227
|
+
const tasksRaw = extractTag(raw, "tasks");
|
|
3228
|
+
const tasks = tasksRaw ? parseTasks(tasksRaw) : [];
|
|
3229
|
+
const successCriteria = extractTag(raw, "success_criteria");
|
|
3230
|
+
const verification = extractTag(raw, "verification");
|
|
3231
|
+
const summaryPath = join(milestoneFolder, `${actionId}-SUMMARY.md`);
|
|
3232
|
+
const summaryExists = existsSync(summaryPath);
|
|
3233
|
+
const summaryContent = summaryExists ? readFileSync(summaryPath, "utf-8") : null;
|
|
3234
|
+
return {
|
|
3235
|
+
actionId,
|
|
3236
|
+
actionTitle: action.title,
|
|
3237
|
+
status: action.status,
|
|
3238
|
+
milestoneId: milestone.id,
|
|
3239
|
+
milestoneTitle: milestone.title,
|
|
3240
|
+
execPlan: {
|
|
3241
|
+
wave: frontmatter.wave ? Number(frontmatter.wave) : null,
|
|
3242
|
+
autonomous: frontmatter.autonomous === "true" || frontmatter.autonomous === true,
|
|
3243
|
+
dependsOn: Array.isArray(frontmatter.depends_on) ? frontmatter.depends_on : [],
|
|
3244
|
+
filesModified: Array.isArray(frontmatter.files_modified) ? frontmatter.files_modified : [],
|
|
3245
|
+
declarations: Array.isArray(frontmatter.declarations) ? frontmatter.declarations : [],
|
|
3246
|
+
mustHaves: frontmatter.must_haves || null,
|
|
3247
|
+
objective,
|
|
3248
|
+
tasks,
|
|
3249
|
+
successCriteria,
|
|
3250
|
+
verification
|
|
3251
|
+
},
|
|
3252
|
+
summaryExists,
|
|
3253
|
+
summaryContent
|
|
3254
|
+
};
|
|
3255
|
+
}
|
|
3256
|
+
module2.exports = { runGetExecPlan: runGetExecPlan2 };
|
|
3257
|
+
}
|
|
3258
|
+
});
|
|
3259
|
+
|
|
3099
3260
|
// src/commands/quick-task.js
|
|
3100
3261
|
var require_quick_task = __commonJS({
|
|
3101
3262
|
"src/commands/quick-task.js"(exports2, module2) {
|
|
@@ -3666,6 +3827,7 @@ var require_server = __commonJS({
|
|
|
3666
3827
|
var path = require("node:path");
|
|
3667
3828
|
var { runLoadGraph: runLoadGraph2 } = require_load_graph();
|
|
3668
3829
|
var { runStatus: runStatus2 } = require_status();
|
|
3830
|
+
var { runGetExecPlan: runGetExecPlan2 } = require_get_exec_plan();
|
|
3669
3831
|
var MIME_TYPES = {
|
|
3670
3832
|
".html": "text/html; charset=utf-8",
|
|
3671
3833
|
".js": "application/javascript; charset=utf-8",
|
|
@@ -3677,7 +3839,9 @@ var require_server = __commonJS({
|
|
|
3677
3839
|
};
|
|
3678
3840
|
function getPublicDir(cwd) {
|
|
3679
3841
|
const installed = path.join(cwd, ".claude", "server", "public");
|
|
3680
|
-
if (
|
|
3842
|
+
if (fs.existsSync(installed)) return installed;
|
|
3843
|
+
const bundled = path.join(__dirname, "public");
|
|
3844
|
+
if (fs.existsSync(bundled)) return bundled;
|
|
3681
3845
|
return path.join(cwd, "src", "server", "public");
|
|
3682
3846
|
}
|
|
3683
3847
|
function sendJson(res, statusCode, data) {
|
|
@@ -3760,6 +3924,67 @@ var require_server = __commonJS({
|
|
|
3760
3924
|
sendJson(res, 500, { error: String(err) });
|
|
3761
3925
|
}
|
|
3762
3926
|
}
|
|
3927
|
+
function handleActivity(res, cwd) {
|
|
3928
|
+
const activityFile = path.join(cwd, ".planning", "activity.jsonl");
|
|
3929
|
+
if (!fs.existsSync(activityFile)) {
|
|
3930
|
+
sendJson(res, 200, { events: [] });
|
|
3931
|
+
return;
|
|
3932
|
+
}
|
|
3933
|
+
try {
|
|
3934
|
+
const lines = fs.readFileSync(activityFile, "utf-8").split("\n").filter(Boolean).slice(-100);
|
|
3935
|
+
const events = lines.map((l) => {
|
|
3936
|
+
try {
|
|
3937
|
+
return JSON.parse(l);
|
|
3938
|
+
} catch {
|
|
3939
|
+
return null;
|
|
3940
|
+
}
|
|
3941
|
+
}).filter(Boolean).reverse();
|
|
3942
|
+
sendJson(res, 200, { events });
|
|
3943
|
+
} catch (err) {
|
|
3944
|
+
sendJson(res, 500, { error: String(err) });
|
|
3945
|
+
}
|
|
3946
|
+
}
|
|
3947
|
+
var sseClients = /* @__PURE__ */ new Set();
|
|
3948
|
+
function broadcastChange() {
|
|
3949
|
+
for (const client of sseClients) {
|
|
3950
|
+
try {
|
|
3951
|
+
client.write("event: change\ndata: {}\n\n");
|
|
3952
|
+
} catch (_) {
|
|
3953
|
+
sseClients.delete(client);
|
|
3954
|
+
}
|
|
3955
|
+
}
|
|
3956
|
+
}
|
|
3957
|
+
function watchPlanning(cwd) {
|
|
3958
|
+
const planningDir = path.join(cwd, ".planning");
|
|
3959
|
+
if (!fs.existsSync(planningDir)) return;
|
|
3960
|
+
let graphTimer = null;
|
|
3961
|
+
let activityTimer = null;
|
|
3962
|
+
const activityFile = path.join(planningDir, "activity.jsonl");
|
|
3963
|
+
try {
|
|
3964
|
+
fs.watch(planningDir, { recursive: true }, (_evt, filename) => {
|
|
3965
|
+
if (filename && filename.endsWith("activity.jsonl")) {
|
|
3966
|
+
if (activityTimer) clearTimeout(activityTimer);
|
|
3967
|
+
activityTimer = setTimeout(() => {
|
|
3968
|
+
for (const client of sseClients) {
|
|
3969
|
+
try {
|
|
3970
|
+
client.write("event: activity\ndata: {}\n\n");
|
|
3971
|
+
} catch {
|
|
3972
|
+
sseClients.delete(client);
|
|
3973
|
+
}
|
|
3974
|
+
}
|
|
3975
|
+
activityTimer = null;
|
|
3976
|
+
}, 50);
|
|
3977
|
+
} else {
|
|
3978
|
+
if (graphTimer) clearTimeout(graphTimer);
|
|
3979
|
+
graphTimer = setTimeout(() => {
|
|
3980
|
+
broadcastChange();
|
|
3981
|
+
graphTimer = null;
|
|
3982
|
+
}, 200);
|
|
3983
|
+
}
|
|
3984
|
+
});
|
|
3985
|
+
} catch (_) {
|
|
3986
|
+
}
|
|
3987
|
+
}
|
|
3763
3988
|
function route(req, res, cwd) {
|
|
3764
3989
|
const method = req.method || "GET";
|
|
3765
3990
|
const url = req.url || "/";
|
|
@@ -3777,6 +4002,18 @@ var require_server = __commonJS({
|
|
|
3777
4002
|
sendJson(res, 405, { error: "Method Not Allowed" });
|
|
3778
4003
|
return;
|
|
3779
4004
|
}
|
|
4005
|
+
if (urlPath === "/events") {
|
|
4006
|
+
res.writeHead(200, {
|
|
4007
|
+
"Content-Type": "text/event-stream",
|
|
4008
|
+
"Cache-Control": "no-cache",
|
|
4009
|
+
"Connection": "keep-alive",
|
|
4010
|
+
"Access-Control-Allow-Origin": "*"
|
|
4011
|
+
});
|
|
4012
|
+
res.write("retry: 3000\n\n");
|
|
4013
|
+
sseClients.add(res);
|
|
4014
|
+
req.on("close", () => sseClients.delete(res));
|
|
4015
|
+
return;
|
|
4016
|
+
}
|
|
3780
4017
|
if (urlPath === "/api/graph") {
|
|
3781
4018
|
handleGraph(res, cwd);
|
|
3782
4019
|
return;
|
|
@@ -3790,6 +4027,16 @@ var require_server = __commonJS({
|
|
|
3790
4027
|
handleMilestone(res, cwd, milestoneMatch[1]);
|
|
3791
4028
|
return;
|
|
3792
4029
|
}
|
|
4030
|
+
if (urlPath === "/api/activity") {
|
|
4031
|
+
handleActivity(res, cwd);
|
|
4032
|
+
return;
|
|
4033
|
+
}
|
|
4034
|
+
const actionMatch = urlPath.match(/^\/api\/action\/([^/]+)$/);
|
|
4035
|
+
if (actionMatch) {
|
|
4036
|
+
const result = runGetExecPlan2(cwd, ["--action", actionMatch[1]]);
|
|
4037
|
+
sendJson(res, result.error ? 404 : 200, result);
|
|
4038
|
+
return;
|
|
4039
|
+
}
|
|
3793
4040
|
const publicDir = getPublicDir(cwd);
|
|
3794
4041
|
if (urlPath === "/") {
|
|
3795
4042
|
const indexPath = path.join(publicDir, "index.html");
|
|
@@ -3818,6 +4065,7 @@ var require_server = __commonJS({
|
|
|
3818
4065
|
const resolvedPort = port || parseInt(process.env.PORT || "", 10) || 3847;
|
|
3819
4066
|
const server = createServer(cwd, resolvedPort);
|
|
3820
4067
|
server.listen(resolvedPort, "127.0.0.1", () => {
|
|
4068
|
+
watchPlanning(cwd);
|
|
3821
4069
|
});
|
|
3822
4070
|
const url = `http://localhost:${resolvedPort}`;
|
|
3823
4071
|
return { server, port: resolvedPort, url };
|
|
@@ -3878,6 +4126,7 @@ var { runComputePerformance } = require_compute_performance();
|
|
|
3878
4126
|
var { runRenegotiate } = require_renegotiate();
|
|
3879
4127
|
var { runCompleteMilestone } = require_complete_milestone();
|
|
3880
4128
|
var { runSyncStatus } = require_sync_status();
|
|
4129
|
+
var { runGetExecPlan } = require_get_exec_plan();
|
|
3881
4130
|
var { runQuickTask } = require_quick_task();
|
|
3882
4131
|
var { runAddTodo, runCheckTodos, runCompleteTodo } = require_todo();
|
|
3883
4132
|
var { runConfigGet } = require_config_get();
|
|
@@ -4054,6 +4303,13 @@ function main() {
|
|
|
4054
4303
|
if (result.error) process.exit(1);
|
|
4055
4304
|
break;
|
|
4056
4305
|
}
|
|
4306
|
+
case "get-exec-plan": {
|
|
4307
|
+
const cwdGep = parseCwdFlag(args) || process.cwd();
|
|
4308
|
+
const result = runGetExecPlan(cwdGep, args.slice(1));
|
|
4309
|
+
console.log(JSON.stringify(result));
|
|
4310
|
+
if (result.error) process.exit(1);
|
|
4311
|
+
break;
|
|
4312
|
+
}
|
|
4057
4313
|
case "execute": {
|
|
4058
4314
|
const cwdExecute = parseCwdFlag(args) || process.cwd();
|
|
4059
4315
|
const result = runExecute(cwdExecute, args.slice(1));
|