codekin 0.6.2 → 0.6.4
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/README.md +3 -2
- package/dist/assets/index-BRB_Ksyk.js +182 -0
- package/dist/assets/index-Q2WSVlHo.css +1 -0
- package/dist/index.html +2 -2
- package/package.json +3 -3
- package/server/dist/auth-routes.js +6 -0
- package/server/dist/auth-routes.js.map +1 -1
- package/server/dist/claude-process.js +3 -2
- package/server/dist/claude-process.js.map +1 -1
- package/server/dist/commit-event-handler.d.ts +2 -1
- package/server/dist/commit-event-handler.js +4 -3
- package/server/dist/commit-event-handler.js.map +1 -1
- package/server/dist/commit-event-hooks.d.ts +11 -0
- package/server/dist/commit-event-hooks.js +61 -11
- package/server/dist/commit-event-hooks.js.map +1 -1
- package/server/dist/config.d.ts +7 -0
- package/server/dist/config.js +19 -1
- package/server/dist/config.js.map +1 -1
- package/server/dist/docs-routes.js +4 -7
- package/server/dist/docs-routes.js.map +1 -1
- package/server/dist/json-parse.d.ts +8 -0
- package/server/dist/json-parse.js +9 -0
- package/server/dist/json-parse.js.map +1 -0
- package/server/dist/opencode-process.d.ts +8 -0
- package/server/dist/opencode-process.js +63 -5
- package/server/dist/opencode-process.js.map +1 -1
- package/server/dist/orchestrator-learning-router.d.ts +8 -0
- package/server/dist/orchestrator-learning-router.js +126 -0
- package/server/dist/orchestrator-learning-router.js.map +1 -0
- package/server/dist/orchestrator-learning.d.ts +0 -5
- package/server/dist/orchestrator-learning.js +2 -9
- package/server/dist/orchestrator-learning.js.map +1 -1
- package/server/dist/orchestrator-memory-router.d.ts +10 -0
- package/server/dist/orchestrator-memory-router.js +148 -0
- package/server/dist/orchestrator-memory-router.js.map +1 -0
- package/server/dist/orchestrator-memory.js +2 -1
- package/server/dist/orchestrator-memory.js.map +1 -1
- package/server/dist/orchestrator-monitor.d.ts +6 -0
- package/server/dist/orchestrator-monitor.js +14 -0
- package/server/dist/orchestrator-monitor.js.map +1 -1
- package/server/dist/orchestrator-reports.d.ts +0 -4
- package/server/dist/orchestrator-reports.js +8 -10
- package/server/dist/orchestrator-reports.js.map +1 -1
- package/server/dist/orchestrator-routes.d.ts +2 -2
- package/server/dist/orchestrator-routes.js +11 -506
- package/server/dist/orchestrator-routes.js.map +1 -1
- package/server/dist/orchestrator-session-router.d.ts +13 -0
- package/server/dist/orchestrator-session-router.js +312 -0
- package/server/dist/orchestrator-session-router.js.map +1 -0
- package/server/dist/process-coordinator.d.ts +83 -0
- package/server/dist/process-coordinator.js +167 -0
- package/server/dist/process-coordinator.js.map +1 -0
- package/server/dist/prompt-router.js +2 -1
- package/server/dist/prompt-router.js.map +1 -1
- package/server/dist/session-archive.js +2 -1
- package/server/dist/session-archive.js.map +1 -1
- package/server/dist/session-lifecycle.js +21 -37
- package/server/dist/session-lifecycle.js.map +1 -1
- package/server/dist/session-manager.d.ts +4 -0
- package/server/dist/session-manager.js +64 -75
- package/server/dist/session-manager.js.map +1 -1
- package/server/dist/session-persistence.js +3 -1
- package/server/dist/session-persistence.js.map +1 -1
- package/server/dist/session-routes.d.ts +18 -0
- package/server/dist/session-routes.js +56 -11
- package/server/dist/session-routes.js.map +1 -1
- package/server/dist/stepflow-handler.js +5 -1
- package/server/dist/stepflow-handler.js.map +1 -1
- package/server/dist/stepflow-prompt.js +16 -12
- package/server/dist/stepflow-prompt.js.map +1 -1
- package/server/dist/tsconfig.tsbuildinfo +1 -1
- package/server/dist/types.d.ts +6 -0
- package/server/dist/types.js +1 -0
- package/server/dist/types.js.map +1 -1
- package/server/dist/upload-routes.d.ts +5 -0
- package/server/dist/upload-routes.js +48 -11
- package/server/dist/upload-routes.js.map +1 -1
- package/server/dist/version-check.js +3 -2
- package/server/dist/version-check.js.map +1 -1
- package/server/dist/webhook-rate-limiter.js +9 -1
- package/server/dist/webhook-rate-limiter.js.map +1 -1
- package/server/dist/webhook-workspace.d.ts +12 -0
- package/server/dist/webhook-workspace.js +126 -3
- package/server/dist/webhook-workspace.js.map +1 -1
- package/server/dist/workflow-engine.d.ts +80 -7
- package/server/dist/workflow-engine.js +209 -28
- package/server/dist/workflow-engine.js.map +1 -1
- package/server/dist/workflow-loader.d.ts +6 -1
- package/server/dist/workflow-loader.js +97 -27
- package/server/dist/workflow-loader.js.map +1 -1
- package/server/dist/workflow-routes.d.ts +13 -0
- package/server/dist/workflow-routes.js +106 -4
- package/server/dist/workflow-routes.js.map +1 -1
- package/server/dist/ws-origin-check.d.ts +11 -0
- package/server/dist/ws-origin-check.js +20 -0
- package/server/dist/ws-origin-check.js.map +1 -0
- package/server/dist/ws-rate-limit.d.ts +19 -0
- package/server/dist/ws-rate-limit.js +30 -0
- package/server/dist/ws-rate-limit.js.map +1 -0
- package/server/dist/ws-server.js +41 -22
- package/server/dist/ws-server.js.map +1 -1
- package/dist/assets/index-C8GlUCii.js +0 -182
- package/dist/assets/index-DgeUVGjz.css +0 -1
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session lifecycle, child session management, reports, and dashboard routes
|
|
3
|
+
* for the orchestrator.
|
|
4
|
+
*/
|
|
5
|
+
import { Router } from 'express';
|
|
6
|
+
import { resolve } from 'path';
|
|
7
|
+
import { existsSync, statSync, realpathSync } from 'fs';
|
|
8
|
+
import { ensureOrchestratorRunning, getOrchestratorSessionId, getOrCreateOrchestratorId } from './orchestrator-manager.js';
|
|
9
|
+
import { getAgentDisplayName, REPOS_ROOT, resolveRepoPathInRoot } from './config.js';
|
|
10
|
+
import { scanRepoReports, readReport, getReportsSince } from './orchestrator-reports.js';
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
// Per-IP rate limiter for child-session spawn (mirrors auth-routes pattern).
|
|
13
|
+
// Each spawn allocates a real subprocess, so we cap aggressively per IP and
|
|
14
|
+
// hard-cap the tracking map to bound memory under DoS conditions.
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
/** Maximum tracked IPs in the spawn rate-limiter map (matches PR #418 cap). */
|
|
17
|
+
const SPAWN_RATE_MAP_MAX_SIZE = 10_000;
|
|
18
|
+
function createSpawnRateLimiter(maxRequests, windowMs) {
|
|
19
|
+
const ipTimestamps = new Map();
|
|
20
|
+
// Periodic cleanup of stale entries to bound memory growth.
|
|
21
|
+
const cleanup = setInterval(() => {
|
|
22
|
+
const now = Date.now();
|
|
23
|
+
for (const [ip, timestamps] of ipTimestamps) {
|
|
24
|
+
const recent = timestamps.filter(t => now - t < windowMs);
|
|
25
|
+
if (recent.length === 0)
|
|
26
|
+
ipTimestamps.delete(ip);
|
|
27
|
+
else
|
|
28
|
+
ipTimestamps.set(ip, recent);
|
|
29
|
+
}
|
|
30
|
+
}, Math.max(60_000, windowMs));
|
|
31
|
+
if (cleanup.unref)
|
|
32
|
+
cleanup.unref();
|
|
33
|
+
return (req, res, next) => {
|
|
34
|
+
const ip = req.ip || req.socket.remoteAddress || 'unknown';
|
|
35
|
+
const now = Date.now();
|
|
36
|
+
const timestamps = (ipTimestamps.get(ip) ?? []).filter(t => now - t < windowMs);
|
|
37
|
+
if (timestamps.length >= maxRequests) {
|
|
38
|
+
ipTimestamps.set(ip, timestamps);
|
|
39
|
+
return res.status(429).json({ error: 'Too Many Requests', retryAfter: Math.ceil(windowMs / 1000) });
|
|
40
|
+
}
|
|
41
|
+
// Reject new IPs once the map is full (DoS protection, matches PR #418).
|
|
42
|
+
if (timestamps.length === 0 && ipTimestamps.size >= SPAWN_RATE_MAP_MAX_SIZE) {
|
|
43
|
+
return res.status(429).json({ error: 'Too Many Requests', retryAfter: Math.ceil(windowMs / 1000) });
|
|
44
|
+
}
|
|
45
|
+
timestamps.push(now);
|
|
46
|
+
ipTimestamps.set(ip, timestamps);
|
|
47
|
+
next();
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
// ---------------------------------------------------------------------------
|
|
51
|
+
// Router factory
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
export function createSessionRouter(verifyOrchestratorAuth, sessions, memory, children, monitorRef) {
|
|
54
|
+
const router = Router();
|
|
55
|
+
// 20 spawns per 5 minutes per IP — child sessions allocate real subprocesses,
|
|
56
|
+
// so this is intentionally tight. Tune via the constants if needed.
|
|
57
|
+
const spawnRateLimiter = createSpawnRateLimiter(20, 5 * 60_000);
|
|
58
|
+
// -------------------------------------------------------------------------
|
|
59
|
+
// Session lifecycle
|
|
60
|
+
// -------------------------------------------------------------------------
|
|
61
|
+
/** Get orchestrator session status. */
|
|
62
|
+
router.get('/api/orchestrator/status', (req, res) => {
|
|
63
|
+
if (!verifyOrchestratorAuth(req))
|
|
64
|
+
return res.status(401).json({ error: 'Unauthorized' });
|
|
65
|
+
const sessionId = getOrchestratorSessionId(sessions);
|
|
66
|
+
if (!sessionId) {
|
|
67
|
+
return res.json({ sessionId: null, status: 'stopped', agentName: getAgentDisplayName() });
|
|
68
|
+
}
|
|
69
|
+
const session = sessions.get(sessionId);
|
|
70
|
+
const status = session?.claudeProcess?.isAlive() ? 'active' : 'idle';
|
|
71
|
+
res.json({
|
|
72
|
+
sessionId,
|
|
73
|
+
status,
|
|
74
|
+
childSessions: children.activeCount(),
|
|
75
|
+
agentName: getAgentDisplayName(),
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
/** Ensure orchestrator is running and return its session ID. */
|
|
79
|
+
router.post('/api/orchestrator/start', (req, res) => {
|
|
80
|
+
if (!verifyOrchestratorAuth(req))
|
|
81
|
+
return res.status(401).json({ error: 'Unauthorized' });
|
|
82
|
+
try {
|
|
83
|
+
const sessionId = ensureOrchestratorRunning(sessions);
|
|
84
|
+
res.json({ sessionId, status: 'active', agentName: getAgentDisplayName() });
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
console.error('[orchestrator] Failed to start:', err);
|
|
88
|
+
res.status(500).json({ error: `Failed to start Agent ${getAgentDisplayName()}` });
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
// -------------------------------------------------------------------------
|
|
92
|
+
// Reports
|
|
93
|
+
// -------------------------------------------------------------------------
|
|
94
|
+
/** Scan reports for a single repo. */
|
|
95
|
+
router.get('/api/orchestrator/reports', (req, res) => {
|
|
96
|
+
if (!verifyOrchestratorAuth(req))
|
|
97
|
+
return res.status(401).json({ error: 'Unauthorized' });
|
|
98
|
+
const repoPath = req.query.repo;
|
|
99
|
+
const since = req.query.since;
|
|
100
|
+
if (repoPath) {
|
|
101
|
+
const resolvedRepoPath = resolveRepoPathInRoot(repoPath);
|
|
102
|
+
if (!resolvedRepoPath) {
|
|
103
|
+
return res.status(400).json({ error: 'Invalid repo path: must be an existing directory under the configured repos root' });
|
|
104
|
+
}
|
|
105
|
+
const reports = scanRepoReports(resolvedRepoPath);
|
|
106
|
+
res.json({ reports });
|
|
107
|
+
}
|
|
108
|
+
else if (since) {
|
|
109
|
+
const repoItems = memory.list({ memoryType: 'repo_context' });
|
|
110
|
+
const repoPaths = repoItems.map(r => r.scope).filter((s) => !!s);
|
|
111
|
+
const reports = getReportsSince(repoPaths, since);
|
|
112
|
+
res.json({ reports });
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
res.status(400).json({ error: 'Provide ?repo=<path> or ?since=<YYYY-MM-DD>' });
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
/** Read a specific report's content. */
|
|
119
|
+
router.get('/api/orchestrator/reports/read', (req, res) => {
|
|
120
|
+
if (!verifyOrchestratorAuth(req))
|
|
121
|
+
return res.status(401).json({ error: 'Unauthorized' });
|
|
122
|
+
const filePath = req.query.path;
|
|
123
|
+
if (!filePath)
|
|
124
|
+
return res.status(400).json({ error: 'Provide ?path=<filePath>' });
|
|
125
|
+
const report = readReport(filePath);
|
|
126
|
+
if (!report)
|
|
127
|
+
return res.status(404).json({ error: 'Report not found' });
|
|
128
|
+
res.json({ report });
|
|
129
|
+
});
|
|
130
|
+
// -------------------------------------------------------------------------
|
|
131
|
+
// Child sessions
|
|
132
|
+
// -------------------------------------------------------------------------
|
|
133
|
+
/** List child sessions. */
|
|
134
|
+
router.get('/api/orchestrator/children', (req, res) => {
|
|
135
|
+
if (!verifyOrchestratorAuth(req))
|
|
136
|
+
return res.status(401).json({ error: 'Unauthorized' });
|
|
137
|
+
res.json({ children: children.list() });
|
|
138
|
+
});
|
|
139
|
+
/** Spawn a child session. */
|
|
140
|
+
router.post('/api/orchestrator/children', spawnRateLimiter, async (req, res) => {
|
|
141
|
+
if (!verifyOrchestratorAuth(req))
|
|
142
|
+
return res.status(401).json({ error: 'Unauthorized' });
|
|
143
|
+
const { repo, task, branchName, completionPolicy, deployAfter, useWorktree, model, allowedTools } = req.body;
|
|
144
|
+
if (!repo || !task || !branchName) {
|
|
145
|
+
return res.status(400).json({ error: 'Missing required fields: repo, task, branchName' });
|
|
146
|
+
}
|
|
147
|
+
// Validate branchName to prevent prompt injection
|
|
148
|
+
if (!/^[a-zA-Z0-9][a-zA-Z0-9/_.-]*$/.test(branchName)) {
|
|
149
|
+
return res.status(400).json({ error: 'Invalid branchName: only alphanumeric, /, _, ., and - are allowed' });
|
|
150
|
+
}
|
|
151
|
+
// Validate allowedTools if provided: must be an array of strings
|
|
152
|
+
if (allowedTools !== undefined) {
|
|
153
|
+
if (!Array.isArray(allowedTools) || !allowedTools.every((t) => typeof t === 'string')) {
|
|
154
|
+
return res.status(400).json({ error: 'Invalid allowedTools: must be an array of strings' });
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
// Validate repo path: must exist and be a directory
|
|
158
|
+
const absRepo = resolve(repo);
|
|
159
|
+
if (!existsSync(absRepo) || !statSync(absRepo).isDirectory()) {
|
|
160
|
+
return res.status(400).json({ error: 'Invalid repo path: directory does not exist' });
|
|
161
|
+
}
|
|
162
|
+
// Use realpathSync to resolve symlinks before boundary check (prevents symlink bypass)
|
|
163
|
+
const resolvedRepo = realpathSync(absRepo);
|
|
164
|
+
if (!resolvedRepo.startsWith(REPOS_ROOT + '/') && resolvedRepo !== REPOS_ROOT) {
|
|
165
|
+
return res.status(400).json({ error: 'Invalid repo path: must be under configured repos root' });
|
|
166
|
+
}
|
|
167
|
+
try {
|
|
168
|
+
const child = await children.spawn({
|
|
169
|
+
repo,
|
|
170
|
+
task,
|
|
171
|
+
branchName,
|
|
172
|
+
completionPolicy: completionPolicy ?? 'pr',
|
|
173
|
+
deployAfter: deployAfter ?? false,
|
|
174
|
+
useWorktree: useWorktree ?? true,
|
|
175
|
+
model,
|
|
176
|
+
allowedTools,
|
|
177
|
+
});
|
|
178
|
+
res.json({ child });
|
|
179
|
+
}
|
|
180
|
+
catch (err) {
|
|
181
|
+
res.status(503).json({ error: err instanceof Error ? err.message : 'Failed to spawn child session' });
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
/** Get a specific child session. */
|
|
185
|
+
router.get('/api/orchestrator/children/:id', (req, res) => {
|
|
186
|
+
if (!verifyOrchestratorAuth(req))
|
|
187
|
+
return res.status(401).json({ error: 'Unauthorized' });
|
|
188
|
+
const child = children.get(req.params.id);
|
|
189
|
+
if (!child)
|
|
190
|
+
return res.status(404).json({ error: 'Child session not found' });
|
|
191
|
+
res.json({ child });
|
|
192
|
+
});
|
|
193
|
+
// -------------------------------------------------------------------------
|
|
194
|
+
// Session prompts & approvals
|
|
195
|
+
// -------------------------------------------------------------------------
|
|
196
|
+
/** Get all sessions with pending prompts (waiting for approval or answer). */
|
|
197
|
+
router.get('/api/orchestrator/sessions/pending-prompts', (req, res) => {
|
|
198
|
+
if (!verifyOrchestratorAuth(req))
|
|
199
|
+
return res.status(401).json({ error: 'Unauthorized' });
|
|
200
|
+
res.json({ sessions: sessions.getPendingPrompts() });
|
|
201
|
+
});
|
|
202
|
+
/** Approve or deny a pending prompt in any session. */
|
|
203
|
+
router.post('/api/orchestrator/sessions/:id/respond', (req, res) => {
|
|
204
|
+
if (!verifyOrchestratorAuth(req))
|
|
205
|
+
return res.status(401).json({ error: 'Unauthorized' });
|
|
206
|
+
const sessionId = req.params.id;
|
|
207
|
+
const { requestId, value } = req.body;
|
|
208
|
+
if (!value) {
|
|
209
|
+
return res.status(400).json({ error: 'Missing required field: value (e.g. "allow", "deny", or answer text)' });
|
|
210
|
+
}
|
|
211
|
+
const session = sessions.get(sessionId);
|
|
212
|
+
if (!session)
|
|
213
|
+
return res.status(404).json({ error: 'Session not found' });
|
|
214
|
+
// Verify there's actually a pending prompt (optionally for the specific requestId)
|
|
215
|
+
const hasPending = requestId
|
|
216
|
+
? (session.pendingToolApprovals.has(requestId) || session.pendingControlRequests.has(requestId))
|
|
217
|
+
: (session.pendingToolApprovals.size > 0 || session.pendingControlRequests.size > 0);
|
|
218
|
+
if (!hasPending) {
|
|
219
|
+
return res.status(409).json({ error: 'No pending prompt to respond to' });
|
|
220
|
+
}
|
|
221
|
+
// Capture prompt details before responding (response clears them)
|
|
222
|
+
let promptToolName = 'unknown';
|
|
223
|
+
let promptType = 'permission';
|
|
224
|
+
if (requestId) {
|
|
225
|
+
const toolApproval = session.pendingToolApprovals.get(requestId);
|
|
226
|
+
const controlReq = session.pendingControlRequests.get(requestId);
|
|
227
|
+
if (toolApproval) {
|
|
228
|
+
promptToolName = toolApproval.toolName;
|
|
229
|
+
promptType = toolApproval.toolName === 'AskUserQuestion' ? 'question' : 'permission';
|
|
230
|
+
}
|
|
231
|
+
else if (controlReq) {
|
|
232
|
+
promptToolName = controlReq.toolName;
|
|
233
|
+
promptType = controlReq.toolName === 'AskUserQuestion' ? 'question' : 'permission';
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
sessions.sendPromptResponse(sessionId, value, requestId);
|
|
237
|
+
// Broadcast a notification to the orchestrator channel
|
|
238
|
+
const orchestratorId = getOrCreateOrchestratorId();
|
|
239
|
+
const orchestratorSession = sessions.get(orchestratorId);
|
|
240
|
+
if (orchestratorSession && orchestratorSession.clients.size > 0) {
|
|
241
|
+
const actionLabel = promptType === 'question'
|
|
242
|
+
? `answered question from ${promptToolName}`
|
|
243
|
+
: `responded "${value}" to ${promptToolName}`;
|
|
244
|
+
const notifMsg = {
|
|
245
|
+
type: 'system_message',
|
|
246
|
+
subtype: 'info',
|
|
247
|
+
text: `[${getAgentDisplayName()}] ${actionLabel} in session "${session.name}"`,
|
|
248
|
+
};
|
|
249
|
+
for (const ws of orchestratorSession.clients) {
|
|
250
|
+
ws.send(JSON.stringify(notifMsg));
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
res.json({ ok: true });
|
|
254
|
+
});
|
|
255
|
+
// -------------------------------------------------------------------------
|
|
256
|
+
// Session cleanup & listing
|
|
257
|
+
// -------------------------------------------------------------------------
|
|
258
|
+
/** List all sessions (unfiltered, includes source field). */
|
|
259
|
+
router.get('/api/orchestrator/sessions', (req, res) => {
|
|
260
|
+
if (!verifyOrchestratorAuth(req))
|
|
261
|
+
return res.status(401).json({ error: 'Unauthorized' });
|
|
262
|
+
res.json({ sessions: sessions.listAll() });
|
|
263
|
+
});
|
|
264
|
+
/** Delete all automated sessions (source: workflow, webhook, stepflow, agent). */
|
|
265
|
+
router.delete('/api/orchestrator/sessions/cleanup', (req, res) => {
|
|
266
|
+
if (!verifyOrchestratorAuth(req))
|
|
267
|
+
return res.status(401).json({ error: 'Unauthorized' });
|
|
268
|
+
const automatedSources = new Set(['workflow', 'webhook', 'stepflow', 'agent']);
|
|
269
|
+
const toDelete = sessions.listAll().filter((s) => automatedSources.has(s.source ?? ''));
|
|
270
|
+
let deleted = 0;
|
|
271
|
+
for (const s of toDelete) {
|
|
272
|
+
if (sessions.delete(s.id))
|
|
273
|
+
deleted++;
|
|
274
|
+
}
|
|
275
|
+
res.json({ deleted });
|
|
276
|
+
});
|
|
277
|
+
/** Delete a specific session by ID. */
|
|
278
|
+
router.delete('/api/orchestrator/sessions/:id', (req, res) => {
|
|
279
|
+
if (!verifyOrchestratorAuth(req))
|
|
280
|
+
return res.status(401).json({ error: 'Unauthorized' });
|
|
281
|
+
const success = sessions.delete(req.params.id);
|
|
282
|
+
if (!success)
|
|
283
|
+
return res.status(404).json({ error: 'Session not found' });
|
|
284
|
+
res.json({ deleted: true });
|
|
285
|
+
});
|
|
286
|
+
// -------------------------------------------------------------------------
|
|
287
|
+
// Dashboard stats
|
|
288
|
+
// -------------------------------------------------------------------------
|
|
289
|
+
/** Get summary stats for the dashboard header. */
|
|
290
|
+
router.get('/api/orchestrator/dashboard', (req, res) => {
|
|
291
|
+
if (!verifyOrchestratorAuth(req))
|
|
292
|
+
return res.status(401).json({ error: 'Unauthorized' });
|
|
293
|
+
const repoItems = memory.list({ memoryType: 'repo_context' });
|
|
294
|
+
const pendingNotifications = monitorRef?.current?.getPending() ?? [];
|
|
295
|
+
const activeChildren = children.activeCount();
|
|
296
|
+
const trustRecords = memory.listTrustRecords();
|
|
297
|
+
const autoApproved = trustRecords.filter(t => t.effectiveLevel !== 'ask').length;
|
|
298
|
+
res.json({
|
|
299
|
+
stats: {
|
|
300
|
+
managedRepos: repoItems.length,
|
|
301
|
+
pendingNotifications: pendingNotifications.length,
|
|
302
|
+
activeChildSessions: activeChildren,
|
|
303
|
+
totalChildSessions: children.list().length,
|
|
304
|
+
trustRecords: trustRecords.length,
|
|
305
|
+
autoApprovedActions: autoApproved,
|
|
306
|
+
memoryItems: memory.list().length,
|
|
307
|
+
},
|
|
308
|
+
});
|
|
309
|
+
});
|
|
310
|
+
return router;
|
|
311
|
+
}
|
|
312
|
+
//# sourceMappingURL=orchestrator-session-router.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orchestrator-session-router.js","sourceRoot":"","sources":["../orchestrator-session-router.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified process lifecycle coordinator for a single session.
|
|
3
|
+
*
|
|
4
|
+
* Replaces the scattered flag/timer pattern (_restartTimer, _isStarting,
|
|
5
|
+
* _processGeneration, _apiRetry.timer) with a single promise-chain mutex
|
|
6
|
+
* and centralized timer management.
|
|
7
|
+
*
|
|
8
|
+
* Every lifecycle transition (start, stop, reconfigure) is serialized through
|
|
9
|
+
* the mutex so at most one operation is in-flight at a time. All pending
|
|
10
|
+
* timers (restart, API retry) are cancelled on any new transition.
|
|
11
|
+
*/
|
|
12
|
+
export interface ProcessCoordinatorDeps {
|
|
13
|
+
/** Spawn the Claude process. Returns true on success. */
|
|
14
|
+
startProcess(sessionId: string): boolean;
|
|
15
|
+
/** Stop the process and wait for it to fully exit. */
|
|
16
|
+
stopProcessAndWait(sessionId: string): Promise<void>;
|
|
17
|
+
}
|
|
18
|
+
export declare class ProcessCoordinator {
|
|
19
|
+
private readonly sessionId;
|
|
20
|
+
private readonly deps;
|
|
21
|
+
/** Monotonically increasing counter. Bumped on every start. Scheduled
|
|
22
|
+
* timers capture the generation at schedule time and bail if it changed. */
|
|
23
|
+
private generation;
|
|
24
|
+
/** Promise chain that serializes lifecycle operations. */
|
|
25
|
+
private chain;
|
|
26
|
+
/** Active lifecycle timers, keyed by purpose (e.g. 'restart', 'apiRetry'). */
|
|
27
|
+
private timers;
|
|
28
|
+
/** True when the user (or idle reaper / delete / shutdown) explicitly stopped
|
|
29
|
+
* the process. Prevents scheduled restarts from firing. */
|
|
30
|
+
private _userStopped;
|
|
31
|
+
constructor(sessionId: string, deps: ProcessCoordinatorDeps);
|
|
32
|
+
/**
|
|
33
|
+
* Request a process start. If another operation is in-flight, waits for it.
|
|
34
|
+
* If the process is already running, the underlying startProcess decides
|
|
35
|
+
* whether to replace it (current behavior: kills old, spawns new).
|
|
36
|
+
*/
|
|
37
|
+
requestStart(): Promise<boolean>;
|
|
38
|
+
/**
|
|
39
|
+
* Request a full stop. Cancels all timers, marks userStopped.
|
|
40
|
+
*/
|
|
41
|
+
requestStop(): Promise<void>;
|
|
42
|
+
/**
|
|
43
|
+
* Stop the current process, apply a config change, then start a new one.
|
|
44
|
+
* Used by setModel, setProvider, setPermissionMode.
|
|
45
|
+
*
|
|
46
|
+
* @param apply — callback that mutates session config (model, provider, etc.)
|
|
47
|
+
* before the new process is spawned.
|
|
48
|
+
*/
|
|
49
|
+
requestReconfigure(apply: () => void): Promise<boolean>;
|
|
50
|
+
/**
|
|
51
|
+
* Schedule a delayed restart (crash recovery). The timer is automatically
|
|
52
|
+
* cancelled if any other lifecycle transition happens before it fires.
|
|
53
|
+
*
|
|
54
|
+
* @param onBeforeStart — optional callback invoked after the timer fires but
|
|
55
|
+
* before startProcess. Return false to abort the restart.
|
|
56
|
+
* @param onAfterStart — optional callback invoked after startProcess completes
|
|
57
|
+
* successfully, for post-restart context injection.
|
|
58
|
+
*/
|
|
59
|
+
scheduleRestart(delayMs: number, onBeforeStart?: () => boolean, onAfterStart?: () => void): void;
|
|
60
|
+
/**
|
|
61
|
+
* Schedule an API retry. Tied to the current generation — if the process
|
|
62
|
+
* restarts or stops before the timer fires, the retry is silently dropped.
|
|
63
|
+
*/
|
|
64
|
+
scheduleApiRetry(delayMs: number, sendRetry: () => void): void;
|
|
65
|
+
/** Cancel a pending API retry timer (e.g. on successful result). */
|
|
66
|
+
cancelApiRetry(): void;
|
|
67
|
+
/**
|
|
68
|
+
* Cancel all timers and mark as user-stopped. Used by delete() and
|
|
69
|
+
* shutdown() which handle process killing themselves.
|
|
70
|
+
*/
|
|
71
|
+
teardown(): void;
|
|
72
|
+
/** Current generation counter. */
|
|
73
|
+
get currentGeneration(): number;
|
|
74
|
+
/** Whether the user has explicitly stopped the process. */
|
|
75
|
+
get isUserStopped(): boolean;
|
|
76
|
+
/** Clear the userStopped flag (e.g. when sendInput reactivates an idle-reaped session). */
|
|
77
|
+
clearUserStopped(): void;
|
|
78
|
+
private enqueue;
|
|
79
|
+
private doStart;
|
|
80
|
+
private doStop;
|
|
81
|
+
private setTimer;
|
|
82
|
+
private cancelAllTimers;
|
|
83
|
+
}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified process lifecycle coordinator for a single session.
|
|
3
|
+
*
|
|
4
|
+
* Replaces the scattered flag/timer pattern (_restartTimer, _isStarting,
|
|
5
|
+
* _processGeneration, _apiRetry.timer) with a single promise-chain mutex
|
|
6
|
+
* and centralized timer management.
|
|
7
|
+
*
|
|
8
|
+
* Every lifecycle transition (start, stop, reconfigure) is serialized through
|
|
9
|
+
* the mutex so at most one operation is in-flight at a time. All pending
|
|
10
|
+
* timers (restart, API retry) are cancelled on any new transition.
|
|
11
|
+
*/
|
|
12
|
+
export class ProcessCoordinator {
|
|
13
|
+
sessionId;
|
|
14
|
+
deps;
|
|
15
|
+
/** Monotonically increasing counter. Bumped on every start. Scheduled
|
|
16
|
+
* timers capture the generation at schedule time and bail if it changed. */
|
|
17
|
+
generation = 0;
|
|
18
|
+
/** Promise chain that serializes lifecycle operations. */
|
|
19
|
+
chain = Promise.resolve();
|
|
20
|
+
/** Active lifecycle timers, keyed by purpose (e.g. 'restart', 'apiRetry'). */
|
|
21
|
+
timers = new Map();
|
|
22
|
+
/** True when the user (or idle reaper / delete / shutdown) explicitly stopped
|
|
23
|
+
* the process. Prevents scheduled restarts from firing. */
|
|
24
|
+
_userStopped = false;
|
|
25
|
+
constructor(sessionId, deps) {
|
|
26
|
+
this.sessionId = sessionId;
|
|
27
|
+
this.deps = deps;
|
|
28
|
+
}
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
// Public intent-based API
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
/**
|
|
33
|
+
* Request a process start. If another operation is in-flight, waits for it.
|
|
34
|
+
* If the process is already running, the underlying startProcess decides
|
|
35
|
+
* whether to replace it (current behavior: kills old, spawns new).
|
|
36
|
+
*/
|
|
37
|
+
requestStart() {
|
|
38
|
+
this._userStopped = false;
|
|
39
|
+
return this.enqueue('start', () => this.doStart());
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Request a full stop. Cancels all timers, marks userStopped.
|
|
43
|
+
*/
|
|
44
|
+
requestStop() {
|
|
45
|
+
this._userStopped = true;
|
|
46
|
+
this.cancelAllTimers();
|
|
47
|
+
return this.enqueue('stop', () => this.doStop());
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Stop the current process, apply a config change, then start a new one.
|
|
51
|
+
* Used by setModel, setProvider, setPermissionMode.
|
|
52
|
+
*
|
|
53
|
+
* @param apply — callback that mutates session config (model, provider, etc.)
|
|
54
|
+
* before the new process is spawned.
|
|
55
|
+
*/
|
|
56
|
+
requestReconfigure(apply) {
|
|
57
|
+
this.cancelAllTimers();
|
|
58
|
+
return this.enqueue('reconfigure', async () => {
|
|
59
|
+
await this.doStop();
|
|
60
|
+
apply();
|
|
61
|
+
this._userStopped = false;
|
|
62
|
+
return this.doStart();
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Schedule a delayed restart (crash recovery). The timer is automatically
|
|
67
|
+
* cancelled if any other lifecycle transition happens before it fires.
|
|
68
|
+
*
|
|
69
|
+
* @param onBeforeStart — optional callback invoked after the timer fires but
|
|
70
|
+
* before startProcess. Return false to abort the restart.
|
|
71
|
+
* @param onAfterStart — optional callback invoked after startProcess completes
|
|
72
|
+
* successfully, for post-restart context injection.
|
|
73
|
+
*/
|
|
74
|
+
scheduleRestart(delayMs, onBeforeStart, onAfterStart) {
|
|
75
|
+
if (this._userStopped)
|
|
76
|
+
return;
|
|
77
|
+
const gen = this.generation;
|
|
78
|
+
this.setTimer('restart', delayMs, () => {
|
|
79
|
+
if (this.generation !== gen || this._userStopped)
|
|
80
|
+
return;
|
|
81
|
+
// Enqueue through the mutex so it doesn't race with other operations
|
|
82
|
+
void this.enqueue('scheduledRestart', async () => {
|
|
83
|
+
// Re-check after acquiring the mutex
|
|
84
|
+
if (this.generation !== gen || this._userStopped)
|
|
85
|
+
return false;
|
|
86
|
+
if (onBeforeStart && !onBeforeStart())
|
|
87
|
+
return false;
|
|
88
|
+
const started = await this.doStart();
|
|
89
|
+
if (started && onAfterStart)
|
|
90
|
+
onAfterStart();
|
|
91
|
+
return started;
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Schedule an API retry. Tied to the current generation — if the process
|
|
97
|
+
* restarts or stops before the timer fires, the retry is silently dropped.
|
|
98
|
+
*/
|
|
99
|
+
scheduleApiRetry(delayMs, sendRetry) {
|
|
100
|
+
const gen = this.generation;
|
|
101
|
+
this.setTimer('apiRetry', delayMs, () => {
|
|
102
|
+
if (this.generation !== gen || this._userStopped)
|
|
103
|
+
return;
|
|
104
|
+
sendRetry();
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
/** Cancel a pending API retry timer (e.g. on successful result). */
|
|
108
|
+
cancelApiRetry() {
|
|
109
|
+
const timer = this.timers.get('apiRetry');
|
|
110
|
+
if (timer) {
|
|
111
|
+
clearTimeout(timer);
|
|
112
|
+
this.timers.delete('apiRetry');
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Cancel all timers and mark as user-stopped. Used by delete() and
|
|
117
|
+
* shutdown() which handle process killing themselves.
|
|
118
|
+
*/
|
|
119
|
+
teardown() {
|
|
120
|
+
this._userStopped = true;
|
|
121
|
+
this.cancelAllTimers();
|
|
122
|
+
}
|
|
123
|
+
/** Current generation counter. */
|
|
124
|
+
get currentGeneration() { return this.generation; }
|
|
125
|
+
/** Whether the user has explicitly stopped the process. */
|
|
126
|
+
get isUserStopped() { return this._userStopped; }
|
|
127
|
+
/** Clear the userStopped flag (e.g. when sendInput reactivates an idle-reaped session). */
|
|
128
|
+
clearUserStopped() { this._userStopped = false; }
|
|
129
|
+
// ---------------------------------------------------------------------------
|
|
130
|
+
// Internal machinery
|
|
131
|
+
// ---------------------------------------------------------------------------
|
|
132
|
+
enqueue(label, op) {
|
|
133
|
+
this.cancelAllTimers();
|
|
134
|
+
let resolve;
|
|
135
|
+
let reject;
|
|
136
|
+
const result = new Promise((res, rej) => { resolve = res; reject = rej; });
|
|
137
|
+
this.chain = this.chain
|
|
138
|
+
.then(() => {
|
|
139
|
+
console.log(`[coordinator] ${this.sessionId} enqueue=${label} gen=${this.generation}`);
|
|
140
|
+
return op().then(resolve, reject);
|
|
141
|
+
})
|
|
142
|
+
.catch((err) => { console.warn(`[coordinator] ${this.sessionId} enqueue=${label} swallowed error:`, err); });
|
|
143
|
+
return result;
|
|
144
|
+
}
|
|
145
|
+
async doStart() {
|
|
146
|
+
this.generation++;
|
|
147
|
+
return this.deps.startProcess(this.sessionId);
|
|
148
|
+
}
|
|
149
|
+
async doStop() {
|
|
150
|
+
await this.deps.stopProcessAndWait(this.sessionId);
|
|
151
|
+
}
|
|
152
|
+
setTimer(key, delayMs, callback) {
|
|
153
|
+
const existing = this.timers.get(key);
|
|
154
|
+
if (existing)
|
|
155
|
+
clearTimeout(existing);
|
|
156
|
+
this.timers.set(key, setTimeout(() => {
|
|
157
|
+
this.timers.delete(key);
|
|
158
|
+
callback();
|
|
159
|
+
}, delayMs));
|
|
160
|
+
}
|
|
161
|
+
cancelAllTimers() {
|
|
162
|
+
for (const timer of this.timers.values())
|
|
163
|
+
clearTimeout(timer);
|
|
164
|
+
this.timers.clear();
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
//# sourceMappingURL=process-coordinator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"process-coordinator.js","sourceRoot":"","sources":["../process-coordinator.ts"],"names":[],"mappings":"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"}
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import { randomUUID } from 'crypto';
|
|
12
12
|
import { ApprovalManager } from './approval-manager.js';
|
|
13
|
+
import { jsonParse } from './json-parse.js';
|
|
13
14
|
export class PromptRouter {
|
|
14
15
|
deps;
|
|
15
16
|
constructor(deps) {
|
|
@@ -473,7 +474,7 @@ export class PromptRouter {
|
|
|
473
474
|
if (typeof value === 'string') {
|
|
474
475
|
// Try parsing as JSON answers map (multi-question flow)
|
|
475
476
|
try {
|
|
476
|
-
const parsed =
|
|
477
|
+
const parsed = jsonParse(value);
|
|
477
478
|
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
|
|
478
479
|
answers = parsed;
|
|
479
480
|
}
|