@kenkaiiii/ggcoder 5.28.0 → 5.29.1
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/dist/app-sidecar-auth-broadcast.test.d.ts +2 -0
- package/dist/app-sidecar-auth-broadcast.test.d.ts.map +1 -0
- package/dist/app-sidecar-auth-broadcast.test.js +271 -0
- package/dist/app-sidecar-auth-broadcast.test.js.map +1 -0
- package/dist/app-sidecar-sessions.test.js +8 -1
- package/dist/app-sidecar-sessions.test.js.map +1 -1
- package/dist/app-sidecar.js +151 -10
- package/dist/app-sidecar.js.map +1 -1
- package/dist/core/agent-session-checkpoint-flush.test.d.ts +2 -0
- package/dist/core/agent-session-checkpoint-flush.test.d.ts.map +1 -0
- package/dist/core/agent-session-checkpoint-flush.test.js +201 -0
- package/dist/core/agent-session-checkpoint-flush.test.js.map +1 -0
- package/dist/core/agent-session-crash-durability.test.d.ts +2 -0
- package/dist/core/agent-session-crash-durability.test.d.ts.map +1 -0
- package/dist/core/agent-session-crash-durability.test.js +95 -0
- package/dist/core/agent-session-crash-durability.test.js.map +1 -0
- package/dist/core/agent-session-review-coverage.test.js +75 -22
- package/dist/core/agent-session-review-coverage.test.js.map +1 -1
- package/dist/core/agent-session.d.ts +53 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +132 -8
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/event-bus.d.ts +4 -0
- package/dist/core/event-bus.d.ts.map +1 -1
- package/dist/core/event-bus.js +3 -0
- package/dist/core/event-bus.js.map +1 -1
- package/dist/core/ideal-review.d.ts +20 -1
- package/dist/core/ideal-review.d.ts.map +1 -1
- package/dist/core/ideal-review.js +33 -2
- package/dist/core/ideal-review.js.map +1 -1
- package/dist/core/ideal-review.test.js +99 -3
- package/dist/core/ideal-review.test.js.map +1 -1
- package/dist/core/lsp/client.d.ts +15 -0
- package/dist/core/lsp/client.d.ts.map +1 -1
- package/dist/core/lsp/client.js +39 -1
- package/dist/core/lsp/client.js.map +1 -1
- package/dist/core/lsp/manager.d.ts +3 -0
- package/dist/core/lsp/manager.d.ts.map +1 -1
- package/dist/core/lsp/manager.js +33 -1
- package/dist/core/lsp/manager.js.map +1 -1
- package/dist/core/lsp/manager.test.js +18 -0
- package/dist/core/lsp/manager.test.js.map +1 -1
- package/dist/core/mcp/client-session-recovery.test.d.ts +2 -0
- package/dist/core/mcp/client-session-recovery.test.d.ts.map +1 -0
- package/dist/core/mcp/client-session-recovery.test.js +231 -0
- package/dist/core/mcp/client-session-recovery.test.js.map +1 -0
- package/dist/core/mcp/client.d.ts +57 -0
- package/dist/core/mcp/client.d.ts.map +1 -1
- package/dist/core/mcp/client.js +146 -8
- package/dist/core/mcp/client.js.map +1 -1
- package/dist/core/mcp/elicitation-bridge.d.ts +41 -0
- package/dist/core/mcp/elicitation-bridge.d.ts.map +1 -0
- package/dist/core/mcp/elicitation-bridge.js +52 -0
- package/dist/core/mcp/elicitation-bridge.js.map +1 -0
- package/dist/core/mcp/elicitation.test.d.ts +2 -0
- package/dist/core/mcp/elicitation.test.d.ts.map +1 -0
- package/dist/core/mcp/elicitation.test.js +158 -0
- package/dist/core/mcp/elicitation.test.js.map +1 -0
- package/dist/core/mcp/index.d.ts +3 -1
- package/dist/core/mcp/index.d.ts.map +1 -1
- package/dist/core/mcp/index.js +1 -0
- package/dist/core/mcp/index.js.map +1 -1
- package/dist/core/process-manager-notifications.test.js +102 -0
- package/dist/core/process-manager-notifications.test.js.map +1 -1
- package/dist/core/process-manager.d.ts +14 -4
- package/dist/core/process-manager.d.ts.map +1 -1
- package/dist/core/process-manager.js +83 -21
- package/dist/core/process-manager.js.map +1 -1
- package/dist/core/run-journal.test.d.ts +2 -0
- package/dist/core/run-journal.test.d.ts.map +1 -0
- package/dist/core/run-journal.test.js +195 -0
- package/dist/core/run-journal.test.js.map +1 -0
- package/dist/core/run-lifecycle.d.ts +22 -3
- package/dist/core/run-lifecycle.d.ts.map +1 -1
- package/dist/core/run-lifecycle.js +12 -3
- package/dist/core/run-lifecycle.js.map +1 -1
- package/dist/core/session-export.d.ts.map +1 -1
- package/dist/core/session-export.js +5 -0
- package/dist/core/session-export.js.map +1 -1
- package/dist/core/session-history.d.ts +10 -0
- package/dist/core/session-history.d.ts.map +1 -1
- package/dist/core/session-history.js +17 -2
- package/dist/core/session-history.js.map +1 -1
- package/dist/core/session-history.test.js +26 -1
- package/dist/core/session-history.test.js.map +1 -1
- package/dist/core/session-manager.d.ts +63 -1
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +94 -1
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/session-notification-visibility.test.d.ts +2 -0
- package/dist/core/session-notification-visibility.test.d.ts.map +1 -0
- package/dist/core/session-notification-visibility.test.js +79 -0
- package/dist/core/session-notification-visibility.test.js.map +1 -0
- package/dist/core/session-preview.d.ts +4 -2
- package/dist/core/session-preview.d.ts.map +1 -1
- package/dist/core/session-preview.js +8 -3
- package/dist/core/session-preview.js.map +1 -1
- package/dist/core/session-storage.test.js +6 -1
- package/dist/core/session-storage.test.js.map +1 -1
- package/dist/core/settings-manager.d.ts +2 -2
- package/dist/modes/json-mode.d.ts +28 -0
- package/dist/modes/json-mode.d.ts.map +1 -1
- package/dist/modes/json-mode.js +32 -0
- package/dist/modes/json-mode.js.map +1 -1
- package/dist/modes/json-mode.test.d.ts +2 -0
- package/dist/modes/json-mode.test.d.ts.map +1 -0
- package/dist/modes/json-mode.test.js +84 -0
- package/dist/modes/json-mode.test.js.map +1 -0
- package/dist/tools/subagent.d.ts.map +1 -1
- package/dist/tools/subagent.js +43 -8
- package/dist/tools/subagent.js.map +1 -1
- package/dist/tools/subagent.test.js +65 -3
- package/dist/tools/subagent.test.js.map +1 -1
- package/dist/ui/hooks/useAgentLoop.d.ts.map +1 -1
- package/dist/ui/hooks/useAgentLoop.js +18 -4
- package/dist/ui/hooks/useAgentLoop.js.map +1 -1
- package/dist/utils/image.d.ts +26 -3
- package/dist/utils/image.d.ts.map +1 -1
- package/dist/utils/image.js +83 -14
- package/dist/utils/image.js.map +1 -1
- package/dist/utils/image.test.d.ts +2 -0
- package/dist/utils/image.test.d.ts.map +1 -0
- package/dist/utils/image.test.js +139 -0
- package/dist/utils/image.test.js.map +1 -0
- package/package.json +4 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-sidecar-auth-broadcast.test.d.ts","sourceRoot":"","sources":["../src/app-sidecar-auth-broadcast.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import http from "node:http";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { spawn } from "node:child_process";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
8
|
+
/**
|
|
9
|
+
* Boots the REAL app sidecar daemon and drives it over HTTP, because the bug
|
|
10
|
+
* being covered is cross-session: connecting a provider in one window has to
|
|
11
|
+
* refresh the model picker in every window. A per-session unit test cannot see
|
|
12
|
+
* that — the whole failure lives in which SSE streams receive the frame.
|
|
13
|
+
*/
|
|
14
|
+
const SIDECAR = path.join(path.dirname(fileURLToPath(import.meta.url)), "..", "dist", "app-sidecar.js");
|
|
15
|
+
let tmpHome;
|
|
16
|
+
let tmpProject;
|
|
17
|
+
let daemon;
|
|
18
|
+
let port = 0;
|
|
19
|
+
const openStreams = [];
|
|
20
|
+
/** Start the daemon on an ephemeral port and wait for its listening handshake. */
|
|
21
|
+
async function startDaemon() {
|
|
22
|
+
daemon = spawn(process.execPath, [SIDECAR], {
|
|
23
|
+
cwd: tmpProject,
|
|
24
|
+
env: {
|
|
25
|
+
...process.env,
|
|
26
|
+
HOME: tmpHome,
|
|
27
|
+
USERPROFILE: tmpHome,
|
|
28
|
+
GG_APP_CWD: tmpProject,
|
|
29
|
+
GG_APP_PORT: "0",
|
|
30
|
+
},
|
|
31
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
32
|
+
});
|
|
33
|
+
port = await new Promise((resolve, reject) => {
|
|
34
|
+
let out = "";
|
|
35
|
+
const timer = setTimeout(() => reject(new Error(`daemon never listened: ${out}`)), 60_000);
|
|
36
|
+
daemon.stdout.on("data", (chunk) => {
|
|
37
|
+
out += chunk;
|
|
38
|
+
const match = /GG_APP_LISTENING (\d+)/.exec(out);
|
|
39
|
+
if (match) {
|
|
40
|
+
clearTimeout(timer);
|
|
41
|
+
resolve(Number(match[1]));
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
daemon.on("error", reject);
|
|
45
|
+
daemon.on("exit", (code) => reject(new Error(`daemon exited (${code}): ${out}`)));
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
function request(method, urlPath, opts = {}) {
|
|
49
|
+
return new Promise((resolve, reject) => {
|
|
50
|
+
const payload = opts.body === undefined ? undefined : JSON.stringify(opts.body);
|
|
51
|
+
const req = http.request({
|
|
52
|
+
host: "127.0.0.1",
|
|
53
|
+
port,
|
|
54
|
+
path: urlPath,
|
|
55
|
+
method,
|
|
56
|
+
headers: {
|
|
57
|
+
...(payload ? { "content-type": "application/json" } : {}),
|
|
58
|
+
...(opts.session ? { "x-gg-session": opts.session } : {}),
|
|
59
|
+
},
|
|
60
|
+
}, (res) => {
|
|
61
|
+
let raw = "";
|
|
62
|
+
res.on("data", (c) => {
|
|
63
|
+
raw += c;
|
|
64
|
+
});
|
|
65
|
+
res.on("end", () => {
|
|
66
|
+
try {
|
|
67
|
+
resolve({ status: res.statusCode ?? 0, json: raw ? JSON.parse(raw) : {} });
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
resolve({ status: res.statusCode ?? 0, json: {} });
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
req.on("error", reject);
|
|
75
|
+
if (payload)
|
|
76
|
+
req.write(payload);
|
|
77
|
+
req.end();
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
/** Open a window's SSE stream and collect the event types it receives. */
|
|
81
|
+
function openEventStream(session) {
|
|
82
|
+
return new Promise((resolve, reject) => {
|
|
83
|
+
const types = [];
|
|
84
|
+
const req = http.request({ host: "127.0.0.1", port, path: `/events?session=${session}`, method: "GET" }, (res) => {
|
|
85
|
+
openStreams.push(res);
|
|
86
|
+
let buf = "";
|
|
87
|
+
res.on("data", (chunk) => {
|
|
88
|
+
buf += chunk;
|
|
89
|
+
let split = buf.indexOf("\n\n");
|
|
90
|
+
while (split !== -1) {
|
|
91
|
+
const frame = buf.slice(0, split);
|
|
92
|
+
buf = buf.slice(split + 2);
|
|
93
|
+
for (const line of frame.split("\n")) {
|
|
94
|
+
if (!line.startsWith("data: "))
|
|
95
|
+
continue;
|
|
96
|
+
try {
|
|
97
|
+
types.push(JSON.parse(line.slice(6)).type);
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
// Non-JSON keepalives are not events.
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
split = buf.indexOf("\n\n");
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
resolve({ types });
|
|
107
|
+
});
|
|
108
|
+
req.on("error", reject);
|
|
109
|
+
req.end();
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
async function createSession() {
|
|
113
|
+
const res = await request("POST", "/session", {
|
|
114
|
+
body: { mode: "code", cwd: tmpProject },
|
|
115
|
+
});
|
|
116
|
+
expect(res.status).toBe(200);
|
|
117
|
+
return res.json.sessionId;
|
|
118
|
+
}
|
|
119
|
+
async function waitFor(predicate, timeoutMs = 15_000) {
|
|
120
|
+
const deadline = Date.now() + timeoutMs;
|
|
121
|
+
while (!predicate()) {
|
|
122
|
+
if (Date.now() > deadline)
|
|
123
|
+
throw new Error("timed out waiting for condition");
|
|
124
|
+
await new Promise((r) => setTimeout(r, 25));
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
beforeEach(async () => {
|
|
128
|
+
tmpHome = await fs.mkdtemp(path.join(os.tmpdir(), "gg-models-home-"));
|
|
129
|
+
tmpProject = await fs.mkdtemp(path.join(os.tmpdir(), "gg-models-project-"));
|
|
130
|
+
await fs.mkdir(path.join(tmpHome, ".gg"), { recursive: true });
|
|
131
|
+
// No auth.json: the daemon is boot-tolerant when logged out, which is exactly
|
|
132
|
+
// the state a user is in right before they connect their first provider.
|
|
133
|
+
await fs.writeFile(path.join(tmpHome, ".gg", "settings.json"), JSON.stringify({ autoCompact: false }));
|
|
134
|
+
await startDaemon();
|
|
135
|
+
});
|
|
136
|
+
afterEach(async () => {
|
|
137
|
+
for (const stream of openStreams.splice(0))
|
|
138
|
+
stream.destroy();
|
|
139
|
+
daemon?.kill("SIGKILL");
|
|
140
|
+
daemon = undefined;
|
|
141
|
+
await fs.rm(tmpHome, { recursive: true, force: true });
|
|
142
|
+
await fs.rm(tmpProject, { recursive: true, force: true });
|
|
143
|
+
});
|
|
144
|
+
describe("connecting a provider", () => {
|
|
145
|
+
it("refreshes models in every window, not just the one that connected", async () => {
|
|
146
|
+
const windowA = await createSession();
|
|
147
|
+
const windowB = await createSession();
|
|
148
|
+
const streamA = await openEventStream(windowA);
|
|
149
|
+
const streamB = await openEventStream(windowB);
|
|
150
|
+
// Logged out: no provider's models are offered yet.
|
|
151
|
+
const before = await request("GET", "/models", { session: windowA });
|
|
152
|
+
expect(before.json.models).toEqual([]);
|
|
153
|
+
// Connect a provider from window A only.
|
|
154
|
+
const connect = await request("POST", "/auth/apikey", {
|
|
155
|
+
session: windowA,
|
|
156
|
+
body: { provider: "xai", key: "sk-test-key" },
|
|
157
|
+
});
|
|
158
|
+
expect(connect.status).toBe(200);
|
|
159
|
+
// Both windows must be told, because ~/.gg/auth.json is shared. Without the
|
|
160
|
+
// fan-out, window B's picker stayed stale until the session was reopened.
|
|
161
|
+
await waitFor(() => streamA.types.includes("models_change"));
|
|
162
|
+
await waitFor(() => streamB.types.includes("models_change"));
|
|
163
|
+
// And the refetch each window now performs actually returns the new models.
|
|
164
|
+
const after = await request("GET", "/models", { session: windowB });
|
|
165
|
+
const models = after.json.models;
|
|
166
|
+
expect(models.length).toBeGreaterThan(0);
|
|
167
|
+
expect(models.every((m) => m.provider === "xai")).toBe(true);
|
|
168
|
+
}, 90_000);
|
|
169
|
+
it("closes the login modal in every window via auth_done", async () => {
|
|
170
|
+
const windowA = await createSession();
|
|
171
|
+
const windowB = await createSession();
|
|
172
|
+
const streamA = await openEventStream(windowA);
|
|
173
|
+
const streamB = await openEventStream(windowB);
|
|
174
|
+
await request("POST", "/auth/apikey", {
|
|
175
|
+
session: windowA,
|
|
176
|
+
body: { provider: "xai", key: "sk-test-key" },
|
|
177
|
+
});
|
|
178
|
+
// auth_done closes the modal; auth_change refreshes the connection dots.
|
|
179
|
+
// A second window sitting on the login screen needs both.
|
|
180
|
+
await waitFor(() => streamA.types.includes("auth_done"));
|
|
181
|
+
await waitFor(() => streamB.types.includes("auth_done"));
|
|
182
|
+
await waitFor(() => streamA.types.includes("auth_change"));
|
|
183
|
+
await waitFor(() => streamB.types.includes("auth_change"));
|
|
184
|
+
}, 90_000);
|
|
185
|
+
});
|
|
186
|
+
describe("OAuth login across windows", () => {
|
|
187
|
+
/** Park an Anthropic OAuth flow at its "paste the code" step in one window. */
|
|
188
|
+
async function startParkedLogin(session) {
|
|
189
|
+
const stream = await openEventStream(session);
|
|
190
|
+
const started = await request("POST", "/auth/oauth/start", {
|
|
191
|
+
session,
|
|
192
|
+
body: { provider: "anthropic" },
|
|
193
|
+
});
|
|
194
|
+
expect(started.status).toBe(202);
|
|
195
|
+
// The flow opens a browser URL, then blocks on the pasted code.
|
|
196
|
+
await waitFor(() => stream.types.includes("auth_need_code"));
|
|
197
|
+
return stream;
|
|
198
|
+
}
|
|
199
|
+
it("keeps login progress in the window that started it", async () => {
|
|
200
|
+
const windowA = await createSession();
|
|
201
|
+
const windowB = await createSession();
|
|
202
|
+
const streamB = await openEventStream(windowB);
|
|
203
|
+
const streamA = await startParkedLogin(windowA);
|
|
204
|
+
expect(streamA.types).toContain("auth_url");
|
|
205
|
+
expect(streamA.types).toContain("auth_need_code");
|
|
206
|
+
// Window B never pressed Connect — opening its browser or prompting it for
|
|
207
|
+
// a code it does not have would be nonsense. Progress stays scoped.
|
|
208
|
+
expect(streamB.types).not.toContain("auth_url");
|
|
209
|
+
expect(streamB.types).not.toContain("auth_need_code");
|
|
210
|
+
}, 90_000);
|
|
211
|
+
it("refuses a second window's login for the same provider", async () => {
|
|
212
|
+
const windowA = await createSession();
|
|
213
|
+
const windowB = await createSession();
|
|
214
|
+
await startParkedLogin(windowA);
|
|
215
|
+
// Two flows for one provider means two browser tabs and two token
|
|
216
|
+
// exchanges racing to write the same auth.json entry. The per-session
|
|
217
|
+
// guard cannot see across windows; the daemon-wide one must.
|
|
218
|
+
const second = await request("POST", "/auth/oauth/start", {
|
|
219
|
+
session: windowB,
|
|
220
|
+
body: { provider: "anthropic" },
|
|
221
|
+
});
|
|
222
|
+
expect(second.status).toBe(409);
|
|
223
|
+
expect(String(second.json.error)).toContain("another window");
|
|
224
|
+
}, 90_000);
|
|
225
|
+
it("allows a different provider to log in concurrently", async () => {
|
|
226
|
+
const windowA = await createSession();
|
|
227
|
+
const windowB = await createSession();
|
|
228
|
+
await startParkedLogin(windowA);
|
|
229
|
+
// The guard is per provider, not a global lock: connecting Anthropic in
|
|
230
|
+
// one window must not block connecting OpenAI in another.
|
|
231
|
+
const other = await request("POST", "/auth/oauth/start", {
|
|
232
|
+
session: windowB,
|
|
233
|
+
body: { provider: "openai" },
|
|
234
|
+
});
|
|
235
|
+
expect(other.status).toBe(202);
|
|
236
|
+
}, 90_000);
|
|
237
|
+
it("reports a failed login only to the window that attempted it", async () => {
|
|
238
|
+
const windowA = await createSession();
|
|
239
|
+
const windowB = await createSession();
|
|
240
|
+
const streamB = await openEventStream(windowB);
|
|
241
|
+
const streamA = await startParkedLogin(windowA);
|
|
242
|
+
// A malformed code fails the state check locally — no network needed.
|
|
243
|
+
const sent = await request("POST", "/auth/oauth/code", {
|
|
244
|
+
session: windowA,
|
|
245
|
+
body: { code: "bogus#mismatch" },
|
|
246
|
+
});
|
|
247
|
+
expect(sent.status).toBe(200);
|
|
248
|
+
await waitFor(() => streamA.types.includes("auth_error"));
|
|
249
|
+
// Window B attempted nothing, so it has no failure to report. Its modal
|
|
250
|
+
// correctly still offers to connect.
|
|
251
|
+
expect(streamB.types).not.toContain("auth_error");
|
|
252
|
+
}, 90_000);
|
|
253
|
+
it("frees the provider again after a failed login", async () => {
|
|
254
|
+
const windowA = await createSession();
|
|
255
|
+
const windowB = await createSession();
|
|
256
|
+
const streamA = await startParkedLogin(windowA);
|
|
257
|
+
await request("POST", "/auth/oauth/code", {
|
|
258
|
+
session: windowA,
|
|
259
|
+
body: { code: "bogus#mismatch" },
|
|
260
|
+
});
|
|
261
|
+
await waitFor(() => streamA.types.includes("auth_error"));
|
|
262
|
+
// A failed attempt must release the daemon-wide guard, or the provider
|
|
263
|
+
// would be permanently unloggable until the app restarts.
|
|
264
|
+
const retry = await request("POST", "/auth/oauth/start", {
|
|
265
|
+
session: windowB,
|
|
266
|
+
body: { provider: "anthropic" },
|
|
267
|
+
});
|
|
268
|
+
expect(retry.status).toBe(202);
|
|
269
|
+
}, 90_000);
|
|
270
|
+
});
|
|
271
|
+
//# sourceMappingURL=app-sidecar-auth-broadcast.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-sidecar-auth-broadcast.test.js","sourceRoot":"","sources":["../src/app-sidecar-auth-broadcast.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -14,7 +14,14 @@ import { SessionManager } from "./core/session-manager.js";
|
|
|
14
14
|
* records — not the folder name — is what discovery matches on.
|
|
15
15
|
*/
|
|
16
16
|
async function writeClaudeTranscript(homeDir, cwd, sessionId, prompt) {
|
|
17
|
-
|
|
17
|
+
// The folder name is deliberately only *shaped* like Claude's encoding: since
|
|
18
|
+
// discovery reads the cwd out of the records, the exact name is irrelevant to
|
|
19
|
+
// what these tests assert. It does have to be a VALID single directory name on
|
|
20
|
+
// the host though — collapsing only "/" left Windows paths as `-C:\Users\...`,
|
|
21
|
+
// whose drive colon and backslashes made `mkdir` fail with ENOENT. Fold both
|
|
22
|
+
// separators and the drive colon into dashes so the fixture is portable.
|
|
23
|
+
const encoded = `-${cwd.replace(/[\\/:]/g, "-")}`;
|
|
24
|
+
const projectDir = path.join(homeDir, ".claude", "projects", encoded);
|
|
18
25
|
await fs.mkdir(projectDir, { recursive: true });
|
|
19
26
|
const file = path.join(projectDir, `${sessionId}.jsonl`);
|
|
20
27
|
const stamp = new Date().toISOString();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-sidecar-sessions.test.js","sourceRoot":"","sources":["../src/app-sidecar-sessions.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAErE,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AACnF,OAAO,EAAE,oBAAoB,EAAE,MAAM,kCAAkC,CAAC;AACxE,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAE3D;;;;GAIG;AACH,KAAK,UAAU,qBAAqB,CAClC,OAAe,EACf,GAAW,EACX,SAAiB,EACjB,MAAc;IAEd,MAAM,
|
|
1
|
+
{"version":3,"file":"app-sidecar-sessions.test.js","sourceRoot":"","sources":["../src/app-sidecar-sessions.test.ts"],"names":[],"mappings":"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"}
|
package/dist/app-sidecar.js
CHANGED
|
@@ -65,7 +65,7 @@ import { enrichProcessPath } from "./core/shell-path.js";
|
|
|
65
65
|
import { downscaleForPreview, shrinkToFit, validateVisionImage } from "./utils/image.js";
|
|
66
66
|
import { startServeMode } from "./modes/serve-mode.js";
|
|
67
67
|
import { loadTelegramConfig, saveTelegramConfig, verifyBotToken } from "./core/telegram-config.js";
|
|
68
|
-
import { loadServers, addServer, removeServer, getServer, parseMcpAddCommand, MCPClientManager, McpOAuthStore, } from "./core/mcp/index.js";
|
|
68
|
+
import { loadServers, addServer, removeServer, getServer, parseMcpAddCommand, MCPClientManager, McpOAuthStore, createElicitationBridge, } from "./core/mcp/index.js";
|
|
69
69
|
import { buildSnapshot, levelForXp, rankForLevel } from "./core/progress/ranks.js";
|
|
70
70
|
import { loadProgress, peekProgress, updateProgress } from "./core/progress/store.js";
|
|
71
71
|
import { awardPrompt, awardCommits } from "./core/progress/engine.js";
|
|
@@ -575,6 +575,20 @@ async function main() {
|
|
|
575
575
|
// request to its window's session via the `x-gg-session` header (and the
|
|
576
576
|
// `?session=` query for the SSE /events stream).
|
|
577
577
|
const sessions = new Map();
|
|
578
|
+
/**
|
|
579
|
+
* Fan one frame out to every window.
|
|
580
|
+
*
|
|
581
|
+
* For state that is genuinely global rather than per-session — `~/.gg/auth.json`
|
|
582
|
+
* is shared by all windows, so connecting a provider in one must refresh the
|
|
583
|
+
* model picker in all of them. Mirrors the memory/jiwa/progress fan-outs.
|
|
584
|
+
*/
|
|
585
|
+
const broadcastAll = (type, data) => {
|
|
586
|
+
for (const ctx of sessions.values())
|
|
587
|
+
ctx.broadcast(type, data);
|
|
588
|
+
};
|
|
589
|
+
// Providers currently mid-OAuth in some window. Daemon-level so two windows
|
|
590
|
+
// cannot race two browser flows for the same provider into one auth file.
|
|
591
|
+
const oauthInFlightProviders = new Set();
|
|
578
592
|
const memoryStore = new MemoryStore({
|
|
579
593
|
onChange: ({ memories }) => {
|
|
580
594
|
for (const ctx of sessions.values()) {
|
|
@@ -770,7 +784,15 @@ async function main() {
|
|
|
770
784
|
const sessionPath = typeof body.sessionPath === "string" && body.sessionPath ? body.sessionPath : undefined;
|
|
771
785
|
const id = randomUUID();
|
|
772
786
|
try {
|
|
773
|
-
const ctx = await createSession({
|
|
787
|
+
const ctx = await createSession({
|
|
788
|
+
auth,
|
|
789
|
+
paths,
|
|
790
|
+
progress,
|
|
791
|
+
memoryStore,
|
|
792
|
+
jiwaStore,
|
|
793
|
+
broadcastAll,
|
|
794
|
+
oauthInFlightProviders,
|
|
795
|
+
}, { id, mode, chatAgent, cwd: sessionCwd, sessionPath });
|
|
774
796
|
sessions.set(id, ctx);
|
|
775
797
|
log("INFO", "app-sidecar", "session created", {
|
|
776
798
|
id,
|
|
@@ -1046,7 +1068,7 @@ async function createProgressManager(agentDir, broadcastAll) {
|
|
|
1046
1068
|
* logger, PATH, shared auth file, and radio live at the daemon level.
|
|
1047
1069
|
*/
|
|
1048
1070
|
async function createSession(deps, opts) {
|
|
1049
|
-
const { auth, progress, memoryStore, jiwaStore } = deps;
|
|
1071
|
+
const { auth, progress, memoryStore, jiwaStore, broadcastAll, oauthInFlightProviders } = deps;
|
|
1050
1072
|
const paths = deps.paths;
|
|
1051
1073
|
const mode = opts.mode;
|
|
1052
1074
|
let chatAgent = opts.chatAgent;
|
|
@@ -1182,6 +1204,17 @@ async function createSession(deps, opts) {
|
|
|
1182
1204
|
})
|
|
1183
1205
|
.catch(() => { });
|
|
1184
1206
|
}
|
|
1207
|
+
// ── MCP elicitation bridge ─────────────────────────────────
|
|
1208
|
+
// An MCP server can ask for user input in the middle of a tool call. The
|
|
1209
|
+
// bridge parks the promise; we broadcast the prompt over SSE and resolve it
|
|
1210
|
+
// when the webview POSTs /mcp/elicit/:id.
|
|
1211
|
+
const elicitations = createElicitationBridge({
|
|
1212
|
+
broadcast: (prompt) => broadcast("mcp_elicit", prompt),
|
|
1213
|
+
onTimeout: (prompt) => log("WARN", "app-sidecar", "MCP elicitation timed out", {
|
|
1214
|
+
id: prompt.id,
|
|
1215
|
+
server: prompt.server,
|
|
1216
|
+
}),
|
|
1217
|
+
});
|
|
1185
1218
|
// The session file path to resume (passed by the daemon's POST /session);
|
|
1186
1219
|
// empty/unset starts a fresh session.
|
|
1187
1220
|
const resumeSessionPath = opts.sessionPath;
|
|
@@ -1195,6 +1228,7 @@ async function createSession(deps, opts) {
|
|
|
1195
1228
|
signal: abort.signal,
|
|
1196
1229
|
// Keep MCP startup off the readiness path in both modes.
|
|
1197
1230
|
backgroundMcpConnect: true,
|
|
1231
|
+
onMcpElicit: elicitations.onElicit,
|
|
1198
1232
|
// Keep restore-time auto-compaction off the readiness path too: its summary
|
|
1199
1233
|
// LLM call (30s timeout) used to freeze waitForReady — and with it the whole
|
|
1200
1234
|
// window (project picker, session list) — whenever a resumed session was
|
|
@@ -1566,6 +1600,21 @@ async function createSession(deps, opts) {
|
|
|
1566
1600
|
running = runState !== "idle";
|
|
1567
1601
|
if (runState === "cancelling")
|
|
1568
1602
|
broadcast("run_cancelling", { runState });
|
|
1603
|
+
},
|
|
1604
|
+
// Durable run journal. Fire-and-forget on purpose: an unwritten journal
|
|
1605
|
+
// entry is a missed crash hint, while a journal write that throws inside
|
|
1606
|
+
// begin()/settle() would break run ownership itself.
|
|
1607
|
+
{
|
|
1608
|
+
started: (generation) => void session.persistRunStarted(generation).catch((err) => {
|
|
1609
|
+
log("WARN", "app-sidecar", "failed to journal run start", {
|
|
1610
|
+
error: err instanceof Error ? err.message : String(err),
|
|
1611
|
+
});
|
|
1612
|
+
}),
|
|
1613
|
+
finished: (generation, outcome) => void session.persistRunFinished(generation, outcome).catch((err) => {
|
|
1614
|
+
log("WARN", "app-sidecar", "failed to journal run finish", {
|
|
1615
|
+
error: err instanceof Error ? err.message : String(err),
|
|
1616
|
+
});
|
|
1617
|
+
}),
|
|
1569
1618
|
});
|
|
1570
1619
|
const cancelledRunEndGenerations = new Set();
|
|
1571
1620
|
let pendingCancelDrain = null;
|
|
@@ -1791,6 +1840,10 @@ async function createSession(deps, opts) {
|
|
|
1791
1840
|
function abortOwnedWork() {
|
|
1792
1841
|
cancelGeneration++;
|
|
1793
1842
|
abort.abort();
|
|
1843
|
+
// An MCP tool call parked on user input is not cancelled by the signal —
|
|
1844
|
+
// the promise lives in the bridge. Release it, or the aborted turn's tool
|
|
1845
|
+
// call never returns.
|
|
1846
|
+
elicitations.cancelAll();
|
|
1794
1847
|
// Stop a run-all sweep and every async child through AgentSession's signal.
|
|
1795
1848
|
taskRunAll = false;
|
|
1796
1849
|
autopilotCancelled = true;
|
|
@@ -1802,9 +1855,9 @@ async function createSession(deps, opts) {
|
|
|
1802
1855
|
kenAutoAbort = new AbortController();
|
|
1803
1856
|
kenAutoSession?.setSignal(kenAutoAbort.signal);
|
|
1804
1857
|
}
|
|
1805
|
-
function finishOwnedGeneration(generation, emitCancelledFallback) {
|
|
1858
|
+
function finishOwnedGeneration(generation, emitCancelledFallback, outcome = "completed") {
|
|
1806
1859
|
const cancelled = runLifecycle.isCancellationRequested(generation);
|
|
1807
|
-
const settlement = runLifecycle.settle(generation);
|
|
1860
|
+
const settlement = runLifecycle.settle(generation, outcome);
|
|
1808
1861
|
if (!settlement.settled)
|
|
1809
1862
|
return cancelled;
|
|
1810
1863
|
// A replacement signal is safe only after the provider-backed owner settled.
|
|
@@ -1882,8 +1935,9 @@ async function createSession(deps, opts) {
|
|
|
1882
1935
|
});
|
|
1883
1936
|
}
|
|
1884
1937
|
}
|
|
1885
|
-
if (ownsGeneration)
|
|
1886
|
-
finishOwnedGeneration(generation, false);
|
|
1938
|
+
if (ownsGeneration) {
|
|
1939
|
+
finishOwnedGeneration(generation, false, runSucceeded ? "completed" : "failed");
|
|
1940
|
+
}
|
|
1887
1941
|
// A cancelled injected run is still owned by the surrounding autopilot
|
|
1888
1942
|
// cycle; its outer finalizer emits the one terminal cancelled run_end.
|
|
1889
1943
|
if (!(cancelled && !ownsGeneration)) {
|
|
@@ -2762,6 +2816,21 @@ async function createSession(deps, opts) {
|
|
|
2762
2816
|
},
|
|
2763
2817
|
});
|
|
2764
2818
|
}
|
|
2819
|
+
else if (marker.kind === "interrupted_run") {
|
|
2820
|
+
// Rendered as an error row: the run's tools already changed the
|
|
2821
|
+
// repo, so the user needs to see it and decide what to do. We
|
|
2822
|
+
// never replay it — that would duplicate those changes.
|
|
2823
|
+
history.push({
|
|
2824
|
+
role: "assistant",
|
|
2825
|
+
text: "",
|
|
2826
|
+
error: {
|
|
2827
|
+
scope: "interrupted_run",
|
|
2828
|
+
headline: "A run was interrupted",
|
|
2829
|
+
message: "GG Coder stopped mid-run, so this turn is incomplete. Any files its tools already changed are still on disk.",
|
|
2830
|
+
guidance: "Review the working tree, then re-send the request if you still want it.",
|
|
2831
|
+
},
|
|
2832
|
+
});
|
|
2833
|
+
}
|
|
2765
2834
|
}
|
|
2766
2835
|
};
|
|
2767
2836
|
let nonSystemCount = 0;
|
|
@@ -2842,7 +2911,14 @@ async function createSession(deps, opts) {
|
|
|
2842
2911
|
// Autopilot injected this turn — live showed only the Ken-tinted
|
|
2843
2912
|
// marker for it, never a user bubble. Emitting one here would print
|
|
2844
2913
|
// the injected instruction a second time, unstyled.
|
|
2845
|
-
|
|
2914
|
+
//
|
|
2915
|
+
// Pushed background-status updates are skipped for the same reason:
|
|
2916
|
+
// the live run rendered no bubble for them, so showing them here
|
|
2917
|
+
// would fill a reopened session with machine-facing status lines
|
|
2918
|
+
// the user never saw while working.
|
|
2919
|
+
if (!restored.autopilotInjected &&
|
|
2920
|
+
!restored.notification &&
|
|
2921
|
+
(text.trim() || restored.images.length > 0)) {
|
|
2846
2922
|
history.push({
|
|
2847
2923
|
role: "user",
|
|
2848
2924
|
text: command ?? text,
|
|
@@ -3799,7 +3875,17 @@ async function createSession(deps, opts) {
|
|
|
3799
3875
|
...(baseUrl ? { baseUrl } : {}),
|
|
3800
3876
|
};
|
|
3801
3877
|
await auth.setCredentials(storageKey, creds);
|
|
3802
|
-
|
|
3878
|
+
// auth.json is shared by every window, so this is a global change:
|
|
3879
|
+
// close their login modals and refresh their provider lists too.
|
|
3880
|
+
broadcastAll("auth_done", { provider });
|
|
3881
|
+
// `auth_done` means "a login succeeded" (modals close on it).
|
|
3882
|
+
// `auth_change` means "auth.json changed" — which a DISCONNECT also is,
|
|
3883
|
+
// so connection state has one signal that covers both directions.
|
|
3884
|
+
broadcastAll("auth_change", { provider });
|
|
3885
|
+
// A newly connected provider unlocks its models. `/models` filters on
|
|
3886
|
+
// who is logged in, so every window's picker is now stale — without
|
|
3887
|
+
// this the new models don't appear until the session is reopened.
|
|
3888
|
+
broadcastAll("models_change", {});
|
|
3803
3889
|
json(res, 200, { ok: true });
|
|
3804
3890
|
});
|
|
3805
3891
|
return;
|
|
@@ -3825,7 +3911,18 @@ async function createSession(deps, opts) {
|
|
|
3825
3911
|
json(res, 409, { error: "a login is already in progress" });
|
|
3826
3912
|
return;
|
|
3827
3913
|
}
|
|
3914
|
+
// A login writes the shared ~/.gg/auth.json, so two windows racing the
|
|
3915
|
+
// same provider means two browser tabs and two token exchanges whose
|
|
3916
|
+
// writes clobber each other. The per-session flag above cannot see
|
|
3917
|
+
// that — guard the provider daemon-wide as well.
|
|
3918
|
+
if (oauthInFlightProviders.has(provider)) {
|
|
3919
|
+
json(res, 409, {
|
|
3920
|
+
error: `a ${meta.label} login is already in progress in another window`,
|
|
3921
|
+
});
|
|
3922
|
+
return;
|
|
3923
|
+
}
|
|
3828
3924
|
oauthInFlight = true;
|
|
3925
|
+
oauthInFlightProviders.add(provider);
|
|
3829
3926
|
json(res, 202, { accepted: true });
|
|
3830
3927
|
void (async () => {
|
|
3831
3928
|
const cb = authCallbacks();
|
|
@@ -3846,10 +3943,19 @@ async function createSession(deps, opts) {
|
|
|
3846
3943
|
throw new Error(`OAuth not implemented for ${provider}`);
|
|
3847
3944
|
}
|
|
3848
3945
|
await auth.setCredentials(storageKey, creds);
|
|
3849
|
-
|
|
3946
|
+
// Terminal outcome of a GLOBAL change: every window's login modal
|
|
3947
|
+
// should close and its provider list refresh, not just the one
|
|
3948
|
+
// that started the flow.
|
|
3949
|
+
broadcastAll("auth_done", { provider });
|
|
3950
|
+
broadcastAll("auth_change", { provider });
|
|
3951
|
+
// The OAuth provider's models just became selectable everywhere.
|
|
3952
|
+
broadcastAll("models_change", {});
|
|
3850
3953
|
}
|
|
3851
3954
|
catch (err) {
|
|
3852
3955
|
captureSidecarError(err, "app-sidecar.auth.oauth", { provider });
|
|
3956
|
+
// Deliberately session-scoped: this is the outcome of ONE window's
|
|
3957
|
+
// attempt. Another window that never pressed Connect has nothing to
|
|
3958
|
+
// show an error about, and its modal correctly still offers login.
|
|
3853
3959
|
broadcast("auth_error", {
|
|
3854
3960
|
provider,
|
|
3855
3961
|
message: err instanceof Error ? err.message : String(err),
|
|
@@ -3857,6 +3963,7 @@ async function createSession(deps, opts) {
|
|
|
3857
3963
|
}
|
|
3858
3964
|
finally {
|
|
3859
3965
|
oauthInFlight = false;
|
|
3966
|
+
oauthInFlightProviders.delete(provider);
|
|
3860
3967
|
pendingCode = null;
|
|
3861
3968
|
}
|
|
3862
3969
|
})();
|
|
@@ -3885,6 +3992,39 @@ async function createSession(deps, opts) {
|
|
|
3885
3992
|
});
|
|
3886
3993
|
return;
|
|
3887
3994
|
}
|
|
3995
|
+
if (method === "POST" && url.startsWith("/mcp/elicit/")) {
|
|
3996
|
+
const id = decodeURIComponent(url.slice("/mcp/elicit/".length));
|
|
3997
|
+
void readBody(req, res).then((raw) => {
|
|
3998
|
+
if (raw === null)
|
|
3999
|
+
return;
|
|
4000
|
+
let result;
|
|
4001
|
+
try {
|
|
4002
|
+
const parsed = JSON.parse(raw);
|
|
4003
|
+
if (parsed.action !== "accept" &&
|
|
4004
|
+
parsed.action !== "decline" &&
|
|
4005
|
+
parsed.action !== "cancel") {
|
|
4006
|
+
json(res, 400, { error: "action must be accept, decline, or cancel" });
|
|
4007
|
+
return;
|
|
4008
|
+
}
|
|
4009
|
+
result =
|
|
4010
|
+
parsed.action === "accept"
|
|
4011
|
+
? { action: "accept", content: parsed.content ?? {} }
|
|
4012
|
+
: { action: parsed.action };
|
|
4013
|
+
}
|
|
4014
|
+
catch {
|
|
4015
|
+
json(res, 400, { error: "invalid JSON body" });
|
|
4016
|
+
return;
|
|
4017
|
+
}
|
|
4018
|
+
// Unknown id means it already timed out or was cancelled by an abort —
|
|
4019
|
+
// the tool call has moved on, so the answer has nowhere to go.
|
|
4020
|
+
if (!elicitations.settle(id, result)) {
|
|
4021
|
+
json(res, 409, { error: "no elicitation is awaiting a response" });
|
|
4022
|
+
return;
|
|
4023
|
+
}
|
|
4024
|
+
json(res, 200, { ok: true });
|
|
4025
|
+
});
|
|
4026
|
+
return;
|
|
4027
|
+
}
|
|
3888
4028
|
if (method === "POST" && url === "/auth/logout") {
|
|
3889
4029
|
void readBody(req, res).then(async (raw) => {
|
|
3890
4030
|
if (raw === null)
|
|
@@ -4270,6 +4410,7 @@ async function createSession(deps, opts) {
|
|
|
4270
4410
|
json(res, 404, { error: "not found" });
|
|
4271
4411
|
}
|
|
4272
4412
|
async function dispose() {
|
|
4413
|
+
elicitations.cancelAll();
|
|
4273
4414
|
tasksPollStopped = true;
|
|
4274
4415
|
if (tasksPoll)
|
|
4275
4416
|
clearTimeout(tasksPoll);
|