@euqns/nudge-mcp 1.36.0 → 1.37.0

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 CHANGED
@@ -680,6 +680,42 @@ Overrides are read at each job startup; already-running turns retain their
680
680
  existing settings. Do not repeat generated top-level model/auth keys in the
681
681
  TOML overrides. Desktop MCP servers remain isolated unless explicitly enabled.
682
682
 
683
+ ### T3 Code desktop runner threads
684
+
685
+ When T3 Code is running on the runner's machine, new jobs automatically create
686
+ a thread under the matching checkout's T3 project (creating the project if
687
+ needed). Look for **Nudge · running · Board · task …** in the T3 Code sidebar.
688
+ Open that thread's **terminal drawer** to watch the task prompt and live runner
689
+ output. The title changes to the final job status, including `needs human`;
690
+ retries and resumed jobs reuse the same thread.
691
+
692
+ This is a view of the external Nudge runner. Output appears in the terminal,
693
+ not as messages in T3's conversation pane. Continue to answer questions, steer,
694
+ or cancel the job in Nudge. The integration does not start a T3 agent turn or
695
+ attach T3's composer to the runner's agent session.
696
+
697
+ Discovery reads `~/.t3/userdata/server-runtime.json` (or the `dev` variant) and
698
+ only connects over loopback. On macOS it finds T3 Code or T3 Code (Nightly) in
699
+ `/Applications` or `~/Applications`; other installs need a `t3` executable on
700
+ the runner's `PATH`. The installed CLI issues a short-lived local session for
701
+ each update and revokes it afterward; credentials are not saved by Nudge.
702
+ The terminal log viewer supports macOS/Linux. Windows gets the thread and
703
+ status updates, with its log saved locally.
704
+
705
+ | Runner environment variable | Purpose |
706
+ | --- | --- |
707
+ | `NUDGE_T3=0` | Disable automatic T3 threads. |
708
+ | `T3CODE_HOME=/path/to/.t3` | Find a nonstandard T3 data directory. |
709
+ | `NUDGE_T3_CLI=/path/to/t3` | Use a specific installed T3 CLI or executable wrapper. |
710
+
711
+ T3 must be open before the job starts; jobs already in progress are not
712
+ backfilled. Missing T3 is silently skipped. An incompatible or unreachable T3
713
+ reports a warning and the runner continues. Verified against T3 Code Nightly
714
+ `0.0.41-nightly.20260908.1400`; this requires its HTTP orchestration and terminal
715
+ RPC interfaces. Local JSONL logs are owner-only under `~/.nudge/t3-logs` and
716
+ retain up to 8 MiB of live output per run, followed by its final result.
717
+ They remain available after completion and can be removed when no longer needed.
718
+
683
719
  ### Runner output files
684
720
 
685
721
  A coding turn can optionally write the JSON manifest at the absolute path supplied
