aisnitch 0.2.20 → 0.2.21

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/cli/index.js CHANGED
@@ -8,7 +8,7 @@ import { Command, InvalidArgumentError } from "commander";
8
8
 
9
9
  // src/package-info.ts
10
10
  var AISNITCH_PACKAGE_NAME = "aisnitch";
11
- var AISNITCH_VERSION = "0.2.20";
11
+ var AISNITCH_VERSION = "0.2.21";
12
12
  var AISNITCH_DESCRIPTION = "Universal bridge for AI coding tool activity \u2014 capture, normalize, stream.";
13
13
 
14
14
  // src/core/events/schema.ts
@@ -49,6 +49,8 @@ var TOOL_NAMES = [
49
49
  "kiro",
50
50
  "augment-code",
51
51
  "mistral",
52
+ "zed",
53
+ "pi",
52
54
  "unknown"
53
55
  ];
54
56
  var ERROR_TYPES = [
@@ -96,6 +98,11 @@ var ToolInputSchema = z.strictObject({
96
98
  (value) => value.filePath !== void 0 || value.command !== void 0,
97
99
  "toolInput must include filePath or command"
98
100
  );
101
+ var ThinkingContentSchema = z.string().max(1e5).describe("Raw thinking/reasoning content from the AI model");
102
+ var ToolCallNameSchema = z.string().min(1).max(100).describe("Name of the tool being invoked (e.g., Edit, Bash, Grep)");
103
+ var FinalMessageSchema = z.string().max(5e4).describe("End-of-run summary or completion message");
104
+ var ToolResultSchema = z.string().max(1e4).describe("Tool execution result or output");
105
+ var MessageContentSchema = z.string().max(1e5).describe("Raw text content from AI messages");
99
106
  var ToolNameSchema = z.enum(TOOL_NAMES);
100
107
  var AISnitchEventTypeSchema = z.enum(AISNITCH_EVENT_TYPES);
101
108
  var ErrorTypeSchema = z.enum(ERROR_TYPES);
@@ -118,7 +125,13 @@ var EventDataSchema = z.strictObject({
118
125
  pid: z.number().int().positive().optional(),
119
126
  instanceId: z.string().min(1).max(255).optional(),
120
127
  instanceIndex: z.number().int().min(1).optional(),
121
- instanceTotal: z.number().int().min(1).optional()
128
+ instanceTotal: z.number().int().min(1).optional(),
129
+ // New fields for enhanced content capture
130
+ thinkingContent: ThinkingContentSchema.optional(),
131
+ toolCallName: ToolCallNameSchema.optional(),
132
+ finalMessage: FinalMessageSchema.optional(),
133
+ toolResult: ToolResultSchema.optional(),
134
+ messageContent: MessageContentSchema.optional()
122
135
  });
123
136
  var AISnitchEventSchema = z.strictObject({
124
137
  specversion: z.literal("1.0"),
@@ -2432,11 +2445,11 @@ function toConfigPathOptions(options) {
2432
2445
  // src/cli/runtime.ts
2433
2446
  import { execFile as execFileCallback14, spawn as spawnChildProcess2 } from "child_process";
2434
2447
  import { closeSync, openSync } from "fs";
2435
- import { mkdtemp, readFile as readFile14, rename, rm as rm4, writeFile as writeFile5 } from "fs/promises";
2448
+ import { mkdtemp, readFile as readFile15, rename, rm as rm4, writeFile as writeFile5 } from "fs/promises";
2436
2449
  import { createConnection as createConnection3 } from "net";
2437
2450
  import { tmpdir } from "os";
2438
- import { basename as basename11, join as join16 } from "path";
2439
- import { promisify as promisify14 } from "util";
2451
+ import { basename as basename12, join as join18 } from "path";
2452
+ import { promisify as promisify15 } from "util";
2440
2453
 
2441
2454
  // src/adapters/generic-pty.ts
2442
2455
  import { basename as basename3 } from "path";
@@ -2507,9 +2520,11 @@ var TOOL_BINARY_MAP = {
2507
2520
  "openhands": "openhands",
2508
2521
  "openclaw": "openclaw",
2509
2522
  "opencode": "opencode",
2523
+ "pi": "pi",
2510
2524
  "qwen-code": "qwen",
2511
2525
  "unknown": "unknown",
2512
- "windsurf": "windsurf"
2526
+ "windsurf": "windsurf",
2527
+ "zed": "zed"
2513
2528
  };
2514
2529
  var ContextDetector = class {
2515
2530
  cache = /* @__PURE__ */ new Map();
@@ -4370,7 +4385,7 @@ var UDSServer = class {
4370
4385
  };
4371
4386
 
4372
4387
  // src/core/engine/pipeline.ts
4373
- import { join as join13 } from "path";
4388
+ import { join as join15 } from "path";
4374
4389
  import { z as z4 } from "zod";
4375
4390
 
4376
4391
  // src/adapters/aider.ts
@@ -4477,20 +4492,29 @@ var BaseAdapter = class {
4477
4492
  });
4478
4493
  let published;
4479
4494
  try {
4480
- published = await this.publishEventImplementation(event, {
4481
- cwd: context.cwd,
4482
- env: context.env,
4483
- hookPayload: context.hookPayload,
4484
- pid: context.pid,
4485
- sessionId,
4486
- source: context.source,
4487
- transcriptPath: context.transcriptPath
4495
+ published = await SHARED_BREAKERS.adapterEmit.execute(async () => {
4496
+ return await this.publishEventImplementation(event, {
4497
+ cwd: context.cwd,
4498
+ env: context.env,
4499
+ hookPayload: context.hookPayload,
4500
+ pid: context.pid,
4501
+ sessionId,
4502
+ source: context.source,
4503
+ transcriptPath: context.transcriptPath
4504
+ });
4488
4505
  });
4489
4506
  } catch (error) {
4490
- logger.error(
4491
- { error, eventType: type, adapter: this.name, sessionId },
4492
- "\u{1F4D6} Failed to publish event \u2014 swallowing to prevent daemon crash"
4493
- );
4507
+ if (error instanceof Error && error.name === "CircuitOpenError") {
4508
+ logger.warn(
4509
+ { error, eventType: type, adapter: this.name },
4510
+ "\u{1F4D6} Adapter emit blocked by open circuit \u2014 event dropped"
4511
+ );
4512
+ } else {
4513
+ logger.error(
4514
+ { error, eventType: type, adapter: this.name, sessionId },
4515
+ "\u{1F4D6} Failed to publish event \u2014 swallowing to prevent daemon crash"
4516
+ );
4517
+ }
4494
4518
  published = false;
4495
4519
  }
4496
4520
  if (published) {
@@ -5504,7 +5528,11 @@ var ClaudeCodeAdapter = class extends BaseAdapter {
5504
5528
  return;
5505
5529
  }
5506
5530
  case "SessionEnd": {
5507
- await this.emitStateChange("session.end", sharedData, context);
5531
+ const finalMessage = extractFinalMessageFromPayload(payload);
5532
+ await this.emitStateChange("session.end", {
5533
+ ...sharedData,
5534
+ finalMessage
5535
+ }, context);
5508
5536
  return;
5509
5537
  }
5510
5538
  case "UserPromptSubmit":
@@ -5521,12 +5549,22 @@ var ClaudeCodeAdapter = class extends BaseAdapter {
5521
5549
  return;
5522
5550
  }
5523
5551
  case "PreToolUse": {
5524
- await this.emitStateChange("agent.tool_call", sharedData, context);
5552
+ const toolCallName = extractToolNameFromPayload(payload);
5553
+ await this.emitStateChange("agent.tool_call", {
5554
+ ...sharedData,
5555
+ toolCallName
5556
+ }, context);
5525
5557
  return;
5526
5558
  }
5527
5559
  case "PostToolUse": {
5560
+ const toolCallName = extractToolNameFromPayload(payload);
5561
+ const toolResult = extractToolResultFromPayload(payload);
5528
5562
  const emittedType = isClaudeCodingTool(sharedData.toolName) ? "agent.coding" : "agent.tool_call";
5529
- await this.emitStateChange(emittedType, sharedData, context);
5563
+ await this.emitStateChange(emittedType, {
5564
+ ...sharedData,
5565
+ toolCallName,
5566
+ toolResult
5567
+ }, context);
5530
5568
  return;
5531
5569
  }
5532
5570
  case "PostToolUseFailure":
@@ -5728,21 +5766,50 @@ function extractClaudeTranscriptObservations(payload, transcriptPath) {
5728
5766
  };
5729
5767
  const observations = [];
5730
5768
  if (contentParts.some((part) => part.type === "thinking")) {
5769
+ const thinkingParts = contentParts.filter((part) => part.type === "thinking");
5770
+ const thinkingText = thinkingParts.map((part) => {
5771
+ const text = part.text;
5772
+ return typeof text === "string" ? text : void 0;
5773
+ }).filter((text) => text !== void 0).join("\n");
5731
5774
  observations.push({
5732
5775
  context: sharedContext,
5733
- data: sharedData,
5776
+ data: {
5777
+ ...sharedData,
5778
+ thinkingContent: thinkingText.length > 0 ? thinkingText : void 0
5779
+ },
5734
5780
  type: "agent.thinking"
5735
5781
  });
5736
5782
  }
5737
5783
  if (contentParts.some(
5738
5784
  (part) => part.type === "text" && typeof part.text === "string" && part.text.trim().length > 0
5739
5785
  )) {
5786
+ const messageTexts = contentParts.filter((part) => part.type === "text").map((part) => part.text).filter((text) => text.trim().length > 0);
5787
+ const messageContent = messageTexts.join("\n");
5740
5788
  observations.push({
5741
5789
  context: sharedContext,
5742
- data: sharedData,
5790
+ data: {
5791
+ ...sharedData,
5792
+ messageContent: messageContent.length > 0 ? messageContent : void 0
5793
+ },
5743
5794
  type: "agent.streaming"
5744
5795
  });
5745
5796
  }
5797
+ const toolUseParts = contentParts.filter(
5798
+ (part) => part.type === "tool_use" || part.type === "toolUse"
5799
+ );
5800
+ if (toolUseParts.length > 0) {
5801
+ const toolName = getString(toolUseParts[0], "name") ?? getString(toolUseParts[0], "tool");
5802
+ if (toolName) {
5803
+ observations.push({
5804
+ context: sharedContext,
5805
+ data: {
5806
+ ...sharedData,
5807
+ toolCallName: toolName
5808
+ },
5809
+ type: "agent.tool_call"
5810
+ });
5811
+ }
5812
+ }
5746
5813
  return observations;
5747
5814
  }
5748
5815
  function extractClaudeContentParts(payload) {
@@ -5865,6 +5932,51 @@ function getString(payload, key) {
5865
5932
  const value = payload[key];
5866
5933
  return typeof value === "string" && value.trim().length > 0 ? value : void 0;
5867
5934
  }
5935
+ function extractToolNameFromPayload(payload) {
5936
+ const directToolName = getString(payload, "tool_name") ?? getString(payload, "toolName");
5937
+ if (directToolName) {
5938
+ return directToolName;
5939
+ }
5940
+ const toolUse = getRecord(payload.tool_use) ?? getRecord(payload.toolUse);
5941
+ if (toolUse) {
5942
+ return getString(toolUse, "name") ?? getString(toolUse, "tool");
5943
+ }
5944
+ const toolInput = getRecord(payload.tool_input) ?? getRecord(payload.toolInput);
5945
+ if (toolInput) {
5946
+ return getString(toolInput, "tool_name") ?? getString(toolInput, "type");
5947
+ }
5948
+ return void 0;
5949
+ }
5950
+ function extractToolResultFromPayload(payload) {
5951
+ const directResult = getString(payload, "result") ?? getString(payload, "output");
5952
+ if (directResult) {
5953
+ return directResult;
5954
+ }
5955
+ const toolResult = getRecord(payload.tool_result) ?? getRecord(payload.toolResult);
5956
+ if (toolResult) {
5957
+ return getString(toolResult, "content") ?? getString(toolResult, "output");
5958
+ }
5959
+ const errorField = getString(payload, "error") ?? getString(payload, "error_message");
5960
+ if (errorField) {
5961
+ return errorField;
5962
+ }
5963
+ return void 0;
5964
+ }
5965
+ function extractFinalMessageFromPayload(payload) {
5966
+ const directMessage = getString(payload, "final_message") ?? getString(payload, "finalMessage") ?? getString(payload, "summary") ?? getString(payload, "completion_message");
5967
+ if (directMessage) {
5968
+ return directMessage;
5969
+ }
5970
+ const result = getString(payload, "result") ?? getString(payload, "output") ?? getString(payload, "message");
5971
+ if (result) {
5972
+ return result;
5973
+ }
5974
+ const stats = getRecord(payload.stats);
5975
+ if (stats) {
5976
+ return getString(stats, "summary") ?? getString(stats, "completion_summary");
5977
+ }
5978
+ return void 0;
5979
+ }
5868
5980
 
5869
5981
  // src/adapters/copilot-cli.ts
5870
5982
  import { execFile as execFileCallback5 } from "child_process";
@@ -10838,7 +10950,11 @@ var OpenCodeAdapter = class extends BaseAdapter {
10838
10950
  return;
10839
10951
  }
10840
10952
  case "session.deleted": {
10841
- await this.emitStateChange("session.end", sharedData, context);
10953
+ const finalMessage = extractOpenCodeFinalMessage(payload);
10954
+ await this.emitStateChange("session.end", {
10955
+ ...sharedData,
10956
+ finalMessage
10957
+ }, context);
10842
10958
  return;
10843
10959
  }
10844
10960
  case "session.error": {
@@ -10863,12 +10979,22 @@ var OpenCodeAdapter = class extends BaseAdapter {
10863
10979
  return;
10864
10980
  }
10865
10981
  case "tool.execute.before": {
10866
- await this.emitStateChange("agent.tool_call", sharedData, context);
10982
+ const toolCallName = extractOpenCodeToolName(payload);
10983
+ await this.emitStateChange("agent.tool_call", {
10984
+ ...sharedData,
10985
+ toolCallName
10986
+ }, context);
10867
10987
  return;
10868
10988
  }
10869
10989
  case "tool.execute.after": {
10990
+ const toolCallName = extractOpenCodeToolName(payload);
10991
+ const toolResult = extractOpenCodeToolResult(payload);
10870
10992
  const emittedType = isOpenCodeCodingTool(sharedData.toolName) ? "agent.coding" : "agent.tool_call";
10871
- await this.emitStateChange(emittedType, sharedData, context);
10993
+ await this.emitStateChange(emittedType, {
10994
+ ...sharedData,
10995
+ toolCallName,
10996
+ toolResult
10997
+ }, context);
10872
10998
  return;
10873
10999
  }
10874
11000
  default: {
@@ -11035,6 +11161,535 @@ function getString10(payload, key) {
11035
11161
  const value = payload[key];
11036
11162
  return typeof value === "string" && value.trim().length > 0 ? value : void 0;
11037
11163
  }
11164
+ function extractOpenCodeFinalMessage(payload) {
11165
+ const directMessage = getString10(payload, "final_message") ?? getString10(payload, "finalMessage") ?? getString10(payload, "summary") ?? getString10(payload, "completion_message");
11166
+ if (directMessage) {
11167
+ return directMessage;
11168
+ }
11169
+ const result = getString10(payload, "result") ?? getString10(payload, "output") ?? getString10(getRecord9(payload.properties), "result");
11170
+ if (result) {
11171
+ return result;
11172
+ }
11173
+ return void 0;
11174
+ }
11175
+ function extractOpenCodeToolResult(payload) {
11176
+ const directResult = getString10(payload, "result") ?? getString10(payload, "output") ?? getString10(payload, "toolResult");
11177
+ if (directResult) {
11178
+ return directResult;
11179
+ }
11180
+ const toolResult = getRecord9(payload.tool_result) ?? getRecord9(payload.toolResult);
11181
+ if (toolResult) {
11182
+ return getString10(toolResult, "content") ?? getString10(toolResult, "output");
11183
+ }
11184
+ const props = getRecord9(payload.properties);
11185
+ if (props) {
11186
+ const nestedResult = getRecord9(props.tool_result) ?? getRecord9(props.toolResult);
11187
+ if (nestedResult) {
11188
+ return getString10(nestedResult, "content") ?? getString10(nestedResult, "output");
11189
+ }
11190
+ }
11191
+ return void 0;
11192
+ }
11193
+
11194
+ // src/adapters/pi.ts
11195
+ import { execFile as execFile14 } from "child_process";
11196
+ import { join as join13 } from "path";
11197
+ import { promisify as promisify14 } from "util";
11198
+ var execFileAsync = promisify14(execFile14);
11199
+ var PiAdapter = class extends BaseAdapter {
11200
+ displayName = "Pi (MiniMax)";
11201
+ name = "pi";
11202
+ strategies = [
11203
+ "process-detect",
11204
+ "api-client",
11205
+ "log-watch"
11206
+ ];
11207
+ apiPort = 7890;
11208
+ logPath;
11209
+ poller = null;
11210
+ activePiSessions = /* @__PURE__ */ new Map();
11211
+ lastCheckedTime = 0;
11212
+ constructor(options) {
11213
+ super(options);
11214
+ this.logPath = join13(
11215
+ options.homeDirectory ?? process.env.HOME ?? "",
11216
+ ".pi",
11217
+ "agent.log"
11218
+ );
11219
+ }
11220
+ start() {
11221
+ if (this.getStatus().running) {
11222
+ return Promise.resolve();
11223
+ }
11224
+ this.setRunning(true);
11225
+ this.startPolling();
11226
+ logger.info({ adapter: this.name }, "Pi adapter started");
11227
+ return Promise.resolve();
11228
+ }
11229
+ stop() {
11230
+ if (this.poller !== null) {
11231
+ clearInterval(this.poller);
11232
+ this.poller = null;
11233
+ }
11234
+ this.setRunning(false);
11235
+ logger.info({ adapter: this.name }, "Pi adapter stopped");
11236
+ return Promise.resolve();
11237
+ }
11238
+ async handleHook(payload) {
11239
+ const normalized = this.parseNormalizedHookPayload(payload);
11240
+ if (normalized === null) {
11241
+ return;
11242
+ }
11243
+ const context = {
11244
+ cwd: normalized.cwd,
11245
+ pid: normalized.pid,
11246
+ sessionId: normalized.sessionId,
11247
+ source: "pi-hook"
11248
+ };
11249
+ const eventType = this.mapEventType(normalized.type ?? "");
11250
+ const eventData = this.buildEventData(eventType, normalized);
11251
+ await this.emit(eventType, eventData, context);
11252
+ }
11253
+ startPolling() {
11254
+ this.poller = setInterval(() => {
11255
+ void this.pollPiActivity();
11256
+ }, 2e3);
11257
+ }
11258
+ async pollPiActivity() {
11259
+ const running = await this.detectPiInstance();
11260
+ if (!running) {
11261
+ for (const [sessionId, activity] of this.activePiSessions) {
11262
+ if (activity.state !== "idle") {
11263
+ activity.state = "idle";
11264
+ await this.emitIdle(sessionId);
11265
+ }
11266
+ }
11267
+ return;
11268
+ }
11269
+ try {
11270
+ const response = await fetch(
11271
+ `http://127.0.0.1:${this.apiPort}/api/status`,
11272
+ {
11273
+ signal: AbortSignal.timeout(500)
11274
+ }
11275
+ );
11276
+ if (response.ok) {
11277
+ const data = await response.json();
11278
+ await this.processPiApiResponse(data);
11279
+ }
11280
+ } catch {
11281
+ await this.checkMiniMaxApi();
11282
+ }
11283
+ }
11284
+ async detectPiInstance() {
11285
+ try {
11286
+ const result = await execFileAsync("pgrep", ["-l", "pi|minimax"]);
11287
+ if (result.stdout.includes("pi") || result.stdout.includes("minimax")) {
11288
+ return true;
11289
+ }
11290
+ } catch {
11291
+ }
11292
+ try {
11293
+ const response = await fetch(
11294
+ `http://127.0.0.1:${this.apiPort}/health`,
11295
+ {
11296
+ signal: AbortSignal.timeout(200)
11297
+ }
11298
+ );
11299
+ if (response.ok) {
11300
+ return true;
11301
+ }
11302
+ } catch {
11303
+ }
11304
+ return false;
11305
+ }
11306
+ async checkMiniMaxApi() {
11307
+ try {
11308
+ const response = await fetch("http://127.0.0.1:3000/api/agent/status", {
11309
+ signal: AbortSignal.timeout(500)
11310
+ });
11311
+ if (response.ok) {
11312
+ const data = await response.json();
11313
+ await this.processPiApiResponse(data);
11314
+ }
11315
+ } catch {
11316
+ }
11317
+ }
11318
+ async processPiApiResponse(data) {
11319
+ const rawSession = data.sessionId ?? data.project ?? "default";
11320
+ const sessionId = `pi:${rawSession.replace(/[^a-zA-Z0-9-_]/g, "-")}`;
11321
+ let activity = this.activePiSessions.get(sessionId);
11322
+ if (!activity) {
11323
+ activity = { sessionId, state: "idle" };
11324
+ this.activePiSessions.set(sessionId, activity);
11325
+ await this.emitSessionStart(sessionId, data);
11326
+ }
11327
+ const rawState = data.state ?? "idle";
11328
+ const state = rawState;
11329
+ if (state !== activity.state) {
11330
+ switch (state) {
11331
+ case "thinking": {
11332
+ const rawThinking = data.thinking;
11333
+ if (rawThinking) {
11334
+ await this.emitThinking(sessionId, rawThinking);
11335
+ }
11336
+ break;
11337
+ }
11338
+ case "tool": {
11339
+ const rawFilePath = data.filePath;
11340
+ const rawCommand = data.command;
11341
+ const rawToolName = data.toolName ?? "unknown";
11342
+ await this.emitToolCall(
11343
+ sessionId,
11344
+ {
11345
+ filePath: rawFilePath ?? "",
11346
+ command: rawCommand ?? ""
11347
+ },
11348
+ rawToolName
11349
+ );
11350
+ break;
11351
+ }
11352
+ case "output": {
11353
+ const rawOutput = data.output;
11354
+ if (rawOutput) {
11355
+ await this.emitOutput(sessionId, rawOutput);
11356
+ }
11357
+ break;
11358
+ }
11359
+ case "error": {
11360
+ const rawError = data.error ?? "Unknown error";
11361
+ await this.emitError(sessionId, rawError);
11362
+ break;
11363
+ }
11364
+ case "idle":
11365
+ await this.emitIdle(sessionId);
11366
+ break;
11367
+ }
11368
+ activity.state = state;
11369
+ }
11370
+ }
11371
+ async emitSessionStart(sessionId, data) {
11372
+ const rawProject = data.project ?? "pi-project";
11373
+ const rawModel = data.model ?? "minimax/moonshot";
11374
+ const eventData = {
11375
+ state: "session.start",
11376
+ project: rawProject,
11377
+ model: rawModel,
11378
+ raw: data
11379
+ };
11380
+ await this.emit("session.start", eventData, { sessionId });
11381
+ }
11382
+ async emitThinking(sessionId, content) {
11383
+ if (!content) return;
11384
+ const eventData = {
11385
+ state: "agent.thinking",
11386
+ thinkingContent: content
11387
+ };
11388
+ await this.emit("agent.thinking", eventData, { sessionId });
11389
+ }
11390
+ async emitToolCall(sessionId, toolInput, toolName) {
11391
+ const eventData = {
11392
+ state: "agent.tool_call",
11393
+ toolCallName: toolName,
11394
+ toolInput,
11395
+ activeFile: toolInput.filePath
11396
+ };
11397
+ await this.emit("agent.tool_call", eventData, { sessionId });
11398
+ }
11399
+ async emitOutput(sessionId, content) {
11400
+ if (!content) return;
11401
+ const eventData = {
11402
+ state: "agent.streaming",
11403
+ messageContent: content
11404
+ };
11405
+ await this.emit("agent.streaming", eventData, { sessionId });
11406
+ }
11407
+ async emitError(sessionId, errorMessage) {
11408
+ const eventData = {
11409
+ state: "agent.error",
11410
+ errorMessage,
11411
+ errorType: "api_error"
11412
+ };
11413
+ await this.emit("agent.error", eventData, { sessionId });
11414
+ }
11415
+ async emitIdle(sessionId) {
11416
+ const eventData = {
11417
+ state: "agent.idle"
11418
+ };
11419
+ await this.emit("agent.idle", eventData, { sessionId });
11420
+ }
11421
+ mapEventType(type) {
11422
+ const mapping = {
11423
+ "session.start": "session.start",
11424
+ "session.end": "session.end",
11425
+ "task.start": "task.start",
11426
+ "task.complete": "task.complete",
11427
+ thinking: "agent.thinking",
11428
+ tool: "agent.tool_call",
11429
+ coding: "agent.coding",
11430
+ output: "agent.streaming",
11431
+ message: "agent.streaming",
11432
+ ask: "agent.asking_user",
11433
+ error: "agent.error",
11434
+ idle: "agent.idle",
11435
+ compact: "agent.compact"
11436
+ };
11437
+ return mapping[type] ?? "agent.streaming";
11438
+ }
11439
+ buildEventData(eventType, payload) {
11440
+ const data = payload.data ?? {};
11441
+ return {
11442
+ state: eventType,
11443
+ project: data.project,
11444
+ activeFile: data.activeFile,
11445
+ model: data.model,
11446
+ toolInput: data.toolInput,
11447
+ toolCallName: data.toolCallName,
11448
+ thinkingContent: data.thinkingContent,
11449
+ messageContent: data.messageContent,
11450
+ finalMessage: data.finalMessage,
11451
+ toolResult: data.toolResult,
11452
+ errorMessage: data.errorMessage,
11453
+ errorType: data.errorType,
11454
+ raw: data.raw
11455
+ };
11456
+ }
11457
+ };
11458
+
11459
+ // src/adapters/zed.ts
11460
+ import { readFile as readFile12 } from "fs/promises";
11461
+ import { basename as basename11, join as join14 } from "path";
11462
+ var ZedAdapter = class extends BaseAdapter {
11463
+ displayName = "Zed AI";
11464
+ name = "zed";
11465
+ strategies = [
11466
+ "process-detect",
11467
+ "api-client"
11468
+ ];
11469
+ logPaths;
11470
+ apiPort = 9876;
11471
+ pollIntervalMs;
11472
+ poller = null;
11473
+ lastEventTime = 0;
11474
+ activeZedSessions = /* @__PURE__ */ new Map();
11475
+ constructor(options) {
11476
+ super(options);
11477
+ this.pollIntervalMs = 2e3;
11478
+ this.logPaths = [
11479
+ join14(options.homeDirectory ?? process.env.HOME ?? "", ".config", "zed", "logs", "agent.log"),
11480
+ "/tmp/zed-agent.log"
11481
+ ];
11482
+ }
11483
+ start() {
11484
+ if (this.getStatus().running) {
11485
+ return Promise.resolve();
11486
+ }
11487
+ this.setRunning(true);
11488
+ this.startPolling();
11489
+ logger.info({ adapter: this.name }, "Zed adapter started");
11490
+ return Promise.resolve();
11491
+ }
11492
+ stop() {
11493
+ if (this.poller !== null) {
11494
+ clearInterval(this.poller);
11495
+ this.poller = null;
11496
+ }
11497
+ this.setRunning(false);
11498
+ logger.info({ adapter: this.name }, "Zed adapter stopped");
11499
+ return Promise.resolve();
11500
+ }
11501
+ async handleHook(payload) {
11502
+ const normalized = this.parseNormalizedHookPayload(payload);
11503
+ if (normalized === null) {
11504
+ return;
11505
+ }
11506
+ const context = {
11507
+ cwd: normalized.cwd,
11508
+ pid: normalized.pid,
11509
+ sessionId: normalized.sessionId,
11510
+ source: "zed-hook"
11511
+ };
11512
+ const eventType = this.mapEventType(normalized.type ?? "");
11513
+ const eventData = this.buildEventData(eventType, normalized);
11514
+ await this.emit(eventType, eventData, context);
11515
+ }
11516
+ startPolling() {
11517
+ this.poller = setInterval(() => {
11518
+ void this.pollZedStatus();
11519
+ }, this.pollIntervalMs);
11520
+ }
11521
+ async pollZedStatus() {
11522
+ try {
11523
+ const response = await fetch(`http://127.0.0.1:${this.apiPort}/api/agent/status`, {
11524
+ signal: AbortSignal.timeout(1e3)
11525
+ });
11526
+ if (response.ok) {
11527
+ const data = await response.json();
11528
+ if (data.sessionId && typeof data.sessionId === "string") {
11529
+ const sessionId = `zed:${data.sessionId}`;
11530
+ if (!this.activeZedSessions.has(sessionId)) {
11531
+ this.activeZedSessions.set(sessionId, sessionId);
11532
+ await this.emitSessionStart(sessionId, data);
11533
+ }
11534
+ if (data.state === "thinking" && this.lastEventTime < Date.now() - 5e3) {
11535
+ const rawThinking = data.thinking;
11536
+ if (rawThinking) {
11537
+ await this.emitThinking(sessionId, rawThinking);
11538
+ }
11539
+ } else if (data.state === "tool" && data.toolName) {
11540
+ const rawFilePath = data.filePath;
11541
+ const rawCommand = data.command;
11542
+ const rawToolName = data.toolName ?? "unknown";
11543
+ await this.emitToolCall(
11544
+ sessionId,
11545
+ {
11546
+ filePath: rawFilePath ?? "",
11547
+ command: rawCommand ?? ""
11548
+ },
11549
+ rawToolName
11550
+ );
11551
+ } else if (data.state === "idle") {
11552
+ await this.emitIdle(sessionId);
11553
+ }
11554
+ }
11555
+ }
11556
+ } catch {
11557
+ await this.checkLogFiles();
11558
+ }
11559
+ }
11560
+ async checkLogFiles() {
11561
+ for (const logPath of this.logPaths) {
11562
+ try {
11563
+ const content = await readFile12(logPath, "utf8");
11564
+ await this.parseLogContent(content);
11565
+ } catch {
11566
+ }
11567
+ }
11568
+ }
11569
+ async parseLogContent(content) {
11570
+ const lines = content.split("\n").filter((line) => line.trim());
11571
+ for (const line of lines) {
11572
+ if (this.lastEventTime > 0 && this.lastEventTime >= Date.now() - 2e3) {
11573
+ continue;
11574
+ }
11575
+ const event = this.extractZedEventFromLog(line);
11576
+ if (event) {
11577
+ await this.handleHook(event);
11578
+ this.lastEventTime = Date.now();
11579
+ }
11580
+ }
11581
+ }
11582
+ extractZedEventFromLog(line) {
11583
+ try {
11584
+ const parsed = JSON.parse(line);
11585
+ if (!parsed.type || typeof parsed.type !== "string") {
11586
+ return null;
11587
+ }
11588
+ const rawSessionId = parsed.sessionId;
11589
+ const rawWorkspace = parsed.workspace;
11590
+ const sessionId = rawSessionId ? rawSessionId : rawWorkspace ? `zed:${basename11(rawWorkspace)}` : `zed:${Date.now()}`;
11591
+ const rawCwd = parsed.cwd ?? rawWorkspace;
11592
+ return {
11593
+ type: parsed.type,
11594
+ sessionId,
11595
+ cwd: rawCwd,
11596
+ data: {
11597
+ project: parsed.project ?? rawWorkspace ? basename11(String(rawWorkspace)) : void 0,
11598
+ model: parsed.model,
11599
+ state: parsed.type,
11600
+ thinkingContent: parsed.thinking,
11601
+ toolCallName: parsed.toolName,
11602
+ toolInput: parsed.toolInput,
11603
+ messageContent: parsed.message ?? parsed.output,
11604
+ errorMessage: parsed.error,
11605
+ raw: parsed
11606
+ }
11607
+ };
11608
+ } catch {
11609
+ if (line.includes("[zed:agent]")) {
11610
+ const cleaned = line.replace(/^\[.*?\] \[.*?\] /, "");
11611
+ if (cleaned.includes("Thinking:")) {
11612
+ return { type: "thinking", thinkingContent: cleaned.replace("Thinking:", "").trim() };
11613
+ }
11614
+ if (cleaned.includes("Executing tool:")) {
11615
+ return { type: "tool", toolCallName: cleaned.replace("Executing tool:", "").trim() };
11616
+ }
11617
+ if (cleaned.includes("Error:")) {
11618
+ return { type: "error", errorMessage: cleaned.replace("Error:", "").trim() };
11619
+ }
11620
+ }
11621
+ return null;
11622
+ }
11623
+ }
11624
+ async emitSessionStart(sessionId, _data) {
11625
+ const eventData = {
11626
+ state: "session.start",
11627
+ project: sessionId.split(":")[1] ?? "unknown"
11628
+ };
11629
+ await this.emit("session.start", eventData, { sessionId });
11630
+ }
11631
+ async emitThinking(sessionId, content) {
11632
+ if (!content) return;
11633
+ const eventData = {
11634
+ state: "agent.thinking",
11635
+ thinkingContent: content
11636
+ };
11637
+ await this.emit("agent.thinking", eventData, { sessionId });
11638
+ this.lastEventTime = Date.now();
11639
+ }
11640
+ async emitToolCall(sessionId, toolInput, toolName) {
11641
+ const eventData = {
11642
+ state: "agent.tool_call",
11643
+ toolCallName: toolName,
11644
+ toolInput,
11645
+ activeFile: toolInput.filePath
11646
+ };
11647
+ await this.emit("agent.tool_call", eventData, { sessionId });
11648
+ this.lastEventTime = Date.now();
11649
+ }
11650
+ async emitIdle(sessionId) {
11651
+ const eventData = {
11652
+ state: "agent.idle"
11653
+ };
11654
+ await this.emit("agent.idle", eventData, { sessionId });
11655
+ }
11656
+ mapEventType(type) {
11657
+ const mapping = {
11658
+ "session.start": "session.start",
11659
+ "session.end": "session.end",
11660
+ "task.start": "task.start",
11661
+ "task.complete": "task.complete",
11662
+ thinking: "agent.thinking",
11663
+ tool: "agent.tool_call",
11664
+ coding: "agent.coding",
11665
+ output: "agent.streaming",
11666
+ message: "agent.streaming",
11667
+ ask: "agent.asking_user",
11668
+ error: "agent.error",
11669
+ idle: "agent.idle",
11670
+ compact: "agent.compact"
11671
+ };
11672
+ return mapping[type] ?? "agent.streaming";
11673
+ }
11674
+ buildEventData(eventType, payload) {
11675
+ const data = payload.data ?? {};
11676
+ return {
11677
+ state: eventType,
11678
+ project: data.project,
11679
+ activeFile: data.activeFile,
11680
+ model: data.model,
11681
+ toolInput: data.toolInput,
11682
+ toolCallName: data.toolCallName,
11683
+ thinkingContent: data.thinkingContent,
11684
+ messageContent: data.messageContent,
11685
+ finalMessage: data.finalMessage,
11686
+ toolResult: data.toolResult,
11687
+ errorMessage: data.errorMessage,
11688
+ errorType: data.errorType,
11689
+ raw: data.raw
11690
+ };
11691
+ }
11692
+ };
11038
11693
 
11039
11694
  // src/adapters/registry.ts
11040
11695
  var AdapterRegistry = class {
@@ -11119,7 +11774,9 @@ function createDefaultAdapters(options) {
11119
11774
  new KiloAdapter(options),
11120
11775
  new CodexAdapter(options),
11121
11776
  new OpenClawAdapter(options),
11122
- new OpenCodeAdapter(options)
11777
+ new OpenCodeAdapter(options),
11778
+ new PiAdapter(options),
11779
+ new ZedAdapter(options)
11123
11780
  ];
11124
11781
  }
11125
11782
 
@@ -11140,7 +11797,7 @@ function getSocketPath(aisnitchHomePath) {
11140
11797
  if (process.platform === "win32") {
11141
11798
  return "\\\\.\\pipe\\aisnitch.sock";
11142
11799
  }
11143
- return join13(aisnitchHomePath, "aisnitch.sock");
11800
+ return join15(aisnitchHomePath, "aisnitch.sock");
11144
11801
  }
11145
11802
  var Pipeline = class {
11146
11803
  eventBus = new EventBus();
@@ -11345,6 +12002,30 @@ var Pipeline = class {
11345
12002
  getEventBus() {
11346
12003
  return this.eventBus;
11347
12004
  }
12005
+ /**
12006
+ * Returns the adapter registry for graceful shutdown coordination.
12007
+ */
12008
+ getAdapterRegistry() {
12009
+ return this.adapterRegistry ?? void 0;
12010
+ }
12011
+ /**
12012
+ * Returns the HTTP receiver for graceful shutdown coordination.
12013
+ */
12014
+ getHttpReceiver() {
12015
+ return this.httpReceiver;
12016
+ }
12017
+ /**
12018
+ * Returns the UDS server for graceful shutdown coordination.
12019
+ */
12020
+ getUdsServer() {
12021
+ return this.udsServer;
12022
+ }
12023
+ /**
12024
+ * Returns the WebSocket server for graceful shutdown coordination.
12025
+ */
12026
+ getWsServer() {
12027
+ return this.wsServer;
12028
+ }
11348
12029
  getHealthSnapshot() {
11349
12030
  const status = this.getStatus();
11350
12031
  return {
@@ -11469,6 +12150,72 @@ var DEFAULT_TIMEOUTS = Object.freeze({
11469
12150
  pipelineStartup: 15e3
11470
12151
  });
11471
12152
 
12153
+ // src/core/graceful-shutdown.ts
12154
+ async function withShutdownTimeout(fn, timeoutMs, component) {
12155
+ if (timeoutMs <= 0) {
12156
+ await fn();
12157
+ return;
12158
+ }
12159
+ const timeoutPromise = new Promise((resolve2) => {
12160
+ setTimeout(() => {
12161
+ resolve2("timed_out");
12162
+ }, timeoutMs).unref();
12163
+ });
12164
+ const result = await Promise.race([
12165
+ fn().then(() => "completed"),
12166
+ timeoutPromise
12167
+ ]);
12168
+ if (result === "timed_out") {
12169
+ logger.warn(
12170
+ { component, timeoutMs },
12171
+ `Graceful shutdown exceeded ${timeoutMs}ms timeout \u2014 forcing through`
12172
+ );
12173
+ }
12174
+ }
12175
+ async function shutdownInOrder(components, timeouts, label) {
12176
+ const getTimeout = (key) => {
12177
+ return timeouts[key] ?? DEFAULT_TIMEOUTS.daemonShutdown;
12178
+ };
12179
+ const stopSafely = async (key, fn) => {
12180
+ const timeoutMs = getTimeout(key);
12181
+ try {
12182
+ await withShutdownTimeout(fn, timeoutMs, `${label}.${key}`);
12183
+ } catch (error) {
12184
+ logger.warn(
12185
+ { error, key, label },
12186
+ `Error during shutdown of ${key} \u2014 continuing with remaining components`
12187
+ );
12188
+ }
12189
+ };
12190
+ if (components.cleanupFns) {
12191
+ for (const cleanupFn of components.cleanupFns) {
12192
+ try {
12193
+ await withShutdownTimeout(
12194
+ async () => {
12195
+ const result = cleanupFn();
12196
+ if (result instanceof Promise) {
12197
+ await result;
12198
+ }
12199
+ },
12200
+ 1e3,
12201
+ `${label}.cleanup`
12202
+ );
12203
+ } catch (error) {
12204
+ logger.warn({ error, label }, "Cleanup function failed");
12205
+ }
12206
+ }
12207
+ }
12208
+ if (components.eventBus) {
12209
+ components.eventBus.unsubscribeAll();
12210
+ }
12211
+ await stopSafely("wsServer", () => components.wsServer.stop());
12212
+ await stopSafely("udsServer", () => components.udsServer.stop());
12213
+ await stopSafely("httpReceiver", () => components.httpReceiver.stop());
12214
+ if (components.adapterRegistry) {
12215
+ await stopSafely("adapterRegistry", () => components.adapterRegistry.stopAll());
12216
+ }
12217
+ }
12218
+
11472
12219
  // src/tui/index.tsx
11473
12220
  import { render } from "ink";
11474
12221
  import { withFullScreen } from "fullscreen-ink";
@@ -11672,9 +12419,11 @@ var TOOL_COLORS = {
11672
12419
  "openhands": "#facc15",
11673
12420
  "openclaw": "#ef4444",
11674
12421
  "opencode": "#10b981",
12422
+ "pi": "#1db954",
11675
12423
  "qwen-code": "#22c55e",
11676
12424
  "unknown": "#94a3b8",
11677
- "windsurf": "#a855f7"
12425
+ "windsurf": "#a855f7",
12426
+ "zed": "#e85d04"
11678
12427
  };
11679
12428
  var EVENT_COLORS = {
11680
12429
  "agent.asking_user": "#ef4444",
@@ -13428,10 +14177,10 @@ async function renderManagedTui(options) {
13428
14177
 
13429
14178
  // src/cli/pid.ts
13430
14179
  import { constants as constants3 } from "fs";
13431
- import { mkdir as mkdir3, readFile as readFile12, rm as rm3, stat as stat10, writeFile as writeFile3, access as access3 } from "fs/promises";
14180
+ import { mkdir as mkdir3, readFile as readFile13, rm as rm3, stat as stat10, writeFile as writeFile3, access as access3 } from "fs/promises";
13432
14181
  import { createConnection as createConnection2 } from "net";
13433
14182
  import { homedir as homedir4 } from "os";
13434
- import { dirname as dirname7, join as join14 } from "path";
14183
+ import { dirname as dirname7, join as join16 } from "path";
13435
14184
  import { z as z5 } from "zod";
13436
14185
  var DaemonStateSchema = z5.strictObject({
13437
14186
  pid: z5.number().int().positive(),
@@ -13446,7 +14195,7 @@ function getDefaultSocketPath(options) {
13446
14195
  if (process.platform === "win32") {
13447
14196
  return "\\\\.\\pipe\\aisnitch.sock";
13448
14197
  }
13449
- return join14(getAISnitchHomePath(options), "aisnitch.sock");
14198
+ return join16(getAISnitchHomePath(options), "aisnitch.sock");
13450
14199
  }
13451
14200
  async function cleanupSocketPathIfStale(socketPath) {
13452
14201
  if (process.platform === "win32") {
@@ -13481,16 +14230,16 @@ async function cleanupSocketPathIfStale(socketPath) {
13481
14230
  return true;
13482
14231
  }
13483
14232
  function getPidFilePath(options = {}) {
13484
- return join14(getAISnitchHomePath(options), "aisnitch.pid");
14233
+ return join16(getAISnitchHomePath(options), "aisnitch.pid");
13485
14234
  }
13486
14235
  function getDaemonStatePath(options = {}) {
13487
- return join14(getAISnitchHomePath(options), "daemon-state.json");
14236
+ return join16(getAISnitchHomePath(options), "daemon-state.json");
13488
14237
  }
13489
14238
  function getDaemonLogPath(options = {}) {
13490
- return join14(getAISnitchHomePath(options), "daemon.log");
14239
+ return join16(getAISnitchHomePath(options), "daemon.log");
13491
14240
  }
13492
14241
  function getLaunchAgentPath(options = {}) {
13493
- return join14(
14242
+ return join16(
13494
14243
  options.launchAgentHomeDirectory ?? homedir4(),
13495
14244
  "Library",
13496
14245
  "LaunchAgents",
@@ -13506,7 +14255,7 @@ async function writePid(pid, options = {}) {
13506
14255
  }
13507
14256
  async function readPid(options = {}) {
13508
14257
  try {
13509
- const rawPid = await readFile12(getPidFilePath(options), "utf8");
14258
+ const rawPid = await readFile13(getPidFilePath(options), "utf8");
13510
14259
  const parsedPid = Number.parseInt(rawPid.trim(), 10);
13511
14260
  if (!Number.isInteger(parsedPid) || parsedPid <= 0) {
13512
14261
  throw new Error("Invalid PID file contents.");
@@ -13536,7 +14285,7 @@ async function writeDaemonState(state, options = {}) {
13536
14285
  }
13537
14286
  async function readDaemonState(options = {}) {
13538
14287
  try {
13539
- const rawJson = await readFile12(getDaemonStatePath(options), "utf8");
14288
+ const rawJson = await readFile13(getDaemonStatePath(options), "utf8");
13540
14289
  const parsedJson = JSON.parse(rawJson);
13541
14290
  return DaemonStateSchema.parse(parsedJson);
13542
14291
  } catch (error) {
@@ -13604,9 +14353,9 @@ function getEffectiveCliConfigPath(options = {}) {
13604
14353
 
13605
14354
  // src/cli/auto-update.ts
13606
14355
  import { spawn as spawnChildProcess } from "child_process";
13607
- import { mkdir as mkdir4, readFile as readFile13, writeFile as writeFile4 } from "fs/promises";
14356
+ import { mkdir as mkdir4, readFile as readFile14, writeFile as writeFile4 } from "fs/promises";
13608
14357
  import { realpath } from "fs/promises";
13609
- import { join as join15 } from "path";
14358
+ import { join as join17 } from "path";
13610
14359
  var AUTO_UPDATE_STATE_FILE = "auto-update.json";
13611
14360
  var AUTO_UPDATE_LOG_FILE = "auto-update.log";
13612
14361
  function createAutoUpdateController(dependencies = {}) {
@@ -13621,7 +14370,7 @@ function createAutoUpdateController(dependencies = {}) {
13621
14370
  const args = resolveUpdateArgs(options.manager);
13622
14371
  const aisnitchHomePath = getAISnitchHomePath(pathOptions);
13623
14372
  await mkdir4(aisnitchHomePath, { recursive: true });
13624
- const logFilePath = join15(aisnitchHomePath, AUTO_UPDATE_LOG_FILE);
14373
+ const logFilePath = join17(aisnitchHomePath, AUTO_UPDATE_LOG_FILE);
13625
14374
  const startedAt = now().toISOString();
13626
14375
  await writeAutoUpdateState(
13627
14376
  {
@@ -13809,7 +14558,7 @@ function resolveUpdateArgs(manager) {
13809
14558
  async function readAutoUpdateState(options) {
13810
14559
  const statePath = getAutoUpdateStatePath(options);
13811
14560
  try {
13812
- const rawJson = await readFile13(statePath, "utf8");
14561
+ const rawJson = await readFile14(statePath, "utf8");
13813
14562
  return JSON.parse(rawJson);
13814
14563
  } catch (error) {
13815
14564
  if (error instanceof Error && "code" in error && error.code === "ENOENT") {
@@ -13829,7 +14578,7 @@ async function writeAutoUpdateState(state, options) {
13829
14578
  );
13830
14579
  }
13831
14580
  function getAutoUpdateStatePath(options) {
13832
- return join15(getAISnitchHomePath(options), AUTO_UPDATE_STATE_FILE);
14581
+ return join17(getAISnitchHomePath(options), AUTO_UPDATE_STATE_FILE);
13833
14582
  }
13834
14583
  function toPathOptions(options) {
13835
14584
  return {
@@ -14020,7 +14769,7 @@ function isRecord13(value) {
14020
14769
  }
14021
14770
 
14022
14771
  // src/cli/runtime.ts
14023
- var execFile14 = promisify14(execFileCallback14);
14772
+ var execFile15 = promisify15(execFileCallback14);
14024
14773
  var DAEMON_READY_TIMEOUT_MS = 4e3;
14025
14774
  var DAEMON_READY_POLL_INTERVAL_MS = 100;
14026
14775
  var DAEMON_STOP_TIMEOUT_MS = 4e3;
@@ -14036,7 +14785,7 @@ function createCliRuntime(dependencies = {}) {
14036
14785
  spawn: spawnImplementation
14037
14786
  });
14038
14787
  const execFileImplementation = dependencies.execFile ?? (async (file, args) => {
14039
- return await execFile14(file, [...args], {
14788
+ return await execFile15(file, [...args], {
14040
14789
  encoding: "utf8"
14041
14790
  });
14042
14791
  });
@@ -14211,7 +14960,7 @@ function createCliRuntime(dependencies = {}) {
14211
14960
  }
14212
14961
  async function readDaemonStartupFailure(pathOptions) {
14213
14962
  try {
14214
- const daemonLog = await readFile14(getDaemonLogPath(pathOptions), "utf8");
14963
+ const daemonLog = await readFile15(getDaemonLogPath(pathOptions), "utf8");
14215
14964
  const logLines = daemonLog.split(/\r?\n/u).map((line) => line.trim()).filter((line) => line.length > 0);
14216
14965
  const lastLine = logLines.at(-1);
14217
14966
  if (!lastLine) {
@@ -14309,22 +15058,35 @@ function createCliRuntime(dependencies = {}) {
14309
15058
  return;
14310
15059
  }
14311
15060
  shuttingDown = true;
14312
- try {
14313
- await pipeline.stop();
14314
- } finally {
14315
- if (daemonMode) {
14316
- const daemonPathOptions = toPathOptions2(options);
15061
+ const shutdownTimeouts = {
15062
+ adapterRegistry: DEFAULT_TIMEOUTS.adapterShutdown,
15063
+ httpReceiver: DEFAULT_TIMEOUTS.httpRequest,
15064
+ udsServer: DEFAULT_TIMEOUTS.fileOperation,
15065
+ wsServer: DEFAULT_TIMEOUTS.wsConnection,
15066
+ cleanupFns: 1e3
15067
+ };
15068
+ const components = {
15069
+ adapterRegistry: pipeline.getAdapterRegistry(),
15070
+ httpReceiver: pipeline.getHttpReceiver(),
15071
+ udsServer: pipeline.getUdsServer(),
15072
+ wsServer: pipeline.getWsServer(),
15073
+ eventBus: pipeline.getEventBus(),
15074
+ cleanupFns: daemonMode ? [async () => {
14317
15075
  await Promise.all([
14318
- removePid(daemonPathOptions),
14319
- removeDaemonState(daemonPathOptions)
15076
+ removePid(toPathOptions2(options)),
15077
+ removeDaemonState(toPathOptions2(options))
14320
15078
  ]);
14321
- }
14322
- }
14323
- if (!daemonMode) {
14324
- output.stdout(`AISnitch stopped after ${signal}.
15079
+ }] : []
15080
+ };
15081
+ try {
15082
+ await shutdownInOrder(components, shutdownTimeouts, "pipeline");
15083
+ } finally {
15084
+ if (!daemonMode) {
15085
+ output.stdout(`AISnitch stopped after ${signal}.
14325
15086
  `);
15087
+ }
15088
+ process.exit(exitCode);
14326
15089
  }
14327
- process.exit(exitCode);
14328
15090
  };
14329
15091
  if (daemonMode) {
14330
15092
  process.once("SIGTERM", () => {
@@ -14581,7 +15343,7 @@ function createCliRuntime(dependencies = {}) {
14581
15343
  }
14582
15344
  const { config } = await loadEffectiveConfig(options);
14583
15345
  setLoggerLevel(getForegroundSafeLogLevel(config.logLevel, false));
14584
- const ephemeralHomeDirectory = await mkdtemp(join16(tmpdir(), "aisnitch-mock-"));
15346
+ const ephemeralHomeDirectory = await mkdtemp(join18(tmpdir(), "aisnitch-mock-"));
14585
15347
  const ephemeralPipeline = new Pipeline();
14586
15348
  const status2 = await ephemeralPipeline.start({
14587
15349
  config: {
@@ -14665,7 +15427,7 @@ function createCliRuntime(dependencies = {}) {
14665
15427
  } else {
14666
15428
  const { config } = await loadEffectiveConfig(options);
14667
15429
  setLoggerLevel(getForegroundSafeLogLevel(config.logLevel, false));
14668
- ephemeralHomeDirectory = await mkdtemp(join16(tmpdir(), "aisnitch-wrap-"));
15430
+ ephemeralHomeDirectory = await mkdtemp(join18(tmpdir(), "aisnitch-wrap-"));
14669
15431
  ephemeralPipeline = new Pipeline();
14670
15432
  await ephemeralPipeline.start({
14671
15433
  config: {
@@ -14740,7 +15502,7 @@ function createCliRuntime(dependencies = {}) {
14740
15502
  },
14741
15503
  pid: process.ppid > 1 ? process.ppid : void 0,
14742
15504
  source: "aisnitch://adapters/aider/notifications-command",
14743
- transcriptPath: join16(process.cwd(), ".aider.chat.history.md"),
15505
+ transcriptPath: join18(process.cwd(), ".aider.chat.history.md"),
14744
15506
  type: "agent.idle"
14745
15507
  }),
14746
15508
  headers: {
@@ -14941,7 +15703,7 @@ function joinSocketPath(pathOptions) {
14941
15703
  }
14942
15704
  function resolveCliEntryPath() {
14943
15705
  const cliEntryPath = process.argv[1];
14944
- if (!cliEntryPath || basename11(cliEntryPath).length === 0) {
15706
+ if (!cliEntryPath || basename12(cliEntryPath).length === 0) {
14945
15707
  throw new Error("Unable to resolve the AISnitch CLI entry path.");
14946
15708
  }
14947
15709
  return cliEntryPath;