pi-forge 0.0.0 → 1.1.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/LICENSE +21 -0
- package/README.md +48 -4
- package/bin/pi-forge.mjs +37 -0
- package/dist/client/assets/CodeMirrorEditor-BqaaP1EE.js +34 -0
- package/dist/client/assets/CodeMirrorEditor-BqaaP1EE.js.map +1 -0
- package/dist/client/assets/index-B-529kgJ.css +32 -0
- package/dist/client/assets/index-BzKzxXFs.js +392 -0
- package/dist/client/assets/index-BzKzxXFs.js.map +1 -0
- package/dist/client/assets/workbox-window.prod.es5-BBnX5xw4.js +3 -0
- package/dist/client/assets/workbox-window.prod.es5-BBnX5xw4.js.map +1 -0
- package/dist/client/icons/icon-192.png +0 -0
- package/dist/client/icons/icon-512.png +0 -0
- package/dist/client/icons/icon-maskable-512.png +0 -0
- package/dist/client/icons/icon.svg +9 -0
- package/dist/client/index.html +24 -0
- package/dist/client/manifest.webmanifest +1 -0
- package/dist/client/offline.html +142 -0
- package/dist/client/sw.js +3 -0
- package/dist/client/sw.js.map +1 -0
- package/dist/client/workbox-6d7155ed.js +3 -0
- package/dist/client/workbox-6d7155ed.js.map +1 -0
- package/dist/server/agent-resource-loader.js +126 -0
- package/dist/server/agent-resource-loader.js.map +1 -0
- package/dist/server/attachment-converters.js +96 -0
- package/dist/server/attachment-converters.js.map +1 -0
- package/dist/server/auth.js +209 -0
- package/dist/server/auth.js.map +1 -0
- package/dist/server/compaction-history.js +106 -0
- package/dist/server/compaction-history.js.map +1 -0
- package/dist/server/concurrency.js +49 -0
- package/dist/server/concurrency.js.map +1 -0
- package/dist/server/config-export.js +220 -0
- package/dist/server/config-export.js.map +1 -0
- package/dist/server/config-manager.js +528 -0
- package/dist/server/config-manager.js.map +1 -0
- package/dist/server/config.js +326 -0
- package/dist/server/config.js.map +1 -0
- package/dist/server/conversion-worker.mjs +90 -0
- package/dist/server/diagnostics.js +137 -0
- package/dist/server/diagnostics.js.map +1 -0
- package/dist/server/extensions-discovery.js +147 -0
- package/dist/server/extensions-discovery.js.map +1 -0
- package/dist/server/file-manager.js +734 -0
- package/dist/server/file-manager.js.map +1 -0
- package/dist/server/file-references.js +215 -0
- package/dist/server/file-references.js.map +1 -0
- package/dist/server/file-searcher.js +385 -0
- package/dist/server/file-searcher.js.map +1 -0
- package/dist/server/git-runner.js +684 -0
- package/dist/server/git-runner.js.map +1 -0
- package/dist/server/index.js +468 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/mcp/config.js +133 -0
- package/dist/server/mcp/config.js.map +1 -0
- package/dist/server/mcp/manager.js +351 -0
- package/dist/server/mcp/manager.js.map +1 -0
- package/dist/server/mcp/tool-bridge.js +173 -0
- package/dist/server/mcp/tool-bridge.js.map +1 -0
- package/dist/server/project-manager.js +301 -0
- package/dist/server/project-manager.js.map +1 -0
- package/dist/server/pty-manager.js +354 -0
- package/dist/server/pty-manager.js.map +1 -0
- package/dist/server/routes/_schemas.js +73 -0
- package/dist/server/routes/_schemas.js.map +1 -0
- package/dist/server/routes/auth.js +164 -0
- package/dist/server/routes/auth.js.map +1 -0
- package/dist/server/routes/config.js +1163 -0
- package/dist/server/routes/config.js.map +1 -0
- package/dist/server/routes/control.js +464 -0
- package/dist/server/routes/control.js.map +1 -0
- package/dist/server/routes/exec.js +217 -0
- package/dist/server/routes/exec.js.map +1 -0
- package/dist/server/routes/files.js +847 -0
- package/dist/server/routes/files.js.map +1 -0
- package/dist/server/routes/git.js +837 -0
- package/dist/server/routes/git.js.map +1 -0
- package/dist/server/routes/health.js +97 -0
- package/dist/server/routes/health.js.map +1 -0
- package/dist/server/routes/mcp.js +300 -0
- package/dist/server/routes/mcp.js.map +1 -0
- package/dist/server/routes/projects.js +259 -0
- package/dist/server/routes/projects.js.map +1 -0
- package/dist/server/routes/prompt.js +496 -0
- package/dist/server/routes/prompt.js.map +1 -0
- package/dist/server/routes/sessions.js +783 -0
- package/dist/server/routes/sessions.js.map +1 -0
- package/dist/server/routes/stream.js +69 -0
- package/dist/server/routes/stream.js.map +1 -0
- package/dist/server/routes/terminal.js +335 -0
- package/dist/server/routes/terminal.js.map +1 -0
- package/dist/server/session-registry.js +1197 -0
- package/dist/server/session-registry.js.map +1 -0
- package/dist/server/skill-overrides.js +151 -0
- package/dist/server/skill-overrides.js.map +1 -0
- package/dist/server/skills-export.js +257 -0
- package/dist/server/skills-export.js.map +1 -0
- package/dist/server/sse-bridge.js +220 -0
- package/dist/server/sse-bridge.js.map +1 -0
- package/dist/server/tool-overrides.js +277 -0
- package/dist/server/tool-overrides.js.map +1 -0
- package/dist/server/turn-diff-builder.js +280 -0
- package/dist/server/turn-diff-builder.js.map +1 -0
- package/package.json +53 -12
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { errorSchema } from "./_schemas.js";
|
|
3
|
+
import { getSession } from "../session-registry.js";
|
|
4
|
+
import { scrubbedEnv } from "../pty-manager.js";
|
|
5
|
+
/**
|
|
6
|
+
* One-shot user bash execution — the chat input's `!` / `!!` prefix.
|
|
7
|
+
*
|
|
8
|
+
* Mirrors pi-tui's UserBashEvent semantics:
|
|
9
|
+
* - `!cmd` → output appended to the session's message history as a
|
|
10
|
+
* BashExecutionMessage; the next agent turn sees it in
|
|
11
|
+
* LLM context.
|
|
12
|
+
* - `!!cmd` → same render, `excludeFromContext: true` keeps it out
|
|
13
|
+
* of the next turn's prompt. Local convenience only.
|
|
14
|
+
*
|
|
15
|
+
* Implementation uses the SDK's `AgentSession.executeBash()` directly.
|
|
16
|
+
* That call:
|
|
17
|
+
* 1. Spawns the command via the BashOperations we hand it
|
|
18
|
+
* 2. Pushes a BashExecutionMessage into `agent.state.messages` so
|
|
19
|
+
* the next prompt's context window includes it (or skips it
|
|
20
|
+
* when excludeFromContext is true)
|
|
21
|
+
* 3. Persists the message via `sessionManager.appendMessage` so the
|
|
22
|
+
* session JSONL captures it on agent_end (pi defers session
|
|
23
|
+
* writes until at least one assistant message has landed —
|
|
24
|
+
* our message is held in the in-memory list until then)
|
|
25
|
+
*
|
|
26
|
+
* Hand-rolling the spawn would let us emit ANSI-stripped output and
|
|
27
|
+
* apply our own timeout, but it would NOT update agent.state.messages
|
|
28
|
+
* (that's a private field). The SDK's path is the supported way to
|
|
29
|
+
* inject context.
|
|
30
|
+
*
|
|
31
|
+
* Security posture: BashOperations is overridden to inject our
|
|
32
|
+
* `scrubbedEnv()` — an allowlist-based filter that only passes
|
|
33
|
+
* known-harmless system vars (PATH, HOME, TERM, locales, …). pi-forge
|
|
34
|
+
* secrets, provider keys, cloud credentials, and any other host-env
|
|
35
|
+
* vars are dropped unless the operator opts them back in via
|
|
36
|
+
* `TERMINAL_PASSTHROUGH_ENV`. Matches the integrated terminal's
|
|
37
|
+
* posture. The agent's own bash TOOL may still have an env-exposure
|
|
38
|
+
* surface — that's a separate fix for a separate code path.
|
|
39
|
+
*/
|
|
40
|
+
const DEFAULT_TIMEOUT_MS = 30_000;
|
|
41
|
+
/**
|
|
42
|
+
* Build a BashOperations that delegates to local spawn, but with our
|
|
43
|
+
* scrubbed env. createLocalBashOperations from the SDK would inherit
|
|
44
|
+
* `process.env` verbatim, leaking secrets the pi-forge process
|
|
45
|
+
* carries (JWT_SECRET, API_KEY, etc.) — see
|
|
46
|
+
* pty-manager.TERMINAL_ENV_ALLOWLIST for the full set of allowed
|
|
47
|
+
* passthrough vars and rationale.
|
|
48
|
+
*/
|
|
49
|
+
function forgeBashOperations() {
|
|
50
|
+
return {
|
|
51
|
+
exec: (command, cwd, options) => {
|
|
52
|
+
return new Promise((resolve, reject) => {
|
|
53
|
+
const proc = spawn("/bin/sh", ["-c", command], {
|
|
54
|
+
cwd,
|
|
55
|
+
env: scrubbedEnv(),
|
|
56
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
57
|
+
});
|
|
58
|
+
// Honor an external AbortSignal (the SDK ties this to its own
|
|
59
|
+
// _bashAbortController so abortBash() propagates).
|
|
60
|
+
const onAbort = () => {
|
|
61
|
+
try {
|
|
62
|
+
proc.kill("SIGTERM");
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
// best-effort
|
|
66
|
+
}
|
|
67
|
+
// SIGKILL after grace if SIGTERM is ignored.
|
|
68
|
+
setTimeout(() => {
|
|
69
|
+
try {
|
|
70
|
+
proc.kill("SIGKILL");
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
// best-effort
|
|
74
|
+
}
|
|
75
|
+
}, 2000);
|
|
76
|
+
};
|
|
77
|
+
if (options.signal !== undefined) {
|
|
78
|
+
if (options.signal.aborted)
|
|
79
|
+
onAbort();
|
|
80
|
+
else
|
|
81
|
+
options.signal.addEventListener("abort", onAbort, { once: true });
|
|
82
|
+
}
|
|
83
|
+
// Stream chunks back so the SDK's truncation-and-buffering
|
|
84
|
+
// logic gets to apply (executor caps total output, writes
|
|
85
|
+
// overflow to a temp file, etc.).
|
|
86
|
+
proc.stdout?.on("data", (data) => options.onData(data));
|
|
87
|
+
proc.stderr?.on("data", (data) => options.onData(data));
|
|
88
|
+
proc.on("error", (err) => reject(err));
|
|
89
|
+
proc.on("close", (code) => resolve({ exitCode: code }));
|
|
90
|
+
});
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Wrap a BashOperations so that `options.signal` is the union of the
|
|
96
|
+
* caller's signal and our own timeout signal. The SDK's executeBash
|
|
97
|
+
* passes its abort controller as `options.signal`; we still need our
|
|
98
|
+
* 30s wall-clock cap, so this union forwards an abort from EITHER
|
|
99
|
+
* source to the inner exec.
|
|
100
|
+
*/
|
|
101
|
+
function timeoutOperations(inner, timeoutSignal) {
|
|
102
|
+
return {
|
|
103
|
+
exec: (command, cwd, options) => {
|
|
104
|
+
const merged = options.signal !== undefined ? mergeSignals(options.signal, timeoutSignal) : timeoutSignal;
|
|
105
|
+
return inner.exec(command, cwd, { ...options, signal: merged });
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
function mergeSignals(a, b) {
|
|
110
|
+
const controller = new AbortController();
|
|
111
|
+
const onAbort = () => controller.abort();
|
|
112
|
+
if (a.aborted || b.aborted) {
|
|
113
|
+
controller.abort();
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
a.addEventListener("abort", onAbort, { once: true });
|
|
117
|
+
b.addEventListener("abort", onAbort, { once: true });
|
|
118
|
+
}
|
|
119
|
+
return controller.signal;
|
|
120
|
+
}
|
|
121
|
+
export const execRoutes = async (fastify) => {
|
|
122
|
+
fastify.post("/sessions/:id/exec", {
|
|
123
|
+
schema: {
|
|
124
|
+
description: "Run a one-shot bash command in the session's project cwd " +
|
|
125
|
+
"(the chat input's `!` / `!!` prefix dispatches here). The " +
|
|
126
|
+
"result is added to the session's in-memory context AND " +
|
|
127
|
+
"persisted to the session JSONL (deferred until the next " +
|
|
128
|
+
"agent turn finalizes — pi's session-write is gated on " +
|
|
129
|
+
"having at least one assistant message). With " +
|
|
130
|
+
"`excludeFromContext: true` (the `!!` prefix) the result " +
|
|
131
|
+
"is recorded but kept out of the next turn's LLM input. " +
|
|
132
|
+
"Output is captured whole — no streaming for v1. The " +
|
|
133
|
+
"spawned shell inherits a scrubbed env (no pi-forge / " +
|
|
134
|
+
"provider secrets), same posture as the integrated " +
|
|
135
|
+
"terminal.",
|
|
136
|
+
tags: ["sessions"],
|
|
137
|
+
params: {
|
|
138
|
+
type: "object",
|
|
139
|
+
required: ["id"],
|
|
140
|
+
properties: { id: { type: "string" } },
|
|
141
|
+
},
|
|
142
|
+
body: {
|
|
143
|
+
type: "object",
|
|
144
|
+
required: ["command"],
|
|
145
|
+
additionalProperties: false,
|
|
146
|
+
properties: {
|
|
147
|
+
command: { type: "string", minLength: 1, maxLength: 4096 },
|
|
148
|
+
excludeFromContext: { type: "boolean" },
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
response: {
|
|
152
|
+
200: {
|
|
153
|
+
type: "object",
|
|
154
|
+
required: ["exitCode", "output", "durationMs", "truncated", "cancelled"],
|
|
155
|
+
properties: {
|
|
156
|
+
exitCode: { type: ["integer", "null"] },
|
|
157
|
+
output: { type: "string" },
|
|
158
|
+
durationMs: { type: "integer" },
|
|
159
|
+
truncated: { type: "boolean" },
|
|
160
|
+
cancelled: { type: "boolean" },
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
404: errorSchema,
|
|
164
|
+
500: errorSchema,
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
}, async (req, reply) => {
|
|
168
|
+
const live = getSession(req.params.id);
|
|
169
|
+
if (live === undefined) {
|
|
170
|
+
return reply.code(404).send({ error: "session_not_found" });
|
|
171
|
+
}
|
|
172
|
+
const { command, excludeFromContext = false } = req.body;
|
|
173
|
+
const started = Date.now();
|
|
174
|
+
// Defense-in-depth timeout — the SDK's bash executor has its
|
|
175
|
+
// own truncation behavior but no time cap. We pre-bake an abort
|
|
176
|
+
// signal that fires after DEFAULT_TIMEOUT_MS so a runaway loop
|
|
177
|
+
// can't tie up the request handler indefinitely.
|
|
178
|
+
const timeoutController = new AbortController();
|
|
179
|
+
const timer = setTimeout(() => timeoutController.abort(), DEFAULT_TIMEOUT_MS);
|
|
180
|
+
try {
|
|
181
|
+
const result = await live.session.executeBash(command, undefined, {
|
|
182
|
+
excludeFromContext,
|
|
183
|
+
operations: timeoutOperations(forgeBashOperations(), timeoutController.signal),
|
|
184
|
+
});
|
|
185
|
+
const durationMs = Date.now() - started;
|
|
186
|
+
live.lastActivityAt = new Date();
|
|
187
|
+
// Cross-tab refetch trigger — every other browser viewing this
|
|
188
|
+
// session schedules a getMessages refetch on `user_bash_result`.
|
|
189
|
+
// The acting tab refetches off the HTTP response directly.
|
|
190
|
+
for (const c of live.clients) {
|
|
191
|
+
try {
|
|
192
|
+
c.send({ type: "user_bash_result" });
|
|
193
|
+
}
|
|
194
|
+
catch {
|
|
195
|
+
// best-effort fan-out; sse-bridge handles client drop on its own
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return {
|
|
199
|
+
exitCode: result.exitCode === undefined ? null : result.exitCode,
|
|
200
|
+
output: result.output,
|
|
201
|
+
durationMs,
|
|
202
|
+
truncated: result.truncated,
|
|
203
|
+
cancelled: result.cancelled,
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
catch (err) {
|
|
207
|
+
return reply.code(500).send({
|
|
208
|
+
error: "exec_failed",
|
|
209
|
+
message: err instanceof Error ? err.message : String(err),
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
finally {
|
|
213
|
+
clearTimeout(timer);
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
};
|
|
217
|
+
//# sourceMappingURL=exec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exec.js","sourceRoot":"","sources":["../../src/routes/exec.ts"],"names":[],"mappings":"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"}
|