acp-devtools 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -5,9 +5,16 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __getProtoOf = Object.getPrototypeOf;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __esm = (fn, res) => function __init() {
9
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
10
+ };
8
11
  var __commonJS = (cb, mod) => function __require() {
9
12
  return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
10
13
  };
14
+ var __export = (target, all) => {
15
+ for (var name in all)
16
+ __defProp(target, name, { get: all[name], enumerable: true });
17
+ };
11
18
  var __copyProps = (to, from, except, desc) => {
12
19
  if (from && typeof from === "object" || typeof from === "function") {
13
20
  for (let key of __getOwnPropNames(from))
@@ -25,6 +32,124 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
25
32
  mod
26
33
  ));
27
34
 
35
+ // ../core/dist/acp/types.js
36
+ var init_types = __esm({
37
+ "../core/dist/acp/types.js"() {
38
+ "use strict";
39
+ }
40
+ });
41
+
42
+ // ../core/dist/acp/parser.js
43
+ function isPlainObject(value) {
44
+ return typeof value === "object" && value !== null && !Array.isArray(value);
45
+ }
46
+ function classify(payload) {
47
+ if ("method" in payload && "id" in payload) {
48
+ const req = payload;
49
+ return { kind: "request", method: req.method, rpcId: req.id };
50
+ }
51
+ if ("method" in payload) {
52
+ const note = payload;
53
+ return { kind: "notification", method: note.method };
54
+ }
55
+ if ("error" in payload) {
56
+ const err = payload;
57
+ return { kind: "error", rpcId: err.id ?? null };
58
+ }
59
+ if ("result" in payload) {
60
+ const ok = payload;
61
+ return { kind: "response", rpcId: ok.id ?? null };
62
+ }
63
+ return { kind: "unknown" };
64
+ }
65
+ function parseFrame(raw) {
66
+ let json;
67
+ try {
68
+ json = JSON.parse(raw);
69
+ } catch (err) {
70
+ const message = err instanceof Error ? err.message : String(err);
71
+ return { raw, payload: null, kind: "unknown", parseError: `invalid JSON: ${message}` };
72
+ }
73
+ if (!isPlainObject(json) || json.jsonrpc !== "2.0") {
74
+ return { raw, payload: null, kind: "unknown", parseError: "not a JSON-RPC 2.0 message" };
75
+ }
76
+ const payload = json;
77
+ return { raw, payload, ...classify(payload) };
78
+ }
79
+ var LineFramer;
80
+ var init_parser = __esm({
81
+ "../core/dist/acp/parser.js"() {
82
+ "use strict";
83
+ LineFramer = class {
84
+ buffer = "";
85
+ /** Push a chunk; returns zero or more complete frames (without the trailing `\n`). */
86
+ feed(chunk) {
87
+ this.buffer += typeof chunk === "string" ? chunk : chunk.toString("utf8");
88
+ const lines = [];
89
+ let nl = this.buffer.indexOf("\n");
90
+ while (nl >= 0) {
91
+ let line = this.buffer.slice(0, nl);
92
+ this.buffer = this.buffer.slice(nl + 1);
93
+ if (line.endsWith("\r"))
94
+ line = line.slice(0, -1);
95
+ if (line.length > 0)
96
+ lines.push(line);
97
+ nl = this.buffer.indexOf("\n");
98
+ }
99
+ return lines;
100
+ }
101
+ /** Return and discard any unterminated trailing data. */
102
+ flush() {
103
+ if (this.buffer.length === 0)
104
+ return null;
105
+ const remaining = this.buffer;
106
+ this.buffer = "";
107
+ return remaining.length > 0 ? remaining : null;
108
+ }
109
+ };
110
+ }
111
+ });
112
+
113
+ // ../core/dist/acp/text.js
114
+ function extractTextPreview(m) {
115
+ if (!m.payload || typeof m.payload !== "object")
116
+ return null;
117
+ const params = m.payload.params;
118
+ if (!params || typeof params !== "object")
119
+ return null;
120
+ if (m.method === "session/prompt") {
121
+ const blocks = params.prompt;
122
+ if (!Array.isArray(blocks))
123
+ return null;
124
+ const parts = [];
125
+ for (const block of blocks) {
126
+ if (block?.type === "text" && typeof block.text === "string") {
127
+ parts.push(block.text);
128
+ }
129
+ }
130
+ const joined = parts.join(" ").trim();
131
+ return joined.length > 0 ? joined : null;
132
+ }
133
+ if (m.method === "session/update") {
134
+ const update = params.update;
135
+ if (!update)
136
+ return null;
137
+ const text = update.content?.text ?? update.text;
138
+ if (typeof text === "string" && text.length > 0)
139
+ return text;
140
+ return null;
141
+ }
142
+ return null;
143
+ }
144
+ function isUserPrompt(m) {
145
+ return m.method === "session/prompt" && m.kind === "request";
146
+ }
147
+ var init_text = __esm({
148
+ "../core/dist/acp/text.js"() {
149
+ "use strict";
150
+ }
151
+ });
152
+
28
153
  // ../core/node_modules/ajv/dist/compile/codegen/code.js
