@dadado/agent-kit-cli 4.7.2 → 4.8.2
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/dashboard/dashboard-data.mjs +813 -0
- package/dashboard/dashboard.html +6882 -0
- package/dashboard/lib/guards.mjs +917 -0
- package/dashboard/lib/live-refresh.mjs +147 -0
- package/dashboard/lib/semantic-model.d.mts +34 -0
- package/dashboard/lib/semantic-model.mjs +3581 -0
- package/dashboard/logo-cursor.svg +10 -0
- package/dashboard/logo.svg +1 -0
- package/dashboard/serve.mjs +550 -0
- package/dashboard/start-broadcast.mjs +231 -0
- package/dashboard/start.mjs +292 -0
- package/dist/index.js +1782 -285
- package/package.json +5 -3
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
// dashboard/lib/live-refresh.mjs
|
|
2
|
+
// Pure helpers for Mission Control live refresh (watch coverage, debounce, silence).
|
|
3
|
+
|
|
4
|
+
import { join, resolve } from "node:path";
|
|
5
|
+
|
|
6
|
+
/** Coalesce bursty fs.watch events into one trailing snapshot. */
|
|
7
|
+
export const WATCH_DEBOUNCE_MS = 400;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* When SSE clients are connected, re-broadcast on this interval so git / terminals /
|
|
11
|
+
* processes (sources that do not touch watched files) cannot stay stale forever.
|
|
12
|
+
*/
|
|
13
|
+
export const PERIODIC_REFRESH_MS = 15000;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Client: if no SSE data payload arrives within this window, resume polling.
|
|
17
|
+
* Must stay above PERIODIC_REFRESH_MS; kept tight so a quiet stream cannot
|
|
18
|
+
* suppress poll for long after the prior open-but-silent failure mode.
|
|
19
|
+
*/
|
|
20
|
+
export const SSE_SILENCE_MS = 20000;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* In-repo paths that dashboard-data.mjs reads. External sources (git state via
|
|
24
|
+
* child_process, ~/.cursor terminals / agent-transcripts, `ps`) are not listed;
|
|
25
|
+
* terminals/processes still need periodic refresh. Agent transcripts are watched
|
|
26
|
+
* separately via resolveAgentTranscriptsWatchPath (not this allowlist).
|
|
27
|
+
*/
|
|
28
|
+
export const SNAPSHOT_REPO_SOURCE_RELS = Object.freeze([
|
|
29
|
+
".cursor/plans",
|
|
30
|
+
".cursor/HANDOFF.md",
|
|
31
|
+
".cursor/agents",
|
|
32
|
+
".cursor/commands",
|
|
33
|
+
".cursor/memory",
|
|
34
|
+
".cursor/context/config.json",
|
|
35
|
+
".cursor/context/current",
|
|
36
|
+
".cursor/context/readiness.json",
|
|
37
|
+
".cursor/context/field-report-dismissals.json",
|
|
38
|
+
".cursor/context/mission-timing.json",
|
|
39
|
+
".cursor/context/flight-log.json",
|
|
40
|
+
".cursor/context/field-report-cadence.json",
|
|
41
|
+
".cursor/skills",
|
|
42
|
+
"package.json",
|
|
43
|
+
]);
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Cursor project slug for this repo: root path with `/` → `-` (leading dash stripped).
|
|
47
|
+
* Matches `dashboard-data.mjs` terminals / agent-transcripts layout.
|
|
48
|
+
* @param {string} root - repository root
|
|
49
|
+
*/
|
|
50
|
+
export function projectSlugFromRoot(root) {
|
|
51
|
+
return String(root).replace(/\//g, "-").replace(/^-/, "");
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Absolute path to this project's agent-transcripts store (outside the repo).
|
|
56
|
+
* Field Report prompt discovery reads here; it is not in SNAPSHOT_REPO_SOURCE_RELS.
|
|
57
|
+
* @param {string} root - repository root
|
|
58
|
+
* @param {string} [home] - HOME (defaults to process.env.HOME)
|
|
59
|
+
* @returns {string}
|
|
60
|
+
*/
|
|
61
|
+
export function resolveAgentTranscriptsWatchPath(root, home = process.env.HOME || "") {
|
|
62
|
+
const projectsDir = resolve(home || "~", ".cursor", "projects");
|
|
63
|
+
return join(projectsDir, projectSlugFromRoot(root), "agent-transcripts");
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Resolve fs.watch roots. Watching `.cursor` covers create-after-start for HANDOFF
|
|
68
|
+
* and nested sources (readiness, agents, skills) that a narrow allowlist missed.
|
|
69
|
+
*
|
|
70
|
+
* @param {string} root - repository root
|
|
71
|
+
* @param {string} dashboardDir - dashboard/ directory
|
|
72
|
+
* @returns {string[]}
|
|
73
|
+
*/
|
|
74
|
+
export function resolveWatchPaths(root, dashboardDir) {
|
|
75
|
+
return [
|
|
76
|
+
join(root, ".cursor"),
|
|
77
|
+
join(root, "package.json"),
|
|
78
|
+
join(dashboardDir, "dashboard-data.mjs"),
|
|
79
|
+
];
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* True when `targetAbs` is the watch root or nested under it.
|
|
84
|
+
* @param {string} watchAbs
|
|
85
|
+
* @param {string} targetAbs
|
|
86
|
+
*/
|
|
87
|
+
export function watchCoversPath(watchAbs, targetAbs) {
|
|
88
|
+
if (watchAbs === targetAbs) return true;
|
|
89
|
+
const prefix = watchAbs.endsWith("/") ? watchAbs : `${watchAbs}/`;
|
|
90
|
+
return targetAbs.startsWith(prefix);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* @param {string[]} watchAbsPaths
|
|
95
|
+
* @param {string} targetAbs
|
|
96
|
+
*/
|
|
97
|
+
export function isCoveredByWatchPaths(watchAbsPaths, targetAbs) {
|
|
98
|
+
return watchAbsPaths.some((w) => watchCoversPath(w, targetAbs));
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Trailing debounce: each call resets the timer; fn runs once after the quiet period.
|
|
103
|
+
* Optional `maxWait` flushes even when calls never go quiet (watch-event storms).
|
|
104
|
+
* @param {() => void} fn
|
|
105
|
+
* @param {number} ms
|
|
106
|
+
* @param {{
|
|
107
|
+
* setTimeout?: typeof setTimeout,
|
|
108
|
+
* clearTimeout?: typeof clearTimeout,
|
|
109
|
+
* now?: () => number,
|
|
110
|
+
* maxWait?: number,
|
|
111
|
+
* }} [timers]
|
|
112
|
+
*/
|
|
113
|
+
export function createTrailingDebounce(fn, ms, timers = {}) {
|
|
114
|
+
const schedule = timers.setTimeout || setTimeout;
|
|
115
|
+
const cancel = timers.clearTimeout || clearTimeout;
|
|
116
|
+
const nowFn = timers.now || Date.now;
|
|
117
|
+
const maxWait = timers.maxWait;
|
|
118
|
+
let handle = null;
|
|
119
|
+
let firstScheduledAt = null;
|
|
120
|
+
return () => {
|
|
121
|
+
const now = nowFn();
|
|
122
|
+
if (firstScheduledAt == null) firstScheduledAt = now;
|
|
123
|
+
if (handle != null) cancel(handle);
|
|
124
|
+
const invoke = () => {
|
|
125
|
+
handle = null;
|
|
126
|
+
firstScheduledAt = null;
|
|
127
|
+
fn();
|
|
128
|
+
};
|
|
129
|
+
const elapsed = now - firstScheduledAt;
|
|
130
|
+
if (maxWait != null && elapsed >= maxWait) {
|
|
131
|
+
invoke();
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
const delay = maxWait != null ? Math.min(ms, Math.max(0, maxWait - elapsed)) : ms;
|
|
135
|
+
handle = schedule(invoke, delay);
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* @param {number} lastEventAt - ms epoch of last SSE data payload
|
|
141
|
+
* @param {number} now - ms epoch
|
|
142
|
+
* @param {number} [silenceMs]
|
|
143
|
+
*/
|
|
144
|
+
export function isSseSilent(lastEventAt, now, silenceMs = SSE_SILENCE_MS) {
|
|
145
|
+
if (!Number.isFinite(lastEventAt) || !Number.isFinite(now)) return false;
|
|
146
|
+
return now - lastEventAt > silenceMs;
|
|
147
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type shim for `semantic-model.mjs` (JS runtime remains SoT).
|
|
3
|
+
* NodeNext resolves `*.mjs` imports to a sibling `*.d.mts` declaration.
|
|
4
|
+
* Unblocks packages/cli `tsc --noEmit` (orchestrator test). Extend named
|
|
5
|
+
* exports only when a typechecked consumer needs them.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/** Parsed HANDOFF machine fields (presence-based; keys optional). */
|
|
9
|
+
export type HandoffMarkdown = {
|
|
10
|
+
plan?: string;
|
|
11
|
+
planPath?: string;
|
|
12
|
+
lastUpdated?: string;
|
|
13
|
+
mode?: string;
|
|
14
|
+
phaseCompleted?: string;
|
|
15
|
+
nextPhase?: string;
|
|
16
|
+
completedTodos?: string;
|
|
17
|
+
nextTodos?: string;
|
|
18
|
+
parkedPlansRaw?: string;
|
|
19
|
+
parkedPlans?: string[];
|
|
20
|
+
backlogPlansRaw?: string;
|
|
21
|
+
backlogPlans?: string[];
|
|
22
|
+
runQueueRaw?: string;
|
|
23
|
+
runQueue?: string[];
|
|
24
|
+
queueCursor?: number | null;
|
|
25
|
+
queueCursorPlan?: string | null;
|
|
26
|
+
queueStatus?: string;
|
|
27
|
+
queueOutcomesRaw?: string;
|
|
28
|
+
queueOutcomes?: Record<string, string>;
|
|
29
|
+
gaps?: string;
|
|
30
|
+
instruction?: string;
|
|
31
|
+
[key: string]: unknown;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export function parseHandoffMarkdown(content: string): HandoffMarkdown | null;
|