cyrus-edge-worker 0.2.1 → 0.2.3

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.
@@ -1,17 +1,16 @@
1
- import { type LinearClient } from "@linear/sdk";
2
1
  import type { ClaudeRunner, SDKMessage, SDKResultMessage, SDKSystemMessage } from "cyrus-claude-runner";
3
- import type { CyrusAgentSession, CyrusAgentSessionEntry, IssueMinimal, SerializedCyrusAgentSession, SerializedCyrusAgentSessionEntry, Workspace } from "cyrus-core";
2
+ import { type CyrusAgentSession, type CyrusAgentSessionEntry, type IIssueTrackerService, type IssueMinimal, type SerializedCyrusAgentSession, type SerializedCyrusAgentSessionEntry, type Workspace } from "cyrus-core";
4
3
  import type { ProcedureRouter } from "./procedures/ProcedureRouter.js";
5
4
  import type { SharedApplicationServer } from "./SharedApplicationServer.js";
6
5
  /**
7
- * Manages Linear Agent Sessions integration with Claude Code SDK
6
+ * Manages Agent Sessions integration with Claude Code SDK
8
7
  * Transforms Claude streaming messages into Agent Session format
9
8
  * Handles session lifecycle: create → active → complete/error
10
9
  *
11
10
  * CURRENTLY BEING HANDLED 'per repository'
12
11
  */
