ccgateway 0.1.7 → 0.1.8

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/router.js CHANGED
@@ -1,3 +1,7 @@
1
+ import { getCcgHome } from "./config.js";
2
+ import { writeFile, mkdir, rm } from "node:fs/promises";
3
+ import { join } from "node:path";
4
+ import { tmpdir } from "node:os";
1
5
  // ── MessageRouter ─────────────────────────────────────────────────────────
2
6
  export class MessageRouter {
3
7
  agents;
@@ -5,12 +9,14 @@ export class MessageRouter {
5
9
  context;
6
10
  spawner;
7
11
  bindings;
8
- constructor(agents, sessions, context, spawner, bindings) {
12
+ watcher;
13
+ constructor(agents, sessions, context, spawner, bindings, watcher) {
9
14
  this.agents = agents;
10
15
  this.sessions = sessions;
11
16
  this.context = context;
12
17
  this.spawner = spawner;
13
18
  this.bindings = bindings;
19
+ this.watcher = watcher;
14
20
  }
15
21
  /**
16
22
  * Resolve which agent handles a message based on bindings.
@@ -58,23 +64,87 @@ export class MessageRouter {
58
64
  sourceUser: message.from.user,
59
65
  sourceMessageId: message.from.messageId,
60
66
  });
61
- // 4. Build context
67
+ // 4. Download attachments (if any)
68
+ // Images → base64 in-memory, passed as content blocks (no Read-tool round-trip)
69
+ // Other → saved to temp dir so Claude can read them via the Read tool
70
+ let attachmentDir;
71
+ let messageContent = message.content;
72
+ const images = [];
73
+ if (message.attachments.length > 0) {
74
+ const result = await this.downloadAttachments(message.attachments);
75
+ attachmentDir = result.dir;
76
+ images.push(...result.images);
77
+ if (result.filePaths.length > 0) {
78
+ const fileList = result.filePaths
79
+ .map((p) => ` - ${p}`)
80
+ .join("\n");
81
+ messageContent += `\n\n[Attached files — use the Read tool to view them]\n${fileList}`;
82
+ }
83
+ if (result.rejected.length > 0) {
84
+ const rejectedList = result.rejected.join(", ");
85
+ messageContent += `\n\n[Rejected attachments (blocked file type): ${rejectedList}]`;
86
+ }
87
+ }
88
+ // 5. Build context
62
89
  const systemPrompt = await this.context.build(agentId, sessionKey);
63
- // 5. Spawn claude --print
90
+ // 5.5 Triage: should this run async?
91
+ // Skip triage for image messages — they require stream-json (sync only)
92
+ // and the triage call adds unnecessary latency.
93
+ const mode = this.watcher && images.length === 0
94
+ ? await this.spawner.triage(messageContent, agent.model)
95
+ : "sync";
96
+ if (mode === "async") {
97
+ const { sessionName, taskDir } = await this.spawner.spawnAsync({
98
+ workspace: agent.workspace,
99
+ message: messageContent,
100
+ systemPrompt,
101
+ model: agent.model,
102
+ ccgHome: getCcgHome(),
103
+ agentId,
104
+ });
105
+ // Register with watcher
106
+ const binding = this.bindings.find((b) => b.agent === agentId);
107
+ this.watcher.register({
108
+ sessionName,
109
+ taskDir,
110
+ agentId,
111
+ gateway: message.from.gateway,
112
+ channel: message.from.channel,
113
+ botId: binding?.bot ?? agentId,
114
+ sessionKey,
115
+ workspace: agent.workspace,
116
+ startedAt: Date.now(),
117
+ });
118
+ const placeholder = `[async] Task dispatched to tmux session \`${sessionName}\`. I'll post the result here when done.`;
119
+ await this.sessions.appendMessage(agentId, sessionKey, {
120
+ role: "assistant",
121
+ content: placeholder,
122
+ ts: Date.now(),
123
+ tokens: { in: 0, out: 0 },
124
+ });
125
+ return placeholder;
126
+ }
127
+ // 6. Spawn claude --print (sync path — unchanged)
64
128
  const result = await this.spawner.spawn({
65
129
  workspace: agent.workspace,
66
- message: message.content,
130
+ message: messageContent,
67
131
  systemPrompt,
68
132
  model: agent.model,
69
133
  allowedTools: agent.allowedTools,
70
134
  ...(agent.timeoutMs ? { timeoutMs: agent.timeoutMs } : {}),
135
+ ...(images.length > 0 ? { images } : {}),
71
136
  });
72
- // 6. Handle failure: append error to session and throw
137
+ // 7. Clean up attachment temp dir
138
+ if (attachmentDir) {
139
+ rm(attachmentDir, { recursive: true, force: true }).catch(() => { });
140
+ }
141
+ // 8. Handle failure: append error to session and throw
73
142
  if (result.exitCode !== 0) {
74
143
  const isTimeout = result.exitCode === 124;
144
+ const stderrHint = result.stderr ? `\n\nDetails: ${result.stderr.slice(0, 500)}` : "";
75
145
  const errorContent = isTimeout
76
146
  ? "The task timed out — it took longer than the allowed time. Try breaking it into smaller steps, or increase the agent's `timeoutMs` setting."
77
- : result.response || `Spawner failed with exit code ${result.exitCode}`;
147
+ : (result.response || `Spawner failed with exit code ${result.exitCode}`) + stderrHint;
78
148
  await this.sessions.appendMessage(agentId, sessionKey, {
79
149
  role: "assistant",
80
150
  content: `[error] ${errorContent}`,
@@ -83,14 +153,14 @@ export class MessageRouter {
83
153
  });
84
154
  throw new Error(errorContent);
85
155
  }
86
- // 7. Append assistant response to session
156
+ // 9. Append assistant response to session
87
157
  await this.sessions.appendMessage(agentId, sessionKey, {
88
158
  role: "assistant",
89
159
  content: result.response,
90
160
  ts: Date.now(),
91
161
  tokens: result.tokensEstimate,
92
162
  });
93
- // 8. Return response text
163
+ // 10. Return response text
94
164
  return result.response;
95
165
  }
96
166
  /**
@@ -111,5 +181,116 @@ export class MessageRouter {
111
181
  getPrimaryBinding(agentId) {
112
182
  return this.bindings.find((b) => b.agent === agentId);
113
183
  }
184
+ /**
185
+ * Download attachments, separating images (kept as base64 in-memory)
186
+ * from other files (saved to a temp directory for Read-tool access).
187
+ * Rejects blocked file types (executables, archives, etc.).
188
+ */
189
+ async downloadAttachments(attachments) {
190
+ const dir = join(tmpdir(), `ccg-attach-${Date.now()}`);
191
+ const filePaths = [];
192
+ const images = [];
193
+ const rejected = [];
194
+ let dirCreated = false;
195
+ for (const att of attachments) {
196
+ if (!att.url && !att.data)
197
+ continue;
198
+ const filename = att.filename || "attachment";
199
+ if (isBlockedAttachment(att.type, filename)) {
200
+ rejected.push(filename);
201
+ continue;
202
+ }
203
+ try {
204
+ // Use pre-downloaded data if available, otherwise fetch from URL
205
+ let buffer;
206
+ if (att.data) {
207
+ buffer = att.data;
208
+ }
209
+ else {
210
+ const resp = await fetch(att.url);
211
+ if (!resp.ok)
212
+ continue;
213
+ buffer = Buffer.from(await resp.arrayBuffer());
214
+ }
215
+ if (att.type.startsWith("image/")) {
216
+ images.push({
217
+ base64: buffer.toString("base64"),
218
+ mediaType: att.type,
219
+ });
220
+ }
221
+ else {
222
+ if (!dirCreated) {
223
+ await mkdir(dir, { recursive: true });
224
+ dirCreated = true;
225
+ }
226
+ const filePath = join(dir, filename);
227
+ await writeFile(filePath, buffer);
228
+ filePaths.push(filePath);
229
+ }
230
+ }
231
+ catch {
232
+ // Skip failed downloads
233
+ }
234
+ }
235
+ return { dir, filePaths, images, rejected };
236
+ }
237
+ }
238
+ // ── Attachment filtering ──────────────────────────────────────────────────
239
+ /** MIME types that are never allowed through. */
240
+ const BLOCKED_MIME_PREFIXES = [
241
+ "application/x-executable",
242
+ "application/x-msdos-program",
243
+ "application/x-msdownload",
244
+ "application/x-sharedlib",
245
+ "application/x-dosexec",
246
+ "application/vnd.microsoft.portable-executable",
247
+ ];
248
+ const BLOCKED_MIME_EXACT = new Set([
249
+ "application/x-sh",
250
+ "application/x-csh",
251
+ "application/x-bat",
252
+ "application/x-msi",
253
+ "application/java-archive",
254
+ "application/x-rar-compressed",
255
+ "application/x-7z-compressed",
256
+ "application/x-tar",
257
+ "application/gzip",
258
+ "application/zip",
259
+ "application/x-bzip2",
260
+ "application/x-xz",
261
+ "application/x-iso9660-image",
262
+ "application/x-apple-diskimage",
263
+ "application/vnd.debian.binary-package",
264
+ "application/x-rpm",
265
+ ]);
266
+ /** File extensions that are never allowed through (lowercase, with dot). */
267
+ const BLOCKED_EXTENSIONS = new Set([
268
+ // Executables & scripts
269
+ ".exe", ".bat", ".cmd", ".com", ".msi", ".scr", ".pif",
270
+ ".sh", ".bash", ".csh", ".ksh", ".zsh",
271
+ ".ps1", ".psm1", ".psd1", ".vbs", ".vbe", ".wsf", ".wsh",
272
+ // Compiled / bytecode
273
+ ".dll", ".so", ".dylib", ".sys", ".drv", ".o", ".obj",
274
+ ".class", ".jar", ".war", ".ear",
275
+ // Archives
276
+ ".zip", ".tar", ".gz", ".tgz", ".bz2", ".xz", ".7z",
277
+ ".rar", ".iso", ".dmg", ".img",
278
+ // Packages
279
+ ".deb", ".rpm", ".apk", ".snap", ".flatpak",
280
+ ".whl", ".gem", ".nupkg",
281
+ ]);
282
+ /** Returns true if the attachment should be rejected. */
283
+ export function isBlockedAttachment(mimeType, filename) {
284
+ const mime = mimeType.toLowerCase();
285
+ if (BLOCKED_MIME_EXACT.has(mime))
286
+ return true;
287
+ if (BLOCKED_MIME_PREFIXES.some((p) => mime.startsWith(p)))
288
+ return true;
289
+ const ext = filename.lastIndexOf(".") >= 0
290
+ ? filename.slice(filename.lastIndexOf(".")).toLowerCase()
291
+ : "";
292
+ if (ext && BLOCKED_EXTENSIONS.has(ext))
293
+ return true;
294
+ return false;
114
295
  }
115
296
  //# sourceMappingURL=router.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"router.js","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAMA,6EAA6E;AAE7E,MAAM,OAAO,aAAa;IAEd;IACA;IACA;IACA;IACA;IALV,YACU,MAAqB,EACrB,QAAwB,EACxB,OAAuB,EACvB,OAAkB,EAClB,QAAyB;QAJzB,WAAM,GAAN,MAAM,CAAe;QACrB,aAAQ,GAAR,QAAQ,CAAgB;QACxB,YAAO,GAAP,OAAO,CAAgB;QACvB,YAAO,GAAP,OAAO,CAAW;QAClB,aAAQ,GAAR,QAAQ,CAAiB;IAChC,CAAC;IAEJ;;;OAGG;IACH,YAAY,CAAC,OAAe,EAAE,SAAiB;QAC7C,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAChC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,OAAO,IAAI,CAAC,CAAC,OAAO,KAAK,SAAS,CACxD,CAAC;QACF,OAAO,OAAO,EAAE,KAAK,CAAC;IACxB,CAAC;IAED;;;OAGG;IACH,iBAAiB,CAAC,OAAe,EAAE,KAAa;QAC9C,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAChC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,OAAO,IAAI,CAAC,CAAC,GAAG,KAAK,KAAK,CAChD,CAAC;QACF,OAAO,OAAO,EAAE,KAAK,CAAC;IACxB,CAAC;IAED;;;;;;;;;;;OAWG;IACH,KAAK,CAAC,KAAK,CAAC,OAAwB;QAClC,MAAM,OAAO,GAAG,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC;QAEjC,sBAAsB;QACtB,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAC5C,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,IAAI,KAAK,CAAC,UAAU,OAAO,yBAAyB,CAAC,CAAC;QAC9D,CAAC;QAED,wBAAwB;QACxB,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,kBAAkB,CACjD,OAAO,EACP,OAAO,CAAC,IAAI,CAAC,OAAO,EACpB,OAAO,CAAC,IAAI,CAAC,OAAO,CACrB,CAAC;QAEF,oCAAoC;QACpC,MAAM,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,OAAO,EAAE,UAAU,EAAE;YACrD,IAAI,EAAE,MAAM;YACZ,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE;YACd,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,OAAO;YAC5B,UAAU,EAAE,OAAO,CAAC,IAAI,CAAC,IAAI;YAC7B,eAAe,EAAE,OAAO,CAAC,IAAI,CAAC,SAAS;SACxC,CAAC,CAAC;QAEH,mBAAmB;QACnB,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;QAEnE,0BAA0B;QAC1B,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC;YACtC,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,YAAY;YACZ,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC3D,CAAC,CAAC;QAEH,uDAAuD;QACvD,IAAI,MAAM,CAAC,QAAQ,KAAK,CAAC,EAAE,CAAC;YAC1B,MAAM,SAAS,GAAG,MAAM,CAAC,QAAQ,KAAK,GAAG,CAAC;YAC1C,MAAM,YAAY,GAAG,SAAS;gBAC5B,CAAC,CAAC,6IAA6I;gBAC/I,CAAC,CAAC,MAAM,CAAC,QAAQ,IAAI,iCAAiC,MAAM,CAAC,QAAQ,EAAE,CAAC;YAC1E,MAAM,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,OAAO,EAAE,UAAU,EAAE;gBACrD,IAAI,EAAE,WAAW;gBACjB,OAAO,EAAE,WAAW,YAAY,EAAE;gBAClC,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE;gBACd,MAAM,EAAE,MAAM,CAAC,cAAc;aAC9B,CAAC,CAAC;YACH,MAAM,IAAI,KAAK,CAAC,YAAY,CAAC,CAAC;QAChC,CAAC;QAED,0CAA0C;QAC1C,MAAM,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,OAAO,EAAE,UAAU,EAAE;YACrD,IAAI,EAAE,WAAW;YACjB,OAAO,EAAE,MAAM,CAAC,QAAQ;YACxB,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE;YACd,MAAM,EAAE,MAAM,CAAC,cAAc;SAC9B,CAAC,CAAC;QAEH,0BAA0B;QAC1B,OAAO,MAAM,CAAC,QAAQ,CAAC;IACzB,CAAC;IAED;;OAEG;IACH,UAAU,CAAC,OAAsB;QAC/B,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC9B,CAAC;IAED;;OAEG;IACH,mBAAmB,CAAC,OAAe;QACjC,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,OAAO,CAAC,CAAC;IAC1D,CAAC;IAED;;OAEG;IACH,iBAAiB,CAAC,OAAe;QAC/B,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,OAAO,CAAC,CAAC;IACxD,CAAC;CACF"}
1
+ {"version":3,"file":"router.js","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEjC,6EAA6E;AAE7E,MAAM,OAAO,aAAa;IAEd;IACA;IACA;IACA;IACA;IACA;IANV,YACU,MAAqB,EACrB,QAAwB,EACxB,OAAuB,EACvB,OAAkB,EAClB,QAAyB,EACzB,OAA0B;QAL1B,WAAM,GAAN,MAAM,CAAe;QACrB,aAAQ,GAAR,QAAQ,CAAgB;QACxB,YAAO,GAAP,OAAO,CAAgB;QACvB,YAAO,GAAP,OAAO,CAAW;QAClB,aAAQ,GAAR,QAAQ,CAAiB;QACzB,YAAO,GAAP,OAAO,CAAmB;IACjC,CAAC;IAEJ;;;OAGG;IACH,YAAY,CAAC,OAAe,EAAE,SAAiB;QAC7C,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAChC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,OAAO,IAAI,CAAC,CAAC,OAAO,KAAK,SAAS,CACxD,CAAC;QACF,OAAO,OAAO,EAAE,KAAK,CAAC;IACxB,CAAC;IAED;;;OAGG;IACH,iBAAiB,CAAC,OAAe,EAAE,KAAa;QAC9C,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAChC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,OAAO,IAAI,CAAC,CAAC,GAAG,KAAK,KAAK,CAChD,CAAC;QACF,OAAO,OAAO,EAAE,KAAK,CAAC;IACxB,CAAC;IAED;;;;;;;;;;;OAWG;IACH,KAAK,CAAC,KAAK,CAAC,OAAwB;QAClC,MAAM,OAAO,GAAG,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC;QAEjC,sBAAsB;QACtB,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAC5C,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,IAAI,KAAK,CAAC,UAAU,OAAO,yBAAyB,CAAC,CAAC;QAC9D,CAAC;QAED,wBAAwB;QACxB,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,kBAAkB,CACjD,OAAO,EACP,OAAO,CAAC,IAAI,CAAC,OAAO,EACpB,OAAO,CAAC,IAAI,CAAC,OAAO,CACrB,CAAC;QAEF,oCAAoC;QACpC,MAAM,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,OAAO,EAAE,UAAU,EAAE;YACrD,IAAI,EAAE,MAAM;YACZ,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE;YACd,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,OAAO;YAC5B,UAAU,EAAE,OAAO,CAAC,IAAI,CAAC,IAAI;YAC7B,eAAe,EAAE,OAAO,CAAC,IAAI,CAAC,SAAS;SACxC,CAAC,CAAC;QAEH,mCAAmC;QACnC,oFAAoF;QACpF,2EAA2E;QAC3E,IAAI,aAAiC,CAAC;QACtC,IAAI,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC;QACrC,MAAM,MAAM,GAAiB,EAAE,CAAC;QAEhC,IAAI,OAAO,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACnC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;YACnE,aAAa,GAAG,MAAM,CAAC,GAAG,CAAC;YAC3B,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;YAE9B,IAAI,MAAM,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAChC,MAAM,QAAQ,GAAG,MAAM,CAAC,SAAS;qBAC9B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;qBACtB,IAAI,CAAC,IAAI,CAAC,CAAC;gBACd,cAAc,IAAI,0DAA0D,QAAQ,EAAE,CAAC;YACzF,CAAC;YAED,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC/B,MAAM,YAAY,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAChD,cAAc,IAAI,kDAAkD,YAAY,GAAG,CAAC;YACtF,CAAC;QACH,CAAC;QAED,mBAAmB;QACnB,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;QAEnE,qCAAqC;QACrC,4EAA4E;QAC5E,oDAAoD;QACpD,MAAM,IAAI,GACR,IAAI,CAAC,OAAO,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;YACjC,CAAC,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,cAAc,EAAE,KAAK,CAAC,KAAK,CAAC;YACxD,CAAC,CAAE,MAAgB,CAAC;QAExB,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;YACrB,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC;gBAC7D,SAAS,EAAE,KAAK,CAAC,SAAS;gBAC1B,OAAO,EAAE,cAAc;gBACvB,YAAY;gBACZ,KAAK,EAAE,KAAK,CAAC,KAAK;gBAClB,OAAO,EAAE,UAAU,EAAE;gBACrB,OAAO;aACR,CAAC,CAAC;YAEH,wBAAwB;YACxB,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,OAAO,CAAC,CAAC;YAC/D,IAAI,CAAC,OAAQ,CAAC,QAAQ,CAAC;gBACrB,WAAW;gBACX,OAAO;gBACP,OAAO;gBACP,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,OAAO;gBAC7B,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,OAAO;gBAC7B,KAAK,EAAE,OAAO,EAAE,GAAG,IAAI,OAAO;gBAC9B,UAAU;gBACV,SAAS,EAAE,KAAK,CAAC,SAAS;gBAC1B,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;aACtB,CAAC,CAAC;YAEH,MAAM,WAAW,GAAG,6CAA6C,WAAW,0CAA0C,CAAC;YACvH,MAAM,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,OAAO,EAAE,UAAU,EAAE;gBACrD,IAAI,EAAE,WAAW;gBACjB,OAAO,EAAE,WAAW;gBACpB,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE;gBACd,MAAM,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE;aAC1B,CAAC,CAAC;YAEH,OAAO,WAAW,CAAC;QACrB,CAAC;QAED,kDAAkD;QAClD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC;YACtC,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,OAAO,EAAE,cAAc;YACvB,YAAY;YACZ,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC1D,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACzC,CAAC,CAAC;QAEH,kCAAkC;QAClC,IAAI,aAAa,EAAE,CAAC;YAClB,EAAE,CAAC,aAAa,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QACtE,CAAC;QAED,uDAAuD;QACvD,IAAI,MAAM,CAAC,QAAQ,KAAK,CAAC,EAAE,CAAC;YAC1B,MAAM,SAAS,GAAG,MAAM,CAAC,QAAQ,KAAK,GAAG,CAAC;YAC1C,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,gBAAgB,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACtF,MAAM,YAAY,GAAG,SAAS;gBAC5B,CAAC,CAAC,6IAA6I;gBAC/I,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,IAAI,iCAAiC,MAAM,CAAC,QAAQ,EAAE,CAAC,GAAG,UAAU,CAAC;YACzF,MAAM,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,OAAO,EAAE,UAAU,EAAE;gBACrD,IAAI,EAAE,WAAW;gBACjB,OAAO,EAAE,WAAW,YAAY,EAAE;gBAClC,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE;gBACd,MAAM,EAAE,MAAM,CAAC,cAAc;aAC9B,CAAC,CAAC;YACH,MAAM,IAAI,KAAK,CAAC,YAAY,CAAC,CAAC;QAChC,CAAC;QAED,0CAA0C;QAC1C,MAAM,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,OAAO,EAAE,UAAU,EAAE;YACrD,IAAI,EAAE,WAAW;YACjB,OAAO,EAAE,MAAM,CAAC,QAAQ;YACxB,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE;YACd,MAAM,EAAE,MAAM,CAAC,cAAc;SAC9B,CAAC,CAAC;QAEH,2BAA2B;QAC3B,OAAO,MAAM,CAAC,QAAQ,CAAC;IACzB,CAAC;IAED;;OAEG;IACH,UAAU,CAAC,OAAsB;QAC/B,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC9B,CAAC;IAED;;OAEG;IACH,mBAAmB,CAAC,OAAe;QACjC,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,OAAO,CAAC,CAAC;IAC1D,CAAC;IAED;;OAEG;IACH,iBAAiB,CAAC,OAAe;QAC/B,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,OAAO,CAAC,CAAC;IACxD,CAAC;IAED;;;;OAIG;IACK,KAAK,CAAC,mBAAmB,CAC/B,WAAyB;QAEzB,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,cAAc,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACvD,MAAM,SAAS,GAAa,EAAE,CAAC;QAC/B,MAAM,MAAM,GAAiB,EAAE,CAAC;QAChC,MAAM,QAAQ,GAAa,EAAE,CAAC;QAC9B,IAAI,UAAU,GAAG,KAAK,CAAC;QAEvB,KAAK,MAAM,GAAG,IAAI,WAAW,EAAE,CAAC;YAC9B,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI;gBAAE,SAAS;YAEpC,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,IAAI,YAAY,CAAC;YAE9C,IAAI,mBAAmB,CAAC,GAAG,CAAC,IAAI,EAAE,QAAQ,CAAC,EAAE,CAAC;gBAC5C,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;gBACxB,SAAS;YACX,CAAC;YAED,IAAI,CAAC;gBACH,iEAAiE;gBACjE,IAAI,MAAc,CAAC;gBACnB,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC;oBACb,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC;gBACpB,CAAC;qBAAM,CAAC;oBACN,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,GAAI,CAAC,CAAC;oBACnC,IAAI,CAAC,IAAI,CAAC,EAAE;wBAAE,SAAS;oBACvB,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;gBACjD,CAAC;gBAED,IAAI,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;oBAClC,MAAM,CAAC,IAAI,CAAC;wBACV,MAAM,EAAE,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC;wBACjC,SAAS,EAAE,GAAG,CAAC,IAAI;qBACpB,CAAC,CAAC;gBACL,CAAC;qBAAM,CAAC;oBACN,IAAI,CAAC,UAAU,EAAE,CAAC;wBAChB,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;wBACtC,UAAU,GAAG,IAAI,CAAC;oBACpB,CAAC;oBACD,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;oBACrC,MAAM,SAAS,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;oBAClC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;gBAC3B,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,wBAAwB;YAC1B,CAAC;QACH,CAAC;QAED,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;IAC9C,CAAC;CACF;AAED,6EAA6E;AAE7E,iDAAiD;AACjD,MAAM,qBAAqB,GAAG;IAC5B,0BAA0B;IAC1B,6BAA6B;IAC7B,0BAA0B;IAC1B,yBAAyB;IACzB,uBAAuB;IACvB,+CAA+C;CAChD,CAAC;AAEF,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAAC;IACjC,kBAAkB;IAClB,mBAAmB;IACnB,mBAAmB;IACnB,mBAAmB;IACnB,0BAA0B;IAC1B,8BAA8B;IAC9B,6BAA6B;IAC7B,mBAAmB;IACnB,kBAAkB;IAClB,iBAAiB;IACjB,qBAAqB;IACrB,kBAAkB;IAClB,6BAA6B;IAC7B,+BAA+B;IAC/B,uCAAuC;IACvC,mBAAmB;CACpB,CAAC,CAAC;AAEH,4EAA4E;AAC5E,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAAC;IACjC,wBAAwB;IACxB,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IACtD,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IACtC,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IACxD,sBAAsB;IACtB,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;IACrD,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAChC,WAAW;IACX,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK;IACnD,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAC9B,WAAW;IACX,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU;IAC3C,MAAM,EAAE,MAAM,EAAE,QAAQ;CACzB,CAAC,CAAC;AAEH,yDAAyD;AACzD,MAAM,UAAU,mBAAmB,CAAC,QAAgB,EAAE,QAAgB;IACpE,MAAM,IAAI,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;IAEpC,IAAI,kBAAkB,CAAC,GAAG,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAC9C,IAAI,qBAAqB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAEvE,MAAM,GAAG,GAAG,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC;QACxC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE;QACzD,CAAC,CAAC,EAAE,CAAC;IACP,IAAI,GAAG,IAAI,kBAAkB,CAAC,GAAG,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAEpD,OAAO,KAAK,CAAC;AACf,CAAC"}
package/dist/spawner.d.ts CHANGED
@@ -1,11 +1,28 @@
1
1
  export interface SpawnResult {
2
2
  response: string;
3
+ stderr: string;
3
4
  exitCode: number;
4
5
  tokensEstimate: {
5
6
  in: number;
6
7
  out: number;
7
8
  };
8
9
  }
10
+ export interface ImageInput {
11
+ base64: string;
12
+ mediaType: string;
13
+ }
14
+ export interface AsyncSpawnOptions {
15
+ workspace: string;
16
+ message: string;
17
+ systemPrompt: string;
18
+ model: string;
19
+ ccgHome: string;
20
+ agentId: string;
21
+ }
22
+ export interface AsyncSpawnResult {
23
+ sessionName: string;
24
+ taskDir: string;
25
+ }
9
26
  export interface SpawnOptions {
10
27
  workspace: string;
11
28
  message: string;
@@ -13,17 +30,39 @@ export interface SpawnOptions {
13
30
  model: string;
14
31
  allowedTools: string[];
15
32
  timeoutMs?: number;
33
+ /** When provided, switches to --input-format stream-json so images are
34
+ * sent as content blocks directly (no Read-tool round-trip). */
35
+ images?: ImageInput[];
16
36
  }
17
37
  export declare class CCSpawner {
38
+ private static readonly TRIAGE_TIMEOUT_MS;
39
+ private static readonly TRIAGE_PROMPT;
18
40
  /**
19
- * Spawn a `claude --print` invocation.
41
+ * Run a quick `claude --print` with Sonnet to classify a message as
42
+ * "sync" (quick task) or "async" (intensive, long-running).
20
43
  *
21
- * Executes:
22
- * claude --print -p "<message>" --append-system-prompt "<context>"
23
- * --model <model> --allowedTools Tool1,Tool2,...
44
+ * Defaults to "sync" on timeout, unexpected output, or errors.
45
+ */
46
+ triage(message: string, _model: string): Promise<"sync" | "async">;
47
+ /**
48
+ * Spawn a `claude --print` invocation.
24
49
  *
25
- * Captures stdout as the response. Estimates tokens as chars / 4.
50
+ * When `images` are provided, uses `--input-format stream-json` to pass
51
+ * image content blocks directly via stdin (avoids the Read-tool
52
+ * round-trip). Otherwise falls back to the simpler `-p "<message>"` form
53
+ * with stdin closed.
26
54
  */
27
55
  spawn(options: SpawnOptions): Promise<SpawnResult>;
56
+ private detectMultiplexer;
57
+ spawnAsync(options: AsyncSpawnOptions): Promise<AsyncSpawnResult>;
58
+ private spawnText;
59
+ private spawnStreamJson;
28
60
  }
61
+ /**
62
+ * Extract the assistant's text response from stream-json JSONL output.
63
+ *
64
+ * Looks for a `{"type":"result","result":"..."}` event first (final output),
65
+ * then falls back to collecting text from assistant message content blocks.
66
+ */
67
+ export declare function parseStreamOutput(stdout: string): string;
29
68
  //# sourceMappingURL=spawner.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"spawner.d.ts","sourceRoot":"","sources":["../src/spawner.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;CAC7C;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAMD,qBAAa,SAAS;IACpB;;;;;;;;OAQG;IACG,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC;CAwDzD"}
1
+ {"version":3,"file":"spawner.d.ts","sourceRoot":"","sources":["../src/spawner.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;CAC7C;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;qEACiE;IACjE,MAAM,CAAC,EAAE,UAAU,EAAE,CAAC;CACvB;AAOD,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,iBAAiB,CAAU;IACnD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAIxB;IAEb;;;;;OAKG;IACG,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,OAAO,CAAC;IA8CxE;;;;;;;OAOG;IACG,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC;IAOxD,OAAO,CAAC,iBAAiB;IAoBnB,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAiCvE,OAAO,CAAC,SAAS;IAkFjB,OAAO,CAAC,eAAe;CAmHxB;AAID;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAyCxD"}