@@ -0,0 +1,44 @@
1
+ // Invoked in a T3 terminal. The JSONL file is data, never shell input.
2
+ import { open, stat } from "node:fs/promises";
3
+ import { fileURLToPath } from "node:url";
4
+ export function safeTerminalText(text) {
5
+ // Strip controls including ESC, OSC and C1 so agent output cannot issue
6
+ // terminal/clipboard commands. Preserve readable tabs and line breaks.
7
+ return text.replace(/[\x00-\x08\x0b-\x1f\x7f-\x9f]/g, "");
8
+ }
9
+ export async function viewRunnerLog(file) {
10
+ let offset = 0;
11
+ let pending = "";
12
+ const decoder = new TextDecoder();
13
+ for (;;) {
14
+ const handle = await open(file, "r");
15
+ let bytesRead;
16
+ try {
17
+ const buffer = Buffer.alloc(64 * 1024);
18
+ ({ bytesRead } = await handle.read(buffer, 0, buffer.length, offset));
19
+ offset += bytesRead;
20
+ pending += decoder.decode(buffer.subarray(0, bytesRead), { stream: true });
21
+ }
22
+ finally {
23
+ await handle.close();
24
+ }
25
+ let end;
26
+ while ((end = pending.indexOf("\n")) >= 0) {
27
+ const entry = JSON.parse(pending.slice(0, end));
28
+ pending = pending.slice(end + 1);
29
+ process.stdout.write(safeTerminalText(String(entry.text ?? "")));
30
+ if (entry.done)
31
+ return;
32
+ }
33
+ if (!bytesRead) {
34
+ // A crashed runner must not leave a viewer alive indefinitely.
35
+ if (Date.now() - (await stat(file)).mtimeMs > 24 * 60 * 60 * 1000)
36
+ return;
37
+ await new Promise((resolve) => setTimeout(resolve, 500));
38
+ }
39
+ }
40
+ }
41
+ if (process.argv[1] === fileURLToPath(import.meta.url) && process.argv[2]) {
42
+ viewRunnerLog(process.argv[2]).catch(() => { console.error("Nudge runner log is unavailable."); process.exitCode = 1; });
43
+ }
44
+ //# sourceMappingURL=runner-t3-log-viewer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner-t3-log-viewer.js","sourceRoot":"","sources":["../src/runner-t3-log-viewer.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,wEAAwE;IACxE,uEAAuE;IACvE,OAAO,IAAI,CAAC,OAAO,CAAC,gCAAgC,EAAE,EAAE,CAAC,CAAC;AAC5D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAAY;IAC9C,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,IAAI,OAAO,GAAG,EAAE,CAAC;IACjB,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;IAClC,SAAS,CAAC;QACR,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QACrC,IAAI,SAAiB,CAAC;QACtB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC;YACvC,CAAC,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;YACtE,MAAM,IAAI,SAAS,CAAC;YACpB,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7E,CAAC;gBAAS,CAAC;YAAC,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QAAC,CAAC;QACnC,IAAI,GAAW,CAAC;QAChB,OAAO,CAAC,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;YAC1C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;YAChD,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;YACjC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,gBAAgB,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;YACjE,IAAI,KAAK,CAAC,IAAI;gBAAE,OAAO;QACzB,CAAC;QACD,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,+DAA+D;YAC/D,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI;gBAAE,OAAO;YAC1E,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC;QAC3D,CAAC;IACH,CAAC;AACH,CAAC;AAED,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1E,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,kCAAkC,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3H,CAAC"}
@@ -0,0 +1,327 @@
1
+ // Optional local T3 view. Only public HTTP commands and terminal RPCs are used:
2
+ // never write T3's database or start a second provider turn for a runner job.
3
+ import { execFile } from "node:child_process";
4
+ import { createHash, randomUUID } from "node:crypto";
5
+ import { access, appendFile, mkdir, readFile, realpath, writeFile } from "node:fs/promises";
6
+ import os from "node:os";
7
+ import { createRequire } from "node:module";
8
+ import path from "node:path";
9
+ import { fileURLToPath } from "node:url";
10
+ import { promisify } from "node:util";
11
+ import WebSocket from "ws";
12
+ const exec = promisify(execFile);
13
+ const TIMEOUT = 3_000;
14
+ const MAX_LOG_BYTES = 8 * 1024 * 1024;
15
+ export function localT3Origin(runtime) {
16
+ if (runtime.version !== 1 || !Number.isInteger(runtime.port) || runtime.port < 1 || runtime.port > 65535) {
17
+ throw new Error("Unsupported T3 runtime descriptor");
18
+ }
19
+ const url = new URL(runtime.origin);
20
+ if (url.protocol !== "http:" || !["127.0.0.1", "localhost", "[::1]", "0.0.0.0", "[::]"].includes(url.hostname)
21
+ || url.username || url.password || url.search || url.hash || url.pathname !== "/"
22
+ || Number(url.port || 80) !== runtime.port) {
23
+ throw new Error("T3 runner integration requires a loopback server");
24
+ }
25
+ // Wildcard listeners are reachable through loopback; never follow a remote origin.
26
+ return `http://${url.hostname.includes(":") ? "[::1]" : "127.0.0.1"}:${runtime.port}`;
27
+ }
28
+ export function t3JobThreadId(deployment, jobId) {
29
+ return `nudge-${createHash("sha256").update(`${deployment}\0${jobId}`).digest("hex").slice(0, 32)}`;
30
+ }
31
+ export function t3JobTitle(job, status) {
32
+ return `Nudge · ${status.replaceAll("_", " ")} · ${job.boardTitle} · ${job.kind} ${job.id.slice(-6)}`.slice(0, 220);
33
+ }
34
+ // T3's terminals use the machine's shell. This integration currently opens log
35
+ // viewers only on POSIX hosts; Windows still gets a thread and status updates.
36
+ export function shellQuote(value) {
37
+ return `'${value.replaceAll("'", "'\\''")}'`;
38
+ }
39
+ async function findCli() {
40
+ const env = { ...process.env };
41
+ // An explicit executable supports nonstandard installs and wrapper scripts.
42
+ if (env.NUDGE_T3_CLI)
43
+ return { command: env.NUDGE_T3_CLI, args: [], env };
44
+ if (process.platform === "darwin") {
45
+ for (const root of ["/Applications", path.join(os.homedir(), "Applications")]) {
46
+ for (const name of ["T3 Code (Nightly)", "T3 Code"]) {
47
+ const app = path.join(root, `${name}.app`, "Contents");
48
+ const command = path.join(app, "MacOS", name);
49
+ const entry = path.join(app, "Resources/app.asar/apps/server/dist/bin.mjs");
50
+ try {
51
+ await access(command);
52
+ return { command, args: [entry], env: { ...env, ELECTRON_RUN_AS_NODE: "1" } };
53
+ }
54
+ catch { /* Try the next installation. */ }
55
+ }
56
+ }
57
+ }
58
+ for (const dir of (env.PATH ?? "").split(path.delimiter)) {
59
+ const command = path.join(dir, process.platform === "win32" ? "t3.exe" : "t3");
60
+ try {
61
+ await access(command);
62
+ return { command, args: [], env };
63
+ }
64
+ catch { /* Not installed here. */ }
65
+ }
66
+ return null;
67
+ }
68
+ export class T3Client {
69
+ origin;
70
+ token;
71
+ constructor(origin, token) {
72
+ this.origin = origin;
73
+ this.token = token;
74
+ }
75
+ async request(route, body) {
76
+ const response = await fetch(`${this.origin}${route}`, {
77
+ method: body ? "POST" : "GET",
78
+ headers: { authorization: `Bearer ${this.token}`, "content-type": "application/json" },
79
+ ...(body ? { body: JSON.stringify(body) } : {}),
80
+ redirect: "error",
81
+ signal: AbortSignal.timeout(TIMEOUT),
82
+ });
83
+ // Error bodies can contain prompts or credentials: do not include them in logs.
84
+ if (!response.ok)
85
+ throw new Error(`T3 ${route} returned HTTP ${response.status}`);
86
+ return await response.json();
87
+ }
88
+ dispatch(command) {
89
+ return this.request("/api/orchestration/dispatch", { commandId: randomUUID(), ...command });
90
+ }
91
+ async terminalLog(threadId, cwd, logPath) {
92
+ if (process.platform === "win32")
93
+ return;
94
+ const socket = new WebSocket(`${this.origin.replace("http:", "ws:")}/ws`, {
95
+ headers: { authorization: `Bearer ${this.token}` },
96
+ handshakeTimeout: TIMEOUT,
97
+ maxPayload: 1024 * 1024,
98
+ });
99
+ // Keep an error handler installed even during teardown.
100
+ socket.on("error", () => undefined);
101
+ try {
102
+ await new Promise((resolve, reject) => {
103
+ const timer = setTimeout(() => reject(new Error("T3 socket timed out")), TIMEOUT);
104
+ socket.once("open", () => { clearTimeout(timer); resolve(); });
105
+ socket.once("error", () => { clearTimeout(timer); reject(new Error("T3 socket failed")); });
106
+ });
107
+ await t3Rpc(socket, "terminal.open", { threadId, terminalId: "term-1", cwd, cols: 120, rows: 32 });
108
+ let viewer = fileURLToPath(new URL("./runner-t3-log-viewer.js", import.meta.url));
109
+ const nodeArgs = [];
110
+ try {
111
+ await access(viewer);
112
+ }
113
+ catch {
114
+ viewer = fileURLToPath(new URL("./runner-t3-log-viewer.ts", import.meta.url));
115
+ nodeArgs.push("--import", createRequire(import.meta.url).resolve("tsx"));
116
+ }
117
+ // Never send task text to a shell. The viewer only prints a local data file.
118
+ await t3Rpc(socket, "terminal.write", {
119
+ threadId, terminalId: "term-1",
120
+ data: `${[process.execPath, ...nodeArgs, viewer, logPath].map(shellQuote).join(" ")}\r`,
121
+ });
122
+ }
123
+ finally {
124
+ socket.terminate();
125
+ }
126
+ }
127
+ }
128
+ export function t3Rpc(socket, tag, payload) {
129
+ return new Promise((resolve, reject) => {
130
+ const id = randomUUID();
131
+ const cleanup = () => {
132
+ clearTimeout(timer);
133
+ socket.off("message", onMessage);
134
+ socket.off("close", onClose);
135
+ socket.off("error", onClose);
136
+ };
137
+ const onClose = () => { cleanup(); reject(new Error("T3 socket closed")); };
138
+ const onMessage = (raw) => {
139
+ try {
140
+ const parsed = JSON.parse(raw.toString());
141
+ for (const message of Array.isArray(parsed) ? parsed : [parsed]) {
142
+ if (message._tag !== "Exit" || message.requestId !== id)
143
+ continue;
144
+ cleanup();
145
+ if (message.exit?._tag === "Success")
146
+ resolve(message.exit.value);
147
+ else
148
+ reject(new Error(`T3 ${tag} failed`));
149
+ }
150
+ }
151
+ catch {
152
+ cleanup();
153
+ reject(new Error("Invalid T3 RPC response"));
154
+ }
155
+ };
156
+ const timer = setTimeout(() => { cleanup(); reject(new Error(`T3 ${tag} timed out`)); }, TIMEOUT);
157
+ socket.on("message", onMessage);
158
+ socket.once("close", onClose);
159
+ socket.once("error", onClose);
160
+ try {
161
+ socket.send(JSON.stringify({ _tag: "Request", id, tag, payload, headers: [] }));
162
+ }
163
+ catch {
164
+ cleanup();
165
+ reject(new Error("T3 socket send failed"));
166
+ }
167
+ });
168
+ }
169
+ async function discover() {
170
+ if (process.env.NUDGE_T3 === "0")
171
+ return null;
172
+ const home = path.resolve(process.env.T3CODE_HOME ?? path.join(os.homedir(), ".t3"));
173
+ for (const variant of ["userdata", "dev"]) {
174
+ let runtime;
175
+ try {
176
+ runtime = JSON.parse(await readFile(path.join(home, variant, "server-runtime.json"), "utf8"));
177
+ }
178
+ catch (error) {
179
+ if (error.code === "ENOENT")
180
+ continue;
181
+ throw new Error("Cannot read T3 runtime descriptor");
182
+ }
183
+ const origin = localT3Origin(runtime);
184
+ if (!Number.isInteger(runtime.pid) || runtime.pid < 1)
185
+ continue;
186
+ try {
187
+ process.kill(runtime.pid, 0);
188
+ }
189
+ catch {
190
+ continue;
191
+ }
192
+ const probe = await fetch(`${origin}/.well-known/t3/environment`, { signal: AbortSignal.timeout(TIMEOUT), redirect: "error" });
193
+ if (!probe.ok)
194
+ throw new Error("Local T3 server is unavailable");
195
+ const descriptor = await probe.json();
196
+ if (typeof descriptor.environmentId !== "string" || typeof descriptor.serverVersion !== "string")
197
+ throw new Error("Unsupported T3 environment descriptor");
198
+ const cli = await findCli();
199
+ if (!cli)
200
+ throw new Error("T3 CLI not found; set NUDGE_T3_CLI to its executable");
201
+ return { origin, cli, home, dev: variant === "dev" };
202
+ }
203
+ return null;
204
+ }
205
+ async function withClient(connection, use) {
206
+ const { cli, home, dev } = connection;
207
+ const location = ["--base-dir", home, ...(dev ? ["--dev-url", "http://localhost"] : [])];
208
+ const run = async (args) => {
209
+ try {
210
+ return await exec(cli.command, [...cli.args, "auth", "session", ...args, ...location], {
211
+ env: cli.env, timeout: 10_000, maxBuffer: 64 * 1024, windowsHide: true,
212
+ });
213
+ }
214
+ catch {
215
+ throw new Error("T3 local session command failed");
216
+ }
217
+ };
218
+ const { stdout } = await run(["issue", "--ttl", "5m", "--label", "Nudge runner view", "--json"]);
219
+ let session;
220
+ try {
221
+ session = JSON.parse(stdout);
222
+ }
223
+ catch {
224
+ throw new Error("Invalid T3 session response");
225
+ }
226
+ if (typeof session.token !== "string" || typeof session.sessionId !== "string")
227
+ throw new Error("Invalid T3 session response");
228
+ try {
229
+ return await use(new T3Client(connection.origin, session.token));
230
+ }
231
+ finally {
232
+ await run(["revoke", session.sessionId]).catch(() => undefined);
233
+ }
234
+ }
235
+ export async function ensureT3JobThread(client, job) {
236
+ const snapshot = await client.request("/api/orchestration/snapshot");
237
+ const cwd = await realpath(job.cwd);
238
+ let project = snapshot.projects.find((p) => path.resolve(p.workspaceRoot) === cwd && !p.deletedAt);
239
+ if (!project) {
240
+ const projectId = `nudge-project-${createHash("sha256").update(cwd).digest("hex").slice(0, 24)}`;
241
+ try {
242
+ await client.dispatch({ type: "project.create", projectId, title: path.basename(cwd), workspaceRoot: cwd, createdAt: new Date().toISOString() });
243
+ }
244
+ catch (error) {
245
+ // Concurrent jobs may have created the same project first.
246
+ const latest = await client.request("/api/orchestration/snapshot");
247
+ if (!latest.projects.some((p) => p.id === projectId && !p.deletedAt))
248
+ throw error;
249
+ }
250
+ project = { id: projectId };
251
+ }
252
+ const threadId = t3JobThreadId(job.deployment, job.id);
253
+ const title = t3JobTitle(job, "running");
254
+ const existing = snapshot.threads.find((t) => t.id === threadId && !t.deletedAt);
255
+ if (!existing) {
256
+ await client.dispatch({
257
+ type: "thread.create", threadId, projectId: project.id, title,
258
+ modelSelection: project.defaultModelSelection ?? { instanceId: job.engine === "claude" ? "claudeAgent" : job.engine, model: job.model },
259
+ runtimeMode: "approval-required", interactionMode: "default",
260
+ branch: null, worktreePath: null, createdAt: new Date().toISOString(),
261
+ });
262
+ }
263
+ else {
264
+ if (existing.archivedAt)
265
+ await client.dispatch({ type: "thread.unarchive", threadId });
266
+ if (existing.settledAt || existing.settledOverride === "settled") {
267
+ await client.dispatch({ type: "thread.unsettle", threadId, reason: "user" });
268
+ }
269
+ await client.dispatch({ type: "thread.meta.update", threadId, title });
270
+ }
271
+ return threadId;
272
+ }
273
+ export async function startT3JobView(job, warn) {
274
+ try {
275
+ const connection = await discover();
276
+ if (!connection)
277
+ return null;
278
+ const threadId = t3JobThreadId(job.deployment, job.id);
279
+ const directory = path.join(os.homedir(), ".nudge", "t3-logs");
280
+ await mkdir(directory, { recursive: true, mode: 0o700 });
281
+ // Separate files for resumes prevent an old viewer consuming the new run.
282
+ const logPath = path.join(directory, `${threadId}-${randomUUID()}.jsonl`);
283
+ const encode = (text, done = false) => `${JSON.stringify({ text, done })}\n`;
284
+ const heading = `Nudge runner · ${job.boardTitle}\nJob: ${job.id} · attempt ${job.attempt}\nAgent: ${job.engine} · ${job.model}\n\nThis terminal displays the external runner. Reply or steer in Nudge.\n\n${job.prompt}\n\n`;
285
+ await writeFile(logPath, encode(heading), { mode: 0o600 });
286
+ await withClient(connection, async (client) => {
287
+ await ensureT3JobThread(client, job);
288
+ // A terminal failure must not discard a successfully created thread.
289
+ await client.terminalLog(threadId, job.cwd, logPath).catch(() => warn(`T3 thread created; its log viewer could not open. Log: ${logPath}`));
290
+ });
291
+ let queued = Promise.resolve();
292
+ let bytes = Buffer.byteLength(heading);
293
+ let truncated = false;
294
+ let finished = false;
295
+ const append = (text, done = false) => {
296
+ queued = queued.then(() => appendFile(logPath, encode(text, done))).catch(() => undefined);
297
+ };
298
+ return {
299
+ threadId, logPath,
300
+ log(stream, text) {
301
+ if (finished || truncated)
302
+ return;
303
+ bytes += Buffer.byteLength(text);
304
+ if (bytes > MAX_LOG_BYTES) {
305
+ truncated = true;
306
+ append("\n[Live log limit reached. Final result will follow.]\n");
307
+ return;
308
+ }
309
+ append(`[${stream}] ${text}\n`);
310
+ },
311
+ async finish(status, summary, error) {
312
+ if (finished)
313
+ return;
314
+ finished = true;
315
+ append(`\nNudge job: ${status}\n${summary ?? ""}\n${error ?? ""}\n`, true);
316
+ await queued;
317
+ await withClient(connection, (client) => client.dispatch({ type: "thread.meta.update", threadId, title: t3JobTitle(job, status) }))
318
+ .catch(() => warn("T3 thread status could not be updated; the job result is recorded in Nudge."));
319
+ },
320
+ };
321
+ }
322
+ catch (error) {
323
+ warn(`T3 view unavailable: ${error instanceof Error ? error.message : "local integration failed"}. The runner will continue.`);
324
+ return null;
325
+ }
326
+ }
327
+ //# sourceMappingURL=runner-t3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner-t3.js","sourceRoot":"","sources":["../src/runner-t3.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,154 @@
1
+ import assert from "node:assert/strict";
2
+ import test from "node:test";
3
+ import { createServer } from "node:http";
4
+ import { once } from "node:events";
5
+ import { appendFile, mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
6
+ import os from "node:os";
7
+ import path from "node:path";
8
+ import { execFile } from "node:child_process";
9
+ import { promisify } from "node:util";
10
+ import { createRequire } from "node:module";
11
+ import WebSocket, { WebSocketServer } from "ws";
12
+ import { ensureT3JobThread, localT3Origin, shellQuote, startT3JobView, T3Client, t3JobThreadId, t3Rpc } from "./runner-t3.js";
13
+ import { safeTerminalText } from "./runner-t3-log-viewer.js";
14
+ test("discovery accepts local wildcard listeners and rejects credential-bearing or remote origins", () => {
15
+ assert.equal(localT3Origin({ version: 1, port: 3773, origin: "http://0.0.0.0:3773" }), "http://127.0.0.1:3773");
16
+ assert.equal(localT3Origin({ version: 1, port: 3773, origin: "http://[::]:3773" }), "http://[::1]:3773");
17
+ for (const origin of ["https://example.com:3773", "http://example.com:3773", "http://user:secret@localhost:3773", "http://localhost:3773/redirect", "http://localhost:3773?token=secret", "http://localhost:80"]) {
18
+ assert.throws(() => localT3Origin({ version: 1, port: 3773, origin }));
19
+ }
20
+ assert.throws(() => localT3Origin({ version: 2, port: 3773, origin: "http://localhost:3773" }));
21
+ });
22
+ test("job identity survives attempts but is scoped to the Nudge deployment", () => {
23
+ assert.equal(t3JobThreadId("a", "job"), t3JobThreadId("a", "job"));
24
+ assert.notEqual(t3JobThreadId("a", "job"), t3JobThreadId("b", "job"));
25
+ assert.match(t3JobThreadId("a", "../../job"), /^nudge-[a-f0-9]{32}$/);
26
+ });
27
+ test("POSIX arguments cannot execute task-controlled shell syntax", { skip: process.platform === "win32" }, async () => {
28
+ const input = "space ' quote `echo BAD` $(echo BAD) ; \n end";
29
+ const { stdout } = await promisify(execFile)("/bin/sh", ["-c", `printf %s ${shellQuote(input)}`]);
30
+ assert.equal(stdout, input);
31
+ });
32
+ test("missing or malformed T3 does not prevent a runner job", async (t) => {
33
+ const directory = await mkdtemp(path.join(os.tmpdir(), "nudge-t3-missing-"));
34
+ t.after(() => rm(directory, { recursive: true, force: true }));
35
+ const previous = process.env.T3CODE_HOME;
36
+ process.env.T3CODE_HOME = directory;
37
+ const warnings = [];
38
+ try {
39
+ assert.equal(await startT3JobView({}, (message) => warnings.push(message)), null);
40
+ assert.equal(warnings.length, 0);
41
+ await mkdir(path.join(directory, "userdata"));
42
+ await writeFile(path.join(directory, "userdata/server-runtime.json"), "invalid descriptor");
43
+ assert.equal(await startT3JobView({}, (message) => warnings.push(message)), null);
44
+ assert.equal(warnings.length, 1);
45
+ assert.match(warnings[0], /runner will continue/);
46
+ }
47
+ finally {
48
+ if (previous === undefined)
49
+ delete process.env.T3CODE_HOME;
50
+ else
51
+ process.env.T3CODE_HOME = previous;
52
+ }
53
+ });
54
+ test("disabled integration performs no T3 work", async () => {
55
+ const previous = process.env.NUDGE_T3;
56
+ process.env.NUDGE_T3 = "0";
57
+ try {
58
+ assert.equal(await startT3JobView({}, () => assert.fail("must stay quiet")), null);
59
+ }
60
+ finally {
61
+ if (previous === undefined)
62
+ delete process.env.NUDGE_T3;
63
+ else
64
+ process.env.NUDGE_T3 = previous;
65
+ }
66
+ });
67
+ test("public API creates one thread, then resumes it without starting another agent", async (t) => {
68
+ const cwd = await mkdtemp(path.join(os.tmpdir(), "nudge-t3-"));
69
+ t.after(() => rm(cwd, { recursive: true, force: true }));
70
+ const commands = [];
71
+ const projects = [];
72
+ const threads = [];
73
+ const server = createServer(async (req, res) => {
74
+ assert.equal(req.headers.authorization, "Bearer test-local-token");
75
+ res.setHeader("content-type", "application/json");
76
+ if (req.url === "/api/orchestration/snapshot")
77
+ return res.end(JSON.stringify({ projects, threads }));
78
+ assert.equal(req.url, "/api/orchestration/dispatch");
79
+ let body = "";
80
+ for await (const part of req)
81
+ body += part;
82
+ const command = JSON.parse(body);
83
+ commands.push(command);
84
+ if (command.type === "project.create")
85
+ projects.push({ id: command.projectId, workspaceRoot: command.workspaceRoot });
86
+ if (command.type === "thread.create")
87
+ threads.push({ id: command.threadId, projectId: command.projectId });
88
+ res.end(JSON.stringify({ sequence: commands.length }));
89
+ });
90
+ server.listen(0, "127.0.0.1");
91
+ await once(server, "listening");
92
+ t.after(() => { server.closeAllConnections(); server.close(); });
93
+ const client = new T3Client(`http://127.0.0.1:${server.address().port}`, "test-local-token");
94
+ const job = { id: "job1", deployment: "local", cwd, boardTitle: "Board", kind: "task", prompt: "Do work", engine: "codex", model: "gpt-6-astra", attempt: 1 };
95
+ const id = await ensureT3JobThread(client, job);
96
+ threads[0].archivedAt = new Date().toISOString();
97
+ threads[0].settledAt = new Date().toISOString();
98
+ assert.equal(await ensureT3JobThread(client, { ...job, attempt: 2 }), id);
99
+ assert.deepEqual(commands.map((c) => c.type), ["project.create", "thread.create", "thread.unarchive", "thread.unsettle", "thread.meta.update"]);
100
+ assert.equal(commands[1].runtimeMode, "approval-required");
101
+ assert.match(commands[4].title, /running/);
102
+ });
103
+ test("T3 errors and redirects never expose response bodies or send a token to another origin", async (t) => {
104
+ let followed = false;
105
+ const server = createServer((req, res) => {
106
+ if (req.url === "/redirect") {
107
+ res.writeHead(302, { location: "/destination" });
108
+ return res.end();
109
+ }
110
+ if (req.url === "/destination")
111
+ followed = true;
112
+ res.writeHead(500);
113
+ res.end("secret-response-body");
114
+ });
115
+ server.listen(0, "127.0.0.1");
116
+ await once(server, "listening");
117
+ t.after(() => { server.closeAllConnections(); server.close(); });
118
+ const client = new T3Client(`http://127.0.0.1:${server.address().port}`, "secret-token");
119
+ await assert.rejects(client.request("/test"), (error) => error.message.includes("HTTP 500") && !error.message.includes("secret"));
120
+ await assert.rejects(client.request("/redirect"));
121
+ assert.equal(followed, false);
122
+ });
123
+ test("terminal RPC handles batched replies and disconnected servers", async (t) => {
124
+ const server = new WebSocketServer({ port: 0, host: "127.0.0.1" });
125
+ await once(server, "listening");
126
+ t.after(() => server.close());
127
+ server.on("connection", (socket) => socket.on("message", (raw) => {
128
+ const message = JSON.parse(raw.toString());
129
+ if (message.tag === "disconnect")
130
+ return socket.close();
131
+ assert.equal(message._tag, "Request");
132
+ socket.send(JSON.stringify([{ _tag: "Pong" }, { _tag: "Exit", requestId: message.id, exit: { _tag: "Success", value: { ready: true } } }]));
133
+ }));
134
+ const socket = new WebSocket(`ws://127.0.0.1:${server.address().port}`);
135
+ socket.on("error", () => undefined);
136
+ await once(socket, "open");
137
+ t.after(() => socket.terminate());
138
+ assert.deepEqual(await t3Rpc(socket, "terminal.open", {}), { ready: true });
139
+ await assert.rejects(t3Rpc(socket, "disconnect", {}), /closed/);
140
+ });
141
+ test("log viewer handles split UTF-8 and exits on the final record", async (t) => {
142
+ const directory = await mkdtemp(path.join(os.tmpdir(), "nudge-t3-viewer-"));
143
+ t.after(() => rm(directory, { recursive: true, force: true }));
144
+ const file = path.join(directory, "log.jsonl");
145
+ const text = "İstanbul ✓ ".repeat(20_000);
146
+ await writeFile(file, `${JSON.stringify({ text, done: false })}\n`);
147
+ const result = promisify(execFile)(process.execPath, ["--import", createRequire(import.meta.url).resolve("tsx"), new URL("./runner-t3-log-viewer.ts", import.meta.url).pathname, file], { maxBuffer: 1024 * 1024, timeout: 10_000 });
148
+ await once(result.child.stdout, "data");
149
+ await appendFile(file, `${JSON.stringify({ text: "Finished", done: true })}\n`);
150
+ const { stdout } = await result;
151
+ assert.equal(stdout, text + "Finished");
152
+ assert.equal(safeTerminalText("hello\x1b]52;c;clipboard\x07\n\tworld\x9b"), "hello]52;c;clipboard\n\tworld");
153
+ });
154
+ //# sourceMappingURL=runner-t3.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner-t3.test.js","sourceRoot":"","sources":["../src/runner-t3.test.ts"],"names":[],"mappings":"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"}