13
12
  export declare class AgentSessionManager {
14
- private linearClient;
13
+ private issueTracker;
15
14
  private sessions;
16
15
  private entries;
17
16
  private activeTasksBySession;
@@ -22,7 +21,7 @@ export declare class AgentSessionManager {
22
21
  private getParentSessionId?;
23
22
  private resumeParentSession?;
24
23
  private resumeNextSubroutine?;
25
- constructor(linearClient: LinearClient, getParentSessionId?: (childSessionId: string) => string | undefined, resumeParentSession?: (parentSessionId: string, prompt: string, childSessionId: string) => Promise<void>, resumeNextSubroutine?: (linearAgentActivitySessionId: string) => Promise<void>, procedureRouter?: ProcedureRouter, sharedApplicationServer?: SharedApplicationServer);
24
+ constructor(issueTracker: IIssueTrackerService, getParentSessionId?: (childSessionId: string) => string | undefined, resumeParentSession?: (parentSessionId: string, prompt: string, childSessionId: string) => Promise<void>, resumeNextSubroutine?: (linearAgentActivitySessionId: string) => Promise<void>, procedureRouter?: ProcedureRouter, sharedApplicationServer?: SharedApplicationServer);
26
25
  /**
27
26
  * Initialize a Linear agent session from webhook
28
27
  * The session is already created by Linear, we just need to track it
@@ -40,6 +39,21 @@ export declare class AgentSessionManager {
40
39
  * Format TodoWrite tool parameter as a nice checklist
41
40
  */
42
41
  private formatTodoWriteParameter;
42
+ /**
43
+ * Format tool input for display in Linear agent activities
44
+ * Converts raw tool inputs into user-friendly parameter strings
45
+ */
46
+ private formatToolParameter;
47
+ /**
48
+ * Format tool action name with description for Bash tool
49
+ * Puts the description in round brackets after the tool name in the action field
50
+ */
51
+ private formatToolActionName;
52
+ /**
53
+ * Format tool result for display in Linear agent activities
54
+ * Converts raw tool results into formatted Markdown
55
+ */
56
+ private formatToolResult;
43
57
  /**
44
58
  * Complete a session from Claude result message
45
59
  */
@@ -1 +1 @@
1
- {"version":3,"file":"AgentSessionManager.d.ts","sourceRoot":"","sources":["../src/AgentSessionManager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"AgentSessionManager.d.ts","sourceRoot":"","sources":["../src/AgentSessionManager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAGX,YAAY,EAEZ,UAAU,EACV,gBAAgB,EAEhB,gBAAgB,EAEhB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAKN,KAAK,iBAAiB,EACtB,KAAK,sBAAsB,EAC3B,KAAK,oBAAoB,EACzB,KAAK,YAAY,EACjB,KAAK,2BAA2B,EAChC,KAAK,gCAAgC,EACrC,KAAK,SAAS,EACd,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AACvE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAE5E;;;;;;GAMG;AACH,qBAAa,mBAAmB;IAC/B,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,QAAQ,CAA6C;IAC7D,OAAO,CAAC,OAAO,CAAoD;IACnE,OAAO,CAAC,oBAAoB,CAAkC;IAC9D,OAAO,CAAC,oBAAoB,CACjB;IACX,OAAO,CAAC,+BAA+B,CAAkC;IACzE,OAAO,CAAC,eAAe,CAAC,CAAkB;IAC1C,OAAO,CAAC,uBAAuB,CAAC,CAA0B;IAC1D,OAAO,CAAC,kBAAkB,CAAC,CAAiD;IAC5E,OAAO,CAAC,mBAAmB,CAAC,CAIT;IACnB,OAAO,CAAC,oBAAoB,CAAC,CAEV;gBAGlB,YAAY,EAAE,oBAAoB,EAClC,kBAAkB,CAAC,EAAE,CAAC,cAAc,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,EACnE,mBAAmB,CAAC,EAAE,CACrB,eAAe,EAAE,MAAM,EACvB,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,MAAM,KAClB,OAAO,CAAC,IAAI,CAAC,EAClB,oBAAoB,CAAC,EAAE,CACtB,4BAA4B,EAAE,MAAM,KAChC,OAAO,CAAC,IAAI,CAAC,EAClB,eAAe,CAAC,EAAE,eAAe,EACjC,uBAAuB,CAAC,EAAE,uBAAuB;IAUlD;;;OAGG;IACH,wBAAwB,CACvB,4BAA4B,EAAE,MAAM,EACpC,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,YAAY,EAC1B,SAAS,EAAE,SAAS,GAClB,iBAAiB;IAwBpB;;OAEG;IACH,qCAAqC,CACpC,4BAA4B,EAAE,MAAM,EACpC,mBAAmB,EAAE,gBAAgB,GACnC,IAAI;IAmBP;;OAEG;YACW,kBAAkB;IAoChC;;OAEG;IACH,OAAO,CAAC,wBAAwB;IA2ChC;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAyI3B;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAuB5B;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IAqMxB;;OAEG;IACG,eAAe,CACpB,4BAA4B,EAAE,MAAM,EACpC,aAAa,EAAE,gBAAgB,GAC7B,OAAO,CAAC,IAAI,CAAC;IAqChB;;OAEG;YACW,yBAAyB;IA+KvC;;OAEG;YACW,4BAA4B;IA+C1C;;OAEG;IACG,mBAAmB,CACxB,4BAA4B,EAAE,MAAM,EACpC,OAAO,EAAE,UAAU,GACjB,OAAO,CAAC,IAAI,CAAC;IAsEhB;;OAEG;YACW,mBAAmB;IAkBjC;;OAEG;YACW,cAAc;IAoB5B;;OAEG;IACH,OAAO,CAAC,cAAc;IA8CtB;;OAEG;IACH,OAAO,CAAC,eAAe;IAyBvB;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAmB7B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAYzB;;OAEG;YACW,iBAAiB;IAiQ/B;;OAEG;IACH,UAAU,CACT,4BAA4B,EAAE,MAAM,GAClC,iBAAiB,GAAG,SAAS;IAIhC;;OAEG;IACH,iBAAiB,CAChB,4BAA4B,EAAE,MAAM,GAClC,sBAAsB,EAAE;IAI3B;;OAEG;IACH,iBAAiB,IAAI,iBAAiB,EAAE;IAMxC;;OAEG;IACH,eAAe,CACd,4BAA4B,EAAE,MAAM,EACpC,YAAY,EAAE,YAAY,GACxB,IAAI;IAgBP;;OAEG;IACH,mBAAmB,IAAI,YAAY,EAAE;IAMrC;;OAEG;IACH,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY,EAAE;IAOzD;;OAEG;IACH,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,iBAAiB,EAAE;IAM1D;;OAEG;IACH,0BAA0B,CAAC,OAAO,EAAE,MAAM,GAAG,iBAAiB,EAAE;IAQhE;;OAEG;IACH,cAAc,IAAI,iBAAiB,EAAE;IAIrC;;OAEG;IACH,eAAe,CACd,4BAA4B,EAAE,MAAM,GAClC,YAAY,GAAG,SAAS;IAK3B;;OAEG;IACH,eAAe,CAAC,4BAA4B,EAAE,MAAM,GAAG,OAAO;IAK9D;;OAEG;IACG,qBAAqB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAoC3E;;OAEG;IACG,oBAAoB,CACzB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC;IA2ChB;;OAEG;IACG,sBAAsB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAoC5E;;OAEG;IACG,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAoCzE;;OAEG;IACG,yBAAyB,CAC9B,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,GACV,OAAO,CAAC,IAAI,CAAC;IAoChB;;OAEG;IACG,yBAAyB,CAC9B,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC;IAwChB;;OAEG;IACH,OAAO,CAAC,WAAW,GAAE,MAA4B,GAAG,IAAI;IAexD;;OAEG;IACH,cAAc,IAAI;QACjB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,2BAA2B,CAAC,CAAC;QACtD,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,gCAAgC,EAAE,CAAC,CAAC;KAC5D;IAqBD;;OAEG;IACH,YAAY,CACX,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,2BAA2B,CAAC,EAC/D,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,gCAAgC,EAAE,CAAC,GACnE,IAAI;IA4BP;;OAEG;YACW,4BAA4B;IA+B1C;;OAEG;IACG,kBAAkB,CACvB,4BAA4B,EAAE,MAAM,GAClC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAiCzB;;OAEG;IACG,6BAA6B,CAClC,4BAA4B,EAAE,MAAM,EACpC,aAAa,EAAE,MAAM,EACrB,cAAc,EAAE,MAAM,GACpB,OAAO,CAAC,IAAI,CAAC;IA6BhB;;OAEG;YACW,mBAAmB;CAyEjC"}
@@ -1,13 +1,13 @@
1
- import { LinearDocument } from "@linear/sdk";
1
+ import { AgentActivitySignal, AgentSessionStatus, AgentSessionType, } from "cyrus-core";
2
2
  /**
3
- * Manages Linear Agent Sessions integration with Claude Code SDK
3
+ * Manages Agent Sessions integration with Claude Code SDK
4
4
  * Transforms Claude streaming messages into Agent Session format
5
5
  * Handles session lifecycle: create → active → complete/error
6
6
  *
7
7
  * CURRENTLY BEING HANDLED 'per repository'
8
8
  */
9
9
  export class AgentSessionManager {
10
- linearClient;
10
+ issueTracker;
11
11
  sessions = new Map();
12
12
  entries = new Map(); // Stores a list of session entries per each session by its linearAgentActivitySessionId
13
13
  activeTasksBySession = new Map(); // Maps session ID to active Task tool use ID
@@ -18,8 +18,8 @@ export class AgentSessionManager {
18
18
  getParentSessionId;
19
19
  resumeParentSession;
20
20
  resumeNextSubroutine;
21
- constructor(linearClient, getParentSessionId, resumeParentSession, resumeNextSubroutine, procedureRouter, sharedApplicationServer) {
22
- this.linearClient = linearClient;
21
+ constructor(issueTracker, getParentSessionId, resumeParentSession, resumeNextSubroutine, procedureRouter, sharedApplicationServer) {
22
+ this.issueTracker = issueTracker;
23
23
  this.getParentSessionId = getParentSessionId;
24
24
  this.resumeParentSession = resumeParentSession;
25
25
  this.resumeNextSubroutine = resumeNextSubroutine;
@@ -34,9 +34,9 @@ export class AgentSessionManager {
34
34
  console.log(`[AgentSessionManager] Tracking Linear session ${linearAgentActivitySessionId} for issue ${issueId}`);
35
35
  const agentSession = {
36
36
  linearAgentActivitySessionId,
37
- type: LinearDocument.AgentSessionType.CommentThread,
38
- status: LinearDocument.AgentSessionStatus.Active,
39
- context: LinearDocument.AgentSessionType.CommentThread,
37
+ type: AgentSessionType.CommentThread,
38
+ status: AgentSessionStatus.Active,
39
+ context: AgentSessionType.CommentThread,
40
40
  createdAt: Date.now(),
41
41
  updatedAt: Date.now(),
42
42
  issueId,
@@ -133,6 +133,319 @@ export class AgentSessionManager {
133
133
  return jsonContent;
134
134
  }
135
135
  }
136
+ /**
137
+ * Format tool input for display in Linear agent activities
138
+ * Converts raw tool inputs into user-friendly parameter strings
139
+ */
140
+ formatToolParameter(toolName, toolInput) {
141
+ // If input is already a string, return it
142
+ if (typeof toolInput === "string") {
143
+ return toolInput;
144
+ }
145
+ try {
146
+ switch (toolName) {
147
+ case "Bash":
148
+ case "↪ Bash": {
149
+ // Show command only - description goes in action field via formatToolActionName
150
+ return toolInput.command || JSON.stringify(toolInput);
151
+ }
152
+ case "Read":
153
+ case "↪ Read":
154
+ if (toolInput.file_path) {
155
+ let param = toolInput.file_path;
156
+ if (toolInput.offset !== undefined ||
157
+ toolInput.limit !== undefined) {
158
+ const start = toolInput.offset || 0;
159
+ const end = toolInput.limit ? start + toolInput.limit : "end";
160
+ param += ` (lines ${start + 1}-${end})`;
161
+ }
162
+ return param;
163
+ }
164
+ break;
165
+ case "Edit":
166
+ case "↪ Edit":
167
+ if (toolInput.file_path) {
168
+ return toolInput.file_path;
169
+ }
170
+ break;
171
+ case "Write":
172
+ case "↪ Write":
173
+ if (toolInput.file_path) {
174
+ return toolInput.file_path;
175
+ }
176
+ break;
177
+ case "Grep":
178
+ case "↪ Grep":
179
+ if (toolInput.pattern) {
180
+ let param = `Pattern: \`${toolInput.pattern}\``;
181
+ if (toolInput.path) {
182
+ param += ` in ${toolInput.path}`;
183
+ }
184
+ if (toolInput.glob) {
185
+ param += ` (${toolInput.glob})`;
186
+ }
187
+ if (toolInput.type) {
188
+ param += ` [${toolInput.type} files]`;
189
+ }
190
+ return param;
191
+ }
192
+ break;
193
+ case "Glob":
194
+ case "↪ Glob":
195
+ if (toolInput.pattern) {
196
+ let param = `Pattern: \`${toolInput.pattern}\``;
197
+ if (toolInput.path) {
198
+ param += ` in ${toolInput.path}`;
199
+ }
200
+ return param;
201
+ }
202
+ break;
203
+ case "Task":
204
+ case "↪ Task":
205
+ if (toolInput.description) {
206
+ return toolInput.description;
207
+ }
208
+ break;
209
+ case "WebFetch":
210
+ case "↪ WebFetch":
211
+ if (toolInput.url) {
212
+ return toolInput.url;
213
+ }
214
+ break;
215
+ case "WebSearch":
216
+ case "↪ WebSearch":
217
+ if (toolInput.query) {
218
+ return `Query: ${toolInput.query}`;
219
+ }
220
+ break;
221
+ case "NotebookEdit":
222
+ case "↪ NotebookEdit":
223
+ if (toolInput.notebook_path) {
224
+ let param = toolInput.notebook_path;
225
+ if (toolInput.cell_id) {
226
+ param += ` (cell ${toolInput.cell_id})`;
227
+ }
228
+ return param;
229
+ }
230
+ break;
231
+ default:
232
+ // For MCP tools or other unknown tools, try to extract meaningful info
233
+ if (toolName.startsWith("mcp__")) {
234
+ // Extract key fields that are commonly meaningful
235
+ const meaningfulFields = [
236
+ "query",
237
+ "id",
238
+ "issueId",
239
+ "title",
240
+ "name",
241
+ "path",
242
+ "file",
243
+ ];
244
+ for (const field of meaningfulFields) {
245
+ if (toolInput[field]) {
246
+ return `${field}: ${toolInput[field]}`;
247
+ }
248
+ }
249
+ }
250
+ break;
251
+ }
252
+ // Fallback to JSON but make it compact
253
+ return JSON.stringify(toolInput);
254
+ }
255
+ catch (error) {
256
+ console.error("[AgentSessionManager] Failed to format tool parameter:", error);
257
+ return JSON.stringify(toolInput);
258
+ }
259
+ }
260
+ /**
261
+ * Format tool action name with description for Bash tool
262
+ * Puts the description in round brackets after the tool name in the action field
263
+ */
264
+ formatToolActionName(toolName, toolInput, isError) {
265
+ // Handle Bash tool with description
266
+ if (toolName === "Bash" || toolName === "↪ Bash") {
267
+ // Check if toolInput has a description field
268
+ if (toolInput &&
269
+ typeof toolInput === "object" &&
270
+ "description" in toolInput &&
271
+ toolInput.description) {
272
+ const baseName = isError ? `${toolName} (Error)` : toolName;
273
+ return `${baseName} (${toolInput.description})`;
274
+ }
275
+ }
276
+ // Default formatting for other tools or Bash without description
277
+ return isError ? `${toolName} (Error)` : toolName;
278
+ }
279
+ /**
280
+ * Format tool result for display in Linear agent activities
281
+ * Converts raw tool results into formatted Markdown
282
+ */
283
+ formatToolResult(toolName, toolInput, result, isError) {
284
+ // If there's an error, wrap in error formatting
285
+ if (isError) {
286
+ return `\`\`\`\n${result}\n\`\`\``;
287
+ }
288
+ try {
289
+ switch (toolName) {
290
+ case "Bash":
291
+ case "↪ Bash": {
292
+ // Show command first if not already in parameter
293
+ let formatted = "";
294
+ if (toolInput.command && !toolInput.description) {
295
+ formatted += `\`\`\`bash\n${toolInput.command}\n\`\`\`\n\n`;
296
+ }
297
+ // Then show output
298
+ if (result?.trim()) {
299
+ formatted += `\`\`\`\n${result}\n\`\`\``;
300
+ }
301
+ else {
302
+ formatted += "*No output*";
303
+ }
304
+ return formatted;
305
+ }
306
+ case "Read":
307
+ case "↪ Read":
308
+ // For Read, the result is file content - use code block
309
+ if (result?.trim()) {
310
+ // Clean up the result: remove line numbers and system-reminder tags
311
+ let cleanedResult = result;
312
+ // Remove line numbers (format: " 123→")
313
+ cleanedResult = cleanedResult.replace(/^\s*\d+→/gm, "");
314
+ // Remove system-reminder blocks
315
+ cleanedResult = cleanedResult.replace(/<system-reminder>[\s\S]*?<\/system-reminder>/g, "");
316
+ // Trim only blank lines (not horizontal whitespace) to preserve indentation
317
+ cleanedResult = cleanedResult
318
+ .replace(/^\n+/, "")
319
+ .replace(/\n+$/, "");
320
+ // Try to detect language from file extension
321
+ let lang = "";
322
+ if (toolInput.file_path) {
323
+ const ext = toolInput.file_path.split(".").pop()?.toLowerCase();
324
+ const langMap = {
325
+ ts: "typescript",
326
+ tsx: "typescript",
327
+ js: "javascript",
328
+ jsx: "javascript",
329
+ py: "python",
330
+ rb: "ruby",
331
+ go: "go",
332
+ rs: "rust",
333
+ java: "java",
334
+ c: "c",
335
+ cpp: "cpp",
336
+ cs: "csharp",
337
+ php: "php",
338
+ swift: "swift",
339
+ kt: "kotlin",
340
+ scala: "scala",
341
+ sh: "bash",
342
+ bash: "bash",
343
+ zsh: "bash",
344
+ yml: "yaml",
345
+ yaml: "yaml",
346
+ json: "json",
347
+ xml: "xml",
348
+ html: "html",
349
+ css: "css",
350
+ scss: "scss",
351
+ md: "markdown",
352
+ sql: "sql",
353
+ };
354
+ lang = langMap[ext || ""] || "";
355
+ }
356
+ return `\`\`\`${lang}\n${cleanedResult}\n\`\`\``;
357
+ }
358
+ return "*Empty file*";
359
+ case "Edit":
360
+ case "↪ Edit": {
361
+ // For Edit, show changes as a diff
362
+ // Extract old_string and new_string from toolInput
363
+ if (toolInput.old_string && toolInput.new_string) {
364
+ // Format as a unified diff
365
+ const oldLines = toolInput.old_string.split("\n");
366
+ const newLines = toolInput.new_string.split("\n");
367
+ let diff = "```diff\n";
368
+ // Add context lines before changes (show all old lines with - prefix)
369
+ for (const line of oldLines) {
370
+ diff += `-${line}\n`;
371
+ }
372
+ // Add new lines with + prefix
373
+ for (const line of newLines) {
374
+ diff += `+${line}\n`;
375
+ }
376
+ diff += "```";
377
+ return diff;
378
+ }
379
+ // Fallback to result if old/new strings not available
380
+ if (result?.trim()) {
381
+ return result;
382
+ }
383
+ return "*Edit completed*";
384
+ }
385
+ case "Write":
386
+ case "↪ Write":
387
+ // For Write, just confirm
388
+ if (result?.trim()) {
389
+ return result; // In case there's an error or message
390
+ }
391
+ return "*File written successfully*";
392
+ case "Grep":
393
+ case "↪ Grep": {
394
+ // Format grep results
395
+ if (result?.trim()) {
396
+ const lines = result.split("\n");
397
+ // If it looks like file paths (files_with_matches mode)
398
+ if (lines.length > 0 &&
399
+ lines[0] &&
400
+ !lines[0].includes(":") &&
401
+ lines[0].trim().length > 0) {
402
+ return `Found ${lines.filter((l) => l.trim()).length} matching files:\n\`\`\`\n${result}\n\`\`\``;
403
+ }
404
+ // Otherwise it's content matches
405
+ return `\`\`\`\n${result}\n\`\`\``;
406
+ }
407
+ return "*No matches found*";
408
+ }
409
+ case "Glob":
410
+ case "↪ Glob": {
411
+ if (result?.trim()) {
412
+ const lines = result.split("\n").filter((l) => l.trim());
413
+ return `Found ${lines.length} matching files:\n\`\`\`\n${result}\n\`\`\``;
414
+ }
415
+ return "*No files found*";
416
+ }
417
+ case "Task":
418
+ case "↪ Task":
419
+ // Task results can be complex - keep as is but in code block if multiline
420
+ if (result?.trim()) {
421
+ if (result.includes("\n")) {
422
+ return `\`\`\`\n${result}\n\`\`\``;
423
+ }
424
+ return result;
425
+ }
426
+ return "*Task completed*";
427
+ case "WebFetch":
428
+ case "↪ WebFetch":
429
+ case "WebSearch":
430
+ case "↪ WebSearch":
431
+ // Web results are usually formatted, keep as is
432
+ return result || "*No results*";
433
+ default:
434
+ // For unknown tools, use code block if result has multiple lines
435
+ if (result?.trim()) {
436
+ if (result.includes("\n") && result.length > 100) {
437
+ return `\`\`\`\n${result}\n\`\`\``;
438
+ }
439
+ return result;
440
+ }
441
+ return "*Completed*";
442
+ }
443
+ }
444
+ catch (error) {
445
+ console.error("[AgentSessionManager] Failed to format tool result:", error);
446
+ return result || "";
447
+ }
448
+ }
136
449
  /**
137
450
  * Complete a session from Claude result message
138
451
  */
@@ -148,8 +461,8 @@ export class AgentSessionManager {
148
461
  // Note: We should ideally track by session, but for now clearing all is safer
149
462
  // to prevent memory leaks
150
463
  const status = resultMessage.subtype === "success"
151
- ? LinearDocument.AgentSessionStatus.Complete
152
- : LinearDocument.AgentSessionStatus.Error;
464
+ ? AgentSessionStatus.Complete
465
+ : AgentSessionStatus.Error;
153
466
  // Update session status and metadata
154
467
  await this.updateSessionStatus(linearAgentActivitySessionId, status, {
155
468
  totalCostUsd: resultMessage.total_cost_usd,
@@ -322,7 +635,7 @@ export class AgentSessionManager {
322
635
  catch (error) {
323
636
  console.error(`[AgentSessionManager] Error handling message:`, error);
324
637
  // Mark session as error state
325
- await this.updateSessionStatus(linearAgentActivitySessionId, LinearDocument.AgentSessionStatus.Error);
638
+ await this.updateSessionStatus(linearAgentActivitySessionId, AgentSessionStatus.Error);
326
639
  }
327
640
  }
328
641
  /**
@@ -491,17 +804,16 @@ export class AgentSessionManager {
491
804
  if (toolName === "TodoWrite" || toolName === "↪ TodoWrite") {
492
805
  return;
493
806
  }
494
- // Format input for display
495
- const formattedInput = typeof toolInput === "string"
496
- ? toolInput
497
- : JSON.stringify(toolInput, null, 2);
498
- // Use tool output directly without collapsible wrapping
499
- const wrappedResult = toolResult.content?.trim() || "";
807
+ // Format parameter and result using our formatters
808
+ const formattedParameter = this.formatToolParameter(toolName, toolInput);
809
+ const formattedResult = this.formatToolResult(toolName, toolInput, toolResult.content?.trim() || "", toolResult.isError);
810
+ // Format the action name (with description for Bash tool)
811
+ const formattedAction = this.formatToolActionName(toolName, toolInput, toolResult.isError);
500
812
  content = {
501
813
  type: "action",
502
- action: toolResult.isError ? `${toolName} (Error)` : toolName,
503
- parameter: formattedInput,
504
- result: wrappedResult,
814
+ action: formattedAction,
815
+ parameter: formattedParameter,
816
+ result: formattedResult,
505
817
  };
506
818
  }
507
819
  else {
@@ -544,7 +856,8 @@ export class AgentSessionManager {
544
856
  }
545
857
  else if (toolName === "Task") {
546
858
  // Special handling for Task tool - add start marker and track active task
547
- const parameter = entry.content;
859
+ const toolInput = entry.metadata.toolInput || entry.content;
860
+ const formattedParameter = this.formatToolParameter(toolName, toolInput);
548
861
  const displayName = toolName;
549
862
  // Track this as the active Task for this session
550
863
  if (entry.metadata?.toolUseId) {
@@ -553,7 +866,7 @@ export class AgentSessionManager {
553
866
  content = {
554
867
  type: "action",
555
868
  action: displayName,
556
- parameter: parameter,
869
+ parameter: formattedParameter,
557
870
  // result will be added later when we get tool result
558
871
  };
559
872
  // Task is not ephemeral
@@ -561,7 +874,7 @@ export class AgentSessionManager {
561
874
  }
562
875
  else {
563
876
  // Other tools - check if they're within an active Task
564
- const parameter = entry.content;
877
+ const toolInput = entry.metadata.toolInput || entry.content;
565
878
  let displayName = toolName;
566
879
  if (entry.metadata?.parentToolUseId) {
567
880
  const activeTaskId = this.activeTasksBySession.get(linearAgentActivitySessionId);
@@ -569,10 +882,11 @@ export class AgentSessionManager {
569
882
  displayName = `↪ ${toolName}`;
570
883
  }
571
884
  }
885
+ const formattedParameter = this.formatToolParameter(displayName, toolInput);
572
886
  content = {
573
887
  type: "action",
574
888
  action: displayName,
575
- parameter: parameter,
889
+ parameter: formattedParameter,
576
890
  // result will be added later when we get tool result
577
891
  };
578
892
  // Standard tool calls are ephemeral
@@ -632,7 +946,7 @@ export class AgentSessionManager {
632
946
  content,
633
947
  ...(ephemeral && { ephemeral: true }),
634
948
  };
635
- const result = await this.linearClient.createAgentActivity(activityInput);
949
+ const result = await this.issueTracker.createAgentActivity(activityInput);
636
950
  if (result.success && result.agentActivity) {
637
951
  const agentActivity = await result.agentActivity;
638
952
  entry.linearAgentActivityId = agentActivity.id;
@@ -662,7 +976,7 @@ export class AgentSessionManager {
662
976
  * Get all active sessions
663
977
  */
664
978
  getActiveSessions() {
665
- return Array.from(this.sessions.values()).filter((session) => session.status === LinearDocument.AgentSessionStatus.Active);
979
+ return Array.from(this.sessions.values()).filter((session) => session.status === AgentSessionStatus.Active);
666
980
  }
667
981
  /**
668
982
  * Add or update ClaudeRunner for a session
@@ -705,7 +1019,7 @@ export class AgentSessionManager {
705
1019
  */
706
1020
  getActiveSessionsByIssueId(issueId) {
707
1021
  return Array.from(this.sessions.values()).filter((session) => session.issueId === issueId &&
708
- session.status === LinearDocument.AgentSessionStatus.Active);
1022
+ session.status === AgentSessionStatus.Active);
709
1023
  }
710
1024
  /**
711
1025
  * Get all sessions
@@ -737,7 +1051,7 @@ export class AgentSessionManager {
737
1051
  return;
738
1052
  }
739
1053
  try {
740
- const result = await this.linearClient.createAgentActivity({
1054
+ const result = await this.issueTracker.createAgentActivity({
741
1055
  agentSessionId: session.linearAgentActivitySessionId,
742
1056
  content: {
743
1057
  type: "thought",
@@ -773,7 +1087,7 @@ export class AgentSessionManager {
773
1087
  if (result !== undefined) {
774
1088
  content.result = result;
775
1089
  }
776
- const response = await this.linearClient.createAgentActivity({
1090
+ const response = await this.issueTracker.createAgentActivity({
777
1091
  agentSessionId: session.linearAgentActivitySessionId,
778
1092
  content,
779
1093
  });
@@ -798,7 +1112,7 @@ export class AgentSessionManager {
798
1112
  return;
799
1113
  }
800
1114
  try {
801
- const result = await this.linearClient.createAgentActivity({
1115
+ const result = await this.issueTracker.createAgentActivity({
802
1116
  agentSessionId: session.linearAgentActivitySessionId,
803
1117
  content: {
804
1118
  type: "response",
@@ -826,7 +1140,7 @@ export class AgentSessionManager {
826
1140
  return;
827
1141
  }
828
1142
  try {
829
- const result = await this.linearClient.createAgentActivity({
1143
+ const result = await this.issueTracker.createAgentActivity({
830
1144
  agentSessionId: session.linearAgentActivitySessionId,
831
1145
  content: {
832
1146
  type: "error",
@@ -854,7 +1168,7 @@ export class AgentSessionManager {
854
1168
  return;
855
1169
  }
856
1170
  try {
857
- const result = await this.linearClient.createAgentActivity({
1171
+ const result = await this.issueTracker.createAgentActivity({
858
1172
  agentSessionId: session.linearAgentActivitySessionId,
859
1173
  content: {
860
1174
  type: "elicitation",
@@ -882,13 +1196,13 @@ export class AgentSessionManager {
882
1196
  return;
883
1197
  }
884
1198
  try {
885
- const result = await this.linearClient.createAgentActivity({
1199
+ const result = await this.issueTracker.createAgentActivity({
886
1200
  agentSessionId: session.linearAgentActivitySessionId,
887
1201
  content: {
888
1202
  type: "elicitation",
889
1203
  body,
890
1204
  },
891
- signal: LinearDocument.AgentActivitySignal.Auth,
1205
+ signal: AgentActivitySignal.Auth,
892
1206
  signalMetadata: {
893
1207
  url: approvalUrl,
894
1208
  },
@@ -966,7 +1280,7 @@ export class AgentSessionManager {
966
1280
  */
967
1281
  async postModelNotificationThought(linearAgentActivitySessionId, model) {
968
1282
  try {
969
- const result = await this.linearClient.createAgentActivity({
1283
+ const result = await this.issueTracker.createAgentActivity({
970
1284
  agentSessionId: linearAgentActivitySessionId,
971
1285
  content: {
972
1286
  type: "thought",
@@ -989,7 +1303,7 @@ export class AgentSessionManager {
989
1303
  */
990
1304
  async postRoutingThought(linearAgentActivitySessionId) {
991
1305
  try {
992
- const result = await this.linearClient.createAgentActivity({
1306
+ const result = await this.issueTracker.createAgentActivity({
993
1307
  agentSessionId: linearAgentActivitySessionId,
994
1308
  content: {
995
1309
  type: "thought",
@@ -1017,7 +1331,7 @@ export class AgentSessionManager {
1017
1331
  */
1018
1332
  async postProcedureSelectionThought(linearAgentActivitySessionId, procedureName, classification) {
1019
1333
  try {
1020
- const result = await this.linearClient.createAgentActivity({
1334
+ const result = await this.issueTracker.createAgentActivity({
1021
1335
  agentSessionId: linearAgentActivitySessionId,
1022
1336
  content: {
1023
1337
  type: "thought",
@@ -1048,7 +1362,7 @@ export class AgentSessionManager {
1048
1362
  try {
1049
1363
  if (message.status === "compacting") {
1050
1364
  // Create an ephemeral thought for the compacting status
1051
- const result = await this.linearClient.createAgentActivity({
1365
+ const result = await this.issueTracker.createAgentActivity({
1052
1366
  agentSessionId: session.linearAgentActivitySessionId,
1053
1367
  content: {
1054
1368
  type: "thought",
@@ -1068,7 +1382,7 @@ export class AgentSessionManager {
1068
1382
  }
1069
1383
  else if (message.status === null) {
1070
1384
  // Clear the status - post a non-ephemeral thought to replace the ephemeral one
1071
- const result = await this.linearClient.createAgentActivity({
1385
+ const result = await this.issueTracker.createAgentActivity({
1072
1386
  agentSessionId: session.linearAgentActivitySessionId,
1073
1387
  content: {
1074
1388
  type: "thought",