29
154
  var require_code = __commonJS({
30
155
  "../core/node_modules/ajv/dist/compile/codegen/code.js"(exports) {
@@ -7139,111 +7264,7 @@ var require__ = __commonJS({
7139
7264
  }
7140
7265
  });
7141
7266
 
7142
- // ../core/dist/acp/parser.js
7143
- var LineFramer = class {
7144
- buffer = "";
7145
- /** Push a chunk; returns zero or more complete frames (without the trailing `\n`). */
7146
- feed(chunk) {
7147
- this.buffer += typeof chunk === "string" ? chunk : chunk.toString("utf8");
7148
- const lines = [];
7149
- let nl = this.buffer.indexOf("\n");
7150
- while (nl >= 0) {
7151
- let line = this.buffer.slice(0, nl);
7152
- this.buffer = this.buffer.slice(nl + 1);
7153
- if (line.endsWith("\r"))
7154
- line = line.slice(0, -1);
7155
- if (line.length > 0)
7156
- lines.push(line);
7157
- nl = this.buffer.indexOf("\n");
7158
- }
7159
- return lines;
7160
- }
7161
- /** Return and discard any unterminated trailing data. */
7162
- flush() {
7163
- if (this.buffer.length === 0)
7164
- return null;
7165
- const remaining = this.buffer;
7166
- this.buffer = "";
7167
- return remaining.length > 0 ? remaining : null;
7168
- }
7169
- };
7170
- function isPlainObject(value) {
7171
- return typeof value === "object" && value !== null && !Array.isArray(value);
7172
- }
7173
- function classify(payload) {
7174
- if ("method" in payload && "id" in payload) {
7175
- const req = payload;
7176
- return { kind: "request", method: req.method, rpcId: req.id };
7177
- }
7178
- if ("method" in payload) {
7179
- const note = payload;
7180
- return { kind: "notification", method: note.method };
7181
- }
7182
- if ("error" in payload) {
7183
- const err = payload;
7184
- return { kind: "error", rpcId: err.id ?? null };
7185
- }
7186
- if ("result" in payload) {
7187
- const ok = payload;
7188
- return { kind: "response", rpcId: ok.id ?? null };
7189
- }
7190
- return { kind: "unknown" };
7191
- }
7192
- function parseFrame(raw) {
7193
- let json;
7194
- try {
7195
- json = JSON.parse(raw);
7196
- } catch (err) {
7197
- const message = err instanceof Error ? err.message : String(err);
7198
- return { raw, payload: null, kind: "unknown", parseError: `invalid JSON: ${message}` };
7199
- }
7200
- if (!isPlainObject(json) || json.jsonrpc !== "2.0") {
7201
- return { raw, payload: null, kind: "unknown", parseError: "not a JSON-RPC 2.0 message" };
7202
- }
7203
- const payload = json;
7204
- return { raw, payload, ...classify(payload) };
7205
- }
7206
-
7207
- // ../core/dist/acp/text.js
7208
- function extractTextPreview(m) {
7209
- if (!m.payload || typeof m.payload !== "object")
7210
- return null;
7211
- const params = m.payload.params;
7212
- if (!params || typeof params !== "object")
7213
- return null;
7214
- if (m.method === "session/prompt") {
7215
- const blocks = params.prompt;
7216
- if (!Array.isArray(blocks))
7217
- return null;
7218
- const parts = [];
7219
- for (const block of blocks) {
7220
- if (block?.type === "text" && typeof block.text === "string") {
7221
- parts.push(block.text);
7222
- }
7223
- }
7224
- const joined = parts.join(" ").trim();
7225
- return joined.length > 0 ? joined : null;
7226
- }
7227
- if (m.method === "session/update") {
7228
- const update = params.update;
7229
- if (!update)
7230
- return null;
7231
- const text = update.content?.text ?? update.text;
7232
- if (typeof text === "string" && text.length > 0)
7233
- return text;
7234
- return null;
7235
- }
7236
- return null;
7237
- }
7238
-
7239
- // ../core/dist/acp/validate.js
7240
- import { createRequire } from "module";
7241
-
7242
7267
  // ../core/dist/acp/validate-factory.js
7243
- var import__ = __toESM(require__(), 1);
7244
- var ajvModule = import__.default;
7245
- var Ajv2020 = ajvModule.default ?? ajvModule;
7246
- var SCHEMA_ID = "acp";
7247
7268
  function toError(e) {
7248
7269
  const v = {
7249
7270
  path: e.instancePath || "/",
@@ -7326,13 +7347,31 @@ function createAcpValidator(schema3) {
7326
7347
  }
7327
7348
  return { validateAcpMessage: validateAcpMessage2, knownAcpMethods: knownAcpMethods2 };
7328
7349
  }
7350
+ var import__, ajvModule, Ajv2020, SCHEMA_ID;
7351
+ var init_validate_factory = __esm({
7352
+ "../core/dist/acp/validate-factory.js"() {
7353
+ "use strict";
7354
+ import__ = __toESM(require__(), 1);
7355
+ ajvModule = import__.default;
7356
+ Ajv2020 = ajvModule.default ?? ajvModule;
7357
+ SCHEMA_ID = "acp";
7358
+ }
7359
+ });
7329
7360
 
7330
7361
  // ../core/dist/acp/validate.js
7331
- var require2 = createRequire(import.meta.url);
7332
- var schema = require2("@agentclientprotocol/sdk/schema/schema.json");
7333
- var validator = createAcpValidator(schema);
7334
- var validateAcpMessage = validator.validateAcpMessage;
7335
- var knownAcpMethods = validator.knownAcpMethods;
7362
+ import { createRequire } from "module";
7363
+ var require2, schema, validator, validateAcpMessage, knownAcpMethods;
7364
+ var init_validate = __esm({
7365
+ "../core/dist/acp/validate.js"() {
7366
+ "use strict";
7367
+ init_validate_factory();
7368
+ require2 = createRequire(import.meta.url);
7369
+ schema = require2("@agentclientprotocol/sdk/schema/schema.json");
7370
+ validator = createAcpValidator(schema);
7371
+ validateAcpMessage = validator.validateAcpMessage;
7372
+ knownAcpMethods = validator.knownAcpMethods;
7373
+ }
7374
+ });
7336
7375
 
7337
7376
  // ../core/dist/acp/session-metadata.js
7338
7377
  function asRecord(value) {
@@ -7517,6 +7556,11 @@ function extractSessionMetadata(messages) {
7517
7556
  extensions: extractExtensions(initReq)
7518
7557
  };
7519
7558
  }
7559
+ var init_session_metadata = __esm({
7560
+ "../core/dist/acp/session-metadata.js"() {
7561
+ "use strict";
7562
+ }
7563
+ });
7520
7564
 
7521
7565
  // ../core/dist/acp/method-stats.js
7522
7566
  function buildPairIndex(messages) {
@@ -7610,9 +7654,18 @@ function percentile(sortedAsc, p) {
7610
7654
  return a;
7611
7655
  return a + (b - a) * (rank - lo);
7612
7656
  }
7657
+ function mean(values) {
7658
+ if (values.length === 0)
7659
+ return 0;
7660
+ return values.reduce((acc, x) => acc + x, 0) / values.length;
7661
+ }
7662
+ var init_method_stats = __esm({
7663
+ "../core/dist/acp/method-stats.js"() {
7664
+ "use strict";
7665
+ }
7666
+ });
7613
7667
 
7614
7668
  // ../core/dist/acp/session-diff.js
7615
- var DEFAULT_MAX_CHANGES = 100;
7616
7669
  function buildSessionDiff(a, b, options = {}) {
7617
7670
  const maxChanges = options.maxChangesPerRow ?? DEFAULT_MAX_CHANGES;
7618
7671
  const sigA = signatures(a);
@@ -7789,6 +7842,14 @@ function deepDiff(a, b, path, out, max) {
7789
7842
  function leafEqual(a, b) {
7790
7843
  return Object.is(a, b);
7791
7844
  }
7845
+ var DEFAULT_MAX_CHANGES;
7846
+ var init_session_diff = __esm({
7847
+ "../core/dist/acp/session-diff.js"() {
7848
+ "use strict";
7849
+ init_method_stats();
7850
+ DEFAULT_MAX_CHANGES = 100;
7851
+ }
7852
+ });
7792
7853
 
7793
7854
  // ../core/dist/acp/session-compare.js
7794
7855
  function comparableMetadata(m) {
@@ -7840,17 +7901,16 @@ function deltaOf(a, b) {
7840
7901
  return null;
7841
7902
  return b - a;
7842
7903
  }
7904
+ var init_session_compare = __esm({
7905
+ "../core/dist/acp/session-compare.js"() {
7906
+ "use strict";
7907
+ init_session_diff();
7908
+ init_method_stats();
7909
+ init_session_metadata();
7910
+ }
7911
+ });
7843
7912
 
7844
7913
  // ../core/dist/acp/perf-insights.js
7845
- var DEFAULTS = {
7846
- minSamplesForTail: 3,
7847
- longTailRatio: 5,
7848
- minBusiestCount: 50,
7849
- minBusiestRatio: 2.5,
7850
- minHotspotShare: 0.4,
7851
- minSamplesForOutlier: 5,
7852
- outlierRatio: 3
7853
- };
7854
7914
  function buildPerformanceInsights(messages, perMethod, cfg = {}) {
7855
7915
  const config = { ...DEFAULTS, ...cfg };
7856
7916
  const out = [];
@@ -7945,9 +8005,23 @@ function formatMs(ms) {
7945
8005
  const s = Math.round(ms % 6e4 / 1e3);
7946
8006
  return `${m}m${s}s`;
7947
8007
  }
8008
+ var DEFAULTS;
8009
+ var init_perf_insights = __esm({
8010
+ "../core/dist/acp/perf-insights.js"() {
8011
+ "use strict";
8012
+ DEFAULTS = {
8013
+ minSamplesForTail: 3,
8014
+ longTailRatio: 5,
8015
+ minBusiestCount: 50,
8016
+ minBusiestRatio: 2.5,
8017
+ minHotspotShare: 0.4,
8018
+ minSamplesForOutlier: 5,
8019
+ outlierRatio: 3
8020
+ };
8021
+ }
8022
+ });
7948
8023
 
7949
8024
  // ../core/dist/acp/sparkline.js
7950
- var BLOCKS = ["\u2581", "\u2582", "\u2583", "\u2584", "\u2585", "\u2586", "\u2587", "\u2588"];
7951
8025
  function sampleEvenly(values, targetCount) {
7952
8026
  if (values.length <= targetCount)
7953
8027
  return values;
@@ -7970,9 +8044,13 @@ function asciiSparkline(values, targetWidth = 8) {
7970
8044
  return BLOCKS[idx];
7971
8045
  }).join("");
7972
8046
  }
7973
-
7974
- // ../core/dist/acp/spec-decoder.js
7975
- import { createRequire as createRequire2 } from "module";
8047
+ var BLOCKS;
8048
+ var init_sparkline = __esm({
8049
+ "../core/dist/acp/sparkline.js"() {
8050
+ "use strict";
8051
+ BLOCKS = ["\u2581", "\u2582", "\u2583", "\u2584", "\u2585", "\u2586", "\u2587", "\u2588"];
8052
+ }
8053
+ });
7976
8054
 
7977
8055
  // ../core/dist/acp/spec-decoder-factory.js
7978
8056
  function createSpecDecoder(schema3) {
@@ -8214,56 +8292,126 @@ function createSpecDecoder(schema3) {
8214
8292
  }
8215
8293
  return { resolveForMessage, knownMethods };
8216
8294
  }
8295
+ var init_spec_decoder_factory = __esm({
8296
+ "../core/dist/acp/spec-decoder-factory.js"() {
8297
+ "use strict";
8298
+ }
8299
+ });
8217
8300
 
8218
8301
  // ../core/dist/acp/spec-decoder.js
8219
- var require3 = createRequire2(import.meta.url);
8220
- var schema2 = require3("@agentclientprotocol/sdk/schema/schema.json");
8221
- var decoder = createSpecDecoder(schema2);
8222
- var resolveSpecForMessage = decoder.resolveForMessage;
8223
- var knownAcpSpecMethods = decoder.knownMethods;
8302
+ import { createRequire as createRequire2 } from "module";
8303
+ var require3, schema2, decoder, resolveSpecForMessage, knownAcpSpecMethods;
8304
+ var init_spec_decoder = __esm({
8305
+ "../core/dist/acp/spec-decoder.js"() {
8306
+ "use strict";
8307
+ init_spec_decoder_factory();
8308
+ require3 = createRequire2(import.meta.url);
8309
+ schema2 = require3("@agentclientprotocol/sdk/schema/schema.json");
8310
+ decoder = createSpecDecoder(schema2);
8311
+ resolveSpecForMessage = decoder.resolveForMessage;
8312
+ knownAcpSpecMethods = decoder.knownMethods;
8313
+ }
8314
+ });
8315
+
8316
+ // ../core/dist/acp/timeline-layout.js
8317
+ function buildTimelineLayout(messages) {
8318
+ const empty = {
8319
+ events: [],
8320
+ startTs: 0,
8321
+ endTs: 0,
8322
+ durationMs: 0,
8323
+ laneCounts: { "editor-req": 0, "agent-req": 0, notification: 0 }
8324
+ };
8325
+ if (messages.length === 0)
8326
+ return empty;
8327
+ const pairs = buildPairIndex(messages);
8328
+ const bySeq = /* @__PURE__ */ new Map();
8329
+ for (const m of messages)
8330
+ bySeq.set(m.seq, m);
8331
+ let startTs = Infinity;
8332
+ let endTs = -Infinity;
8333
+ const events = [];
8334
+ const laneCounts = {
8335
+ "editor-req": 0,
8336
+ "agent-req": 0,
8337
+ notification: 0
8338
+ };
8339
+ for (const m of messages) {
8340
+ if (m.timestamp < startTs)
8341
+ startTs = m.timestamp;
8342
+ if (m.timestamp > endTs)
8343
+ endTs = m.timestamp;
8344
+ if (m.kind === "request") {
8345
+ const lane = m.direction === "editor-to-agent" ? "editor-req" : "agent-req";
8346
+ const pair = pairs.get(m.seq);
8347
+ const pairedMsg = pair ? bySeq.get(pair.pairSeq) : void 0;
8348
+ const erroredOut = pairedMsg?.kind === "error";
8349
+ const evtEnd = pairedMsg ? pairedMsg.timestamp : m.timestamp;
8350
+ if (evtEnd > endTs)
8351
+ endTs = evtEnd;
8352
+ events.push({
8353
+ seq: m.seq,
8354
+ startTs: m.timestamp,
8355
+ endTs: evtEnd,
8356
+ lane,
8357
+ method: m.method ?? null,
8358
+ kind: m.kind,
8359
+ erroredOut,
8360
+ pairedSeq: pairedMsg ? pairedMsg.seq : null
8361
+ });
8362
+ laneCounts[lane] += 1;
8363
+ } else if (m.kind === "notification") {
8364
+ events.push({
8365
+ seq: m.seq,
8366
+ startTs: m.timestamp,
8367
+ endTs: m.timestamp,
8368
+ lane: "notification",
8369
+ method: m.method ?? null,
8370
+ kind: m.kind,
8371
+ erroredOut: false,
8372
+ pairedSeq: null
8373
+ });
8374
+ laneCounts.notification += 1;
8375
+ }
8376
+ }
8377
+ if (!Number.isFinite(startTs) || !Number.isFinite(endTs))
8378
+ return empty;
8379
+ return {
8380
+ events,
8381
+ startTs,
8382
+ endTs,
8383
+ durationMs: Math.max(0, endTs - startTs),
8384
+ laneCounts
8385
+ };
8386
+ }
8387
+ var init_timeline_layout = __esm({
8388
+ "../core/dist/acp/timeline-layout.js"() {
8389
+ "use strict";
8390
+ init_method_stats();
8391
+ }
8392
+ });
8224
8393
 
8225
8394
  // ../core/dist/acp/index.js
8226
8395
  import { AGENT_METHODS, CLIENT_METHODS, PROTOCOL_VERSION } from "@agentclientprotocol/sdk";
8396
+ var init_acp = __esm({
8397
+ "../core/dist/acp/index.js"() {
8398
+ "use strict";
8399
+ init_types();
8400
+ init_parser();
8401
+ init_text();
8402
+ init_validate();
8403
+ init_session_metadata();
8404
+ init_method_stats();
8405
+ init_session_diff();
8406
+ init_session_compare();
8407
+ init_perf_insights();
8408
+ init_sparkline();
8409
+ init_spec_decoder();
8410
+ init_timeline_layout();
8411
+ }
8412
+ });
8227
8413
 
8228
8414
  // ../core/dist/agents/registry.js
8229
- var AGENT_REGISTRY = {
8230
- "claude-code": {
8231
- shortName: "claude-code",
8232
- displayName: "Claude Code",
8233
- description: "Anthropic Claude Code via @agentclientprotocol/claude-agent-acp",
8234
- command: "npx",
8235
- args: ["-y", "@agentclientprotocol/claude-agent-acp"],
8236
- aliases: [
8237
- // The original Zed-scoped package is deprecated as of late 2026,
8238
- // but still very common in existing captures + IDE configs.
8239
- ["npx", "-y", "@zed-industries/claude-code-acp"]
8240
- ]
8241
- },
8242
- codex: {
8243
- shortName: "codex",
8244
- displayName: "Codex",
8245
- description: "OpenAI Codex via @zed-industries/codex-acp",
8246
- command: "npx",
8247
- args: ["-y", "@zed-industries/codex-acp"]
8248
- },
8249
- goose: {
8250
- shortName: "goose",
8251
- displayName: "Goose",
8252
- description: "Block Goose \u2014 install separately, then this runs `goose acp`",
8253
- command: "goose",
8254
- args: ["acp"],
8255
- requiresExternalInstall: true
8256
- },
8257
- opencode: {
8258
- shortName: "opencode",
8259
- displayName: "OpenCode",
8260
- description: "SST OpenCode \u2014 install via opencode.ai/install, then `opencode acp`",
8261
- command: "opencode",
8262
- args: ["acp"],
8263
- requiresExternalInstall: true
8264
- }
8265
- };
8266
- var DEFAULT_AGENT = "claude-code";
8267
8415
  function resolveAgent(shortName) {
8268
8416
  const agent = AGENT_REGISTRY[shortName];
8269
8417
  if (!agent) {
@@ -8278,9 +8426,77 @@ function isAgentShortcut(name) {
8278
8426
  function listAgents() {
8279
8427
  return Object.values(AGENT_REGISTRY).slice();
8280
8428
  }
8429
+ function detectAgentShortcut(agentCommand) {
8430
+ const trimmed = agentCommand.trim();
8431
+ if (trimmed.length === 0)
8432
+ return null;
8433
+ for (const def of Object.values(AGENT_REGISTRY)) {
8434
+ const variants = [
8435
+ [def.command, ...def.args],
8436
+ ...def.aliases ?? []
8437
+ ];
8438
+ for (const variant of variants) {
8439
+ const exact = variant.join(" ");
8440
+ if (trimmed === exact)
8441
+ return def;
8442
+ if (trimmed.startsWith(exact + " "))
8443
+ return def;
8444
+ }
8445
+ }
8446
+ return null;
8447
+ }
8448
+ var AGENT_REGISTRY, DEFAULT_AGENT;
8449
+ var init_registry = __esm({
8450
+ "../core/dist/agents/registry.js"() {
8451
+ "use strict";
8452
+ AGENT_REGISTRY = {
8453
+ "claude-code": {
8454
+ shortName: "claude-code",
8455
+ displayName: "Claude Code",
8456
+ description: "Anthropic Claude Code via @agentclientprotocol/claude-agent-acp",
8457
+ command: "npx",
8458
+ args: ["-y", "@agentclientprotocol/claude-agent-acp"],
8459
+ aliases: [
8460
+ // The original Zed-scoped package is deprecated as of late 2026,
8461
+ // but still very common in existing captures + IDE configs.
8462
+ ["npx", "-y", "@zed-industries/claude-code-acp"]
8463
+ ]
8464
+ },
8465
+ codex: {
8466
+ shortName: "codex",
8467
+ displayName: "Codex",
8468
+ description: "OpenAI Codex via @zed-industries/codex-acp",
8469
+ command: "npx",
8470
+ args: ["-y", "@zed-industries/codex-acp"]
8471
+ },
8472
+ goose: {
8473
+ shortName: "goose",
8474
+ displayName: "Goose",
8475
+ description: "Block Goose \u2014 install separately, then this runs `goose acp`",
8476
+ command: "goose",
8477
+ args: ["acp"],
8478
+ requiresExternalInstall: true
8479
+ },
8480
+ opencode: {
8481
+ shortName: "opencode",
8482
+ displayName: "OpenCode",
8483
+ description: "SST OpenCode \u2014 install via opencode.ai/install, then `opencode acp`",
8484
+ command: "opencode",
8485
+ args: ["acp"],
8486
+ requiresExternalInstall: true
8487
+ }
8488
+ };
8489
+ DEFAULT_AGENT = "claude-code";
8490
+ }
8491
+ });
8281
8492
 
8282
- // ../core/dist/proxy/proxy.js
8283
- import { EventEmitter } from "events";
8493
+ // ../core/dist/agents/index.js
8494
+ var init_agents = __esm({
8495
+ "../core/dist/agents/index.js"() {
8496
+ "use strict";
8497
+ init_registry();
8498
+ }
8499
+ });
8284
8500
 
8285
8501
  // ../core/dist/proxy/subprocess.js
8286
8502
  import { spawn } from "child_process";
@@ -8304,164 +8520,101 @@ function spawnAgent(options) {
8304
8520
  kill: (signal = "SIGTERM") => child.kill(signal)
8305
8521
  };
8306
8522
  }
8523
+ var init_subprocess = __esm({
8524
+ "../core/dist/proxy/subprocess.js"() {
8525
+ "use strict";
8526
+ }
8527
+ });
8307
8528
 
8308
8529
  // ../core/dist/proxy/proxy.js
8309
- var AcpProxy = class extends EventEmitter {
8310
- options;
8311
- agent = null;
8312
- seq = 0;
8313
- editorFramer = new LineFramer();
8314
- agentFramer = new LineFramer();
8315
- constructor(options) {
8316
- super();
8317
- this.options = options;
8318
- }
8319
- on(event, listener) {
8320
- return super.on(event, listener);
8321
- }
8322
- async start() {
8323
- if (this.agent)
8324
- throw new Error("proxy already started");
8325
- const agent = spawnAgent(this.options);
8326
- this.agent = agent;
8327
- this.emit("started", { pid: agent.pid });
8328
- const editorIn = this.options.editorInput ?? process.stdin;
8329
- const editorOut = this.options.editorOutput ?? process.stdout;
8330
- const agentErr = this.options.agentErrorOutput === void 0 ? process.stderr : this.options.agentErrorOutput;
8331
- editorIn.on("data", (chunk) => {
8332
- this.capture("editor-to-agent", chunk);
8333
- agent.stdin.write(chunk);
8334
- });
8335
- editorIn.once("end", () => {
8336
- this.emit("editor-end");
8337
- agent.stdin.end();
8338
- });
8339
- editorIn.on("error", (err) => this.emit("error", err));
8340
- agent.stdout.on("data", (chunk) => {
8341
- this.capture("agent-to-editor", chunk);
8342
- editorOut.write(chunk);
8343
- });
8344
- agent.stdout.on("error", (err) => this.emit("error", err));
8345
- if (agentErr) {
8346
- agent.stderr.on("data", (chunk) => {
8347
- this.emit("agent-stderr", chunk);
8348
- agentErr.write(chunk);
8349
- });
8350
- }
8351
- agent.exited.then((info) => this.emit("agent-exit", info)).catch((err) => this.emit("error", err));
8352
- }
8353
- /** Wait for the underlying agent to exit. */
8354
- waitForExit() {
8355
- if (!this.agent)
8356
- throw new Error("proxy not started");
8357
- return this.agent.exited;
8358
- }
8359
- /** Send a signal to the agent. */
8360
- kill(signal = "SIGTERM") {
8361
- this.agent?.kill(signal);
8362
- }
8363
- capture(direction, chunk) {
8364
- const framer = direction === "editor-to-agent" ? this.editorFramer : this.agentFramer;
8365
- const frames = framer.feed(chunk);
8366
- for (const raw of frames) {
8367
- const parsed = parseFrame(raw);
8368
- const msg = {
8369
- seq: ++this.seq,
8370
- timestamp: Date.now(),
8371
- direction,
8372
- kind: parsed.kind,
8373
- raw,
8374
- payload: parsed.payload
8375
- };
8376
- if (parsed.method !== void 0)
8377
- msg.method = parsed.method;
8378
- if (parsed.rpcId !== void 0)
8379
- msg.rpcId = parsed.rpcId;
8380
- if (parsed.parseError !== void 0)
8381
- msg.parseError = parsed.parseError;
8382
- this.emit("message", msg);
8383
- }
8530
+ import { EventEmitter } from "events";
8531
+ var AcpProxy;
8532
+ var init_proxy = __esm({
8533
+ "../core/dist/proxy/proxy.js"() {
8534
+ "use strict";
8535
+ init_parser();
8536
+ init_subprocess();
8537
+ AcpProxy = class extends EventEmitter {
8538
+ options;
8539
+ agent = null;
8540
+ seq = 0;
8541
+ editorFramer = new LineFramer();
8542
+ agentFramer = new LineFramer();
8543
+ constructor(options) {
8544
+ super();
8545
+ this.options = options;
8546
+ }
8547
+ on(event, listener) {
8548
+ return super.on(event, listener);
8549
+ }
8550
+ async start() {
8551
+ if (this.agent)
8552
+ throw new Error("proxy already started");
8553
+ const agent = spawnAgent(this.options);
8554
+ this.agent = agent;
8555
+ this.emit("started", { pid: agent.pid });
8556
+ const editorIn = this.options.editorInput ?? process.stdin;
8557
+ const editorOut = this.options.editorOutput ?? process.stdout;
8558
+ const agentErr = this.options.agentErrorOutput === void 0 ? process.stderr : this.options.agentErrorOutput;
8559
+ editorIn.on("data", (chunk) => {
8560
+ this.capture("editor-to-agent", chunk);
8561
+ agent.stdin.write(chunk);
8562
+ });
8563
+ editorIn.once("end", () => {
8564
+ this.emit("editor-end");
8565
+ agent.stdin.end();
8566
+ });
8567
+ editorIn.on("error", (err) => this.emit("error", err));
8568
+ agent.stdout.on("data", (chunk) => {
8569
+ this.capture("agent-to-editor", chunk);
8570
+ editorOut.write(chunk);
8571
+ });
8572
+ agent.stdout.on("error", (err) => this.emit("error", err));
8573
+ if (agentErr) {
8574
+ agent.stderr.on("data", (chunk) => {
8575
+ this.emit("agent-stderr", chunk);
8576
+ agentErr.write(chunk);
8577
+ });
8578
+ }
8579
+ agent.exited.then((info) => this.emit("agent-exit", info)).catch((err) => this.emit("error", err));
8580
+ }
8581
+ /** Wait for the underlying agent to exit. */
8582
+ waitForExit() {
8583
+ if (!this.agent)
8584
+ throw new Error("proxy not started");
8585
+ return this.agent.exited;
8586
+ }
8587
+ /** Send a signal to the agent. */
8588
+ kill(signal = "SIGTERM") {
8589
+ this.agent?.kill(signal);
8590
+ }
8591
+ capture(direction, chunk) {
8592
+ const framer = direction === "editor-to-agent" ? this.editorFramer : this.agentFramer;
8593
+ const frames = framer.feed(chunk);
8594
+ for (const raw of frames) {
8595
+ const parsed = parseFrame(raw);
8596
+ const msg = {
8597
+ seq: ++this.seq,
8598
+ timestamp: Date.now(),
8599
+ direction,
8600
+ kind: parsed.kind,
8601
+ raw,
8602
+ payload: parsed.payload
8603
+ };
8604
+ if (parsed.method !== void 0)
8605
+ msg.method = parsed.method;
8606
+ if (parsed.rpcId !== void 0)
8607
+ msg.rpcId = parsed.rpcId;
8608
+ if (parsed.parseError !== void 0)
8609
+ msg.parseError = parsed.parseError;
8610
+ this.emit("message", msg);
8611
+ }
8612
+ }
8613
+ };
8384
8614
  }
8385
- };
8615
+ });
8386
8616
 
8387
8617
  // ../core/dist/proxy/playback.js
8388
- var OUR_DIRECTION_FOR_ROLE = {
8389
- // mock-agent emits agent→editor and waits for editor→agent
8390
- agent: "agent-to-editor",
8391
- editor: "editor-to-agent"
8392
- };
8393
- var PlaybackEngine = class {
8394
- messages;
8395
- pointer = 0;
8396
- scriptIdToRealId = /* @__PURE__ */ new Map();
8397
- ourDirection;
8398
- constructor(messages, role) {
8399
- this.messages = messages;
8400
- this.ourDirection = OUR_DIRECTION_FOR_ROLE[role];
8401
- }
8402
- /**
8403
- * Advance through the script until either we have a line to EMIT, we
8404
- * need to WAIT for the other side, or the script is DONE. Notifications
8405
- * on our side are emitted immediately (no waiting).
8406
- */
8407
- next() {
8408
- while (this.pointer < this.messages.length) {
8409
- const msg = this.messages[this.pointer];
8410
- if (msg.direction === this.ourDirection) {
8411
- const prev = this.pointer > 0 ? this.messages[this.pointer - 1] : null;
8412
- const deltaSincePrevMs = prev ? Math.max(0, msg.timestamp - prev.timestamp) : 0;
8413
- this.pointer += 1;
8414
- return {
8415
- kind: "emit",
8416
- line: this.buildOutbound(msg),
8417
- message: msg,
8418
- deltaSincePrevMs
8419
- };
8420
- }
8421
- return { kind: "wait", expected: msg };
8422
- }
8423
- return { kind: "done" };
8424
- }
8425
- /**
8426
- * Record that the other side sent something the engine was WAITing for.
8427
- * Advances past the matching script frame; remembers the rpc_id mapping
8428
- * so any later response we emit can carry the wire's actual id.
8429
- *
8430
- * Returns `true` when an expected frame was consumed, `false` when there
8431
- * was nothing to consume (script already done or our turn) — caller can
8432
- * decide whether the off-script input is an error or just gets dropped.
8433
- */
8434
- onIncoming(line) {
8435
- if (this.pointer >= this.messages.length)
8436
- return false;
8437
- const msg = this.messages[this.pointer];
8438
- if (msg.direction === this.ourDirection)
8439
- return false;
8440
- const realId = extractRpcId(line);
8441
- if (msg.rpcId !== void 0 && msg.rpcId !== null && realId !== void 0) {
8442
- this.scriptIdToRealId.set(String(msg.rpcId), realId);
8443
- }
8444
- this.pointer += 1;
8445
- return true;
8446
- }
8447
- /** For tests / status output. */
8448
- get position() {
8449
- return this.pointer;
8450
- }
8451
- get exhausted() {
8452
- return this.pointer >= this.messages.length;
8453
- }
8454
- buildOutbound(msg) {
8455
- if (msg.kind !== "response" && msg.kind !== "error")
8456
- return msg.raw;
8457
- if (msg.rpcId === void 0 || msg.rpcId === null)
8458
- return msg.raw;
8459
- const realId = this.scriptIdToRealId.get(String(msg.rpcId));
8460
- if (realId === void 0)
8461
- return msg.raw;
8462
- return substituteRpcId(msg, realId);
8463
- }
8464
- };
8465
8618
  function substituteRpcId(msg, realId) {
8466
8619
  if (!msg.payload)
8467
8620
  return msg.raw;
@@ -8478,47 +8631,103 @@ function extractRpcId(line) {
8478
8631
  return void 0;
8479
8632
  }
8480
8633
  }
8634
+ var OUR_DIRECTION_FOR_ROLE, PlaybackEngine;
8635
+ var init_playback = __esm({
8636
+ "../core/dist/proxy/playback.js"() {
8637
+ "use strict";
8638
+ OUR_DIRECTION_FOR_ROLE = {
8639
+ // mock-agent emits agent→editor and waits for editor→agent
8640
+ agent: "agent-to-editor",
8641
+ editor: "editor-to-agent"
8642
+ };
8643
+ PlaybackEngine = class {
8644
+ messages;
8645
+ pointer = 0;
8646
+ scriptIdToRealId = /* @__PURE__ */ new Map();
8647
+ ourDirection;
8648
+ constructor(messages, role) {
8649
+ this.messages = messages;
8650
+ this.ourDirection = OUR_DIRECTION_FOR_ROLE[role];
8651
+ }
8652
+ /**
8653
+ * Advance through the script until either we have a line to EMIT, we
8654
+ * need to WAIT for the other side, or the script is DONE. Notifications
8655
+ * on our side are emitted immediately (no waiting).
8656
+ */
8657
+ next() {
8658
+ while (this.pointer < this.messages.length) {
8659
+ const msg = this.messages[this.pointer];
8660
+ if (msg.direction === this.ourDirection) {
8661
+ const prev = this.pointer > 0 ? this.messages[this.pointer - 1] : null;
8662
+ const deltaSincePrevMs = prev ? Math.max(0, msg.timestamp - prev.timestamp) : 0;
8663
+ this.pointer += 1;
8664
+ return {
8665
+ kind: "emit",
8666
+ line: this.buildOutbound(msg),
8667
+ message: msg,
8668
+ deltaSincePrevMs
8669
+ };
8670
+ }
8671
+ return { kind: "wait", expected: msg };
8672
+ }
8673
+ return { kind: "done" };
8674
+ }
8675
+ /**
8676
+ * Record that the other side sent something the engine was WAITing for.
8677
+ * Advances past the matching script frame; remembers the rpc_id mapping
8678
+ * so any later response we emit can carry the wire's actual id.
8679
+ *
8680
+ * Returns `true` when an expected frame was consumed, `false` when there
8681
+ * was nothing to consume (script already done or our turn) — caller can
8682
+ * decide whether the off-script input is an error or just gets dropped.
8683
+ */
8684
+ onIncoming(line) {
8685
+ if (this.pointer >= this.messages.length)
8686
+ return false;
8687
+ const msg = this.messages[this.pointer];
8688
+ if (msg.direction === this.ourDirection)
8689
+ return false;
8690
+ const realId = extractRpcId(line);
8691
+ if (msg.rpcId !== void 0 && msg.rpcId !== null && realId !== void 0) {
8692
+ this.scriptIdToRealId.set(String(msg.rpcId), realId);
8693
+ }
8694
+ this.pointer += 1;
8695
+ return true;
8696
+ }
8697
+ /** For tests / status output. */
8698
+ get position() {
8699
+ return this.pointer;
8700
+ }
8701
+ get exhausted() {
8702
+ return this.pointer >= this.messages.length;
8703
+ }
8704
+ buildOutbound(msg) {
8705
+ if (msg.kind !== "response" && msg.kind !== "error")
8706
+ return msg.raw;
8707
+ if (msg.rpcId === void 0 || msg.rpcId === null)
8708
+ return msg.raw;
8709
+ const realId = this.scriptIdToRealId.get(String(msg.rpcId));
8710
+ if (realId === void 0)
8711
+ return msg.raw;
8712
+ return substituteRpcId(msg, realId);
8713
+ }
8714
+ };
8715
+ }
8716
+ });
8717
+
8718
+ // ../core/dist/proxy/index.js
8719
+ var init_proxy2 = __esm({
8720
+ "../core/dist/proxy/index.js"() {
8721
+ "use strict";
8722
+ init_proxy();
8723
+ init_subprocess();
8724
+ init_playback();
8725
+ }
8726
+ });
8481
8727
 
8482
8728
  // ../core/dist/storage/sqlite.js
8483
8729
  import { chmodSync, existsSync, statSync } from "fs";
8484
8730
  import Database from "better-sqlite3";
8485
- var SCHEMA_VERSION = 4;
8486
- var SCHEMA_SQL = `
8487
- CREATE TABLE IF NOT EXISTS sessions (
8488
- id INTEGER PRIMARY KEY AUTOINCREMENT,
8489
- name TEXT,
8490
- agent_command TEXT,
8491
- started_at INTEGER NOT NULL,
8492
- ended_at INTEGER,
8493
- client_name TEXT,
8494
- imported_at INTEGER,
8495
- client_version TEXT,
8496
- client_platform TEXT,
8497
- agent_name TEXT,
8498
- agent_version TEXT,
8499
- protocol_version INTEGER,
8500
- current_mode TEXT,
8501
- current_model TEXT,
8502
- agent_capabilities_json TEXT
8503
- );
8504
-
8505
- CREATE TABLE IF NOT EXISTS messages (
8506
- id INTEGER PRIMARY KEY AUTOINCREMENT,
8507
- session_id INTEGER NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
8508
- seq INTEGER NOT NULL,
8509
- timestamp INTEGER NOT NULL,
8510
- direction TEXT NOT NULL,
8511
- kind TEXT NOT NULL,
8512
- method TEXT,
8513
- rpc_id TEXT,
8514
- raw TEXT NOT NULL,
8515
- payload_json TEXT,
8516
- parse_error TEXT
8517
- );
8518
-
8519
- CREATE INDEX IF NOT EXISTS idx_messages_session_seq ON messages(session_id, seq);
8520
- CREATE INDEX IF NOT EXISTS idx_messages_session_rpc ON messages(session_id, rpc_id);
8521
- `;
8522
8731
  function hasColumn(db, table, column) {
8523
8732
  const cols = db.pragma(`table_info(${table})`);
8524
8733
  return cols.some((c) => c.name === column);
@@ -8575,13 +8784,55 @@ function openExistingDatabase(path) {
8575
8784
  }
8576
8785
  return openDatabase(path);
8577
8786
  }
8787
+ function getSchemaVersion(db) {
8788
+ const row2 = db.pragma("user_version", { simple: true });
8789
+ return typeof row2 === "number" ? row2 : Number(row2);
8790
+ }
8791
+ var SCHEMA_VERSION, SCHEMA_SQL;
8792
+ var init_sqlite = __esm({
8793
+ "../core/dist/storage/sqlite.js"() {
8794
+ "use strict";
8795
+ SCHEMA_VERSION = 4;
8796
+ SCHEMA_SQL = `
8797
+ CREATE TABLE IF NOT EXISTS sessions (
8798
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
8799
+ name TEXT,
8800
+ agent_command TEXT,
8801
+ started_at INTEGER NOT NULL,
8802
+ ended_at INTEGER,
8803
+ client_name TEXT,
8804
+ imported_at INTEGER,
8805
+ client_version TEXT,
8806
+ client_platform TEXT,
8807
+ agent_name TEXT,
8808
+ agent_version TEXT,
8809
+ protocol_version INTEGER,
8810
+ current_mode TEXT,
8811
+ current_model TEXT,
8812
+ agent_capabilities_json TEXT
8813
+ );
8814
+
8815
+ CREATE TABLE IF NOT EXISTS messages (
8816
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
8817
+ session_id INTEGER NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
8818
+ seq INTEGER NOT NULL,
8819
+ timestamp INTEGER NOT NULL,
8820
+ direction TEXT NOT NULL,
8821
+ kind TEXT NOT NULL,
8822
+ method TEXT,
8823
+ rpc_id TEXT,
8824
+ raw TEXT NOT NULL,
8825
+ payload_json TEXT,
8826
+ parse_error TEXT
8827
+ );
8828
+
8829
+ CREATE INDEX IF NOT EXISTS idx_messages_session_seq ON messages(session_id, seq);
8830
+ CREATE INDEX IF NOT EXISTS idx_messages_session_rpc ON messages(session_id, rpc_id);
8831
+ `;
8832
+ }
8833
+ });
8578
8834
 
8579
8835
  // ../core/dist/storage/session.js
8580
- var SESSION_SELECT = `SELECT id, name, agent_command, started_at, ended_at,
8581
- client_name, imported_at, client_version, client_platform,
8582
- agent_name, agent_version, protocol_version, current_mode, current_model,
8583
- agent_capabilities_json
8584
- FROM sessions`;
8585
8836
  function rowToInfo(row2) {
8586
8837
  return {
8587
8838
  id: row2.id,
@@ -8622,84 +8873,94 @@ function parseRpcId(stored) {
8622
8873
  const asNum = Number(stored);
8623
8874
  return Number.isFinite(asNum) && String(asNum) === stored ? asNum : stored;
8624
8875
  }
8625
- var Session = class _Session {
8626
- db;
8627
- info;
8628
- insertStmt;
8629
- endStmt;
8630
- listStmt;
8631
- constructor(db, info) {
8632
- this.db = db;
8633
- this.info = info;
8634
- this.insertStmt = db.prepare(`INSERT INTO messages (
8876
+ var SESSION_SELECT, Session;
8877
+ var init_session = __esm({
8878
+ "../core/dist/storage/session.js"() {
8879
+ "use strict";
8880
+ init_session_metadata();
8881
+ SESSION_SELECT = `SELECT id, name, agent_command, started_at, ended_at,
8882
+ client_name, imported_at, client_version, client_platform,
8883
+ agent_name, agent_version, protocol_version, current_mode, current_model,
8884
+ agent_capabilities_json
8885
+ FROM sessions`;
8886
+ Session = class _Session {
8887
+ db;
8888
+ info;
8889
+ insertStmt;
8890
+ endStmt;
8891
+ listStmt;
8892
+ constructor(db, info) {
8893
+ this.db = db;
8894
+ this.info = info;
8895
+ this.insertStmt = db.prepare(`INSERT INTO messages (
8635
8896
  session_id, seq, timestamp, direction, kind,
8636
8897
  method, rpc_id, raw, payload_json, parse_error
8637
8898
  ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);
8638
- this.endStmt = db.prepare(`UPDATE sessions SET ended_at = ? WHERE id = ?`);
8639
- this.listStmt = db.prepare(`SELECT seq, timestamp, direction, kind, method, rpc_id, raw, payload_json, parse_error
8899
+ this.endStmt = db.prepare(`UPDATE sessions SET ended_at = ? WHERE id = ?`);
8900
+ this.listStmt = db.prepare(`SELECT seq, timestamp, direction, kind, method, rpc_id, raw, payload_json, parse_error
8640
8901
  FROM messages WHERE session_id = ? ORDER BY seq ASC`);
8641
- }
8642
- static start(db, options = {}) {
8643
- const startedAt = options.startedAt ?? Date.now();
8644
- const importedAt = options.importedAt ?? null;
8645
- const stmt = db.prepare(`INSERT INTO sessions (name, agent_command, started_at, imported_at) VALUES (?, ?, ?, ?)`);
8646
- const result = stmt.run(options.name ?? null, options.agentCommand ?? null, startedAt, importedAt);
8647
- const id = Number(result.lastInsertRowid);
8648
- return new _Session(db, {
8649
- id,
8650
- name: options.name ?? null,
8651
- agentCommand: options.agentCommand ?? null,
8652
- startedAt,
8653
- endedAt: null,
8654
- clientName: null,
8655
- importedAt,
8656
- clientVersion: null,
8657
- clientPlatform: null,
8658
- agentName: null,
8659
- agentVersion: null,
8660
- protocolVersion: null,
8661
- currentMode: null,
8662
- currentModel: null,
8663
- agentCapabilitiesJson: null
8664
- });
8665
- }
8666
- static load(db, sessionId) {
8667
- const row2 = db.prepare(`${SESSION_SELECT} WHERE id = ?`).get(sessionId);
8668
- if (!row2)
8669
- throw new Error(`session ${sessionId} not found`);
8670
- return new _Session(db, rowToInfo(row2));
8671
- }
8672
- static latest(db) {
8673
- const row2 = db.prepare(`${SESSION_SELECT} ORDER BY id DESC LIMIT 1`).get();
8674
- if (!row2)
8675
- throw new Error("database has no sessions");
8676
- return new _Session(db, rowToInfo(row2));
8677
- }
8678
- /**
8679
- * Persist a detected client name on the session row. Called once when the
8680
- * first `initialize` request is seen by the proxy. Subsequent calls
8681
- * overwrite — the latest title wins.
8682
- */
8683
- setClientName(name) {
8684
- this.db.prepare(`UPDATE sessions SET client_name = ? WHERE id = ?`).run(name, this.info.id);
8685
- this.info = { ...this.info, clientName: name };
8686
- }
8687
- /**
8688
- * Write the structured-metadata columns from a derived `SessionMetadata`.
8689
- * Used by:
8690
- * - The proxy on every metadata-relevant message (initialize, set_mode,
8691
- * set_model, current_mode_update) so the UI's SessionPicker can label
8692
- * `#21 · Zed 1.3.5 · claude-agent-acp 0.37.0` mid-session.
8693
- * - The `backfill-metadata` CLI command for pre-v4 / imported sessions.
8694
- *
8695
- * Idempotent — running on the same messages produces the same writes.
8696
- */
8697
- setMetadataFromMessages(messages) {
8698
- this.setMetadataFrom(extractSessionMetadata(messages));
8699
- }
8700
- setMetadataFrom(meta) {
8701
- const agentCapsJson = JSON.stringify(meta.agentCapabilities);
8702
- this.db.prepare(`UPDATE sessions SET
8902
+ }
8903
+ static start(db, options = {}) {
8904
+ const startedAt = options.startedAt ?? Date.now();
8905
+ const importedAt = options.importedAt ?? null;
8906
+ const stmt = db.prepare(`INSERT INTO sessions (name, agent_command, started_at, imported_at) VALUES (?, ?, ?, ?)`);
8907
+ const result = stmt.run(options.name ?? null, options.agentCommand ?? null, startedAt, importedAt);
8908
+ const id = Number(result.lastInsertRowid);
8909
+ return new _Session(db, {
8910
+ id,
8911
+ name: options.name ?? null,
8912
+ agentCommand: options.agentCommand ?? null,
8913
+ startedAt,
8914
+ endedAt: null,
8915
+ clientName: null,
8916
+ importedAt,
8917
+ clientVersion: null,
8918
+ clientPlatform: null,
8919
+ agentName: null,
8920
+ agentVersion: null,
8921
+ protocolVersion: null,
8922
+ currentMode: null,
8923
+ currentModel: null,
8924
+ agentCapabilitiesJson: null
8925
+ });
8926
+ }
8927
+ static load(db, sessionId) {
8928
+ const row2 = db.prepare(`${SESSION_SELECT} WHERE id = ?`).get(sessionId);
8929
+ if (!row2)
8930
+ throw new Error(`session ${sessionId} not found`);
8931
+ return new _Session(db, rowToInfo(row2));
8932
+ }
8933
+ static latest(db) {
8934
+ const row2 = db.prepare(`${SESSION_SELECT} ORDER BY id DESC LIMIT 1`).get();
8935
+ if (!row2)
8936
+ throw new Error("database has no sessions");
8937
+ return new _Session(db, rowToInfo(row2));
8938
+ }
8939
+ /**
8940
+ * Persist a detected client name on the session row. Called once when the
8941
+ * first `initialize` request is seen by the proxy. Subsequent calls
8942
+ * overwrite — the latest title wins.
8943
+ */
8944
+ setClientName(name) {
8945
+ this.db.prepare(`UPDATE sessions SET client_name = ? WHERE id = ?`).run(name, this.info.id);
8946
+ this.info = { ...this.info, clientName: name };
8947
+ }
8948
+ /**
8949
+ * Write the structured-metadata columns from a derived `SessionMetadata`.
8950
+ * Used by:
8951
+ * - The proxy on every metadata-relevant message (initialize, set_mode,
8952
+ * set_model, current_mode_update) so the UI's SessionPicker can label
8953
+ * `#21 · Zed 1.3.5 · claude-agent-acp 0.37.0` mid-session.
8954
+ * - The `backfill-metadata` CLI command for pre-v4 / imported sessions.
8955
+ *
8956
+ * Idempotent — running on the same messages produces the same writes.
8957
+ */
8958
+ setMetadataFromMessages(messages) {
8959
+ this.setMetadataFrom(extractSessionMetadata(messages));
8960
+ }
8961
+ setMetadataFrom(meta) {
8962
+ const agentCapsJson = JSON.stringify(meta.agentCapabilities);
8963
+ this.db.prepare(`UPDATE sessions SET
8703
8964
  client_version = ?,
8704
8965
  client_platform = ?,
8705
8966
  agent_name = ?,
@@ -8709,34 +8970,35 @@ var Session = class _Session {
8709
8970
  current_model = ?,
8710
8971
  agent_capabilities_json = ?
8711
8972
  WHERE id = ?`).run(meta.client.version, meta.client.platform, meta.agent.name, meta.agent.version, meta.protocolVersion, meta.runtime.currentMode, meta.runtime.currentModel, agentCapsJson, this.info.id);
8712
- this.info = {
8713
- ...this.info,
8714
- clientVersion: meta.client.version,
8715
- clientPlatform: meta.client.platform,
8716
- agentName: meta.agent.name,
8717
- agentVersion: meta.agent.version,
8718
- protocolVersion: meta.protocolVersion,
8719
- currentMode: meta.runtime.currentMode,
8720
- currentModel: meta.runtime.currentModel,
8721
- agentCapabilitiesJson: agentCapsJson
8973
+ this.info = {
8974
+ ...this.info,
8975
+ clientVersion: meta.client.version,
8976
+ clientPlatform: meta.client.platform,
8977
+ agentName: meta.agent.name,
8978
+ agentVersion: meta.agent.version,
8979
+ protocolVersion: meta.protocolVersion,
8980
+ currentMode: meta.runtime.currentMode,
8981
+ currentModel: meta.runtime.currentModel,
8982
+ agentCapabilitiesJson: agentCapsJson
8983
+ };
8984
+ }
8985
+ record(message) {
8986
+ this.insertStmt.run(this.info.id, message.seq, message.timestamp, message.direction, message.kind, message.method ?? null, message.rpcId === void 0 || message.rpcId === null ? null : String(message.rpcId), message.raw, message.payload ? JSON.stringify(message.payload) : null, message.parseError ?? null);
8987
+ }
8988
+ close(endedAt = Date.now()) {
8989
+ this.endStmt.run(endedAt, this.info.id);
8990
+ this.info = { ...this.info, endedAt };
8991
+ }
8992
+ *messages() {
8993
+ for (const row2 of this.listStmt.iterate(this.info.id)) {
8994
+ yield rowToMessage(row2);
8995
+ }
8996
+ }
8722
8997
  };
8723
8998
  }
8724
- record(message) {
8725
- this.insertStmt.run(this.info.id, message.seq, message.timestamp, message.direction, message.kind, message.method ?? null, message.rpcId === void 0 || message.rpcId === null ? null : String(message.rpcId), message.raw, message.payload ? JSON.stringify(message.payload) : null, message.parseError ?? null);
8726
- }
8727
- close(endedAt = Date.now()) {
8728
- this.endStmt.run(endedAt, this.info.id);
8729
- this.info = { ...this.info, endedAt };
8730
- }
8731
- *messages() {
8732
- for (const row2 of this.listStmt.iterate(this.info.id)) {
8733
- yield rowToMessage(row2);
8734
- }
8735
- }
8736
- };
8999
+ });
8737
9000
 
8738
9001
  // ../core/dist/storage/export.js
8739
- var EXPORT_VERSION = 1;
8740
9002
  function exportSession(session, options) {
8741
9003
  return exportSessionFromParts(session.info, session.messages(), options);
8742
9004
  }
@@ -8759,12 +9021,6 @@ function exportSessionFromParts(info, messages, options) {
8759
9021
  function serializeExport(exp, indent = 4) {
8760
9022
  return JSON.stringify(exp, null, indent) + "\n";
8761
9023
  }
8762
- var ExportParseError = class extends Error {
8763
- constructor(message) {
8764
- super(message);
8765
- this.name = "ExportParseError";
8766
- }
8767
- };
8768
9024
  function parseExport(input) {
8769
9025
  let raw;
8770
9026
  try {
@@ -8866,22 +9122,21 @@ function parseMessage(raw, idx) {
8866
9122
  function isObject(value) {
8867
9123
  return typeof value === "object" && value !== null && !Array.isArray(value);
8868
9124
  }
9125
+ var EXPORT_VERSION, ExportParseError;
9126
+ var init_export = __esm({
9127
+ "../core/dist/storage/export.js"() {
9128
+ "use strict";
9129
+ EXPORT_VERSION = 1;
9130
+ ExportParseError = class extends Error {
9131
+ constructor(message) {
9132
+ super(message);
9133
+ this.name = "ExportParseError";
9134
+ }
9135
+ };
9136
+ }
9137
+ });
8869
9138
 
8870
9139
  // ../core/dist/storage/redact.js
8871
- var REDACTED_PLACEHOLDER = "<REDACTED>";
8872
- var SENSITIVE_HEADER_NAMES = /* @__PURE__ */ new Set([
8873
- "authorization",
8874
- "proxy-authorization",
8875
- "proxy-authentication",
8876
- "x-api-key",
8877
- "x-api-token",
8878
- "x-auth-token",
8879
- "api-key",
8880
- "api_key",
8881
- "proxy_key",
8882
- "cookie",
8883
- "set-cookie"
8884
- ]);
8885
9140
  function redactMessage(message) {
8886
9141
  if (message.payload == null) {
8887
9142
  return { redacted: message, count: 0 };
@@ -8968,110 +9223,171 @@ function redactSessionExport(exp) {
8968
9223
  fieldsRedacted
8969
9224
  };
8970
9225
  }
9226
+ var REDACTED_PLACEHOLDER, SENSITIVE_HEADER_NAMES;
9227
+ var init_redact = __esm({
9228
+ "../core/dist/storage/redact.js"() {
9229
+ "use strict";
9230
+ REDACTED_PLACEHOLDER = "<REDACTED>";
9231
+ SENSITIVE_HEADER_NAMES = /* @__PURE__ */ new Set([
9232
+ "authorization",
9233
+ "proxy-authorization",
9234
+ "proxy-authentication",
9235
+ "x-api-key",
9236
+ "x-api-token",
9237
+ "x-auth-token",
9238
+ "api-key",
9239
+ "api_key",
9240
+ "proxy_key",
9241
+ "cookie",
9242
+ "set-cookie"
9243
+ ]);
9244
+ }
9245
+ });
9246
+
9247
+ // ../core/dist/storage/index.js
9248
+ var init_storage = __esm({
9249
+ "../core/dist/storage/index.js"() {
9250
+ "use strict";
9251
+ init_sqlite();
9252
+ init_session();
9253
+ init_export();
9254
+ init_redact();
9255
+ }
9256
+ });
9257
+
9258
+ // ../core/dist/ws/events.js
9259
+ var WS_PROTOCOL_VERSION;
9260
+ var init_events = __esm({
9261
+ "../core/dist/ws/events.js"() {
9262
+ "use strict";
9263
+ WS_PROTOCOL_VERSION = 1;
9264
+ }
9265
+ });
8971
9266
 
8972
9267
  // ../core/dist/ws/server.js
8973
9268
  import { WebSocketServer } from "ws";
8974
- var WsBroadcaster = class {
8975
- options;
8976
- server = null;
8977
- session = null;
8978
- messages = [];
8979
- sessionEnded = false;
8980
- constructor(options) {
8981
- this.options = options;
8982
- }
8983
- /** Start the server. Resolves when it is listening; rejects on bind errors. */
8984
- start() {
8985
- if (this.server)
8986
- throw new Error("broadcaster already started");
8987
- return new Promise((resolve2, reject) => {
8988
- const host = this.options.host ?? "127.0.0.1";
8989
- const wss = new WebSocketServer({ host, port: this.options.port });
8990
- this.server = wss;
8991
- const onError = (err) => reject(err);
8992
- wss.once("error", onError);
8993
- wss.once("listening", () => {
8994
- wss.off("error", onError);
8995
- wss.on("error", () => void 0);
8996
- wss.on("connection", (ws) => this.onConnection(ws));
8997
- const address = wss.address();
8998
- resolve2({ port: address.port, url: `ws://${host}:${address.port}` });
8999
- });
9000
- });
9269
+ var WsBroadcaster;
9270
+ var init_server = __esm({
9271
+ "../core/dist/ws/server.js"() {
9272
+ "use strict";
9273
+ WsBroadcaster = class {
9274
+ options;
9275
+ server = null;
9276
+ session = null;
9277
+ messages = [];
9278
+ sessionEnded = false;
9279
+ constructor(options) {
9280
+ this.options = options;
9281
+ }
9282
+ /** Start the server. Resolves when it is listening; rejects on bind errors. */
9283
+ start() {
9284
+ if (this.server)
9285
+ throw new Error("broadcaster already started");
9286
+ return new Promise((resolve2, reject) => {
9287
+ const host = this.options.host ?? "127.0.0.1";
9288
+ const wss = new WebSocketServer({ host, port: this.options.port });
9289
+ this.server = wss;
9290
+ const onError = (err) => reject(err);
9291
+ wss.once("error", onError);
9292
+ wss.once("listening", () => {
9293
+ wss.off("error", onError);
9294
+ wss.on("error", () => void 0);
9295
+ wss.on("connection", (ws) => this.onConnection(ws));
9296
+ const address = wss.address();
9297
+ resolve2({ port: address.port, url: `ws://${host}:${address.port}` });
9298
+ });
9299
+ });
9300
+ }
9301
+ async stop() {
9302
+ const wss = this.server;
9303
+ if (!wss)
9304
+ return;
9305
+ this.server = null;
9306
+ for (const client of wss.clients)
9307
+ client.close(1e3, "shutdown");
9308
+ await Promise.race([
9309
+ new Promise((resolve2) => wss.close(() => resolve2())),
9310
+ new Promise((resolve2) => setTimeout(resolve2, 500))
9311
+ ]);
9312
+ for (const client of wss.clients)
9313
+ client.terminate();
9314
+ }
9315
+ publishSessionStart(session) {
9316
+ this.session = session;
9317
+ this.messages = [];
9318
+ this.sessionEnded = false;
9319
+ this.broadcast({ type: "session.start", session });
9320
+ }
9321
+ publishMessage(message) {
9322
+ if (!this.session) {
9323
+ throw new Error("publishMessage called before publishSessionStart");
9324
+ }
9325
+ this.messages.push(message);
9326
+ this.broadcast({ type: "message", message });
9327
+ }
9328
+ publishSessionEnd(session) {
9329
+ this.session = session;
9330
+ this.sessionEnded = true;
9331
+ this.broadcast({ type: "session.end", session });
9332
+ }
9333
+ /**
9334
+ * Pre-load a finished session for the replay command. Must be called before
9335
+ * clients connect; live `publish*` calls afterwards are not supported.
9336
+ */
9337
+ loadHistory(session, messages) {
9338
+ this.session = session;
9339
+ this.messages = [...messages];
9340
+ this.sessionEnded = session.endedAt !== null;
9341
+ }
9342
+ onConnection(ws) {
9343
+ if (this.session) {
9344
+ this.send(ws, { type: "session.start", session: this.session });
9345
+ for (const m of this.messages) {
9346
+ this.send(ws, { type: "message", message: m });
9347
+ }
9348
+ this.send(ws, { type: "replay.done" });
9349
+ if (this.sessionEnded) {
9350
+ this.send(ws, { type: "session.end", session: this.session });
9351
+ }
9352
+ }
9353
+ }
9354
+ broadcast(event) {
9355
+ const wss = this.server;
9356
+ if (!wss)
9357
+ return;
9358
+ const data = JSON.stringify(event);
9359
+ for (const client of wss.clients) {
9360
+ if (client.readyState === 1)
9361
+ client.send(data);
9362
+ }
9363
+ }
9364
+ send(ws, event) {
9365
+ ws.send(JSON.stringify(event));
9366
+ }
9367
+ };
9001
9368
  }
9002
- async stop() {
9003
- const wss = this.server;
9004
- if (!wss)
9005
- return;
9006
- this.server = null;
9007
- for (const client of wss.clients)
9008
- client.close(1e3, "shutdown");
9009
- await Promise.race([
9010
- new Promise((resolve2) => wss.close(() => resolve2())),
9011
- new Promise((resolve2) => setTimeout(resolve2, 500))
9012
- ]);
9013
- for (const client of wss.clients)
9014
- client.terminate();
9015
- }
9016
- publishSessionStart(session) {
9017
- this.session = session;
9018
- this.messages = [];
9019
- this.sessionEnded = false;
9020
- this.broadcast({ type: "session.start", session });
9021
- }
9022
- publishMessage(message) {
9023
- if (!this.session) {
9024
- throw new Error("publishMessage called before publishSessionStart");
9025
- }
9026
- this.messages.push(message);
9027
- this.broadcast({ type: "message", message });
9028
- }
9029
- publishSessionEnd(session) {
9030
- this.session = session;
9031
- this.sessionEnded = true;
9032
- this.broadcast({ type: "session.end", session });
9033
- }
9034
- /**
9035
- * Pre-load a finished session for the replay command. Must be called before
9036
- * clients connect; live `publish*` calls afterwards are not supported.
9037
- */
9038
- loadHistory(session, messages) {
9039
- this.session = session;
9040
- this.messages = [...messages];
9041
- this.sessionEnded = session.endedAt !== null;
9042
- }
9043
- onConnection(ws) {
9044
- if (this.session) {
9045
- this.send(ws, { type: "session.start", session: this.session });
9046
- for (const m of this.messages) {
9047
- this.send(ws, { type: "message", message: m });
9048
- }
9049
- this.send(ws, { type: "replay.done" });
9050
- if (this.sessionEnded) {
9051
- this.send(ws, { type: "session.end", session: this.session });
9052
- }
9053
- }
9054
- }
9055
- broadcast(event) {
9056
- const wss = this.server;
9057
- if (!wss)
9058
- return;
9059
- const data = JSON.stringify(event);
9060
- for (const client of wss.clients) {
9061
- if (client.readyState === 1)
9062
- client.send(data);
9063
- }
9369
+ });
9370
+
9371
+ // ../core/dist/ws/index.js
9372
+ var init_ws = __esm({
9373
+ "../core/dist/ws/index.js"() {
9374
+ "use strict";
9375
+ init_events();
9376
+ init_server();
9064
9377
  }
9065
- send(ws, event) {
9066
- ws.send(JSON.stringify(event));
9378
+ });
9379
+
9380
+ // ../core/dist/discovery/types.js
9381
+ var init_types2 = __esm({
9382
+ "../core/dist/discovery/types.js"() {
9383
+ "use strict";
9067
9384
  }
9068
- };
9385
+ });
9069
9386
 
9070
9387
  // ../core/dist/discovery/registry.js
9071
9388
  import { mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from "fs";
9072
9389
  import { homedir } from "os";
9073
9390
  import { join } from "path";
9074
- var DEFAULT_BASE = join(homedir(), ".acp-devtools");
9075
9391
  function discoveryBaseDir() {
9076
9392
  return process.env.ACP_DEVTOOLS_HOME ?? DEFAULT_BASE;
9077
9393
  }
@@ -9144,6 +9460,22 @@ function listActive(options = {}) {
9144
9460
  out.sort((a, b) => b.startedAt - a.startedAt);
9145
9461
  return out;
9146
9462
  }
9463
+ var DEFAULT_BASE;
9464
+ var init_registry2 = __esm({
9465
+ "../core/dist/discovery/registry.js"() {
9466
+ "use strict";
9467
+ DEFAULT_BASE = join(homedir(), ".acp-devtools");
9468
+ }
9469
+ });
9470
+
9471
+ // ../core/dist/discovery/index.js
9472
+ var init_discovery = __esm({
9473
+ "../core/dist/discovery/index.js"() {
9474
+ "use strict";
9475
+ init_types2();
9476
+ init_registry2();
9477
+ }
9478
+ });
9147
9479
 
9148
9480
  // ../core/dist/server/paths.js
9149
9481
  import { homedir as homedir2 } from "os";
@@ -9154,6 +9486,11 @@ function acpHomeDir() {
9154
9486
  function defaultCapturesDbPath() {
9155
9487
  return join2(acpHomeDir(), "captures.db");
9156
9488
  }
9489
+ var init_paths = __esm({
9490
+ "../core/dist/server/paths.js"() {
9491
+ "use strict";
9492
+ }
9493
+ });
9157
9494
 
9158
9495
  // ../core/dist/server/queries.js
9159
9496
  import { existsSync as existsSync2, mkdirSync as mkdirSync2 } from "fs";
@@ -9184,7 +9521,6 @@ function listSessionsSummary(dbPath, limit = 200) {
9184
9521
  db.close();
9185
9522
  }
9186
9523
  }
9187
- var FIND_BY_CLIENT_POOL_SIZE = 500;
9188
9524
  function findSessionsByClient(dbPath, needle, limit = 200) {
9189
9525
  const pool = listSessionsSummary(dbPath, FIND_BY_CLIENT_POOL_SIZE);
9190
9526
  const lower = needle.toLowerCase();
@@ -9232,17 +9568,18 @@ function deleteSession(dbPath, sessionId) {
9232
9568
  db.close();
9233
9569
  }
9234
9570
  }
9571
+ var FIND_BY_CLIENT_POOL_SIZE;
9572
+ var init_queries = __esm({
9573
+ "../core/dist/server/queries.js"() {
9574
+ "use strict";
9575
+ init_session();
9576
+ init_sqlite();
9577
+ FIND_BY_CLIENT_POOL_SIZE = 500;
9578
+ }
9579
+ });
9235
9580
 
9236
9581
  // ../core/dist/server/replay.js
9237
9582
  import { existsSync as existsSync3 } from "fs";
9238
- var DEFAULT_LOGGER = {
9239
- log: (message) => {
9240
- console.log(message);
9241
- },
9242
- warn: (message, err) => {
9243
- console.warn(message, err);
9244
- }
9245
- };
9246
9583
  function streamReplay(ws, sessionId, dbPath, logger = DEFAULT_LOGGER) {
9247
9584
  const tag = `[replay #${sessionId}]`;
9248
9585
  if (!existsSync3(dbPath)) {
@@ -9315,6 +9652,22 @@ function safeClose(ws) {
9315
9652
  } catch {
9316
9653
  }
9317
9654
  }
9655
+ var DEFAULT_LOGGER;
9656
+ var init_replay = __esm({
9657
+ "../core/dist/server/replay.js"() {
9658
+ "use strict";
9659
+ init_session();
9660
+ init_sqlite();
9661
+ DEFAULT_LOGGER = {
9662
+ log: (message) => {
9663
+ console.log(message);
9664
+ },
9665
+ warn: (message, err) => {
9666
+ console.warn(message, err);
9667
+ }
9668
+ };
9669
+ }
9670
+ });
9318
9671
 
9319
9672
  // ../core/dist/server/http.js
9320
9673
  import { existsSync as existsSync4 } from "fs";
@@ -9460,7 +9813,6 @@ function handleSessionMessages(req, res, dbPath, sessionId) {
9460
9813
  db.close();
9461
9814
  }
9462
9815
  }
9463
- var IMPORT_MAX_BYTES = 64 * 1024 * 1024;
9464
9816
  function handleImport(req, res, dbPath) {
9465
9817
  if (req.method !== "POST") {
9466
9818
  res.statusCode = 405;
@@ -9540,9 +9892,113 @@ function attachReplayUpgrade(httpServer, options) {
9540
9892
  });
9541
9893
  });
9542
9894
  }
9895
+ var IMPORT_MAX_BYTES;
9896
+ var init_http = __esm({
9897
+ "../core/dist/server/http.js"() {
9898
+ "use strict";
9899
+ init_registry2();
9900
+ init_export();
9901
+ init_session();
9902
+ init_sqlite();
9903
+ init_queries();
9904
+ init_replay();
9905
+ IMPORT_MAX_BYTES = 64 * 1024 * 1024;
9906
+ }
9907
+ });
9543
9908
 
9544
- // src/program.ts
9545
- import { Command } from "commander";
9909
+ // ../core/dist/server/index.js
9910
+ var init_server2 = __esm({
9911
+ "../core/dist/server/index.js"() {
9912
+ "use strict";
9913
+ init_paths();
9914
+ init_queries();
9915
+ init_replay();
9916
+ init_http();
9917
+ }
9918
+ });
9919
+
9920
+ // ../core/dist/index.js
9921
+ var dist_exports = {};
9922
+ __export(dist_exports, {
9923
+ AGENT_METHODS: () => AGENT_METHODS,
9924
+ AGENT_REGISTRY: () => AGENT_REGISTRY,
9925
+ AcpProxy: () => AcpProxy,
9926
+ CLIENT_METHODS: () => CLIENT_METHODS,
9927
+ DEFAULT_AGENT: () => DEFAULT_AGENT,
9928
+ EXPORT_VERSION: () => EXPORT_VERSION,
9929
+ ExportParseError: () => ExportParseError,
9930
+ LineFramer: () => LineFramer,
9931
+ PROTOCOL_VERSION: () => PROTOCOL_VERSION,
9932
+ PlaybackEngine: () => PlaybackEngine,
9933
+ REDACTED_PLACEHOLDER: () => REDACTED_PLACEHOLDER,
9934
+ SCHEMA_VERSION: () => SCHEMA_VERSION,
9935
+ Session: () => Session,
9936
+ WS_PROTOCOL_VERSION: () => WS_PROTOCOL_VERSION,
9937
+ WsBroadcaster: () => WsBroadcaster,
9938
+ acpHomeDir: () => acpHomeDir,
9939
+ activeDir: () => activeDir,
9940
+ asciiSparkline: () => asciiSparkline,
9941
+ attachReplayUpgrade: () => attachReplayUpgrade,
9942
+ buildMetadataDiff: () => buildMetadataDiff,
9943
+ buildMethodStatsDiff: () => buildMethodStatsDiff,
9944
+ buildPairIndex: () => buildPairIndex,
9945
+ buildPerMethodStats: () => buildPerMethodStats,
9946
+ buildPerformanceInsights: () => buildPerformanceInsights,
9947
+ buildSessionDiff: () => buildSessionDiff,
9948
+ buildTimelineLayout: () => buildTimelineLayout,
9949
+ createApiHandler: () => createApiHandler,
9950
+ defaultCapturesDbPath: () => defaultCapturesDbPath,
9951
+ deleteSession: () => deleteSession,
9952
+ detectAgentShortcut: () => detectAgentShortcut,
9953
+ diffJson: () => diffJson,
9954
+ discoveryBaseDir: () => discoveryBaseDir,
9955
+ exportSession: () => exportSession,
9956
+ exportSessionFromParts: () => exportSessionFromParts,
9957
+ extractRpcId: () => extractRpcId,
9958
+ extractSessionMetadata: () => extractSessionMetadata,
9959
+ extractTextPreview: () => extractTextPreview,
9960
+ findSessionsByClient: () => findSessionsByClient,
9961
+ getSchemaVersion: () => getSchemaVersion,
9962
+ insertImportedSession: () => insertImportedSession,
9963
+ isAgentShortcut: () => isAgentShortcut,
9964
+ isPidAlive: () => isPidAlive,
9965
+ isUserPrompt: () => isUserPrompt,
9966
+ knownAcpMethods: () => knownAcpMethods,
9967
+ knownAcpSpecMethods: () => knownAcpSpecMethods,
9968
+ listActive: () => listActive,
9969
+ listAgents: () => listAgents,
9970
+ listSessionsSummary: () => listSessionsSummary,
9971
+ mean: () => mean,
9972
+ openDatabase: () => openDatabase,
9973
+ openExistingDatabase: () => openExistingDatabase,
9974
+ parseExport: () => parseExport,
9975
+ parseFrame: () => parseFrame,
9976
+ percentile: () => percentile,
9977
+ redactMessage: () => redactMessage,
9978
+ redactSessionExport: () => redactSessionExport,
9979
+ removeActiveFile: () => removeActiveFile,
9980
+ resolveAgent: () => resolveAgent,
9981
+ resolveSpecForMessage: () => resolveSpecForMessage,
9982
+ sampleEvenly: () => sampleEvenly,
9983
+ serializeExport: () => serializeExport,
9984
+ spawnAgent: () => spawnAgent,
9985
+ streamReplay: () => streamReplay,
9986
+ substituteRpcId: () => substituteRpcId,
9987
+ validateAcpMessage: () => validateAcpMessage,
9988
+ writeActiveFile: () => writeActiveFile
9989
+ });
9990
+ var init_dist = __esm({
9991
+ "../core/dist/index.js"() {
9992
+ "use strict";
9993
+ init_acp();
9994
+ init_agents();
9995
+ init_proxy2();
9996
+ init_storage();
9997
+ init_ws();
9998
+ init_discovery();
9999
+ init_server2();
10000
+ }
10001
+ });
9546
10002
 
9547
10003
  // src/commands/backfill-metadata.ts
9548
10004
  function backfillSession(db, id) {
@@ -9580,8 +10036,8 @@ function listSessionIds(db) {
9580
10036
  const rows = db.prepare(`SELECT id FROM sessions ORDER BY id ASC`).all();
9581
10037
  return rows.map((r) => r.id);
9582
10038
  }
9583
- function registerBackfillMetadataCommand(program2) {
9584
- program2.command("backfill-metadata").description(
10039
+ function registerBackfillMetadataCommand(program) {
10040
+ program.command("backfill-metadata").description(
9585
10041
  "Recompute structured session metadata (client/agent/runtime) for saved sessions by re-scanning their captured messages. Used for sessions that pre-date the v4 schema or were imported from JSON."
9586
10042
  ).argument("[id]", "backfill a single session only (default: all)").option("--db <path>", "captures database", defaultCapturesDbPath()).option("--json", "machine-readable JSON output").action((idArg, opts) => {
9587
10043
  let targetId = null;
@@ -9627,11 +10083,17 @@ function registerBackfillMetadataCommand(program2) {
9627
10083
  }
9628
10084
  });
9629
10085
  }
10086
+ var init_backfill_metadata = __esm({
10087
+ "src/commands/backfill-metadata.ts"() {
10088
+ "use strict";
10089
+ init_dist();
10090
+ }
10091
+ });
9630
10092
 
9631
10093
  // src/commands/delete.ts
9632
10094
  import { existsSync as existsSync5 } from "fs";
9633
- function registerDeleteCommand(program2) {
9634
- program2.command("delete").description(
10095
+ function registerDeleteCommand(program) {
10096
+ program.command("delete").description(
9635
10097
  "Delete one or more saved sessions from the captures database forever. Cascades to messages via the schema. No interactive prompt \u2014 pair with `acp-devtools list` to verify ids before invoking."
9636
10098
  ).argument("<id...>", "one or more session ids to delete").option("--db <path>", "captures database", defaultCapturesDbPath()).action((rawIds, opts) => {
9637
10099
  const ids = [];
@@ -9679,23 +10141,14 @@ function labelFor(s) {
9679
10141
  if (s.client_name) return s.client_name;
9680
10142
  return s.agent_command ?? "";
9681
10143
  }
10144
+ var init_delete = __esm({
10145
+ "src/commands/delete.ts"() {
10146
+ "use strict";
10147
+ init_dist();
10148
+ }
10149
+ });
9682
10150
 
9683
10151
  // src/lib/style.ts
9684
- var ESC = String.fromCharCode(27);
9685
- var CODES = {
9686
- reset: 0,
9687
- bold: 1,
9688
- dim: 2,
9689
- italic: 3,
9690
- underline: 4,
9691
- red: 31,
9692
- green: 32,
9693
- yellow: 33,
9694
- blue: 34,
9695
- magenta: 35,
9696
- cyan: 36,
9697
- gray: 90
9698
- };
9699
10152
  function colorEnabled(stream = process.stdout, env = process.env) {
9700
10153
  if (env.FORCE_COLOR === "0" || env.FORCE_COLOR === "false") return false;
9701
10154
  if (env.FORCE_COLOR !== void 0) return true;
@@ -9723,13 +10176,34 @@ function createStyler(enabled = colorEnabled()) {
9723
10176
  gray: wrap("gray")
9724
10177
  };
9725
10178
  }
9726
- var ANSI_PATTERN = new RegExp(`${ESC}\\[[0-9;]*m`, "g");
9727
10179
  function stripAnsi(s) {
9728
10180
  return s.replace(ANSI_PATTERN, "");
9729
10181
  }
9730
10182
  function visibleWidth(s) {
9731
10183
  return stripAnsi(s).length;
9732
10184
  }
10185
+ var ESC, CODES, ANSI_PATTERN;
10186
+ var init_style = __esm({
10187
+ "src/lib/style.ts"() {
10188
+ "use strict";
10189
+ ESC = String.fromCharCode(27);
10190
+ CODES = {
10191
+ reset: 0,
10192
+ bold: 1,
10193
+ dim: 2,
10194
+ italic: 3,
10195
+ underline: 4,
10196
+ red: 31,
10197
+ green: 32,
10198
+ yellow: 33,
10199
+ blue: 34,
10200
+ magenta: 35,
10201
+ cyan: 36,
10202
+ gray: 90
10203
+ };
10204
+ ANSI_PATTERN = new RegExp(`${ESC}\\[[0-9;]*m`, "g");
10205
+ }
10206
+ });
9733
10207
 
9734
10208
  // src/lib/palette.ts
9735
10209
  function colorKind(s, kind, text) {
@@ -9758,6 +10232,11 @@ function colorLatency(s, ms, text) {
9758
10232
  function colorSessionKind(s, imported, text) {
9759
10233
  return imported ? s.yellow(text) : s.green(text);
9760
10234
  }
10235
+ var init_palette = __esm({
10236
+ "src/lib/palette.ts"() {
10237
+ "use strict";
10238
+ }
10239
+ });
9761
10240
 
9762
10241
  // src/lib/table.ts
9763
10242
  function renderTable(s, columns, rows, opts = {}) {
@@ -9792,10 +10271,16 @@ function renderTable(s, columns, rows, opts = {}) {
9792
10271
  }
9793
10272
  return out.map((l) => l + "\n").join("");
9794
10273
  }
10274
+ var init_table = __esm({
10275
+ "src/lib/table.ts"() {
10276
+ "use strict";
10277
+ init_style();
10278
+ }
10279
+ });
9795
10280
 
9796
10281
  // src/commands/diff.ts
9797
- function registerDiffCommand(program2) {
9798
- program2.command("diff").description(
10282
+ function registerDiffCommand(program) {
10283
+ program.command("diff").description(
9799
10284
  'Align two saved sessions and show what changed between them \u2014 added / removed frames and field-level payload differences. Useful for "worked yesterday, broke today" and A/B comparisons of two agents on the same prompt.'
9800
10285
  ).argument("<a>", "baseline session id (left side)").argument("<b>", "new session id (right side)").option("--db <path>", "captures database", defaultCapturesDbPath()).option("--full", "print unchanged frames too (default collapses equal runs)").option("--json", "machine-readable JSON instead of human-readable text").action((rawA, rawB, opts) => {
9801
10286
  const idA = parseId(rawA);
@@ -9854,16 +10339,9 @@ function registerDiffCommand(program2) {
9854
10339
  );
9855
10340
  });
9856
10341
  }
9857
- var defaultStyler = () => createStyler(colorEnabled(process.stdout));
9858
10342
  function heading(st, label) {
9859
10343
  return st.bold(st.yellow(label));
9860
10344
  }
9861
- var OP_COLOR = {
9862
- equal: (st, t) => st.dim(t),
9863
- changed: (st, t) => st.yellow(t),
9864
- added: (st, t) => st.green(t),
9865
- removed: (st, t) => st.red(t)
9866
- };
9867
10345
  function parseId(raw) {
9868
10346
  const id = Number(raw);
9869
10347
  if (!Number.isInteger(id) || id <= 0) {
@@ -9887,19 +10365,6 @@ function shortLabel(info) {
9887
10365
  if (bits.length === 0 && info.name) bits.push(info.name);
9888
10366
  return bits.join(" \xB7 ") || "\u2014";
9889
10367
  }
9890
- var KIND_LABEL = {
9891
- request: "REQ",
9892
- response: "RSP",
9893
- notification: "NTF",
9894
- error: "ERR",
9895
- unknown: "UNK"
9896
- };
9897
- var OP_MARKER = {
9898
- equal: "=",
9899
- changed: "\u2260",
9900
- added: "\u25B8",
9901
- removed: "\u25C2"
9902
- };
9903
10368
  function dirArrow(m) {
9904
10369
  return m.direction === "editor-to-agent" ? "\u2192A" : "A\u2190";
9905
10370
  }
@@ -9976,7 +10441,6 @@ function renderInfoSection(meta, st = defaultStyler()) {
9976
10441
  }
9977
10442
  return lines.join("");
9978
10443
  }
9979
- var PERF_METHOD_MAX = 40;
9980
10444
  function colorDelta(st, ms) {
9981
10445
  if (ms == null) return st.dim("\u2014");
9982
10446
  const text = signedLatency(ms);
@@ -10020,7 +10484,6 @@ function signedLatency(ms) {
10020
10484
  const sign = ms > 0 ? "+" : "\u2212";
10021
10485
  return sign + formatLatency(Math.abs(ms));
10022
10486
  }
10023
- var VALUE_MAX = 60;
10024
10487
  function fmtValue(v) {
10025
10488
  let s;
10026
10489
  try {
@@ -10033,17 +10496,43 @@ function fmtValue(v) {
10033
10496
  if (s.length > VALUE_MAX) s = s.slice(0, VALUE_MAX - 1) + "\u2026";
10034
10497
  return s;
10035
10498
  }
10499
+ var defaultStyler, OP_COLOR, KIND_LABEL, OP_MARKER, PERF_METHOD_MAX, VALUE_MAX;
10500
+ var init_diff = __esm({
10501
+ "src/commands/diff.ts"() {
10502
+ "use strict";
10503
+ init_dist();
10504
+ init_style();
10505
+ init_palette();
10506
+ init_table();
10507
+ defaultStyler = () => createStyler(colorEnabled(process.stdout));
10508
+ OP_COLOR = {
10509
+ equal: (st, t) => st.dim(t),
10510
+ changed: (st, t) => st.yellow(t),
10511
+ added: (st, t) => st.green(t),
10512
+ removed: (st, t) => st.red(t)
10513
+ };
10514
+ KIND_LABEL = {
10515
+ request: "REQ",
10516
+ response: "RSP",
10517
+ notification: "NTF",
10518
+ error: "ERR",
10519
+ unknown: "UNK"
10520
+ };
10521
+ OP_MARKER = {
10522
+ equal: "=",
10523
+ changed: "\u2260",
10524
+ added: "\u25B8",
10525
+ removed: "\u25C2"
10526
+ };
10527
+ PERF_METHOD_MAX = 40;
10528
+ VALUE_MAX = 60;
10529
+ }
10530
+ });
10036
10531
 
10037
10532
  // src/commands/doctor.ts
10038
10533
  import { existsSync as existsSync6, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
10039
10534
  import { homedir as homedir3, platform, release } from "os";
10040
10535
  import { join as join3 } from "path";
10041
- var STATUS_MARK = {
10042
- ok: "\u2713",
10043
- warn: "!",
10044
- fail: "\u2717",
10045
- info: "\xB7"
10046
- };
10047
10536
  function colorStatus(s, status, text) {
10048
10537
  switch (status) {
10049
10538
  case "ok":
@@ -10157,8 +10646,6 @@ function probeZed() {
10157
10646
  );
10158
10647
  return { name: "Zed", path, exists: existsSync6(path) };
10159
10648
  }
10160
- var JETBRAINS_VERSIONED = /^[A-Z][A-Za-z]+\d{4}\.\d/;
10161
- var JETBRAINS_UNVERSIONED = /* @__PURE__ */ new Set(["Fleet", "Toolbox"]);
10162
10649
  function probeJetBrains() {
10163
10650
  const baseDirs = [];
10164
10651
  if (platform() === "darwin") {
@@ -10252,8 +10739,8 @@ function exitCodeFromSections(sections) {
10252
10739
  }
10253
10740
  return 0;
10254
10741
  }
10255
- function registerDoctorCommand(program2) {
10256
- program2.command("doctor").description("Diagnose acp-devtools setup and report any issues").option("--json", "output machine-readable JSON instead of human text").option("--no-color", "disable ANSI colour output").action((opts) => {
10742
+ function registerDoctorCommand(program) {
10743
+ program.command("doctor").description("Diagnose acp-devtools setup and report any issues").option("--json", "output machine-readable JSON instead of human text").option("--no-color", "disable ANSI colour output").action((opts) => {
10257
10744
  const sections = [
10258
10745
  { title: "Environment", results: checkEnvironment() },
10259
10746
  { title: "State", results: checkState() },
@@ -10273,16 +10760,36 @@ function registerDoctorCommand(program2) {
10273
10760
  process.exit(exitCodeFromSections(sections));
10274
10761
  });
10275
10762
  }
10276
-
10277
- // src/commands/export.ts
10278
- import { writeFileSync as writeFileSync2 } from "fs";
10763
+ var STATUS_MARK, JETBRAINS_VERSIONED, JETBRAINS_UNVERSIONED;
10764
+ var init_doctor = __esm({
10765
+ "src/commands/doctor.ts"() {
10766
+ "use strict";
10767
+ init_dist();
10768
+ init_style();
10769
+ STATUS_MARK = {
10770
+ ok: "\u2713",
10771
+ warn: "!",
10772
+ fail: "\u2717",
10773
+ info: "\xB7"
10774
+ };
10775
+ JETBRAINS_VERSIONED = /^[A-Z][A-Za-z]+\d{4}\.\d/;
10776
+ JETBRAINS_UNVERSIONED = /* @__PURE__ */ new Set(["Fleet", "Toolbox"]);
10777
+ }
10778
+ });
10279
10779
 
10280
10780
  // src/version.ts
10281
- var CLI_VERSION = "0.2.0";
10781
+ var CLI_VERSION;
10782
+ var init_version = __esm({
10783
+ "src/version.ts"() {
10784
+ "use strict";
10785
+ CLI_VERSION = "0.2.1";
10786
+ }
10787
+ });
10282
10788
 
10283
10789
  // src/commands/export.ts
10284
- function registerExportCommand(program2) {
10285
- program2.command("export").description("Export a recorded session as self-contained JSON (suitable for sharing and for mock-replay)").argument("[id]", "session id to export (default: latest in the database)").option("--db <path>", "captures database", defaultCapturesDbPath()).option("-o, --output <file>", "write to a file instead of stdout").option("--no-pretty", "emit compact JSON (no indent, single line)").option(
10790
+ import { writeFileSync as writeFileSync2 } from "fs";
10791
+ function registerExportCommand(program) {
10792
+ program.command("export").description("Export a recorded session as self-contained JSON (suitable for sharing and for mock-replay)").argument("[id]", "session id to export (default: latest in the database)").option("--db <path>", "captures database", defaultCapturesDbPath()).option("-o, --output <file>", "write to a file instead of stdout").option("--no-pretty", "emit compact JSON (no indent, single line)").option(
10286
10793
  "--raw",
10287
10794
  "skip default redaction of auth headers / proxy tokens (use only when the export stays on YOUR machine)",
10288
10795
  false
@@ -10342,12 +10849,19 @@ function registerExportCommand(program2) {
10342
10849
  }
10343
10850
  });
10344
10851
  }
10852
+ var init_export2 = __esm({
10853
+ "src/commands/export.ts"() {
10854
+ "use strict";
10855
+ init_dist();
10856
+ init_version();
10857
+ }
10858
+ });
10345
10859
 
10346
10860
  // src/commands/import.ts
10347
10861
  import { readFileSync as readFileSync2 } from "fs";
10348
10862
  import { basename } from "path";
10349
- function registerImportCommand(program2) {
10350
- program2.command("import").description(
10863
+ function registerImportCommand(program) {
10864
+ program.command("import").description(
10351
10865
  "Insert a JSON session export into the captures database as a new saved session. The new session appears in the inspector picker under its IMPORTED section, with imported_at set to now."
10352
10866
  ).argument("<file>", "path to a JSON export produced by `acp-devtools export`").option(
10353
10867
  "--db <path>",
@@ -10385,21 +10899,16 @@ function registerImportCommand(program2) {
10385
10899
  }
10386
10900
  });
10387
10901
  }
10902
+ var init_import = __esm({
10903
+ "src/commands/import.ts"() {
10904
+ "use strict";
10905
+ init_dist();
10906
+ }
10907
+ });
10388
10908
 
10389
10909
  // src/commands/inspect.ts
10390
- var DIR_FROM_CODE = {
10391
- out: "editor-to-agent",
10392
- in: "agent-to-editor"
10393
- };
10394
- var KIND_FROM_CODE = {
10395
- req: "request",
10396
- rsp: "response",
10397
- ntf: "notification",
10398
- err: "error",
10399
- unk: "unknown"
10400
- };
10401
- function registerInspectCommand(program2) {
10402
- program2.command("inspect").description(
10910
+ function registerInspectCommand(program) {
10911
+ program.command("inspect").description(
10403
10912
  "Print messages of a saved session to stdout \u2014 the terminal equivalent of the inspector timeline. Combine with grep / jq for shell-side analysis."
10404
10913
  ).argument("<id>", "session id (see `acp-devtools list`)").option("--db <path>", "captures database", defaultCapturesDbPath()).option("--limit <n>", "maximum messages to print", "500").option("--from-seq <n>", "start from this seq number (inclusive)").option(
10405
10914
  "--dir <codes>",
@@ -10543,13 +11052,6 @@ function passes(m, f) {
10543
11052
  if (f.grep && !m.raw.toLowerCase().includes(f.grep)) return false;
10544
11053
  return true;
10545
11054
  }
10546
- var KIND_LABEL2 = {
10547
- request: "REQ",
10548
- response: "RSP",
10549
- notification: "NTF",
10550
- error: "ERR",
10551
- unknown: "UNK"
10552
- };
10553
11055
  function toTableRow(m, pair, specCell = "") {
10554
11056
  let paired = "\u2014";
10555
11057
  let latency = "\u2014";
@@ -10609,9 +11111,6 @@ function formatBytes2(n) {
10609
11111
  if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)}KB`;
10610
11112
  return `${(n / 1024 / 1024).toFixed(1)}MB`;
10611
11113
  }
10612
- var PREVIEW_MAX = 50;
10613
- var METHOD_MAX = 40;
10614
- var RPC_MAX = 10;
10615
11114
  function colorSpec(s, cell) {
10616
11115
  if (cell === "\u2713") return s.green(cell);
10617
11116
  if (cell.startsWith("\u26A0")) return s.red(cell);
@@ -10656,10 +11155,41 @@ function truncate(s, max) {
10656
11155
  if (s.length <= max) return s;
10657
11156
  return s.slice(0, Math.max(1, max - 1)) + "\u2026";
10658
11157
  }
11158
+ var DIR_FROM_CODE, KIND_FROM_CODE, KIND_LABEL2, PREVIEW_MAX, METHOD_MAX, RPC_MAX;
11159
+ var init_inspect = __esm({
11160
+ "src/commands/inspect.ts"() {
11161
+ "use strict";
11162
+ init_dist();
11163
+ init_style();
11164
+ init_palette();
11165
+ init_table();
11166
+ DIR_FROM_CODE = {
11167
+ out: "editor-to-agent",
11168
+ in: "agent-to-editor"
11169
+ };
11170
+ KIND_FROM_CODE = {
11171
+ req: "request",
11172
+ rsp: "response",
11173
+ ntf: "notification",
11174
+ err: "error",
11175
+ unk: "unknown"
11176
+ };
11177
+ KIND_LABEL2 = {
11178
+ request: "REQ",
11179
+ response: "RSP",
11180
+ notification: "NTF",
11181
+ error: "ERR",
11182
+ unknown: "UNK"
11183
+ };
11184
+ PREVIEW_MAX = 50;
11185
+ METHOD_MAX = 40;
11186
+ RPC_MAX = 10;
11187
+ }
11188
+ });
10659
11189
 
10660
11190
  // src/commands/list.ts
10661
- function registerListCommand(program2) {
10662
- program2.command("list").description(
11191
+ function registerListCommand(program) {
11192
+ program.command("list").description(
10663
11193
  "List saved sessions in the captures database, newest first. Use `acp-devtools doctor` for live captures (those are not in the database)."
10664
11194
  ).option("--db <path>", "captures database", defaultCapturesDbPath()).option("--limit <n>", "maximum rows to show", "50").option("--imported", "only show imported sessions").option("--saved", "only show non-imported (live-captured) saved sessions").option(
10665
11195
  "--client <substring>",
@@ -10709,13 +11239,6 @@ function formatAge(deltaMs) {
10709
11239
  if (h < 24) return `${h}h${m % 60 > 0 ? `${m % 60}m` : ""}`;
10710
11240
  return `${Math.floor(h / 24)}d`;
10711
11241
  }
10712
- var COLUMNS = [
10713
- { title: "ID", align: "left" },
10714
- { title: "AGE", align: "right" },
10715
- { title: "KIND", align: "left" },
10716
- { title: "MSGS", align: "right" },
10717
- { title: "SESSION", align: "left" }
10718
- ];
10719
11242
  function formatTable(rows) {
10720
11243
  const s = createStyler(colorEnabled(process.stdout));
10721
11244
  const now = Date.now();
@@ -10731,70 +11254,28 @@ function formatTable(rows) {
10731
11254
  });
10732
11255
  return renderTable(s, COLUMNS, body);
10733
11256
  }
11257
+ var COLUMNS;
11258
+ var init_list = __esm({
11259
+ "src/commands/list.ts"() {
11260
+ "use strict";
11261
+ init_dist();
11262
+ init_style();
11263
+ init_palette();
11264
+ init_table();
11265
+ COLUMNS = [
11266
+ { title: "ID", align: "left" },
11267
+ { title: "AGE", align: "right" },
11268
+ { title: "KIND", align: "left" },
11269
+ { title: "MSGS", align: "right" },
11270
+ { title: "SESSION", align: "left" }
11271
+ ];
11272
+ }
11273
+ });
10734
11274
 
10735
11275
  // src/commands/mcp.ts
10736
11276
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
10737
11277
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
10738
11278
  import { z } from "zod";
10739
- var SERVER_INSTRUCTIONS = `acp-devtools exposes a local SQLite store of captured
10740
- Agent Client Protocol (ACP) sessions. ACP is the editor\u2194agent JSON-RPC
10741
- protocol used by Claude Code, Goose, Codex, and other IDE agents.
10742
-
10743
- Every tool here is **read-only** \u2014 nothing in this server writes to the
10744
- database. Use it to investigate:
10745
-
10746
- - a slow session (\`get_latency_stats\` returns per-method p50/p99/max
10747
- plus auto-detected insights: hotspot, long-tail, outlier, busiest,
10748
- errors)
10749
- - a misbehaving agent (\`find_spec_violations\` validates every frame
10750
- against the ACP JSON schema)
10751
- - specific events (\`get_session_messages\` + \`get_message\` for the
10752
- raw JSON-RPC payload)
10753
- - capture inventory (\`list_sessions\`, \`find_sessions_by_client\`)
10754
- - one-shot digest of a session (\`get_session_summary\` bundles
10755
- metadata + latency stats + insights in one call \u2014 preferred over
10756
- three separate calls when you just need an overview)
10757
- - a regression or A/B comparison between two sessions
10758
- (\`diff_sessions\` aligns two captures and reports added / removed
10759
- frames and field-level payload changes)
10760
-
10761
- A typical investigation:
10762
- 1. \`list_sessions\` to see what is captured
10763
- 2. \`get_session_summary({session_id})\` for the headline numbers and
10764
- auto-detected insights \u2014 start here when you don't know what's
10765
- wrong yet
10766
- 3. drill into a specific method or message with
10767
- \`get_session_messages\` / \`get_message\` / \`get_paired\`
10768
-
10769
- For common investigations the server also exposes canned prompts via
10770
- \`prompts/list\` \u2014 \`triage_slow_session\`, \`audit_spec_violations\`,
10771
- \`compare_clients\`. Each prompt seeds the right tool sequence.
10772
-
10773
- Every tool declares an \`outputSchema\`, so results include both
10774
- \`content\` (text JSON) and \`structuredContent\` (typed object matching
10775
- the schema). Prefer \`structuredContent\` if your client supports it \u2014
10776
- it avoids re-parsing the text payload.
10777
-
10778
- Schema notes: sessions have a structured-metadata layer populated by the
10779
- \`backfill-metadata\` CLI; \`client_name\` / \`client_version\` /
10780
- \`client_platform\` may be null on freshly imported captures until that
10781
- command runs.
10782
-
10783
- Redaction: every tool that returns frame contents OR derived views
10784
- of them (\`get_message\`, \`get_session_messages\`, \`search_messages\`,
10785
- \`get_session_metadata\`, \`get_session_summary\`, \`diff_sessions\`)
10786
- redacts auth headers and proxy tokens (\`Authorization\`,
10787
- \`X-Api-Key\`, JetBrains \`_meta.proxyConfig.proxies[*].proxy.headers.*\`,
10788
- etc). Sensitive fields appear as \`<REDACTED>\`. This is
10789
- unconditional; there is no opt-out flag, because the human owns the
10790
- share decision (use \`acp-devtools export <id> --raw\` on the CLI when
10791
- the export stays on your machine). \`search_messages\` indexes the
10792
- pre-redaction bytes so you can still find a frame by a token fragment,
10793
- but the returned \`raw\` is the redacted copy \u2014 do not quote the live
10794
- secret back to the user. \`diff_sessions\` operates on already-redacted
10795
- frames, so a token that rotated between two sessions shows up as equal
10796
- ("<REDACTED>" on both sides) rather than as a change \u2014 this is
10797
- intentional, treating "token rotated" as a leaked side channel.`;
10798
11279
  function annotations(meta) {
10799
11280
  return {
10800
11281
  title: meta.title,
@@ -10809,60 +11290,8 @@ function structuredResult(payload) {
10809
11290
  structuredContent: payload
10810
11291
  };
10811
11292
  }
10812
- var sessionSummaryRowSchema = z.object({
10813
- id: z.number(),
10814
- name: z.string().nullable(),
10815
- agent_command: z.string().nullable(),
10816
- started_at: z.number(),
10817
- ended_at: z.number().nullable(),
10818
- message_count: z.number(),
10819
- client_name: z.string().nullable(),
10820
- imported_at: z.number().nullable(),
10821
- client_version: z.string().nullable(),
10822
- client_platform: z.string().nullable(),
10823
- agent_name: z.string().nullable(),
10824
- agent_version: z.string().nullable(),
10825
- protocol_version: z.number().nullable(),
10826
- current_mode: z.string().nullable(),
10827
- current_model: z.string().nullable()
10828
- });
10829
- var insightSchema = z.object({
10830
- kind: z.enum(["hotspot", "long-tail", "outlier", "busiest", "errors"]),
10831
- summary: z.string(),
10832
- detail: z.string().optional(),
10833
- methods: z.array(z.string())
10834
- });
10835
- var perMethodSchema = z.object({
10836
- method: z.string(),
10837
- kind: z.enum(["request", "notification"]),
10838
- count: z.number(),
10839
- sampleSize: z.number(),
10840
- p50: z.number().nullable(),
10841
- p99: z.number().nullable(),
10842
- max: z.number().nullable(),
10843
- totalLatencyMs: z.number().nullable(),
10844
- latencies: z.array(z.number())
10845
- });
10846
- var messageSchema = z.object({
10847
- seq: z.number(),
10848
- timestamp: z.number(),
10849
- direction: z.enum(["editor-to-agent", "agent-to-editor"]),
10850
- kind: z.enum(["request", "response", "notification", "error", "unknown"]),
10851
- method: z.string().optional(),
10852
- rpcId: z.union([z.string(), z.number()]).optional(),
10853
- raw: z.string(),
10854
- payload: z.unknown().nullable(),
10855
- parseError: z.string().optional()
10856
- });
10857
- var latencySchema = z.object({
10858
- sampleSize: z.number(),
10859
- p50: z.number().nullable(),
10860
- p90: z.number().nullable(),
10861
- p99: z.number().nullable(),
10862
- max: z.number().nullable()
10863
- });
10864
- function registerMcpCommand(program2) {
10865
- program2.command("mcp").description(
11293
+ function registerMcpCommand(program) {
11294
+ program.command("mcp").description(
10866
11295
  'Run an MCP server over stdio that exposes saved captures as read-only tools. Wire into Claude Code via .claude/mcp_servers.json \u2014 then ask Claude to "find spec violations in last 10 sessions" or "compare p99 of WebStorm vs Zed".'
10867
11296
  ).option("--db <path>", "captures database", defaultCapturesDbPath()).option("--name <name>", "server name advertised in MCP handshake", "acp-devtools").action(async (opts) => {
10868
11297
  const server = buildMcpServer(opts);
@@ -11426,10 +11855,125 @@ function errorResult(message) {
11426
11855
  content: [{ type: "text", text: message }]
11427
11856
  };
11428
11857
  }
11858
+ var SERVER_INSTRUCTIONS, sessionSummaryRowSchema, insightSchema, perMethodSchema, messageSchema, latencySchema;
11859
+ var init_mcp = __esm({
11860
+ "src/commands/mcp.ts"() {
11861
+ "use strict";
11862
+ init_dist();
11863
+ init_version();
11864
+ SERVER_INSTRUCTIONS = `acp-devtools exposes a local SQLite store of captured
11865
+ Agent Client Protocol (ACP) sessions. ACP is the editor\u2194agent JSON-RPC
11866
+ protocol used by Claude Code, Goose, Codex, and other IDE agents.
11429
11867
 
11430
- // src/commands/mock-agent.ts
11431
- import { mkdirSync as mkdirSync3 } from "fs";
11432
- import { dirname as dirname2 } from "path";
11868
+ Every tool here is **read-only** \u2014 nothing in this server writes to the
11869
+ database. Use it to investigate:
11870
+
11871
+ - a slow session (\`get_latency_stats\` returns per-method p50/p99/max
11872
+ plus auto-detected insights: hotspot, long-tail, outlier, busiest,
11873
+ errors)
11874
+ - a misbehaving agent (\`find_spec_violations\` validates every frame
11875
+ against the ACP JSON schema)
11876
+ - specific events (\`get_session_messages\` + \`get_message\` for the
11877
+ raw JSON-RPC payload)
11878
+ - capture inventory (\`list_sessions\`, \`find_sessions_by_client\`)
11879
+ - one-shot digest of a session (\`get_session_summary\` bundles
11880
+ metadata + latency stats + insights in one call \u2014 preferred over
11881
+ three separate calls when you just need an overview)
11882
+ - a regression or A/B comparison between two sessions
11883
+ (\`diff_sessions\` aligns two captures and reports added / removed
11884
+ frames and field-level payload changes)
11885
+
11886
+ A typical investigation:
11887
+ 1. \`list_sessions\` to see what is captured
11888
+ 2. \`get_session_summary({session_id})\` for the headline numbers and
11889
+ auto-detected insights \u2014 start here when you don't know what's
11890
+ wrong yet
11891
+ 3. drill into a specific method or message with
11892
+ \`get_session_messages\` / \`get_message\` / \`get_paired\`
11893
+
11894
+ For common investigations the server also exposes canned prompts via
11895
+ \`prompts/list\` \u2014 \`triage_slow_session\`, \`audit_spec_violations\`,
11896
+ \`compare_clients\`. Each prompt seeds the right tool sequence.
11897
+
11898
+ Every tool declares an \`outputSchema\`, so results include both
11899
+ \`content\` (text JSON) and \`structuredContent\` (typed object matching
11900
+ the schema). Prefer \`structuredContent\` if your client supports it \u2014
11901
+ it avoids re-parsing the text payload.
11902
+
11903
+ Schema notes: sessions have a structured-metadata layer populated by the
11904
+ \`backfill-metadata\` CLI; \`client_name\` / \`client_version\` /
11905
+ \`client_platform\` may be null on freshly imported captures until that
11906
+ command runs.
11907
+
11908
+ Redaction: every tool that returns frame contents OR derived views
11909
+ of them (\`get_message\`, \`get_session_messages\`, \`search_messages\`,
11910
+ \`get_session_metadata\`, \`get_session_summary\`, \`diff_sessions\`)
11911
+ redacts auth headers and proxy tokens (\`Authorization\`,
11912
+ \`X-Api-Key\`, JetBrains \`_meta.proxyConfig.proxies[*].proxy.headers.*\`,
11913
+ etc). Sensitive fields appear as \`<REDACTED>\`. This is
11914
+ unconditional; there is no opt-out flag, because the human owns the
11915
+ share decision (use \`acp-devtools export <id> --raw\` on the CLI when
11916
+ the export stays on your machine). \`search_messages\` indexes the
11917
+ pre-redaction bytes so you can still find a frame by a token fragment,
11918
+ but the returned \`raw\` is the redacted copy \u2014 do not quote the live
11919
+ secret back to the user. \`diff_sessions\` operates on already-redacted
11920
+ frames, so a token that rotated between two sessions shows up as equal
11921
+ ("<REDACTED>" on both sides) rather than as a change \u2014 this is
11922
+ intentional, treating "token rotated" as a leaked side channel.`;
11923
+ sessionSummaryRowSchema = z.object({
11924
+ id: z.number(),
11925
+ name: z.string().nullable(),
11926
+ agent_command: z.string().nullable(),
11927
+ started_at: z.number(),
11928
+ ended_at: z.number().nullable(),
11929
+ message_count: z.number(),
11930
+ client_name: z.string().nullable(),
11931
+ imported_at: z.number().nullable(),
11932
+ client_version: z.string().nullable(),
11933
+ client_platform: z.string().nullable(),
11934
+ agent_name: z.string().nullable(),
11935
+ agent_version: z.string().nullable(),
11936
+ protocol_version: z.number().nullable(),
11937
+ current_mode: z.string().nullable(),
11938
+ current_model: z.string().nullable()
11939
+ });
11940
+ insightSchema = z.object({
11941
+ kind: z.enum(["hotspot", "long-tail", "outlier", "busiest", "errors"]),
11942
+ summary: z.string(),
11943
+ detail: z.string().optional(),
11944
+ methods: z.array(z.string())
11945
+ });
11946
+ perMethodSchema = z.object({
11947
+ method: z.string(),
11948
+ kind: z.enum(["request", "notification"]),
11949
+ count: z.number(),
11950
+ sampleSize: z.number(),
11951
+ p50: z.number().nullable(),
11952
+ p99: z.number().nullable(),
11953
+ max: z.number().nullable(),
11954
+ totalLatencyMs: z.number().nullable(),
11955
+ latencies: z.array(z.number())
11956
+ });
11957
+ messageSchema = z.object({
11958
+ seq: z.number(),
11959
+ timestamp: z.number(),
11960
+ direction: z.enum(["editor-to-agent", "agent-to-editor"]),
11961
+ kind: z.enum(["request", "response", "notification", "error", "unknown"]),
11962
+ method: z.string().optional(),
11963
+ rpcId: z.union([z.string(), z.number()]).optional(),
11964
+ raw: z.string(),
11965
+ payload: z.unknown().nullable(),
11966
+ parseError: z.string().optional()
11967
+ });
11968
+ latencySchema = z.object({
11969
+ sampleSize: z.number(),
11970
+ p50: z.number().nullable(),
11971
+ p90: z.number().nullable(),
11972
+ p99: z.number().nullable(),
11973
+ max: z.number().nullable()
11974
+ });
11975
+ }
11976
+ });
11433
11977
 
11434
11978
  // src/commands/playback-source.ts
11435
11979
  import { readFileSync as readFileSync3 } from "fs";
@@ -11475,10 +12019,18 @@ function loadPlaybackScript(opts) {
11475
12019
  db.close();
11476
12020
  }
11477
12021
  }
12022
+ var init_playback_source = __esm({
12023
+ "src/commands/playback-source.ts"() {
12024
+ "use strict";
12025
+ init_dist();
12026
+ }
12027
+ });
11478
12028
 
11479
12029
  // src/commands/mock-agent.ts
11480
- function registerMockAgentCommand(program2) {
11481
- program2.command("mock-agent").description(
12030
+ import { mkdirSync as mkdirSync3 } from "fs";
12031
+ import { dirname as dirname2 } from "path";
12032
+ function registerMockAgentCommand(program) {
12033
+ program.command("mock-agent").description(
11482
12034
  "Pretend to be an ACP agent by replaying a recorded session script. Reads JSON-RPC from stdin (real editor), writes recorded responses to stdout. Wire it into an IDE `agent_servers` config to drive plugin tests without a live LLM. By default reads from the shared captures database (latest session); use --session for a specific id or --script for a JSON export from a teammate."
11483
12035
  ).option("--session <id>", "session id from the captures database (default: latest)").option("--db <path>", "captures database", defaultCapturesDbPath()).option("--script <file>", "load from a JSON export instead of the database (mutually exclusive with --session)").option("--log <mode>", "echo every wire frame to stderr (json | pretty | none)", "none").option(
11484
12036
  "--realtime",
@@ -11612,12 +12164,19 @@ function registerMockAgentCommand(program2) {
11612
12164
  drain();
11613
12165
  });
11614
12166
  }
12167
+ var init_mock_agent = __esm({
12168
+ "src/commands/mock-agent.ts"() {
12169
+ "use strict";
12170
+ init_dist();
12171
+ init_playback_source();
12172
+ }
12173
+ });
11615
12174
 
11616
12175
  // src/commands/mock-editor.ts
11617
12176
  import { mkdirSync as mkdirSync4 } from "fs";
11618
12177
  import { dirname as dirname3 } from "path";
11619
- function registerMockEditorCommand(program2) {
11620
- program2.command("mock-editor").description(
12178
+ function registerMockEditorCommand(program) {
12179
+ program.command("mock-editor").description(
11621
12180
  "Pretend to be an editor by replaying a recorded session script. Spawns the given agent as a child process, sends it the recorded editor-side frames in order, and reads agent responses. Useful for CI tests of your own ACP agent without a real IDE. By default reads from the shared captures database (latest session); use --session for a specific id or --script for a JSON export from a teammate."
11622
12181
  ).passThroughOptions().argument("<agent>", "agent executable (e.g. `node fixtures/mock-agent.js` or the path to a real ACP agent)").argument("[agent-args...]", "arguments forwarded to the agent").option("--session <id>", "session id from the captures database (default: latest)").option("--db <path>", "captures database", defaultCapturesDbPath()).option("--script <file>", "load from a JSON export instead of the database (mutually exclusive with --session)").option("--cwd <dir>", "working directory for the agent").option("--log <mode>", "echo every wire frame to stderr (json | pretty | none)", "none").option(
11623
12182
  "--realtime",
@@ -11780,14 +12339,17 @@ function registerMockEditorCommand(program2) {
11780
12339
  }
11781
12340
  });
11782
12341
  }
12342
+ var init_mock_editor = __esm({
12343
+ "src/commands/mock-editor.ts"() {
12344
+ "use strict";
12345
+ init_dist();
12346
+ init_playback_source();
12347
+ }
12348
+ });
11783
12349
 
11784
12350
  // src/commands/proxy.ts
11785
12351
  import { mkdirSync as mkdirSync5 } from "fs";
11786
12352
  import { dirname as dirname4 } from "path";
11787
- var DIRECTION_LABEL = {
11788
- "editor-to-agent": "\u2192 AGENT",
11789
- "agent-to-editor": "\u2190 AGENT"
11790
- };
11791
12353
  function formatPretty(msg) {
11792
12354
  const time = new Date(msg.timestamp).toISOString().slice(11, 23);
11793
12355
  const dir = DIRECTION_LABEL[msg.direction];
@@ -11797,9 +12359,9 @@ function formatPretty(msg) {
11797
12359
  return `${head}${id}${err}
11798
12360
  ${msg.raw}`;
11799
12361
  }
11800
- function registerProxyCommand(program2) {
12362
+ function registerProxyCommand(program) {
11801
12363
  const knownAgentList = listAgents().map((a) => a.shortName).join(", ");
11802
- program2.command("proxy").description("Run an ACP agent through a capturing proxy").passThroughOptions().argument("[agent]", 'agent executable (e.g. "goose"); optional when --agent is set').argument("[agent-args...]", "arguments forwarded to the agent").option(
12364
+ program.command("proxy").description("Run an ACP agent through a capturing proxy").passThroughOptions().argument("[agent]", 'agent executable (e.g. "goose"); optional when --agent is set').argument("[agent-args...]", "arguments forwarded to the agent").option(
11803
12365
  "--agent <name>",
11804
12366
  `preset for a known ACP agent (${knownAgentList})`
11805
12367
  ).option("--log <mode>", "message log format: json | pretty | none", "none").option("--cwd <dir>", "working directory for the agent").option(
@@ -12025,6 +12587,17 @@ function registerProxyCommand(program2) {
12025
12587
  }
12026
12588
  });
12027
12589
  }
12590
+ var DIRECTION_LABEL;
12591
+ var init_proxy3 = __esm({
12592
+ "src/commands/proxy.ts"() {
12593
+ "use strict";
12594
+ init_dist();
12595
+ DIRECTION_LABEL = {
12596
+ "editor-to-agent": "\u2192 AGENT",
12597
+ "agent-to-editor": "\u2190 AGENT"
12598
+ };
12599
+ }
12600
+ });
12028
12601
 
12029
12602
  // src/commands/replay.ts
12030
12603
  import { readFileSync as readFileSync4 } from "fs";
@@ -12080,8 +12653,8 @@ function loadFromSqlite(dbPath, idArg) {
12080
12653
  cleanup: () => db.close()
12081
12654
  };
12082
12655
  }
12083
- function registerReplayCommand(program2) {
12084
- program2.command("replay").description(
12656
+ function registerReplayCommand(program) {
12657
+ program.command("replay").description(
12085
12658
  "Serve a recorded session over WebSocket for replay in the UI. By default replays the latest session in the captures database; pass a session id, or --file to replay a JSON export."
12086
12659
  ).argument("[id]", "session id to replay (default: latest in the database)").option("--db <path>", "captures database", defaultCapturesDbPath()).option("--file <path>", "replay a JSON export file instead of a saved session").option("--ws-port <port>", "WebSocket port", "3737").option("--ws-host <host>", "WebSocket bind address", "127.0.0.1").action(async (idArg, opts) => {
12087
12660
  const wsPort = Number(opts.wsPort);
@@ -12138,10 +12711,16 @@ function registerReplayCommand(program2) {
12138
12711
  source.cleanup();
12139
12712
  });
12140
12713
  }
12714
+ var init_replay2 = __esm({
12715
+ "src/commands/replay.ts"() {
12716
+ "use strict";
12717
+ init_dist();
12718
+ }
12719
+ });
12141
12720
 
12142
12721
  // src/commands/search.ts
12143
- function registerSearchCommand(program2) {
12144
- program2.command("search").description(
12722
+ function registerSearchCommand(program) {
12723
+ program.command("search").description(
12145
12724
  "Find messages containing a substring across every saved session. Substring match is case-insensitive. Use `inspect` to read individual messages once you know where to look."
12146
12725
  ).argument("<query>", "substring to search for (case-insensitive)").option("--db <path>", "captures database", defaultCapturesDbPath()).option("--limit <n>", "maximum hits to print", "50").option("--session <id>", "restrict search to a single session").option("--in-method", "match only method names (default: match anywhere in the raw frame)").option("--in-payload", "match only inside the payload (skip method-only hits)").option("--json", "emit machine-readable JSON instead of a table").action((query, opts) => {
12147
12726
  const limit = Number(opts.limit);
@@ -12213,7 +12792,6 @@ function registerSearchCommand(program2) {
12213
12792
  process.stdout.write(renderHits(s, hits, needle));
12214
12793
  });
12215
12794
  }
12216
- var SNIPPET_LEN = 80;
12217
12795
  function makeSnippet(raw, needle) {
12218
12796
  const idx = raw.toLowerCase().indexOf(needle);
12219
12797
  if (idx < 0) return raw.slice(0, SNIPPET_LEN);
@@ -12223,12 +12801,6 @@ function makeSnippet(raw, needle) {
12223
12801
  const suffix = end < raw.length ? "\u2026" : "";
12224
12802
  return prefix + raw.slice(start, end).replace(/\s+/g, " ") + suffix;
12225
12803
  }
12226
- var METHOD_MAX2 = 32;
12227
- var COLUMNS2 = [
12228
- { title: "LOC", align: "left" },
12229
- { title: "METHOD", align: "left" },
12230
- { title: "MATCH", align: "left" }
12231
- ];
12232
12804
  function renderHits(s, hits, needle) {
12233
12805
  const body = hits.map((h) => [
12234
12806
  s.cyan(`#${h.sessionId}/${h.seq}`),
@@ -12257,10 +12829,26 @@ function truncate2(s, max) {
12257
12829
  if (s.length <= max) return s;
12258
12830
  return s.slice(0, Math.max(1, max - 1)) + "\u2026";
12259
12831
  }
12832
+ var SNIPPET_LEN, METHOD_MAX2, COLUMNS2;
12833
+ var init_search = __esm({
12834
+ "src/commands/search.ts"() {
12835
+ "use strict";
12836
+ init_dist();
12837
+ init_style();
12838
+ init_table();
12839
+ SNIPPET_LEN = 80;
12840
+ METHOD_MAX2 = 32;
12841
+ COLUMNS2 = [
12842
+ { title: "LOC", align: "left" },
12843
+ { title: "METHOD", align: "left" },
12844
+ { title: "MATCH", align: "left" }
12845
+ ];
12846
+ }
12847
+ });
12260
12848
 
12261
12849
  // src/commands/session-info.ts
12262
- function registerSessionInfoCommand(program2) {
12263
- program2.command("session-info").description(
12850
+ function registerSessionInfoCommand(program) {
12851
+ program.command("session-info").description(
12264
12852
  "Print derived client/agent metadata for a saved session \u2014 the terminal equivalent of the inspector's session info panel."
12265
12853
  ).argument("<id>", "session id (see `acp-devtools list`)").option("--db <path>", "captures database", defaultCapturesDbPath()).option("--json", "machine-readable JSON instead of human-readable text").action((rawId, opts) => {
12266
12854
  const id = Number(rawId);
@@ -12400,11 +12988,17 @@ function shortAgent(agentCommand) {
12400
12988
  }
12401
12989
  return parts[0] ?? null;
12402
12990
  }
12991
+ var init_session_info = __esm({
12992
+ "src/commands/session-info.ts"() {
12993
+ "use strict";
12994
+ init_dist();
12995
+ init_style();
12996
+ }
12997
+ });
12403
12998
 
12404
12999
  // src/commands/stats.ts
12405
- var percentile2 = percentile;
12406
- function registerStatsCommand(program2) {
12407
- program2.command("stats").description(
13000
+ function registerStatsCommand(program) {
13001
+ program.command("stats").description(
12408
13002
  "Aggregate counts and latency percentiles for one saved session \u2014 the equivalent of the inspector's footer StatsBar."
12409
13003
  ).argument("<id>", "session id (see `acp-devtools list`)").option("--db <path>", "captures database", defaultCapturesDbPath()).option("--by-method", "add a per-method breakdown table (method \xB7 count \xB7 p50 \xB7 p99)").option("--json", "machine-readable JSON instead of human-readable text").action((rawId, opts) => {
12410
13004
  const id = Number(rawId);
@@ -12512,13 +13106,13 @@ function computeStats(info, messages) {
12512
13106
  p90: latencies.length ? percentile2(latencies, 90) : null,
12513
13107
  p99: latencies.length ? percentile2(latencies, 99) : null,
12514
13108
  max: latencies.length ? latencies[latencies.length - 1] : null,
12515
- mean: latencies.length ? Math.round(mean(latencies)) : null
13109
+ mean: latencies.length ? Math.round(mean2(latencies)) : null
12516
13110
  },
12517
13111
  perMethod,
12518
13112
  insights
12519
13113
  };
12520
13114
  }
12521
- function mean(xs) {
13115
+ function mean2(xs) {
12522
13116
  return xs.reduce((acc, x) => acc + x, 0) / xs.length;
12523
13117
  }
12524
13118
  function formatLatency3(ms) {
@@ -12623,27 +13217,6 @@ function renderStats(s, stats, byMethod) {
12623
13217
  }
12624
13218
  return lines.join("");
12625
13219
  }
12626
- var INSIGHT_GLYPH = {
12627
- hotspot: "!",
12628
- "long-tail": "~",
12629
- outlier: "*",
12630
- busiest: "#",
12631
- errors: "x"
12632
- };
12633
- var INSIGHT_LABEL = {
12634
- hotspot: "HOTSPOT ",
12635
- "long-tail": "LONG TAIL",
12636
- outlier: "OUTLIER ",
12637
- busiest: "BUSIEST ",
12638
- errors: "ERRORS "
12639
- };
12640
- var INSIGHT_COLOR = {
12641
- hotspot: "red",
12642
- "long-tail": "yellow",
12643
- outlier: "magenta",
12644
- busiest: "cyan",
12645
- errors: "red"
12646
- };
12647
13220
  function renderInsights(s, insights) {
12648
13221
  const lines = [heading3(s, "INSIGHTS") + "\n"];
12649
13222
  for (const i of insights) {
@@ -12656,7 +13229,6 @@ function renderInsights(s, insights) {
12656
13229
  }
12657
13230
  return lines.join("");
12658
13231
  }
12659
- var METHOD_MAX3 = 40;
12660
13232
  function renderPerMethod(s, rows) {
12661
13233
  const columns = [
12662
13234
  { title: "METHOD", align: "left" },
@@ -12681,6 +13253,39 @@ function renderPerMethod(s, rows) {
12681
13253
  });
12682
13254
  return renderTable(s, columns, body);
12683
13255
  }
13256
+ var percentile2, INSIGHT_GLYPH, INSIGHT_LABEL, INSIGHT_COLOR, METHOD_MAX3;
13257
+ var init_stats = __esm({
13258
+ "src/commands/stats.ts"() {
13259
+ "use strict";
13260
+ init_dist();
13261
+ init_style();
13262
+ init_palette();
13263
+ init_table();
13264
+ percentile2 = percentile;
13265
+ INSIGHT_GLYPH = {
13266
+ hotspot: "!",
13267
+ "long-tail": "~",
13268
+ outlier: "*",
13269
+ busiest: "#",
13270
+ errors: "x"
13271
+ };
13272
+ INSIGHT_LABEL = {
13273
+ hotspot: "HOTSPOT ",
13274
+ "long-tail": "LONG TAIL",
13275
+ outlier: "OUTLIER ",
13276
+ busiest: "BUSIEST ",
13277
+ errors: "ERRORS "
13278
+ };
13279
+ INSIGHT_COLOR = {
13280
+ hotspot: "red",
13281
+ "long-tail": "yellow",
13282
+ outlier: "magenta",
13283
+ busiest: "cyan",
13284
+ errors: "red"
13285
+ };
13286
+ METHOD_MAX3 = 40;
13287
+ }
13288
+ });
12684
13289
 
12685
13290
  // src/commands/ui.ts
12686
13291
  import { createReadStream, existsSync as existsSync7, statSync as statSync3 } from "fs";
@@ -12688,26 +13293,6 @@ import { createServer } from "http";
12688
13293
  import { dirname as dirname5, extname, join as join4, normalize, resolve, sep } from "path";
12689
13294
  import { fileURLToPath } from "url";
12690
13295
  import { spawn as spawn2 } from "child_process";
12691
- var MIME_TYPES = {
12692
- ".html": "text/html; charset=utf-8",
12693
- ".js": "application/javascript; charset=utf-8",
12694
- ".mjs": "application/javascript; charset=utf-8",
12695
- ".css": "text/css; charset=utf-8",
12696
- ".json": "application/json; charset=utf-8",
12697
- ".map": "application/json; charset=utf-8",
12698
- ".svg": "image/svg+xml",
12699
- ".png": "image/png",
12700
- ".jpg": "image/jpeg",
12701
- ".jpeg": "image/jpeg",
12702
- ".gif": "image/gif",
12703
- ".webp": "image/webp",
12704
- ".ico": "image/x-icon",
12705
- ".woff": "font/woff",
12706
- ".woff2": "font/woff2",
12707
- ".ttf": "font/ttf",
12708
- ".otf": "font/otf",
12709
- ".txt": "text/plain; charset=utf-8"
12710
- };
12711
13296
  function uiDistDir() {
12712
13297
  const here = dirname5(fileURLToPath(import.meta.url));
12713
13298
  return resolve(here, "ui");
@@ -12762,8 +13347,8 @@ function openBrowser(url) {
12762
13347
  } catch {
12763
13348
  }
12764
13349
  }
12765
- function registerUiCommand(program2) {
12766
- program2.command("ui").description("Serve the acp-devtools UI from an embedded static bundle").option("--port <port>", "HTTP port to bind", "3737").option("--host <host>", "HTTP bind address", "127.0.0.1").option("--no-open", "don't auto-open the browser").option(
13350
+ function registerUiCommand(program) {
13351
+ program.command("ui").description("Serve the acp-devtools UI from an embedded static bundle").option("--port <port>", "HTTP port to bind", "3737").option("--host <host>", "HTTP bind address", "127.0.0.1").option("--no-open", "don't auto-open the browser").option(
12767
13352
  "--captures-db <file>",
12768
13353
  "path to the captures SQLite database (default: ~/.acp-devtools/captures.db)"
12769
13354
  ).action(async (opts) => {
@@ -12826,10 +13411,37 @@ function registerUiCommand(program2) {
12826
13411
  });
12827
13412
  });
12828
13413
  }
13414
+ var MIME_TYPES;
13415
+ var init_ui = __esm({
13416
+ "src/commands/ui.ts"() {
13417
+ "use strict";
13418
+ init_dist();
13419
+ MIME_TYPES = {
13420
+ ".html": "text/html; charset=utf-8",
13421
+ ".js": "application/javascript; charset=utf-8",
13422
+ ".mjs": "application/javascript; charset=utf-8",
13423
+ ".css": "text/css; charset=utf-8",
13424
+ ".json": "application/json; charset=utf-8",
13425
+ ".map": "application/json; charset=utf-8",
13426
+ ".svg": "image/svg+xml",
13427
+ ".png": "image/png",
13428
+ ".jpg": "image/jpeg",
13429
+ ".jpeg": "image/jpeg",
13430
+ ".gif": "image/gif",
13431
+ ".webp": "image/webp",
13432
+ ".ico": "image/x-icon",
13433
+ ".woff": "font/woff",
13434
+ ".woff2": "font/woff2",
13435
+ ".ttf": "font/ttf",
13436
+ ".otf": "font/otf",
13437
+ ".txt": "text/plain; charset=utf-8"
13438
+ };
13439
+ }
13440
+ });
12829
13441
 
12830
13442
  // src/commands/validate.ts
12831
- function registerValidateCommand(program2) {
12832
- program2.command("validate").description(
13443
+ function registerValidateCommand(program) {
13444
+ program.command("validate").description(
12833
13445
  "Check every frame in a session against the official ACP JSON schema (`@agentclientprotocol/sdk`). Use to confirm that an editor or agent you do not control speaks the protocol correctly \u2014 same data the inspector's \u26A0 SPEC badges surface."
12834
13446
  ).argument("<id>", "session id (see `acp-devtools list`)").option("--db <path>", "captures database", defaultCapturesDbPath()).option("--limit <n>", "maximum violations to print", "200").option("--method <pattern>", "only check messages whose method contains this substring").option("--json", "machine-readable JSON").action((rawId, opts) => {
12835
13447
  const id = Number(rawId);
@@ -12933,16 +13545,6 @@ function registerValidateCommand(program2) {
12933
13545
  process.exit(1);
12934
13546
  });
12935
13547
  }
12936
- var METHOD_MAX4 = 28;
12937
- var SCHEMA_MAX = 28;
12938
- var PATH_MAX = 38;
12939
- var COLUMNS3 = [
12940
- { title: "SEQ", align: "right" },
12941
- { title: "METHOD", align: "left" },
12942
- { title: "SCHEMA", align: "left" },
12943
- { title: "PATH", align: "left" },
12944
- { title: "ERROR", align: "left" }
12945
- ];
12946
13548
  function renderViolations(s, violations) {
12947
13549
  const body = violations.map((v) => [
12948
13550
  s.dim(`#${v.seq}`),
@@ -12957,6 +13559,26 @@ function truncate3(s, max) {
12957
13559
  if (s.length <= max) return s;
12958
13560
  return s.slice(0, Math.max(1, max - 1)) + "\u2026";
12959
13561
  }
13562
+ var METHOD_MAX4, SCHEMA_MAX, PATH_MAX, COLUMNS3;
13563
+ var init_validate2 = __esm({
13564
+ "src/commands/validate.ts"() {
13565
+ "use strict";
13566
+ init_dist();
13567
+ init_inspect();
13568
+ init_style();
13569
+ init_table();
13570
+ METHOD_MAX4 = 28;
13571
+ SCHEMA_MAX = 28;
13572
+ PATH_MAX = 38;
13573
+ COLUMNS3 = [
13574
+ { title: "SEQ", align: "right" },
13575
+ { title: "METHOD", align: "left" },
13576
+ { title: "SCHEMA", align: "left" },
13577
+ { title: "PATH", align: "left" },
13578
+ { title: "ERROR", align: "left" }
13579
+ ];
13580
+ }
13581
+ });
12960
13582
 
12961
13583
  // src/lib/help.ts
12962
13584
  import { homedir as homedir4 } from "os";
@@ -12966,102 +13588,6 @@ function tidyHome(text, home = homedir4()) {
12966
13588
  const collapsed = text.split(escapedHome).join("~").split(home).join("~");
12967
13589
  return collapsed.replace(/~[^"\s)]*/g, (segment) => segment.replace(/\\+/g, "/"));
12968
13590
  }
12969
- var GROUPS = [
12970
- { title: "Capture", commands: ["proxy", "mock-agent", "mock-editor"] },
12971
- {
12972
- title: "Inspect",
12973
- commands: ["list", "inspect", "search", "stats", "diff", "session-info", "validate"]
12974
- },
12975
- { title: "View", commands: ["ui", "replay"] },
12976
- { title: "Manage", commands: ["export", "import", "delete", "backfill-metadata"] },
12977
- { title: "Setup", commands: ["doctor", "mcp"] }
12978
- ];
12979
- var SUMMARIES = {
12980
- proxy: "Capture an agent's traffic through a proxy",
12981
- "mock-agent": "Replay a session as a fake ACP agent",
12982
- "mock-editor": "Replay a session as a fake editor",
12983
- list: "List saved sessions, newest first",
12984
- inspect: "Print a session's frames to stdout",
12985
- search: "Search frame payloads across sessions",
12986
- stats: "Latency percentiles for one session",
12987
- diff: "Compare two sessions frame by frame",
12988
- "session-info": "Show a session's client/agent metadata",
12989
- validate: "Check frames against the ACP spec",
12990
- ui: "Open the web inspector",
12991
- replay: "Stream a session to the UI over WebSocket",
12992
- export: "Export a session to self-contained JSON",
12993
- import: "Import a JSON export into the store",
12994
- delete: "Delete saved sessions permanently",
12995
- "backfill-metadata": "Recompute session metadata columns",
12996
- doctor: "Diagnose setup and report issues",
12997
- mcp: "Expose captures to Claude over MCP"
12998
- };
12999
- var ROOT_EXAMPLES = [
13000
- "# Capture a Claude Code session (Zed adapter)",
13001
- "acp-devtools proxy npx -y @zed-industries/claude-code-acp",
13002
- "",
13003
- "# Browse captured sessions in the web inspector",
13004
- "acp-devtools ui",
13005
- "",
13006
- "# List sessions, then print one to the terminal",
13007
- "acp-devtools list",
13008
- "acp-devtools inspect 12",
13009
- "",
13010
- "# Diagnose your setup when nothing's being captured",
13011
- "acp-devtools doctor"
13012
- ];
13013
- var EXAMPLES = {
13014
- proxy: [
13015
- "# Wrap the Zed Claude Code adapter and capture every frame",
13016
- "acp-devtools proxy npx -y @zed-industries/claude-code-acp",
13017
- "",
13018
- "# Capture headless, into a specific database",
13019
- "acp-devtools proxy --no-ws --save-to /tmp/run.db node ./my-agent.js"
13020
- ],
13021
- ui: [
13022
- "# Serve the inspector on :3737 and open a browser",
13023
- "acp-devtools ui",
13024
- "",
13025
- "# Pick a port and stay headless",
13026
- "acp-devtools ui --port 4000 --no-open"
13027
- ],
13028
- list: [
13029
- "acp-devtools list",
13030
- "",
13031
- "# Machine-readable JSON",
13032
- "acp-devtools list --json"
13033
- ],
13034
- inspect: [
13035
- "acp-devtools inspect 12",
13036
- "",
13037
- "# Only request/response frames for one method",
13038
- "acp-devtools inspect 12 --method session/prompt --paired"
13039
- ],
13040
- search: ["acp-devtools search session/prompt", "acp-devtools search rate_limit --in-payload"],
13041
- stats: ["acp-devtools stats 12", "acp-devtools stats 12 --by-method"],
13042
- diff: ["# Worked yesterday, broke today?", "acp-devtools diff 41 42"],
13043
- export: [
13044
- "acp-devtools export 12 -o session-12.json",
13045
- "",
13046
- "# Straight to stdout for sharing",
13047
- "acp-devtools export 12 > session-12.json"
13048
- ],
13049
- import: ["acp-devtools import session-12.json"],
13050
- delete: ["acp-devtools delete 12", "acp-devtools delete 12 13 14"],
13051
- replay: ["acp-devtools replay 12", "acp-devtools replay --file session-12.json"],
13052
- validate: ["acp-devtools validate 12"],
13053
- "session-info": ["acp-devtools session-info 12"],
13054
- doctor: ["acp-devtools doctor"],
13055
- mcp: ["# Read-only MCP server over stdio (wire into .claude/mcp_servers.json)", "acp-devtools mcp"],
13056
- "backfill-metadata": [
13057
- "acp-devtools backfill-metadata",
13058
- "",
13059
- "# Recompute a single session",
13060
- "acp-devtools backfill-metadata 12"
13061
- ]
13062
- };
13063
- var INDENT = " ";
13064
- var GAP = 3;
13065
13591
  function heading4(s, title) {
13066
13592
  return s.bold(s.yellow(title.toUpperCase()));
13067
13593
  }
@@ -13189,8 +13715,8 @@ function formatCommandHelp(cmd, helper, s, width) {
13189
13715
  }
13190
13716
  return out.join("\n");
13191
13717
  }
13192
- function configureCliHelp(program2) {
13193
- program2.configureHelp({
13718
+ function configureCliHelp(program) {
13719
+ program.configureHelp({
13194
13720
  helpWidth: process.stdout.columns ?? 80,
13195
13721
  formatHelp(cmd, helper) {
13196
13722
  const s = createStyler(colorEnabled(process.stdout));
@@ -13199,37 +13725,252 @@ function configureCliHelp(program2) {
13199
13725
  }
13200
13726
  });
13201
13727
  const err = createStyler(colorEnabled(process.stderr));
13202
- program2.configureOutput({
13728
+ program.configureOutput({
13203
13729
  outputError(str, write) {
13204
13730
  write(err.red(str));
13205
13731
  }
13206
13732
  });
13207
13733
  }
13734
+ var GROUPS, SUMMARIES, ROOT_EXAMPLES, EXAMPLES, INDENT, GAP;
13735
+ var init_help = __esm({
13736
+ "src/lib/help.ts"() {
13737
+ "use strict";
13738
+ init_style();
13739
+ GROUPS = [
13740
+ { title: "Capture", commands: ["proxy", "mock-agent", "mock-editor"] },
13741
+ {
13742
+ title: "Inspect",
13743
+ commands: ["list", "inspect", "search", "stats", "diff", "session-info", "validate"]
13744
+ },
13745
+ { title: "View", commands: ["ui", "replay"] },
13746
+ { title: "Manage", commands: ["export", "import", "delete", "backfill-metadata"] },
13747
+ { title: "Setup", commands: ["doctor", "mcp"] }
13748
+ ];
13749
+ SUMMARIES = {
13750
+ proxy: "Capture an agent's traffic through a proxy",
13751
+ "mock-agent": "Replay a session as a fake ACP agent",
13752
+ "mock-editor": "Replay a session as a fake editor",
13753
+ list: "List saved sessions, newest first",
13754
+ inspect: "Print a session's frames to stdout",
13755
+ search: "Search frame payloads across sessions",
13756
+ stats: "Latency percentiles for one session",
13757
+ diff: "Compare two sessions frame by frame",
13758
+ "session-info": "Show a session's client/agent metadata",
13759
+ validate: "Check frames against the ACP spec",
13760
+ ui: "Open the web inspector",
13761
+ replay: "Stream a session to the UI over WebSocket",
13762
+ export: "Export a session to self-contained JSON",
13763
+ import: "Import a JSON export into the store",
13764
+ delete: "Delete saved sessions permanently",
13765
+ "backfill-metadata": "Recompute session metadata columns",
13766
+ doctor: "Diagnose setup and report issues",
13767
+ mcp: "Expose captures to Claude over MCP"
13768
+ };
13769
+ ROOT_EXAMPLES = [
13770
+ "# Capture a Claude Code session (Zed adapter)",
13771
+ "acp-devtools proxy npx -y @zed-industries/claude-code-acp",
13772
+ "",
13773
+ "# Browse captured sessions in the web inspector",
13774
+ "acp-devtools ui",
13775
+ "",
13776
+ "# List sessions, then print one to the terminal",
13777
+ "acp-devtools list",
13778
+ "acp-devtools inspect 12",
13779
+ "",
13780
+ "# Diagnose your setup when nothing's being captured",
13781
+ "acp-devtools doctor"
13782
+ ];
13783
+ EXAMPLES = {
13784
+ proxy: [
13785
+ "# Wrap the Zed Claude Code adapter and capture every frame",
13786
+ "acp-devtools proxy npx -y @zed-industries/claude-code-acp",
13787
+ "",
13788
+ "# Capture headless, into a specific database",
13789
+ "acp-devtools proxy --no-ws --save-to /tmp/run.db node ./my-agent.js"
13790
+ ],
13791
+ ui: [
13792
+ "# Serve the inspector on :3737 and open a browser",
13793
+ "acp-devtools ui",
13794
+ "",
13795
+ "# Pick a port and stay headless",
13796
+ "acp-devtools ui --port 4000 --no-open"
13797
+ ],
13798
+ list: [
13799
+ "acp-devtools list",
13800
+ "",
13801
+ "# Machine-readable JSON",
13802
+ "acp-devtools list --json"
13803
+ ],
13804
+ inspect: [
13805
+ "acp-devtools inspect 12",
13806
+ "",
13807
+ "# Only request/response frames for one method",
13808
+ "acp-devtools inspect 12 --method session/prompt --paired"
13809
+ ],
13810
+ search: ["acp-devtools search session/prompt", "acp-devtools search rate_limit --in-payload"],
13811
+ stats: ["acp-devtools stats 12", "acp-devtools stats 12 --by-method"],
13812
+ diff: ["# Worked yesterday, broke today?", "acp-devtools diff 41 42"],
13813
+ export: [
13814
+ "acp-devtools export 12 -o session-12.json",
13815
+ "",
13816
+ "# Straight to stdout for sharing",
13817
+ "acp-devtools export 12 > session-12.json"
13818
+ ],
13819
+ import: ["acp-devtools import session-12.json"],
13820
+ delete: ["acp-devtools delete 12", "acp-devtools delete 12 13 14"],
13821
+ replay: ["acp-devtools replay 12", "acp-devtools replay --file session-12.json"],
13822
+ validate: ["acp-devtools validate 12"],
13823
+ "session-info": ["acp-devtools session-info 12"],
13824
+ doctor: ["acp-devtools doctor"],
13825
+ mcp: ["# Read-only MCP server over stdio (wire into .claude/mcp_servers.json)", "acp-devtools mcp"],
13826
+ "backfill-metadata": [
13827
+ "acp-devtools backfill-metadata",
13828
+ "",
13829
+ "# Recompute a single session",
13830
+ "acp-devtools backfill-metadata 12"
13831
+ ]
13832
+ };
13833
+ INDENT = " ";
13834
+ GAP = 3;
13835
+ }
13836
+ });
13208
13837
 
13209
13838
  // src/program.ts
13839
+ var program_exports = {};
13840
+ __export(program_exports, {
13841
+ buildProgram: () => buildProgram
13842
+ });
13843
+ import { Command } from "commander";
13210
13844
  function buildProgram() {
13211
- const program2 = new Command();
13212
- program2.name("acp-devtools").description("Visual debugger / inspector for the Agent Client Protocol (ACP)").version(CLI_VERSION).enablePositionalOptions();
13213
- configureCliHelp(program2);
13214
- registerProxyCommand(program2);
13215
- registerReplayCommand(program2);
13216
- registerUiCommand(program2);
13217
- registerDoctorCommand(program2);
13218
- registerExportCommand(program2);
13219
- registerImportCommand(program2);
13220
- registerDeleteCommand(program2);
13221
- registerDiffCommand(program2);
13222
- registerListCommand(program2);
13223
- registerInspectCommand(program2);
13224
- registerSearchCommand(program2);
13225
- registerSessionInfoCommand(program2);
13226
- registerStatsCommand(program2);
13227
- registerBackfillMetadataCommand(program2);
13228
- registerMcpCommand(program2);
13229
- registerMockAgentCommand(program2);
13230
- registerMockEditorCommand(program2);
13231
- registerValidateCommand(program2);
13232
- return program2;
13845
+ const program = new Command();
13846
+ program.name("acp-devtools").description("Visual debugger / inspector for the Agent Client Protocol (ACP)").version(CLI_VERSION).enablePositionalOptions();
13847
+ configureCliHelp(program);
13848
+ registerProxyCommand(program);
13849
+ registerReplayCommand(program);
13850
+ registerUiCommand(program);
13851
+ registerDoctorCommand(program);
13852
+ registerExportCommand(program);
13853
+ registerImportCommand(program);
13854
+ registerDeleteCommand(program);
13855
+ registerDiffCommand(program);
13856
+ registerListCommand(program);
13857
+ registerInspectCommand(program);
13858
+ registerSearchCommand(program);
13859
+ registerSessionInfoCommand(program);
13860
+ registerStatsCommand(program);
13861
+ registerBackfillMetadataCommand(program);
13862
+ registerMcpCommand(program);
13863
+ registerMockAgentCommand(program);
13864
+ registerMockEditorCommand(program);
13865
+ registerValidateCommand(program);
13866
+ return program;
13867
+ }
13868
+ var init_program = __esm({
13869
+ "src/program.ts"() {
13870
+ "use strict";
13871
+ init_backfill_metadata();
13872
+ init_delete();
13873
+ init_diff();
13874
+ init_doctor();
13875
+ init_export2();
13876
+ init_import();
13877
+ init_inspect();
13878
+ init_list();
13879
+ init_mcp();
13880
+ init_mock_agent();
13881
+ init_mock_editor();
13882
+ init_proxy3();
13883
+ init_replay2();
13884
+ init_search();
13885
+ init_session_info();
13886
+ init_stats();
13887
+ init_ui();
13888
+ init_validate2();
13889
+ init_help();
13890
+ init_version();
13891
+ }
13892
+ });
13893
+
13894
+ // src/lib/native-error.ts
13895
+ var BINDING_PATTERNS = [
13896
+ /Could not locate the bindings file/i,
13897
+ /better[_-]sqlite3/i,
13898
+ /node[_-]gyp/i,
13899
+ /prebuild[-_]install/i,
13900
+ /\.node['"]?\)?:?\s/i,
13901
+ /Cannot find module .*\.node/i,
13902
+ /NODE_MODULE_VERSION/i
13903
+ ];
13904
+ function isNativeBindingError(err) {
13905
+ if (!err) return false;
13906
+ const msg = err instanceof Error ? `${err.message}
13907
+ ${err.stack ?? ""}` : String(err);
13908
+ return BINDING_PATTERNS.some((re) => re.test(msg));
13909
+ }
13910
+ function detectInstallSource(ctx) {
13911
+ const p = (ctx.binaryPath ?? "").toLowerCase();
13912
+ if (!p) return "unknown";
13913
+ if (p.includes("/cellar/acp-devtools/") || p.includes("/homebrew/")) {
13914
+ return "homebrew";
13915
+ }
13916
+ if (p.includes("linuxbrew")) return "homebrew";
13917
+ if (p.includes("/lib/node_modules/acp-devtools") || p.includes("\\node_modules\\acp-devtools") || p.includes("/npm/node_modules/acp-devtools") || p.includes("\\npm\\acp-devtools")) {
13918
+ return "npm-global";
13919
+ }
13920
+ return "unknown";
13921
+ }
13922
+ function formatNativeBindingMessage(err, ctx) {
13923
+ const source = detectInstallSource(ctx);
13924
+ const detail = err instanceof Error ? err.message : String(err ?? "unknown error");
13925
+ const lines = [
13926
+ "acp-devtools: native module `better-sqlite3` failed to load.",
13927
+ "",
13928
+ "The SQLite binding (`build/Release/better_sqlite3.node`) is missing or",
13929
+ "incompatible with this Node version. acp-devtools needs it to read and",
13930
+ "write the captures database \u2014 every command depends on it.",
13931
+ ""
13932
+ ];
13933
+ if (source === "homebrew") {
13934
+ lines.push(
13935
+ "You installed via Homebrew. Rebuild the binding in place:",
13936
+ "",
13937
+ ' PREFIX="$(brew --prefix acp-devtools)/libexec/lib/node_modules/acp-devtools"',
13938
+ ' npm rebuild --prefix "$PREFIX" better-sqlite3',
13939
+ "",
13940
+ "Or reinstall once the formula fix lands:",
13941
+ "",
13942
+ " brew update && brew reinstall acp-devtools",
13943
+ ""
13944
+ );
13945
+ } else if (source === "npm-global") {
13946
+ lines.push(
13947
+ "You installed via `npm i -g`. Rebuild the binding:",
13948
+ "",
13949
+ " npm rebuild -g better-sqlite3",
13950
+ "",
13951
+ "If that fails the prebuild lookup probably has no match for your Node",
13952
+ "version, and source build needs Python 3 + a C++ toolchain (Xcode CLT",
13953
+ "on macOS, build-essential on Linux, Visual Studio Build Tools on",
13954
+ "Windows). Install those and retry, or pin to an older Node major.",
13955
+ ""
13956
+ );
13957
+ } else {
13958
+ lines.push(
13959
+ "Try rebuilding the native dependency:",
13960
+ "",
13961
+ " npm rebuild better-sqlite3",
13962
+ "",
13963
+ "If you installed globally via npm, add `-g`. If via Homebrew, run",
13964
+ "`brew reinstall acp-devtools` once the formula is patched.",
13965
+ ""
13966
+ );
13967
+ }
13968
+ lines.push(
13969
+ `Underlying error: ${detail}`,
13970
+ `Node: ${process.version} \xB7 platform: ${process.platform}/${process.arch}`,
13971
+ "Report unresolved cases at https://github.com/maksugr/acp-devtools/issues"
13972
+ );
13973
+ return lines.join("\n") + "\n";
13233
13974
  }
13234
13975
 
13235
13976
  // src/index.ts
@@ -13258,10 +13999,10 @@ var KNOWN_SUBCOMMANDS = /* @__PURE__ */ new Set([
13258
13999
  "-V",
13259
14000
  "--version"
13260
14001
  ]);
13261
- function expandArgv(rawArgs) {
14002
+ function expandArgv(rawArgs, defaultAgent, isAgentShortcut2) {
13262
14003
  if (rawArgs.length === 0) {
13263
14004
  if (!process.stdin.isTTY) {
13264
- return ["proxy", "--agent", DEFAULT_AGENT];
14005
+ return ["proxy", "--agent", defaultAgent];
13265
14006
  }
13266
14007
  return rawArgs;
13267
14008
  }
@@ -13269,16 +14010,50 @@ function expandArgv(rawArgs) {
13269
14010
  if (KNOWN_SUBCOMMANDS.has(first)) {
13270
14011
  return rawArgs;
13271
14012
  }
13272
- if (isAgentShortcut(first)) {
14013
+ if (isAgentShortcut2(first)) {
13273
14014
  return ["proxy", "--agent", first, ...rawArgs.slice(1)];
13274
14015
  }
13275
14016
  return ["proxy", ...rawArgs];
13276
14017
  }
13277
- var expanded = expandArgv(process.argv.slice(2));
13278
- var program = buildProgram();
13279
- program.parseAsync([process.argv[0], process.argv[1], ...expanded]).catch((err) => {
13280
- process.stderr.write(`acp-devtools: ${err instanceof Error ? err.message : String(err)}
13281
- `);
14018
+ function reportFatal(err, prefix = "acp-devtools") {
14019
+ if (isNativeBindingError(err)) {
14020
+ process.stderr.write(
14021
+ formatNativeBindingMessage(err, {
14022
+ binaryPath: process.argv[1] ?? ""
14023
+ })
14024
+ );
14025
+ process.exit(1);
14026
+ }
14027
+ process.stderr.write(
14028
+ `${prefix}: ${err instanceof Error ? err.message : String(err)}
14029
+ `
14030
+ );
13282
14031
  process.exit(1);
13283
- });
14032
+ }
14033
+ async function main() {
14034
+ let core;
14035
+ let buildProgram2;
14036
+ try {
14037
+ core = await Promise.resolve().then(() => (init_dist(), dist_exports));
14038
+ ({ buildProgram: buildProgram2 } = await Promise.resolve().then(() => (init_program(), program_exports)));
14039
+ } catch (err) {
14040
+ reportFatal(err, "acp-devtools: failed to start");
14041
+ }
14042
+ const expanded = expandArgv(
14043
+ process.argv.slice(2),
14044
+ core.DEFAULT_AGENT,
14045
+ core.isAgentShortcut
14046
+ );
14047
+ const program = buildProgram2();
14048
+ try {
14049
+ await program.parseAsync([
14050
+ process.argv[0],
14051
+ process.argv[1],
14052
+ ...expanded
14053
+ ]);
14054
+ } catch (err) {
14055
+ reportFatal(err);
14056
+ }
14057
+ }
14058
+ main();
13284
14059
  //# sourceMappingURL=index.js.map