pi-forge 1.2.3 → 1.2.5
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 +1 -1
- package/dist/client/assets/{CodeMirrorEditor-1gu-DS9k.js → CodeMirrorEditor-DXmxwE2Z.js} +2 -2
- package/dist/client/assets/{CodeMirrorEditor-1gu-DS9k.js.map → CodeMirrorEditor-DXmxwE2Z.js.map} +1 -1
- package/dist/client/assets/index-CMSjnWtF.js +365 -0
- package/dist/client/assets/index-CMSjnWtF.js.map +1 -0
- package/dist/client/assets/index-Cp8qEy7Q.css +1 -0
- package/dist/client/index.html +2 -2
- package/dist/client/sw.js +1 -1
- package/dist/client/sw.js.map +1 -1
- package/dist/server/agent-extensions/compaction-continuation.js +65 -0
- package/dist/server/agent-extensions/compaction-continuation.js.map +1 -0
- package/dist/server/agent-resource-loader.js +10 -0
- package/dist/server/agent-resource-loader.js.map +1 -1
- package/dist/server/ask-user-question/envelope.js +56 -0
- package/dist/server/ask-user-question/envelope.js.map +1 -0
- package/dist/server/ask-user-question/prompt-strings.js +44 -0
- package/dist/server/ask-user-question/prompt-strings.js.map +1 -0
- package/dist/server/ask-user-question/registry.js +157 -0
- package/dist/server/ask-user-question/registry.js.map +1 -0
- package/dist/server/ask-user-question/tool.js +115 -0
- package/dist/server/ask-user-question/tool.js.map +1 -0
- package/dist/server/ask-user-question/types.js +27 -0
- package/dist/server/ask-user-question/types.js.map +1 -0
- package/dist/server/ask-user-question/validate.js +135 -0
- package/dist/server/ask-user-question/validate.js.map +1 -0
- package/dist/server/config.js +10 -0
- package/dist/server/config.js.map +1 -1
- package/dist/server/index.js +16 -0
- package/dist/server/index.js.map +1 -1
- package/dist/server/mcp/tool-bridge.js +14 -8
- package/dist/server/mcp/tool-bridge.js.map +1 -1
- package/dist/server/processes/envelope.js +60 -0
- package/dist/server/processes/envelope.js.map +1 -0
- package/dist/server/processes/log-store.js +132 -0
- package/dist/server/processes/log-store.js.map +1 -0
- package/dist/server/processes/manager.js +348 -0
- package/dist/server/processes/manager.js.map +1 -0
- package/dist/server/processes/prompt-strings.js +43 -0
- package/dist/server/processes/prompt-strings.js.map +1 -0
- package/dist/server/processes/tool.js +273 -0
- package/dist/server/processes/tool.js.map +1 -0
- package/dist/server/processes/types.js +21 -0
- package/dist/server/processes/types.js.map +1 -0
- package/dist/server/processes/watches.js +59 -0
- package/dist/server/processes/watches.js.map +1 -0
- package/dist/server/quick-actions.js +141 -0
- package/dist/server/quick-actions.js.map +1 -0
- package/dist/server/routes/ask-user-question.js +129 -0
- package/dist/server/routes/ask-user-question.js.map +1 -0
- package/dist/server/routes/config.js +12 -0
- package/dist/server/routes/config.js.map +1 -1
- package/dist/server/routes/processes.js +228 -0
- package/dist/server/routes/processes.js.map +1 -0
- package/dist/server/routes/quick-actions.js +384 -0
- package/dist/server/routes/quick-actions.js.map +1 -0
- package/dist/server/routes/todos.js +67 -0
- package/dist/server/routes/todos.js.map +1 -0
- package/dist/server/session-registry.js +72 -4
- package/dist/server/session-registry.js.map +1 -1
- package/dist/server/sse-bridge.js +225 -4
- package/dist/server/sse-bridge.js.map +1 -1
- package/dist/server/todo/envelope.js +87 -0
- package/dist/server/todo/envelope.js.map +1 -0
- package/dist/server/todo/invariants.js +21 -0
- package/dist/server/todo/invariants.js.map +1 -0
- package/dist/server/todo/prompt-strings.js +29 -0
- package/dist/server/todo/prompt-strings.js.map +1 -0
- package/dist/server/todo/reducer.js +189 -0
- package/dist/server/todo/reducer.js.map +1 -0
- package/dist/server/todo/replay.js +45 -0
- package/dist/server/todo/replay.js.map +1 -0
- package/dist/server/todo/store.js +92 -0
- package/dist/server/todo/store.js.map +1 -0
- package/dist/server/todo/task-graph.js +60 -0
- package/dist/server/todo/task-graph.js.map +1 -0
- package/dist/server/todo/tool.js +95 -0
- package/dist/server/todo/tool.js.map +1 -0
- package/dist/server/todo/types.js +23 -0
- package/dist/server/todo/types.js.map +1 -0
- package/package.json +1 -1
- package/dist/client/assets/index-BxZV6ddv.js +0 -359
- package/dist/client/assets/index-BxZV6ddv.js.map +0 -1
- package/dist/client/assets/index-KUhxvBxw.css +0 -1
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { config } from "../config.js";
|
|
3
|
+
import { getProject } from "../project-manager.js";
|
|
4
|
+
import { scrubbedEnv } from "../pty-manager.js";
|
|
5
|
+
import { createQuickAction, DEFAULT_TIMEOUT_MS, deleteQuickAction, getQuickAction, isCommandAction, isPromptAction, MAX_COMMAND_BYTES, MAX_PROMPT_BYTES, MAX_TIMEOUT_MS, QuickActionNotFoundError, readQuickActions, updateQuickAction, } from "../quick-actions.js";
|
|
6
|
+
import { errorSchema } from "./_schemas.js";
|
|
7
|
+
/**
|
|
8
|
+
* Wire shape — same on the way in (POST/PUT body) and out
|
|
9
|
+
* (GET response). Discriminator is presence of `command` vs `text`;
|
|
10
|
+
* the validator below rejects both/neither with 400.
|
|
11
|
+
*/
|
|
12
|
+
const quickActionSchema = {
|
|
13
|
+
type: "object",
|
|
14
|
+
required: ["id", "name"],
|
|
15
|
+
properties: {
|
|
16
|
+
id: { type: "string" },
|
|
17
|
+
name: { type: "string" },
|
|
18
|
+
enabled: { type: "boolean" },
|
|
19
|
+
command: { type: "string" },
|
|
20
|
+
timeoutMs: { type: "integer" },
|
|
21
|
+
text: { type: "string" },
|
|
22
|
+
mode: { type: "string", enum: ["send", "insert"] },
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
const runResultSchema = {
|
|
26
|
+
type: "object",
|
|
27
|
+
required: ["success", "exitCode", "stdout", "stderr", "durationMs", "timedOut", "truncated"],
|
|
28
|
+
properties: {
|
|
29
|
+
success: { type: "boolean" },
|
|
30
|
+
exitCode: { type: ["integer", "null"] },
|
|
31
|
+
stdout: { type: "string" },
|
|
32
|
+
stderr: { type: "string" },
|
|
33
|
+
durationMs: { type: "integer" },
|
|
34
|
+
timedOut: { type: "boolean" },
|
|
35
|
+
truncated: { type: "boolean" },
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
/** Per-stream output cap. A chip that prints 100 MB of node_modules
|
|
39
|
+
* paths shouldn't drag the request handler down — truncate and flag
|
|
40
|
+
* it; the user can re-run in the integrated terminal if they need the
|
|
41
|
+
* full output. */
|
|
42
|
+
const MAX_OUTPUT_BYTES = 1_000_000;
|
|
43
|
+
/**
|
|
44
|
+
* Normalise + validate one wire body into a QuickAction-shaped patch.
|
|
45
|
+
* Centralises the one-of discriminator + byte caps so POST and PUT
|
|
46
|
+
* both produce identical 400s on the same bad input.
|
|
47
|
+
*/
|
|
48
|
+
function validateBody(body, reply) {
|
|
49
|
+
const trimmedName = body.name.trim();
|
|
50
|
+
if (trimmedName.length === 0) {
|
|
51
|
+
reply.code(400).send({ error: "invalid_name" });
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
54
|
+
const hasCmd = typeof body.command === "string" && body.command.length > 0;
|
|
55
|
+
const hasText = typeof body.text === "string" && body.text.length > 0;
|
|
56
|
+
if (hasCmd === hasText) {
|
|
57
|
+
reply.code(400).send({
|
|
58
|
+
error: "invalid_action",
|
|
59
|
+
message: "exactly one of `command` or `text` is required",
|
|
60
|
+
});
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
63
|
+
const out = { name: trimmedName };
|
|
64
|
+
if (body.enabled !== undefined)
|
|
65
|
+
out.enabled = body.enabled;
|
|
66
|
+
if (hasCmd) {
|
|
67
|
+
const cmd = body.command;
|
|
68
|
+
if (Buffer.byteLength(cmd, "utf8") > MAX_COMMAND_BYTES) {
|
|
69
|
+
reply.code(400).send({ error: "command_too_large" });
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
out.command = cmd;
|
|
73
|
+
if (body.timeoutMs !== undefined) {
|
|
74
|
+
const t = body.timeoutMs;
|
|
75
|
+
if (!Number.isInteger(t) || t <= 0) {
|
|
76
|
+
reply.code(400).send({ error: "invalid_timeout" });
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
out.timeoutMs = Math.min(t, MAX_TIMEOUT_MS);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
const text = body.text;
|
|
84
|
+
if (Buffer.byteLength(text, "utf8") > MAX_PROMPT_BYTES) {
|
|
85
|
+
reply.code(400).send({ error: "prompt_too_large" });
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|
|
88
|
+
out.text = text;
|
|
89
|
+
out.mode = body.mode ?? "send";
|
|
90
|
+
}
|
|
91
|
+
return out;
|
|
92
|
+
}
|
|
93
|
+
function handleError(reply, err) {
|
|
94
|
+
if (err instanceof QuickActionNotFoundError) {
|
|
95
|
+
return reply.code(404).send({ error: "action_not_found" });
|
|
96
|
+
}
|
|
97
|
+
reply.log.error({ err }, "quick-actions route error");
|
|
98
|
+
return reply.code(500).send({ error: "internal_error" });
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Spawn the command under `/bin/sh -c` with a scrubbed env (same
|
|
102
|
+
* posture as the integrated terminal — no pi-forge / provider
|
|
103
|
+
* secrets leak into chip output). stdout and stderr are captured
|
|
104
|
+
* separately so the chat card can render them in distinct blocks.
|
|
105
|
+
*/
|
|
106
|
+
async function runCommand(command, cwd, timeoutMs) {
|
|
107
|
+
return new Promise((resolve) => {
|
|
108
|
+
const proc = spawn("/bin/sh", ["-c", command], {
|
|
109
|
+
cwd,
|
|
110
|
+
env: scrubbedEnv(),
|
|
111
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
112
|
+
});
|
|
113
|
+
const stdoutChunks = [];
|
|
114
|
+
const stderrChunks = [];
|
|
115
|
+
let stdoutLen = 0;
|
|
116
|
+
let stderrLen = 0;
|
|
117
|
+
let truncated = false;
|
|
118
|
+
let timedOut = false;
|
|
119
|
+
proc.stdout?.on("data", (chunk) => {
|
|
120
|
+
const remaining = MAX_OUTPUT_BYTES - stdoutLen;
|
|
121
|
+
if (remaining <= 0) {
|
|
122
|
+
truncated = true;
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
if (chunk.length > remaining) {
|
|
126
|
+
stdoutChunks.push(chunk.subarray(0, remaining));
|
|
127
|
+
stdoutLen += remaining;
|
|
128
|
+
truncated = true;
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
stdoutChunks.push(chunk);
|
|
132
|
+
stdoutLen += chunk.length;
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
proc.stderr?.on("data", (chunk) => {
|
|
136
|
+
const remaining = MAX_OUTPUT_BYTES - stderrLen;
|
|
137
|
+
if (remaining <= 0) {
|
|
138
|
+
truncated = true;
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
if (chunk.length > remaining) {
|
|
142
|
+
stderrChunks.push(chunk.subarray(0, remaining));
|
|
143
|
+
stderrLen += remaining;
|
|
144
|
+
truncated = true;
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
stderrChunks.push(chunk);
|
|
148
|
+
stderrLen += chunk.length;
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
const timer = setTimeout(() => {
|
|
152
|
+
timedOut = true;
|
|
153
|
+
try {
|
|
154
|
+
proc.kill("SIGTERM");
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
// best-effort
|
|
158
|
+
}
|
|
159
|
+
// SIGKILL grace — match the exec-route convention.
|
|
160
|
+
setTimeout(() => {
|
|
161
|
+
try {
|
|
162
|
+
proc.kill("SIGKILL");
|
|
163
|
+
}
|
|
164
|
+
catch {
|
|
165
|
+
// best-effort
|
|
166
|
+
}
|
|
167
|
+
}, 2000);
|
|
168
|
+
}, timeoutMs);
|
|
169
|
+
proc.on("error", (err) => {
|
|
170
|
+
clearTimeout(timer);
|
|
171
|
+
// Spawn error (ENOENT on `/bin/sh`, etc.) — surface as a failed
|
|
172
|
+
// run with the error on stderr so the chat card shows it.
|
|
173
|
+
resolve({
|
|
174
|
+
exitCode: null,
|
|
175
|
+
stdout: Buffer.concat(stdoutChunks).toString("utf8"),
|
|
176
|
+
stderr: err.message,
|
|
177
|
+
timedOut,
|
|
178
|
+
truncated,
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
proc.on("close", (code) => {
|
|
182
|
+
clearTimeout(timer);
|
|
183
|
+
resolve({
|
|
184
|
+
exitCode: code,
|
|
185
|
+
stdout: Buffer.concat(stdoutChunks).toString("utf8"),
|
|
186
|
+
stderr: Buffer.concat(stderrChunks).toString("utf8"),
|
|
187
|
+
timedOut,
|
|
188
|
+
truncated,
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
export const quickActionRoutes = async (fastify) => {
|
|
194
|
+
fastify.get("/quick-actions", {
|
|
195
|
+
schema: {
|
|
196
|
+
description: "List all quick-action chips. Global (not per-project) — chips " +
|
|
197
|
+
"are operator-personal, same install-private rationale as the " +
|
|
198
|
+
"other forge-owned config files.",
|
|
199
|
+
tags: ["config"],
|
|
200
|
+
response: {
|
|
201
|
+
200: {
|
|
202
|
+
type: "object",
|
|
203
|
+
required: ["actions"],
|
|
204
|
+
properties: {
|
|
205
|
+
actions: { type: "array", items: quickActionSchema },
|
|
206
|
+
},
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
},
|
|
210
|
+
}, async () => ({ actions: await readQuickActions() }));
|
|
211
|
+
fastify.post("/quick-actions", {
|
|
212
|
+
schema: {
|
|
213
|
+
description: "Create a quick-action chip. Exactly one of `command` or `text` " +
|
|
214
|
+
"must be set — presence is the kind discriminator (no `kind` " +
|
|
215
|
+
"field on the wire, matches the MCP server-config convention). " +
|
|
216
|
+
"400 on both/neither, 400 on byte-cap overflow.",
|
|
217
|
+
tags: ["config"],
|
|
218
|
+
body: {
|
|
219
|
+
type: "object",
|
|
220
|
+
required: ["name"],
|
|
221
|
+
additionalProperties: false,
|
|
222
|
+
properties: {
|
|
223
|
+
name: { type: "string", minLength: 1, maxLength: 200 },
|
|
224
|
+
enabled: { type: "boolean" },
|
|
225
|
+
command: { type: "string" },
|
|
226
|
+
timeoutMs: { type: "integer", minimum: 1 },
|
|
227
|
+
text: { type: "string" },
|
|
228
|
+
mode: { type: "string", enum: ["send", "insert"] },
|
|
229
|
+
},
|
|
230
|
+
},
|
|
231
|
+
response: {
|
|
232
|
+
201: quickActionSchema,
|
|
233
|
+
400: errorSchema,
|
|
234
|
+
},
|
|
235
|
+
},
|
|
236
|
+
}, async (req, reply) => {
|
|
237
|
+
const validated = validateBody(req.body, reply);
|
|
238
|
+
if (validated === undefined)
|
|
239
|
+
return reply;
|
|
240
|
+
try {
|
|
241
|
+
const created = await createQuickAction(validated);
|
|
242
|
+
return reply.code(201).send(created);
|
|
243
|
+
}
|
|
244
|
+
catch (err) {
|
|
245
|
+
return handleError(reply, err);
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
fastify.put("/quick-actions/:id", {
|
|
249
|
+
schema: {
|
|
250
|
+
description: "Replace a quick-action chip. Full record on the body — switching " +
|
|
251
|
+
"kind (command ↔ prompt) drops the now-unused fields. Same " +
|
|
252
|
+
"validation rules as POST.",
|
|
253
|
+
tags: ["config"],
|
|
254
|
+
params: {
|
|
255
|
+
type: "object",
|
|
256
|
+
required: ["id"],
|
|
257
|
+
properties: { id: { type: "string" } },
|
|
258
|
+
},
|
|
259
|
+
body: {
|
|
260
|
+
type: "object",
|
|
261
|
+
required: ["name"],
|
|
262
|
+
additionalProperties: false,
|
|
263
|
+
properties: {
|
|
264
|
+
name: { type: "string", minLength: 1, maxLength: 200 },
|
|
265
|
+
enabled: { type: "boolean" },
|
|
266
|
+
command: { type: "string" },
|
|
267
|
+
timeoutMs: { type: "integer", minimum: 1 },
|
|
268
|
+
text: { type: "string" },
|
|
269
|
+
mode: { type: "string", enum: ["send", "insert"] },
|
|
270
|
+
},
|
|
271
|
+
},
|
|
272
|
+
response: {
|
|
273
|
+
200: quickActionSchema,
|
|
274
|
+
400: errorSchema,
|
|
275
|
+
404: errorSchema,
|
|
276
|
+
},
|
|
277
|
+
},
|
|
278
|
+
}, async (req, reply) => {
|
|
279
|
+
const validated = validateBody(req.body, reply);
|
|
280
|
+
if (validated === undefined)
|
|
281
|
+
return reply;
|
|
282
|
+
try {
|
|
283
|
+
const updated = await updateQuickAction(req.params.id, validated);
|
|
284
|
+
return updated;
|
|
285
|
+
}
|
|
286
|
+
catch (err) {
|
|
287
|
+
return handleError(reply, err);
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
fastify.delete("/quick-actions/:id", {
|
|
291
|
+
schema: {
|
|
292
|
+
description: "Delete a quick-action chip.",
|
|
293
|
+
tags: ["config"],
|
|
294
|
+
params: {
|
|
295
|
+
type: "object",
|
|
296
|
+
required: ["id"],
|
|
297
|
+
properties: { id: { type: "string" } },
|
|
298
|
+
},
|
|
299
|
+
response: {
|
|
300
|
+
204: { type: "null" },
|
|
301
|
+
404: errorSchema,
|
|
302
|
+
},
|
|
303
|
+
},
|
|
304
|
+
}, async (req, reply) => {
|
|
305
|
+
try {
|
|
306
|
+
await deleteQuickAction(req.params.id);
|
|
307
|
+
return reply.code(204).send();
|
|
308
|
+
}
|
|
309
|
+
catch (err) {
|
|
310
|
+
return handleError(reply, err);
|
|
311
|
+
}
|
|
312
|
+
});
|
|
313
|
+
fastify.post("/quick-actions/:id/run", {
|
|
314
|
+
schema: {
|
|
315
|
+
description: "Execute a command-kind quick action in the named project's " +
|
|
316
|
+
"cwd. Returns captured stdout/stderr and the exit code. The " +
|
|
317
|
+
"spawned shell inherits a SCRUBBED env (same as the " +
|
|
318
|
+
"integrated terminal — no pi-forge or provider secrets). " +
|
|
319
|
+
"Hard-gated under MINIMAL_UI: command runs return 403 " +
|
|
320
|
+
"`command_actions_disabled_in_minimal` regardless of who " +
|
|
321
|
+
"is calling. Prompt-kind actions are not executable here " +
|
|
322
|
+
"(420-style validation error) — those are a pure client " +
|
|
323
|
+
"concern that route through the composer or sendPrompt.",
|
|
324
|
+
tags: ["config"],
|
|
325
|
+
params: {
|
|
326
|
+
type: "object",
|
|
327
|
+
required: ["id"],
|
|
328
|
+
properties: { id: { type: "string" } },
|
|
329
|
+
},
|
|
330
|
+
body: {
|
|
331
|
+
type: "object",
|
|
332
|
+
required: ["projectId"],
|
|
333
|
+
additionalProperties: false,
|
|
334
|
+
properties: {
|
|
335
|
+
projectId: { type: "string", minLength: 1 },
|
|
336
|
+
},
|
|
337
|
+
},
|
|
338
|
+
response: {
|
|
339
|
+
200: runResultSchema,
|
|
340
|
+
400: errorSchema,
|
|
341
|
+
403: errorSchema,
|
|
342
|
+
404: errorSchema,
|
|
343
|
+
},
|
|
344
|
+
},
|
|
345
|
+
}, async (req, reply) => {
|
|
346
|
+
// Defense in depth — the client also hides command chips
|
|
347
|
+
// under MINIMAL_UI, but a stale tab or scripted caller could
|
|
348
|
+
// still POST here. Refuse at the route.
|
|
349
|
+
if (config.minimalUi) {
|
|
350
|
+
return reply.code(403).send({ error: "command_actions_disabled_in_minimal" });
|
|
351
|
+
}
|
|
352
|
+
const action = await getQuickAction(req.params.id);
|
|
353
|
+
if (action === undefined) {
|
|
354
|
+
return reply.code(404).send({ error: "action_not_found" });
|
|
355
|
+
}
|
|
356
|
+
if (isPromptAction(action)) {
|
|
357
|
+
return reply.code(400).send({
|
|
358
|
+
error: "not_a_command_action",
|
|
359
|
+
message: "prompt actions are dispatched client-side, not via this route",
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
if (!isCommandAction(action)) {
|
|
363
|
+
return reply.code(400).send({ error: "invalid_action" });
|
|
364
|
+
}
|
|
365
|
+
const project = await getProject(req.body.projectId);
|
|
366
|
+
if (project === undefined) {
|
|
367
|
+
return reply.code(404).send({ error: "project_not_found" });
|
|
368
|
+
}
|
|
369
|
+
const timeoutMs = Math.min(action.timeoutMs ?? DEFAULT_TIMEOUT_MS, MAX_TIMEOUT_MS);
|
|
370
|
+
const started = Date.now();
|
|
371
|
+
const result = await runCommand(action.command, project.path, timeoutMs);
|
|
372
|
+
const durationMs = Date.now() - started;
|
|
373
|
+
return {
|
|
374
|
+
success: result.exitCode === 0 && !result.timedOut,
|
|
375
|
+
exitCode: result.exitCode,
|
|
376
|
+
stdout: result.stdout,
|
|
377
|
+
stderr: result.stderr,
|
|
378
|
+
durationMs,
|
|
379
|
+
timedOut: result.timedOut,
|
|
380
|
+
truncated: result.truncated,
|
|
381
|
+
};
|
|
382
|
+
});
|
|
383
|
+
};
|
|
384
|
+
//# sourceMappingURL=quick-actions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quick-actions.js","sourceRoot":"","sources":["../../src/routes/quick-actions.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { getSession } from "../session-registry.js";
|
|
2
|
+
import { getState } from "../todo/store.js";
|
|
3
|
+
import { errorSchema } from "./_schemas.js";
|
|
4
|
+
/**
|
|
5
|
+
* GET /sessions/:id/todos
|
|
6
|
+
*
|
|
7
|
+
* Returns the current todo state for a session. Used by the UI
|
|
8
|
+
* panel as the initial fetch when an SSE snapshot hasn't landed
|
|
9
|
+
* yet (cold load, cross-tab join). The store's `getState` is
|
|
10
|
+
* cache-first with replay-on-miss, so this is honest after a
|
|
11
|
+
* server restart even if the cache is empty.
|
|
12
|
+
*
|
|
13
|
+
* The wire shape mirrors the SSE `todo_update` event so the
|
|
14
|
+
* client can use one normaliser for both paths.
|
|
15
|
+
*/
|
|
16
|
+
const taskSchema = {
|
|
17
|
+
type: "object",
|
|
18
|
+
required: ["id", "subject", "status"],
|
|
19
|
+
additionalProperties: true,
|
|
20
|
+
properties: {
|
|
21
|
+
id: { type: "integer" },
|
|
22
|
+
subject: { type: "string" },
|
|
23
|
+
description: { type: "string" },
|
|
24
|
+
activeForm: { type: "string" },
|
|
25
|
+
status: { type: "string", enum: ["pending", "in_progress", "completed", "deleted"] },
|
|
26
|
+
blockedBy: { type: "array", items: { type: "integer" } },
|
|
27
|
+
owner: { type: "string" },
|
|
28
|
+
metadata: { type: "object", additionalProperties: true },
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
export const todoRoutes = async (fastify) => {
|
|
32
|
+
fastify.get("/sessions/:id/todos", {
|
|
33
|
+
schema: {
|
|
34
|
+
description: "Return the current todo list for this session. Cache-first; " +
|
|
35
|
+
"rebuilds from the session branch on cache miss so a server " +
|
|
36
|
+
"restart doesn't lie about state.",
|
|
37
|
+
tags: ["sessions"],
|
|
38
|
+
params: {
|
|
39
|
+
type: "object",
|
|
40
|
+
required: ["id"],
|
|
41
|
+
properties: { id: { type: "string" } },
|
|
42
|
+
},
|
|
43
|
+
response: {
|
|
44
|
+
200: {
|
|
45
|
+
type: "object",
|
|
46
|
+
required: ["tasks", "nextId"],
|
|
47
|
+
properties: {
|
|
48
|
+
tasks: { type: "array", items: taskSchema },
|
|
49
|
+
nextId: { type: "integer" },
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
404: errorSchema,
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
}, async (req, reply) => {
|
|
56
|
+
const live = getSession(req.params.id);
|
|
57
|
+
if (live === undefined) {
|
|
58
|
+
return reply.code(404).send({ error: "session_not_found" });
|
|
59
|
+
}
|
|
60
|
+
// AgentSession.sessionManager is the public accessor (see
|
|
61
|
+
// agent-session.d.ts). getState is cache-first with replay-
|
|
62
|
+
// on-miss, so this stays honest after a server restart.
|
|
63
|
+
const state = getState(req.params.id, live.session.sessionManager);
|
|
64
|
+
return { tasks: state.tasks, nextId: state.nextId };
|
|
65
|
+
});
|
|
66
|
+
};
|
|
67
|
+
//# sourceMappingURL=todos.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"todos.js","sourceRoot":"","sources":["../../src/routes/todos.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,GAAG;IACjB,IAAI,EAAE,QAAQ;IACd,QAAQ,EAAE,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,CAAC;IACrC,oBAAoB,EAAE,IAAI;IAC1B,UAAU,EAAE;QACV,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;QACvB,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QAC3B,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QAC/B,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QAC9B,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,SAAS,EAAE,aAAa,EAAE,WAAW,EAAE,SAAS,CAAC,EAAE;QACpF,SAAS,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE;QACxD,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QACzB,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,oBAAoB,EAAE,IAAI,EAAE;KACzD;CACO,CAAC;AAEX,MAAM,CAAC,MAAM,UAAU,GAAuB,KAAK,EAAE,OAAO,EAAE,EAAE;IAC9D,OAAO,CAAC,GAAG,CACT,qBAAqB,EACrB;QACE,MAAM,EAAE;YACN,WAAW,EACT,8DAA8D;gBAC9D,6DAA6D;gBAC7D,kCAAkC;YACpC,IAAI,EAAE,CAAC,UAAU,CAAC;YAClB,MAAM,EAAE;gBACN,IAAI,EAAE,QAAQ;gBACd,QAAQ,EAAE,CAAC,IAAI,CAAC;gBAChB,UAAU,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;aACvC;YACD,QAAQ,EAAE;gBACR,GAAG,EAAE;oBACH,IAAI,EAAE,QAAQ;oBACd,QAAQ,EAAE,CAAC,OAAO,EAAE,QAAQ,CAAC;oBAC7B,UAAU,EAAE;wBACV,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE;wBAC3C,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;qBAC5B;iBACF;gBACD,GAAG,EAAE,WAAW;aACjB;SACF;KACF,EACD,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE;QACnB,MAAM,IAAI,GAAG,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACvC,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAC,CAAC;QAC9D,CAAC;QACD,0DAA0D;QAC1D,4DAA4D;QAC5D,wDAAwD;QACxD,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;QACnE,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC;IACtD,CAAC,CACF,CAAC;AACJ,CAAC,CAAC"}
|
|
@@ -9,6 +9,11 @@ import { readProjects } from "./project-manager.js";
|
|
|
9
9
|
import { filterEnabledTools, readToolOverrides } from "./tool-overrides.js";
|
|
10
10
|
import { discoverExtensionResources } from "./extensions-discovery.js";
|
|
11
11
|
import { customToolsForProject as mcpCustomToolsForProject, ensureProjectLoaded as mcpEnsureProjectLoaded, isGloballyEnabled as mcpIsGloballyEnabled, } from "./mcp/manager.js";
|
|
12
|
+
import { createAskUserQuestionTool } from "./ask-user-question/tool.js";
|
|
13
|
+
import { createTodoTool } from "./todo/tool.js";
|
|
14
|
+
import { clearForSession as clearTodoForSession, refreshFromBranch as refreshTodoFromBranch, } from "./todo/store.js";
|
|
15
|
+
import { createProcessTool } from "./processes/tool.js";
|
|
16
|
+
import { processManager } from "./processes/manager.js";
|
|
12
17
|
export class SessionNotFoundError extends Error {
|
|
13
18
|
constructor(id) {
|
|
14
19
|
super(`session not found: ${id}`);
|
|
@@ -52,6 +57,21 @@ export const BUILTIN_TOOL_NAMES = [
|
|
|
52
57
|
"grep",
|
|
53
58
|
"find",
|
|
54
59
|
"ls",
|
|
60
|
+
// ask_user_question is implemented in pi-forge (see ask-user-question/),
|
|
61
|
+
// not in the pi SDK. Listed here so the Tools settings tab surfaces it
|
|
62
|
+
// under "Built-in tools" — disabling it filters it out of the allowlist
|
|
63
|
+
// passed to createAgentSession, so the agent never sees the tool.
|
|
64
|
+
"ask_user_question",
|
|
65
|
+
// todo is implemented in pi-forge (see todo/), contract-compatible with
|
|
66
|
+
// @juicesharp/rpiv-todo. Same disable-via-settings semantics as
|
|
67
|
+
// ask_user_question.
|
|
68
|
+
"todo",
|
|
69
|
+
// process is implemented in pi-forge (see processes/), contract-
|
|
70
|
+
// compatible with @aliou/pi-processes. Manages background processes
|
|
71
|
+
// the agent spawns (dev servers, watchers, etc.) — separate spawn
|
|
72
|
+
// surface from bash, with lifecycle management + log capture +
|
|
73
|
+
// regex watches. Disable here to filter out of the allowlist.
|
|
74
|
+
"process",
|
|
55
75
|
];
|
|
56
76
|
/**
|
|
57
77
|
* Build the `tools` allowlist passed to `createAgentSession` for this
|
|
@@ -247,7 +267,15 @@ export async function createSession(projectId, workspacePath) {
|
|
|
247
267
|
// agentDir IS passed: without it, the SDK falls back to ~/.pi/agent and
|
|
248
268
|
// ignores PI_CONFIG_DIR entirely, breaking auth.json/models.json wiring
|
|
249
269
|
// for Phase 6's prompt route.
|
|
250
|
-
const
|
|
270
|
+
const mcpTools = await resolveMcpCustomTools(projectId, workspacePath);
|
|
271
|
+
// SessionManager.getSessionId() is synchronous and stable from
|
|
272
|
+
// create() onward — read it BEFORE createAgentSession so the
|
|
273
|
+
// forge-native ask_user_question tool can bind to the right
|
|
274
|
+
// session in its execute() closure.
|
|
275
|
+
const askTool = createAskUserQuestionTool(sessionManager.getSessionId());
|
|
276
|
+
const todoTool = createTodoTool(sessionManager.getSessionId(), sessionManager);
|
|
277
|
+
const processTool = createProcessTool(sessionManager.getSessionId(), workspacePath);
|
|
278
|
+
const customTools = [...mcpTools, askTool, todoTool, processTool];
|
|
251
279
|
const settingsManager = await buildSessionSettingsManager(workspacePath, projectId);
|
|
252
280
|
const resourceLoader = await buildForgeResourceLoader(workspacePath, config.piConfigDir, settingsManager, projectId);
|
|
253
281
|
const { session } = await createAgentSession({
|
|
@@ -426,7 +454,15 @@ export async function resumeSession(sessionId, projectId, workspacePath) {
|
|
|
426
454
|
// collapses to the project session dir.
|
|
427
455
|
const childSessionDir = match.parentSessionId !== undefined ? join(match.path, "..") : dir;
|
|
428
456
|
const sessionManager = SessionManager.open(match.path, childSessionDir, workspacePath);
|
|
429
|
-
const
|
|
457
|
+
const mcpTools = await resolveMcpCustomTools(projectId, workspacePath);
|
|
458
|
+
const askTool = createAskUserQuestionTool(sessionManager.getSessionId());
|
|
459
|
+
const todoTool = createTodoTool(sessionManager.getSessionId(), sessionManager);
|
|
460
|
+
const processTool = createProcessTool(sessionManager.getSessionId(), workspacePath);
|
|
461
|
+
const customTools = [...mcpTools, askTool, todoTool, processTool];
|
|
462
|
+
// Resumed session — refresh the todo cache from the branch so
|
|
463
|
+
// the UI panel sees the persisted state on first SSE connect,
|
|
464
|
+
// not an empty list.
|
|
465
|
+
refreshTodoFromBranch(sessionManager.getSessionId(), sessionManager);
|
|
430
466
|
const settingsManager = await buildSessionSettingsManager(workspacePath, projectId);
|
|
431
467
|
const resourceLoader = await buildForgeResourceLoader(workspacePath, config.piConfigDir, settingsManager, projectId);
|
|
432
468
|
const { session } = await createAgentSession({
|
|
@@ -604,6 +640,17 @@ export async function disposeSession(sessionId) {
|
|
|
604
640
|
catch {
|
|
605
641
|
// ignore — SDK doesn't currently throw, but H2-defensive
|
|
606
642
|
}
|
|
643
|
+
// Drop the todo cache for this session. The cache is a fast
|
|
644
|
+
// path; even without this, a future session with the same id
|
|
645
|
+
// would recover via replay-on-miss. Cleaner to be explicit.
|
|
646
|
+
clearTodoForSession(sessionId);
|
|
647
|
+
// Terminate every live process owned by this session (SIGTERM,
|
|
648
|
+
// brief grace, SIGKILL) and remove the per-session log dir.
|
|
649
|
+
// Best-effort + bounded — disposeSession itself can take up to
|
|
650
|
+
// GRACE_MS but no longer; the outer disposeAllSessions caller
|
|
651
|
+
// doesn't block on this beyond its own ABORT_TIMEOUT_MS race
|
|
652
|
+
// because we await it last.
|
|
653
|
+
await processManager.disposeSession(sessionId).catch(() => undefined);
|
|
607
654
|
}
|
|
608
655
|
finally {
|
|
609
656
|
registry.delete(sessionId);
|
|
@@ -1015,7 +1062,15 @@ async function forkSessionLocked(sessionId, entryId) {
|
|
|
1015
1062
|
throw new Error("fork_failed");
|
|
1016
1063
|
const dir = sessionDirFor(source.projectId);
|
|
1017
1064
|
const sessionManager = SessionManager.open(newPath, dir, source.workspacePath);
|
|
1018
|
-
const
|
|
1065
|
+
const mcpTools = await resolveMcpCustomTools(source.projectId, source.workspacePath);
|
|
1066
|
+
const askTool = createAskUserQuestionTool(sessionManager.getSessionId());
|
|
1067
|
+
const todoTool = createTodoTool(sessionManager.getSessionId(), sessionManager);
|
|
1068
|
+
const processTool = createProcessTool(sessionManager.getSessionId(), source.workspacePath);
|
|
1069
|
+
const customTools = [...mcpTools, askTool, todoTool, processTool];
|
|
1070
|
+
// Forked session — replay the branch (which now belongs to the
|
|
1071
|
+
// fork) so the new session's todo cache reflects the inherited
|
|
1072
|
+
// state, not the parent's stale entry.
|
|
1073
|
+
refreshTodoFromBranch(sessionManager.getSessionId(), sessionManager);
|
|
1019
1074
|
const settingsManager = await buildSessionSettingsManager(source.workspacePath, source.projectId);
|
|
1020
1075
|
const resourceLoader = await buildForgeResourceLoader(source.workspacePath, config.piConfigDir, settingsManager, source.projectId);
|
|
1021
1076
|
const { session } = await createAgentSession({
|
|
@@ -1079,7 +1134,20 @@ async function forkSessionLocked(sessionId, entryId) {
|
|
|
1079
1134
|
try {
|
|
1080
1135
|
source.unsubscribe();
|
|
1081
1136
|
const restoredManager = SessionManager.open(originalSourceFile, dir, source.workspacePath);
|
|
1082
|
-
const
|
|
1137
|
+
const restoredMcpTools = await resolveMcpCustomTools(source.projectId, source.workspacePath);
|
|
1138
|
+
const restoredAskTool = createAskUserQuestionTool(restoredManager.getSessionId());
|
|
1139
|
+
const restoredTodoTool = createTodoTool(restoredManager.getSessionId(), restoredManager);
|
|
1140
|
+
const restoredProcessTool = createProcessTool(restoredManager.getSessionId(), source.workspacePath);
|
|
1141
|
+
const restoredCustomTools = [
|
|
1142
|
+
...restoredMcpTools,
|
|
1143
|
+
restoredAskTool,
|
|
1144
|
+
restoredTodoTool,
|
|
1145
|
+
restoredProcessTool,
|
|
1146
|
+
];
|
|
1147
|
+
// Re-derive the original source's todo cache from the (now
|
|
1148
|
+
// un-mutated) source JSONL — the SDK's fork machinery left
|
|
1149
|
+
// the cache pointing at fork state.
|
|
1150
|
+
refreshTodoFromBranch(restoredManager.getSessionId(), restoredManager);
|
|
1083
1151
|
const restoredSettingsManager = await buildSessionSettingsManager(source.workspacePath, source.projectId);
|
|
1084
1152
|
const restoredResourceLoader = await buildForgeResourceLoader(source.workspacePath, config.piConfigDir, restoredSettingsManager, source.projectId);
|
|
1085
1153
|
const { session: restoredSession } = await createAgentSession({
|