acp-devtools 0.5.0 → 0.6.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/README.md +10 -3
- package/dist/index.js +600 -145
- package/dist/ui/assets/{index-C5YKMrXl.js → index-CbQUeOWm.js} +17 -17
- package/dist/ui/index.html +1 -1
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -3755,21 +3755,21 @@ var require_fast_uri = __commonJS({
|
|
|
3755
3755
|
normalizeString(uri, options);
|
|
3756
3756
|
} else if (typeof uri === "object") {
|
|
3757
3757
|
uri = /** @type {T} */
|
|
3758
|
-
|
|
3758
|
+
parse2(serialize(uri, options), options);
|
|
3759
3759
|
}
|
|
3760
3760
|
return uri;
|
|
3761
3761
|
}
|
|
3762
3762
|
function resolve2(baseURI, relativeURI, options) {
|
|
3763
3763
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
3764
|
-
const resolved = resolveComponent(
|
|
3764
|
+
const resolved = resolveComponent(parse2(baseURI, schemelessOptions), parse2(relativeURI, schemelessOptions), schemelessOptions, true);
|
|
3765
3765
|
schemelessOptions.skipEscape = true;
|
|
3766
3766
|
return serialize(resolved, schemelessOptions);
|
|
3767
3767
|
}
|
|
3768
3768
|
function resolveComponent(base, relative, options, skipNormalization) {
|
|
3769
3769
|
const target = {};
|
|
3770
3770
|
if (!skipNormalization) {
|
|
3771
|
-
base =
|
|
3772
|
-
relative =
|
|
3771
|
+
base = parse2(serialize(base, options), options);
|
|
3772
|
+
relative = parse2(serialize(relative, options), options);
|
|
3773
3773
|
}
|
|
3774
3774
|
options = options || {};
|
|
3775
3775
|
if (!options.tolerant && relative.scheme) {
|
|
@@ -3992,7 +3992,7 @@ var require_fast_uri = __commonJS({
|
|
|
3992
3992
|
}
|
|
3993
3993
|
return { parsed, malformedAuthorityOrPort };
|
|
3994
3994
|
}
|
|
3995
|
-
function
|
|
3995
|
+
function parse2(uri, opts) {
|
|
3996
3996
|
return parseWithStatus(uri, opts).parsed;
|
|
3997
3997
|
}
|
|
3998
3998
|
function normalizeString(uri, opts) {
|
|
@@ -4021,7 +4021,7 @@ var require_fast_uri = __commonJS({
|
|
|
4021
4021
|
resolveComponent,
|
|
4022
4022
|
equal,
|
|
4023
4023
|
serialize,
|
|
4024
|
-
parse
|
|
4024
|
+
parse: parse2
|
|
4025
4025
|
};
|
|
4026
4026
|
module.exports = fastUri;
|
|
4027
4027
|
module.exports.default = fastUri;
|
|
@@ -8518,6 +8518,14 @@ var init_registry = __esm({
|
|
|
8518
8518
|
command: "opencode",
|
|
8519
8519
|
args: ["acp"],
|
|
8520
8520
|
requiresExternalInstall: true
|
|
8521
|
+
},
|
|
8522
|
+
junie: {
|
|
8523
|
+
shortName: "junie",
|
|
8524
|
+
displayName: "Junie",
|
|
8525
|
+
description: "JetBrains Junie CLI \u2014 install separately, then this runs `junie --acp=true`",
|
|
8526
|
+
command: "junie",
|
|
8527
|
+
args: ["--acp=true"],
|
|
8528
|
+
requiresExternalInstall: true
|
|
8521
8529
|
}
|
|
8522
8530
|
};
|
|
8523
8531
|
DEFAULT_AGENT = "claude-code";
|
|
@@ -9171,6 +9179,9 @@ var init_export = __esm({
|
|
|
9171
9179
|
});
|
|
9172
9180
|
|
|
9173
9181
|
// ../core/dist/storage/redact.js
|
|
9182
|
+
function isNameValuePair(v) {
|
|
9183
|
+
return v !== null && typeof v === "object" && !Array.isArray(v) && typeof v["name"] === "string" && typeof v["value"] === "string";
|
|
9184
|
+
}
|
|
9174
9185
|
function redactMessage(message) {
|
|
9175
9186
|
if (message.payload == null) {
|
|
9176
9187
|
return { redacted: message, count: 0 };
|
|
@@ -9201,6 +9212,9 @@ function redactValue(value, ctx) {
|
|
|
9201
9212
|
return { value: out, count };
|
|
9202
9213
|
}
|
|
9203
9214
|
if (value !== null && typeof value === "object") {
|
|
9215
|
+
if (isNameValuePair(value) && SENSITIVE_HEADER_NAMES.has(value.name.toLowerCase())) {
|
|
9216
|
+
return redactPair(value, ctx);
|
|
9217
|
+
}
|
|
9204
9218
|
let count = 0;
|
|
9205
9219
|
const out = {};
|
|
9206
9220
|
for (const [k, v] of Object.entries(value)) {
|
|
@@ -9209,6 +9223,20 @@ function redactValue(value, ctx) {
|
|
|
9209
9223
|
count += 1;
|
|
9210
9224
|
continue;
|
|
9211
9225
|
}
|
|
9226
|
+
if (CREDENTIAL_LIST_KEYS.has(k.toLowerCase())) {
|
|
9227
|
+
if (Array.isArray(v) && v.some(isNameValuePair)) {
|
|
9228
|
+
const r2 = redactPairList(v, ctx);
|
|
9229
|
+
out[k] = r2.value;
|
|
9230
|
+
count += r2.count;
|
|
9231
|
+
continue;
|
|
9232
|
+
}
|
|
9233
|
+
if (k.toLowerCase() === "env" && v !== null && typeof v === "object" && !Array.isArray(v)) {
|
|
9234
|
+
const r2 = redactHeadersBlock(v);
|
|
9235
|
+
out[k] = r2.value;
|
|
9236
|
+
count += r2.count;
|
|
9237
|
+
continue;
|
|
9238
|
+
}
|
|
9239
|
+
}
|
|
9212
9240
|
if (ctx.inProxyConfig && k === "headers" && v !== null && typeof v === "object" && !Array.isArray(v)) {
|
|
9213
9241
|
const r2 = redactHeadersBlock(v);
|
|
9214
9242
|
out[k] = r2.value;
|
|
@@ -9224,13 +9252,37 @@ function redactValue(value, ctx) {
|
|
|
9224
9252
|
}
|
|
9225
9253
|
return { value, count: 0 };
|
|
9226
9254
|
}
|
|
9255
|
+
function redactPair(pair, ctx) {
|
|
9256
|
+
let count = pair.value === REDACTED_PLACEHOLDER ? 0 : 1;
|
|
9257
|
+
const out = {};
|
|
9258
|
+
for (const [k, v] of Object.entries(pair)) {
|
|
9259
|
+
if (k === "value" || k === "name") {
|
|
9260
|
+
out[k] = k === "value" ? REDACTED_PLACEHOLDER : v;
|
|
9261
|
+
continue;
|
|
9262
|
+
}
|
|
9263
|
+
const r = redactValue(v, ctx);
|
|
9264
|
+
out[k] = r.value;
|
|
9265
|
+
count += r.count;
|
|
9266
|
+
}
|
|
9267
|
+
return { value: out, count };
|
|
9268
|
+
}
|
|
9269
|
+
function redactPairList(list, ctx) {
|
|
9270
|
+
let count = 0;
|
|
9271
|
+
const out = list.map((item) => {
|
|
9272
|
+
const r = isNameValuePair(item) ? redactPair(item, ctx) : redactValue(item, ctx);
|
|
9273
|
+
count += r.count;
|
|
9274
|
+
return r.value;
|
|
9275
|
+
});
|
|
9276
|
+
return { value: out, count };
|
|
9277
|
+
}
|
|
9227
9278
|
function redactHeadersBlock(obj) {
|
|
9228
9279
|
let count = 0;
|
|
9229
9280
|
const out = {};
|
|
9230
9281
|
for (const [k, v] of Object.entries(obj)) {
|
|
9231
9282
|
if (typeof v === "string") {
|
|
9232
9283
|
out[k] = REDACTED_PLACEHOLDER;
|
|
9233
|
-
|
|
9284
|
+
if (v !== REDACTED_PLACEHOLDER)
|
|
9285
|
+
count += 1;
|
|
9234
9286
|
} else {
|
|
9235
9287
|
out[k] = v;
|
|
9236
9288
|
}
|
|
@@ -9257,7 +9309,7 @@ function redactSessionExport(exp) {
|
|
|
9257
9309
|
fieldsRedacted
|
|
9258
9310
|
};
|
|
9259
9311
|
}
|
|
9260
|
-
var REDACTED_PLACEHOLDER, SENSITIVE_HEADER_NAMES;
|
|
9312
|
+
var REDACTED_PLACEHOLDER, SENSITIVE_HEADER_NAMES, CREDENTIAL_LIST_KEYS;
|
|
9261
9313
|
var init_redact = __esm({
|
|
9262
9314
|
"../core/dist/storage/redact.js"() {
|
|
9263
9315
|
"use strict";
|
|
@@ -9275,6 +9327,7 @@ var init_redact = __esm({
|
|
|
9275
9327
|
"cookie",
|
|
9276
9328
|
"set-cookie"
|
|
9277
9329
|
]);
|
|
9330
|
+
CREDENTIAL_LIST_KEYS = /* @__PURE__ */ new Set(["headers", "env"]);
|
|
9278
9331
|
}
|
|
9279
9332
|
});
|
|
9280
9333
|
|
|
@@ -10073,6 +10126,142 @@ var init_dist = __esm({
|
|
|
10073
10126
|
}
|
|
10074
10127
|
});
|
|
10075
10128
|
|
|
10129
|
+
// src/lib/style.ts
|
|
10130
|
+
function colorEnabled(stream = process.stdout, env = process.env) {
|
|
10131
|
+
if (env.FORCE_COLOR === "0" || env.FORCE_COLOR === "false") return false;
|
|
10132
|
+
if (env.FORCE_COLOR !== void 0) return true;
|
|
10133
|
+
if (env.NO_COLOR !== void 0) return false;
|
|
10134
|
+
return Boolean(stream.isTTY);
|
|
10135
|
+
}
|
|
10136
|
+
function paint(enabled, code, s) {
|
|
10137
|
+
if (!enabled) return s;
|
|
10138
|
+
return `${ESC}[${CODES[code]}m${s}${ESC}[${CODES.reset}m`;
|
|
10139
|
+
}
|
|
10140
|
+
function createStyler(enabled = colorEnabled()) {
|
|
10141
|
+
const wrap = (code) => (s) => paint(enabled, code, s);
|
|
10142
|
+
return {
|
|
10143
|
+
enabled,
|
|
10144
|
+
bold: wrap("bold"),
|
|
10145
|
+
dim: wrap("dim"),
|
|
10146
|
+
italic: wrap("italic"),
|
|
10147
|
+
underline: wrap("underline"),
|
|
10148
|
+
red: wrap("red"),
|
|
10149
|
+
green: wrap("green"),
|
|
10150
|
+
yellow: wrap("yellow"),
|
|
10151
|
+
blue: wrap("blue"),
|
|
10152
|
+
magenta: wrap("magenta"),
|
|
10153
|
+
cyan: wrap("cyan"),
|
|
10154
|
+
gray: wrap("gray")
|
|
10155
|
+
};
|
|
10156
|
+
}
|
|
10157
|
+
function stripAnsi(s) {
|
|
10158
|
+
return s.replace(ANSI_PATTERN, "");
|
|
10159
|
+
}
|
|
10160
|
+
function visibleWidth(s) {
|
|
10161
|
+
return stripAnsi(s).length;
|
|
10162
|
+
}
|
|
10163
|
+
var ESC, CODES, ANSI_PATTERN;
|
|
10164
|
+
var init_style = __esm({
|
|
10165
|
+
"src/lib/style.ts"() {
|
|
10166
|
+
"use strict";
|
|
10167
|
+
ESC = String.fromCharCode(27);
|
|
10168
|
+
CODES = {
|
|
10169
|
+
reset: 0,
|
|
10170
|
+
bold: 1,
|
|
10171
|
+
dim: 2,
|
|
10172
|
+
italic: 3,
|
|
10173
|
+
underline: 4,
|
|
10174
|
+
red: 31,
|
|
10175
|
+
green: 32,
|
|
10176
|
+
yellow: 33,
|
|
10177
|
+
blue: 34,
|
|
10178
|
+
magenta: 35,
|
|
10179
|
+
cyan: 36,
|
|
10180
|
+
gray: 90
|
|
10181
|
+
};
|
|
10182
|
+
ANSI_PATTERN = new RegExp(`${ESC}\\[[0-9;]*m`, "g");
|
|
10183
|
+
}
|
|
10184
|
+
});
|
|
10185
|
+
|
|
10186
|
+
// src/lib/table.ts
|
|
10187
|
+
function renderTable(s, columns, rows, opts = {}) {
|
|
10188
|
+
const indent = opts.indent ?? "";
|
|
10189
|
+
const gap = opts.gap ?? " ";
|
|
10190
|
+
const widths = columns.map(
|
|
10191
|
+
(col, c) => Math.max(visibleWidth(col.title), ...rows.map((r) => visibleWidth(r[c] ?? "")))
|
|
10192
|
+
);
|
|
10193
|
+
const pad2 = (text, width, align) => {
|
|
10194
|
+
const fill = " ".repeat(Math.max(0, width - visibleWidth(text)));
|
|
10195
|
+
return align === "right" ? fill + text : text + fill;
|
|
10196
|
+
};
|
|
10197
|
+
const lineFor = (cells, color) => {
|
|
10198
|
+
const rendered = columns.map((col, c) => {
|
|
10199
|
+
const align = col.align ?? "left";
|
|
10200
|
+
const text = cells[c] ?? "";
|
|
10201
|
+
const isLast = c === columns.length - 1;
|
|
10202
|
+
const cell = isLast && align === "left" ? text : pad2(text, widths[c], align);
|
|
10203
|
+
return color(cell);
|
|
10204
|
+
});
|
|
10205
|
+
return indent + rendered.join(gap);
|
|
10206
|
+
};
|
|
10207
|
+
const out = [];
|
|
10208
|
+
out.push(
|
|
10209
|
+
lineFor(
|
|
10210
|
+
columns.map((col) => col.title),
|
|
10211
|
+
(t) => s.dim(t)
|
|
10212
|
+
)
|
|
10213
|
+
);
|
|
10214
|
+
for (const row2 of rows) {
|
|
10215
|
+
out.push(lineFor(row2, (t) => t));
|
|
10216
|
+
}
|
|
10217
|
+
return out.map((l) => l + "\n").join("");
|
|
10218
|
+
}
|
|
10219
|
+
var init_table = __esm({
|
|
10220
|
+
"src/lib/table.ts"() {
|
|
10221
|
+
"use strict";
|
|
10222
|
+
init_style();
|
|
10223
|
+
}
|
|
10224
|
+
});
|
|
10225
|
+
|
|
10226
|
+
// src/commands/agents.ts
|
|
10227
|
+
function registerAgentsCommand(program) {
|
|
10228
|
+
program.command("agents").description("List the built-in agent shortcuts (use with proxy / setup / --agent)").option("--json", "emit machine-readable JSON instead of a table").action((opts) => {
|
|
10229
|
+
const agents = listAgents();
|
|
10230
|
+
if (opts.json) {
|
|
10231
|
+
process.stdout.write(JSON.stringify(agents, null, 2) + "\n");
|
|
10232
|
+
return;
|
|
10233
|
+
}
|
|
10234
|
+
const s = createStyler(colorEnabled(process.stdout));
|
|
10235
|
+
const rows = agents.map((a) => [
|
|
10236
|
+
s.green(a.shortName),
|
|
10237
|
+
a.displayName,
|
|
10238
|
+
[a.command, ...a.args].join(" "),
|
|
10239
|
+
a.requiresExternalInstall ? "install separately" : "auto via npx"
|
|
10240
|
+
]);
|
|
10241
|
+
process.stdout.write(renderTable(s, COLUMNS, rows));
|
|
10242
|
+
process.stdout.write(
|
|
10243
|
+
s.dim(
|
|
10244
|
+
"\nUse a shortcut: acp-devtools <name> \xB7 proxy --agent <name> \xB7 setup <name> --editor <zed|jetbrains>\nAny other ACP agent: acp-devtools setup --editor <ed> -- <command\u2026>\n"
|
|
10245
|
+
)
|
|
10246
|
+
);
|
|
10247
|
+
});
|
|
10248
|
+
}
|
|
10249
|
+
var COLUMNS;
|
|
10250
|
+
var init_agents2 = __esm({
|
|
10251
|
+
"src/commands/agents.ts"() {
|
|
10252
|
+
"use strict";
|
|
10253
|
+
init_dist();
|
|
10254
|
+
init_style();
|
|
10255
|
+
init_table();
|
|
10256
|
+
COLUMNS = [
|
|
10257
|
+
{ title: "SHORTCUT" },
|
|
10258
|
+
{ title: "NAME" },
|
|
10259
|
+
{ title: "RUNS" },
|
|
10260
|
+
{ title: "INSTALL" }
|
|
10261
|
+
];
|
|
10262
|
+
}
|
|
10263
|
+
});
|
|
10264
|
+
|
|
10076
10265
|
// src/commands/backfill-metadata.ts
|
|
10077
10266
|
function backfillSession(db, id) {
|
|
10078
10267
|
let session;
|
|
@@ -10221,63 +10410,6 @@ var init_delete = __esm({
|
|
|
10221
10410
|
}
|
|
10222
10411
|
});
|
|
10223
10412
|
|
|
10224
|
-
// src/lib/style.ts
|
|
10225
|
-
function colorEnabled(stream = process.stdout, env = process.env) {
|
|
10226
|
-
if (env.FORCE_COLOR === "0" || env.FORCE_COLOR === "false") return false;
|
|
10227
|
-
if (env.FORCE_COLOR !== void 0) return true;
|
|
10228
|
-
if (env.NO_COLOR !== void 0) return false;
|
|
10229
|
-
return Boolean(stream.isTTY);
|
|
10230
|
-
}
|
|
10231
|
-
function paint(enabled, code, s) {
|
|
10232
|
-
if (!enabled) return s;
|
|
10233
|
-
return `${ESC}[${CODES[code]}m${s}${ESC}[${CODES.reset}m`;
|
|
10234
|
-
}
|
|
10235
|
-
function createStyler(enabled = colorEnabled()) {
|
|
10236
|
-
const wrap = (code) => (s) => paint(enabled, code, s);
|
|
10237
|
-
return {
|
|
10238
|
-
enabled,
|
|
10239
|
-
bold: wrap("bold"),
|
|
10240
|
-
dim: wrap("dim"),
|
|
10241
|
-
italic: wrap("italic"),
|
|
10242
|
-
underline: wrap("underline"),
|
|
10243
|
-
red: wrap("red"),
|
|
10244
|
-
green: wrap("green"),
|
|
10245
|
-
yellow: wrap("yellow"),
|
|
10246
|
-
blue: wrap("blue"),
|
|
10247
|
-
magenta: wrap("magenta"),
|
|
10248
|
-
cyan: wrap("cyan"),
|
|
10249
|
-
gray: wrap("gray")
|
|
10250
|
-
};
|
|
10251
|
-
}
|
|
10252
|
-
function stripAnsi(s) {
|
|
10253
|
-
return s.replace(ANSI_PATTERN, "");
|
|
10254
|
-
}
|
|
10255
|
-
function visibleWidth(s) {
|
|
10256
|
-
return stripAnsi(s).length;
|
|
10257
|
-
}
|
|
10258
|
-
var ESC, CODES, ANSI_PATTERN;
|
|
10259
|
-
var init_style = __esm({
|
|
10260
|
-
"src/lib/style.ts"() {
|
|
10261
|
-
"use strict";
|
|
10262
|
-
ESC = String.fromCharCode(27);
|
|
10263
|
-
CODES = {
|
|
10264
|
-
reset: 0,
|
|
10265
|
-
bold: 1,
|
|
10266
|
-
dim: 2,
|
|
10267
|
-
italic: 3,
|
|
10268
|
-
underline: 4,
|
|
10269
|
-
red: 31,
|
|
10270
|
-
green: 32,
|
|
10271
|
-
yellow: 33,
|
|
10272
|
-
blue: 34,
|
|
10273
|
-
magenta: 35,
|
|
10274
|
-
cyan: 36,
|
|
10275
|
-
gray: 90
|
|
10276
|
-
};
|
|
10277
|
-
ANSI_PATTERN = new RegExp(`${ESC}\\[[0-9;]*m`, "g");
|
|
10278
|
-
}
|
|
10279
|
-
});
|
|
10280
|
-
|
|
10281
10413
|
// src/lib/palette.ts
|
|
10282
10414
|
function colorKind(s, kind, text) {
|
|
10283
10415
|
switch (kind) {
|
|
@@ -10311,46 +10443,6 @@ var init_palette = __esm({
|
|
|
10311
10443
|
}
|
|
10312
10444
|
});
|
|
10313
10445
|
|
|
10314
|
-
// src/lib/table.ts
|
|
10315
|
-
function renderTable(s, columns, rows, opts = {}) {
|
|
10316
|
-
const indent = opts.indent ?? "";
|
|
10317
|
-
const gap = opts.gap ?? " ";
|
|
10318
|
-
const widths = columns.map(
|
|
10319
|
-
(col, c) => Math.max(visibleWidth(col.title), ...rows.map((r) => visibleWidth(r[c] ?? "")))
|
|
10320
|
-
);
|
|
10321
|
-
const pad2 = (text, width, align) => {
|
|
10322
|
-
const fill = " ".repeat(Math.max(0, width - visibleWidth(text)));
|
|
10323
|
-
return align === "right" ? fill + text : text + fill;
|
|
10324
|
-
};
|
|
10325
|
-
const lineFor = (cells, color) => {
|
|
10326
|
-
const rendered = columns.map((col, c) => {
|
|
10327
|
-
const align = col.align ?? "left";
|
|
10328
|
-
const text = cells[c] ?? "";
|
|
10329
|
-
const isLast = c === columns.length - 1;
|
|
10330
|
-
const cell = isLast && align === "left" ? text : pad2(text, widths[c], align);
|
|
10331
|
-
return color(cell);
|
|
10332
|
-
});
|
|
10333
|
-
return indent + rendered.join(gap);
|
|
10334
|
-
};
|
|
10335
|
-
const out = [];
|
|
10336
|
-
out.push(
|
|
10337
|
-
lineFor(
|
|
10338
|
-
columns.map((col) => col.title),
|
|
10339
|
-
(t) => s.dim(t)
|
|
10340
|
-
)
|
|
10341
|
-
);
|
|
10342
|
-
for (const row2 of rows) {
|
|
10343
|
-
out.push(lineFor(row2, (t) => t));
|
|
10344
|
-
}
|
|
10345
|
-
return out.map((l) => l + "\n").join("");
|
|
10346
|
-
}
|
|
10347
|
-
var init_table = __esm({
|
|
10348
|
-
"src/lib/table.ts"() {
|
|
10349
|
-
"use strict";
|
|
10350
|
-
init_style();
|
|
10351
|
-
}
|
|
10352
|
-
});
|
|
10353
|
-
|
|
10354
10446
|
// src/commands/diff.ts
|
|
10355
10447
|
function registerDiffCommand(program) {
|
|
10356
10448
|
program.command("diff").description(
|
|
@@ -10634,10 +10726,130 @@ var init_diff = __esm({
|
|
|
10634
10726
|
}
|
|
10635
10727
|
});
|
|
10636
10728
|
|
|
10729
|
+
// src/lib/setup-config.ts
|
|
10730
|
+
import { homedir as homedir3, platform } from "os";
|
|
10731
|
+
import { join as join3 } from "path";
|
|
10732
|
+
import { applyEdits, modify, parse } from "jsonc-parser";
|
|
10733
|
+
function isEditor(value) {
|
|
10734
|
+
return EDITORS.includes(value);
|
|
10735
|
+
}
|
|
10736
|
+
function zedSettingsPath() {
|
|
10737
|
+
if (platform() === "win32") {
|
|
10738
|
+
return join3(process.env.APPDATA ?? "", "Zed", "settings.json");
|
|
10739
|
+
}
|
|
10740
|
+
if (platform() === "darwin") {
|
|
10741
|
+
return join3(homedir3(), ".config", "zed", "settings.json");
|
|
10742
|
+
}
|
|
10743
|
+
return join3(process.env.XDG_CONFIG_HOME ?? join3(homedir3(), ".config"), "zed", "settings.json");
|
|
10744
|
+
}
|
|
10745
|
+
function jetbrainsConfigPath() {
|
|
10746
|
+
return join3(homedir3(), ".jetbrains", "acp.json");
|
|
10747
|
+
}
|
|
10748
|
+
function editorInfo(editor) {
|
|
10749
|
+
if (editor === "zed") {
|
|
10750
|
+
return {
|
|
10751
|
+
id: "zed",
|
|
10752
|
+
label: "Zed",
|
|
10753
|
+
configPath: zedSettingsPath(),
|
|
10754
|
+
placement: "add the agent_servers block to Zed\u2019s settings.json (create the file or the key if missing)",
|
|
10755
|
+
restart: "reopen the agent panel so Zed re-reads the config",
|
|
10756
|
+
dedicatedFile: false
|
|
10757
|
+
};
|
|
10758
|
+
}
|
|
10759
|
+
return {
|
|
10760
|
+
id: "jetbrains",
|
|
10761
|
+
label: "JetBrains",
|
|
10762
|
+
configPath: jetbrainsConfigPath(),
|
|
10763
|
+
placement: "write this to the global JetBrains ACP config (create it if missing \u2014 every JetBrains IDE shares this one file)",
|
|
10764
|
+
restart: "restart the AI chat tool window (close and reopen it)",
|
|
10765
|
+
dedicatedFile: true
|
|
10766
|
+
};
|
|
10767
|
+
}
|
|
10768
|
+
function deriveCustomName(target) {
|
|
10769
|
+
const first = target[0] ?? "agent";
|
|
10770
|
+
if (first === "npx") {
|
|
10771
|
+
for (let i = 1; i < target.length; i++) {
|
|
10772
|
+
const token = target[i];
|
|
10773
|
+
if (!token.startsWith("-")) return token;
|
|
10774
|
+
}
|
|
10775
|
+
}
|
|
10776
|
+
return first.split(/[/\\]/).pop() || first;
|
|
10777
|
+
}
|
|
10778
|
+
function buildSetupPlan(input) {
|
|
10779
|
+
const target = input.target.length > 0 ? [...input.target] : [DEFAULT_AGENT];
|
|
10780
|
+
const single = target.length === 1 ? target[0] : null;
|
|
10781
|
+
let args;
|
|
10782
|
+
let displayName;
|
|
10783
|
+
let isCustom;
|
|
10784
|
+
let agentDescription;
|
|
10785
|
+
let requiresExternalInstall = false;
|
|
10786
|
+
if (single !== null && isAgentShortcut(single)) {
|
|
10787
|
+
const def = resolveAgent(single);
|
|
10788
|
+
args = [def.shortName];
|
|
10789
|
+
displayName = input.name ?? `${def.displayName} (via ACP Devtools)`;
|
|
10790
|
+
isCustom = false;
|
|
10791
|
+
agentDescription = def.description;
|
|
10792
|
+
requiresExternalInstall = def.requiresExternalInstall ?? false;
|
|
10793
|
+
} else {
|
|
10794
|
+
args = ["proxy", ...target];
|
|
10795
|
+
displayName = input.name ?? `${deriveCustomName(target)} (via ACP Devtools)`;
|
|
10796
|
+
isCustom = true;
|
|
10797
|
+
}
|
|
10798
|
+
return {
|
|
10799
|
+
editor: editorInfo(input.editor),
|
|
10800
|
+
displayName,
|
|
10801
|
+
entry: { type: "custom", command: input.selfPath, args },
|
|
10802
|
+
isCustom,
|
|
10803
|
+
agentDescription,
|
|
10804
|
+
requiresExternalInstall
|
|
10805
|
+
};
|
|
10806
|
+
}
|
|
10807
|
+
function renderConfigBlock(plan) {
|
|
10808
|
+
const entries = { [plan.displayName]: plan.entry };
|
|
10809
|
+
if (plan.editor.dedicatedFile) {
|
|
10810
|
+
return JSON.stringify({ agent_servers: entries }, null, 4);
|
|
10811
|
+
}
|
|
10812
|
+
return `"agent_servers": ${JSON.stringify(entries, null, 4)}`;
|
|
10813
|
+
}
|
|
10814
|
+
function detectFormatting(text) {
|
|
10815
|
+
const match = text.match(/\n([ \t]+)\S/);
|
|
10816
|
+
if (!match) return { insertSpaces: true, tabSize: 4 };
|
|
10817
|
+
const ws = match[1];
|
|
10818
|
+
if (ws.startsWith(" ")) return { insertSpaces: false, tabSize: 1 };
|
|
10819
|
+
return { insertSpaces: true, tabSize: ws.length };
|
|
10820
|
+
}
|
|
10821
|
+
function mergeIntoConfig(existing, name, entry) {
|
|
10822
|
+
const base = existing !== null && existing.trim().length > 0 ? existing : "{}";
|
|
10823
|
+
const errors = [];
|
|
10824
|
+
const root = parse(base, errors, { allowTrailingComma: true });
|
|
10825
|
+
if (errors.length > 0) {
|
|
10826
|
+
throw new Error("config is not valid JSON");
|
|
10827
|
+
}
|
|
10828
|
+
if (typeof root !== "object" || root === null || Array.isArray(root)) {
|
|
10829
|
+
throw new Error("config root is not a JSON object");
|
|
10830
|
+
}
|
|
10831
|
+
const servers = root.agent_servers;
|
|
10832
|
+
const replaced = typeof servers === "object" && servers !== null && !Array.isArray(servers) ? Object.prototype.hasOwnProperty.call(servers, name) : false;
|
|
10833
|
+
const edits = modify(base, ["agent_servers", name], entry, {
|
|
10834
|
+
formattingOptions: detectFormatting(base)
|
|
10835
|
+
});
|
|
10836
|
+
let text = applyEdits(base, edits);
|
|
10837
|
+
if (!text.endsWith("\n")) text += "\n";
|
|
10838
|
+
return { text, replaced };
|
|
10839
|
+
}
|
|
10840
|
+
var EDITORS;
|
|
10841
|
+
var init_setup_config = __esm({
|
|
10842
|
+
"src/lib/setup-config.ts"() {
|
|
10843
|
+
"use strict";
|
|
10844
|
+
init_dist();
|
|
10845
|
+
EDITORS = ["zed", "jetbrains"];
|
|
10846
|
+
}
|
|
10847
|
+
});
|
|
10848
|
+
|
|
10637
10849
|
// src/commands/doctor.ts
|
|
10638
10850
|
import { existsSync as existsSync6, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
|
|
10639
|
-
import { homedir as
|
|
10640
|
-
import { join as
|
|
10851
|
+
import { homedir as homedir4, platform as platform2, release } from "os";
|
|
10852
|
+
import { join as join4 } from "path";
|
|
10641
10853
|
function colorStatus(s, status, text) {
|
|
10642
10854
|
switch (status) {
|
|
10643
10855
|
case "ok":
|
|
@@ -10660,7 +10872,7 @@ function checkEnvironment() {
|
|
|
10660
10872
|
});
|
|
10661
10873
|
results.push({
|
|
10662
10874
|
status: "info",
|
|
10663
|
-
label: `Platform: ${
|
|
10875
|
+
label: `Platform: ${platform2()} ${process.arch} (${release()})`
|
|
10664
10876
|
});
|
|
10665
10877
|
const binary = process.argv[1] ?? "(unknown)";
|
|
10666
10878
|
results.push({
|
|
@@ -10744,21 +10956,17 @@ function checkState() {
|
|
|
10744
10956
|
return results;
|
|
10745
10957
|
}
|
|
10746
10958
|
function probeZed() {
|
|
10747
|
-
const path =
|
|
10748
|
-
process.env.XDG_CONFIG_HOME ?? join3(homedir3(), ".config"),
|
|
10749
|
-
"zed",
|
|
10750
|
-
"settings.json"
|
|
10751
|
-
);
|
|
10959
|
+
const path = zedSettingsPath();
|
|
10752
10960
|
return { name: "Zed", path, exists: existsSync6(path) };
|
|
10753
10961
|
}
|
|
10754
10962
|
function probeJetBrains() {
|
|
10755
10963
|
const baseDirs = [];
|
|
10756
|
-
if (
|
|
10757
|
-
baseDirs.push(
|
|
10758
|
-
} else if (
|
|
10759
|
-
baseDirs.push(
|
|
10964
|
+
if (platform2() === "darwin") {
|
|
10965
|
+
baseDirs.push(join4(homedir4(), "Library", "Application Support", "JetBrains"));
|
|
10966
|
+
} else if (platform2() === "win32") {
|
|
10967
|
+
baseDirs.push(join4(process.env.APPDATA ?? "", "JetBrains"));
|
|
10760
10968
|
} else {
|
|
10761
|
-
baseDirs.push(
|
|
10969
|
+
baseDirs.push(join4(homedir4(), ".config", "JetBrains"));
|
|
10762
10970
|
}
|
|
10763
10971
|
const probes = [];
|
|
10764
10972
|
for (const base of baseDirs) {
|
|
@@ -10772,7 +10980,7 @@ function probeJetBrains() {
|
|
|
10772
10980
|
for (const entry of entries) {
|
|
10773
10981
|
if (entry.startsWith(".")) continue;
|
|
10774
10982
|
if (!JETBRAINS_VERSIONED.test(entry) && !JETBRAINS_UNVERSIONED.has(entry)) continue;
|
|
10775
|
-
const full =
|
|
10983
|
+
const full = join4(base, entry);
|
|
10776
10984
|
try {
|
|
10777
10985
|
if (!statSync2(full).isDirectory()) continue;
|
|
10778
10986
|
} catch {
|
|
@@ -10871,6 +11079,7 @@ var init_doctor = __esm({
|
|
|
10871
11079
|
"use strict";
|
|
10872
11080
|
init_dist();
|
|
10873
11081
|
init_style();
|
|
11082
|
+
init_setup_config();
|
|
10874
11083
|
STATUS_MARK = {
|
|
10875
11084
|
ok: "\u2713",
|
|
10876
11085
|
warn: "!",
|
|
@@ -10887,7 +11096,7 @@ var CLI_VERSION;
|
|
|
10887
11096
|
var init_version = __esm({
|
|
10888
11097
|
"src/version.ts"() {
|
|
10889
11098
|
"use strict";
|
|
10890
|
-
CLI_VERSION = "0.
|
|
11099
|
+
CLI_VERSION = "0.6.1";
|
|
10891
11100
|
}
|
|
10892
11101
|
});
|
|
10893
11102
|
|
|
@@ -11356,9 +11565,9 @@ function formatTable(rows) {
|
|
|
11356
11565
|
labelOf(r)
|
|
11357
11566
|
];
|
|
11358
11567
|
});
|
|
11359
|
-
return renderTable(s,
|
|
11568
|
+
return renderTable(s, COLUMNS2, body);
|
|
11360
11569
|
}
|
|
11361
|
-
var
|
|
11570
|
+
var COLUMNS2;
|
|
11362
11571
|
var init_list = __esm({
|
|
11363
11572
|
"src/commands/list.ts"() {
|
|
11364
11573
|
"use strict";
|
|
@@ -11366,7 +11575,7 @@ var init_list = __esm({
|
|
|
11366
11575
|
init_style();
|
|
11367
11576
|
init_palette();
|
|
11368
11577
|
init_table();
|
|
11369
|
-
|
|
11578
|
+
COLUMNS2 = [
|
|
11370
11579
|
{ title: "ID", align: "left" },
|
|
11371
11580
|
{ title: "AGE", align: "right" },
|
|
11372
11581
|
{ title: "KIND", align: "left" },
|
|
@@ -11623,7 +11832,9 @@ function buildMcpServer(opts) {
|
|
|
11623
11832
|
description: "Fetch a single captured frame by (session_id, seq). Returns the full record: raw JSON bytes, parsed payload, parseError (if any), direction, kind, method, rpcId, timestamp. Use this after find_spec_violations / get_session_messages narrows you down to a specific seq.",
|
|
11624
11833
|
inputSchema: {
|
|
11625
11834
|
session_id: z.number().int().positive().describe("session id from list_sessions"),
|
|
11626
|
-
seq: z.number().int().positive().describe(
|
|
11835
|
+
seq: z.number().int().positive().describe(
|
|
11836
|
+
"per-session sequence number from list_session_messages or find_spec_violations"
|
|
11837
|
+
)
|
|
11627
11838
|
},
|
|
11628
11839
|
outputSchema: {
|
|
11629
11840
|
session_id: z.number(),
|
|
@@ -11717,12 +11928,14 @@ function buildMcpServer(opts) {
|
|
|
11717
11928
|
z.object({
|
|
11718
11929
|
seq: z.number(),
|
|
11719
11930
|
method: z.string().nullable(),
|
|
11720
|
-
errors: z.array(
|
|
11721
|
-
|
|
11722
|
-
|
|
11723
|
-
|
|
11724
|
-
|
|
11725
|
-
|
|
11931
|
+
errors: z.array(
|
|
11932
|
+
z.looseObject({
|
|
11933
|
+
keyword: z.string(),
|
|
11934
|
+
instancePath: z.string().optional(),
|
|
11935
|
+
schemaPath: z.string().optional(),
|
|
11936
|
+
message: z.string().optional()
|
|
11937
|
+
})
|
|
11938
|
+
)
|
|
11726
11939
|
}).loose()
|
|
11727
11940
|
),
|
|
11728
11941
|
advisories: z.array(
|
|
@@ -11851,6 +12064,88 @@ function buildMcpServer(opts) {
|
|
|
11851
12064
|
});
|
|
11852
12065
|
}
|
|
11853
12066
|
);
|
|
12067
|
+
server.registerTool(
|
|
12068
|
+
"list_agent_shortcuts",
|
|
12069
|
+
{
|
|
12070
|
+
description: "List the built-in agent shortcuts you can pass to generate_editor_config as `agent` (or that the CLI accepts as `acp-devtools <name>` / `proxy --agent <name>`). Each is a known ACP agent wired into the registry; anything else is still supported via generate_editor_config's `command` argument. Same data as the CLI `acp-devtools agents`.",
|
|
12071
|
+
inputSchema: {},
|
|
12072
|
+
outputSchema: {
|
|
12073
|
+
agents: z.array(
|
|
12074
|
+
z.object({
|
|
12075
|
+
shortName: z.string(),
|
|
12076
|
+
displayName: z.string(),
|
|
12077
|
+
command: z.string(),
|
|
12078
|
+
args: z.array(z.string()),
|
|
12079
|
+
requiresExternalInstall: z.boolean()
|
|
12080
|
+
})
|
|
12081
|
+
)
|
|
12082
|
+
},
|
|
12083
|
+
annotations: annotations({ title: "List agent shortcuts" })
|
|
12084
|
+
},
|
|
12085
|
+
async () => {
|
|
12086
|
+
const agents = listAgents().map((a) => ({
|
|
12087
|
+
shortName: a.shortName,
|
|
12088
|
+
displayName: a.displayName,
|
|
12089
|
+
command: a.command,
|
|
12090
|
+
args: [...a.args],
|
|
12091
|
+
requiresExternalInstall: a.requiresExternalInstall ?? false
|
|
12092
|
+
}));
|
|
12093
|
+
return structuredResult({ agents });
|
|
12094
|
+
}
|
|
12095
|
+
);
|
|
12096
|
+
server.registerTool(
|
|
12097
|
+
"generate_editor_config",
|
|
12098
|
+
{
|
|
12099
|
+
description: 'Generate the editor config (Zed or JetBrains) that runs an ACP agent through ACP Devtools, with the absolute acp-devtools binary path already filled in. Use this when the user asks to wire up / add an agent \u2014 e.g. "add junie for zed". Returns `block` (the JSON to add to the editor config), `configPath` (where it goes), and `writeCommand` (the equivalent `acp-devtools setup --write` to run instead). This tool only COMPUTES the config \u2014 it does not write any file; add `block` to `configPath` with your own file tools, or tell the user to run `writeCommand`. Pass `agent` for a registry shortcut (see list_agent_shortcuts) or `command` for any other agent (wrapped via `proxy`). Mirrors the CLI `acp-devtools setup`.',
|
|
12100
|
+
inputSchema: {
|
|
12101
|
+
editor: z.enum(["zed", "jetbrains"]).describe("target editor: zed or jetbrains"),
|
|
12102
|
+
agent: z.string().optional().describe(
|
|
12103
|
+
"registry shortcut: junie, goose, codex, opencode, or claude-code (the default when neither agent nor command is given)"
|
|
12104
|
+
),
|
|
12105
|
+
command: z.array(z.string()).optional().describe(
|
|
12106
|
+
'custom agent command tokens (e.g. ["npx","-y","@scope/acp"]), wrapped via proxy; ignored when `agent` is set'
|
|
12107
|
+
),
|
|
12108
|
+
name: z.string().optional().describe("display name override for the agent entry")
|
|
12109
|
+
},
|
|
12110
|
+
outputSchema: {
|
|
12111
|
+
displayName: z.string(),
|
|
12112
|
+
editor: z.enum(["zed", "jetbrains"]),
|
|
12113
|
+
configPath: z.string(),
|
|
12114
|
+
dedicatedFile: z.boolean(),
|
|
12115
|
+
entry: z.object({
|
|
12116
|
+
type: z.literal("custom"),
|
|
12117
|
+
command: z.string(),
|
|
12118
|
+
args: z.array(z.string())
|
|
12119
|
+
}),
|
|
12120
|
+
block: z.string(),
|
|
12121
|
+
writeCommand: z.string(),
|
|
12122
|
+
requiresExternalInstall: z.boolean(),
|
|
12123
|
+
installHint: z.string().optional()
|
|
12124
|
+
},
|
|
12125
|
+
annotations: annotations({ title: "Generate editor config" })
|
|
12126
|
+
},
|
|
12127
|
+
async ({ editor, agent, command, name }) => {
|
|
12128
|
+
const target = command && command.length > 0 ? command : agent ? [agent] : [];
|
|
12129
|
+
const selfPath = process.argv[1] ?? "acp-devtools";
|
|
12130
|
+
const plan = buildSetupPlan({ target, editor, selfPath, name });
|
|
12131
|
+
const writeParts = ["acp-devtools setup", `--editor ${editor}`, "--write"];
|
|
12132
|
+
if (name) writeParts.push(`--name ${JSON.stringify(name)}`);
|
|
12133
|
+
if (target.length === 1) writeParts.push(target[0]);
|
|
12134
|
+
else if (target.length > 1) writeParts.push("--", ...target);
|
|
12135
|
+
const installHint = plan.isCustom ? void 0 : plan.requiresExternalInstall ? plan.agentDescription : "Installs automatically via npx on first run.";
|
|
12136
|
+
return structuredResult({
|
|
12137
|
+
displayName: plan.displayName,
|
|
12138
|
+
editor,
|
|
12139
|
+
configPath: plan.editor.configPath,
|
|
12140
|
+
dedicatedFile: plan.editor.dedicatedFile,
|
|
12141
|
+
entry: plan.entry,
|
|
12142
|
+
block: renderConfigBlock(plan),
|
|
12143
|
+
writeCommand: writeParts.join(" "),
|
|
12144
|
+
requiresExternalInstall: plan.requiresExternalInstall,
|
|
12145
|
+
...installHint !== void 0 ? { installHint } : {}
|
|
12146
|
+
});
|
|
12147
|
+
}
|
|
12148
|
+
);
|
|
11854
12149
|
registerPrompts(server);
|
|
11855
12150
|
return server;
|
|
11856
12151
|
}
|
|
@@ -11974,12 +12269,14 @@ var init_mcp = __esm({
|
|
|
11974
12269
|
"use strict";
|
|
11975
12270
|
init_dist();
|
|
11976
12271
|
init_version();
|
|
12272
|
+
init_setup_config();
|
|
11977
12273
|
SERVER_INSTRUCTIONS = `acp-devtools exposes a local SQLite store of captured
|
|
11978
12274
|
Agent Client Protocol (ACP) sessions. ACP is the editor\u2194agent JSON-RPC
|
|
11979
12275
|
protocol used by Claude Code, Goose, Codex, and other IDE agents.
|
|
11980
12276
|
|
|
11981
12277
|
Every tool here is **read-only** \u2014 nothing in this server writes to the
|
|
11982
|
-
database
|
|
12278
|
+
database or to any file (\`generate_editor_config\` only returns the config
|
|
12279
|
+
text to write; you apply it). Use it to investigate:
|
|
11983
12280
|
|
|
11984
12281
|
- a slow session (\`get_latency_stats\` returns per-method p50/p99/max
|
|
11985
12282
|
plus auto-detected insights: hotspot, long-tail, outlier, busiest,
|
|
@@ -11996,6 +12293,12 @@ database. Use it to investigate:
|
|
|
11996
12293
|
(\`diff_sessions\` aligns two captures and reports added / removed
|
|
11997
12294
|
frames and field-level payload changes)
|
|
11998
12295
|
|
|
12296
|
+
It also helps wire agents up: \`list_agent_shortcuts\` enumerates the known
|
|
12297
|
+
agents, and \`generate_editor_config({editor, agent})\` returns the
|
|
12298
|
+
Zed/JetBrains config block to run one through the proxy (e.g. "add junie for
|
|
12299
|
+
zed") \u2014 apply \`block\` to \`configPath\` with your own file tools, or run the
|
|
12300
|
+
returned \`writeCommand\`.
|
|
12301
|
+
|
|
11999
12302
|
A typical investigation:
|
|
12000
12303
|
1. \`list_sessions\` to see what is captured
|
|
12001
12304
|
2. \`get_session_summary({session_id})\` for the headline numbers and
|
|
@@ -12931,7 +13234,7 @@ function renderHits(s, hits, needle) {
|
|
|
12931
13234
|
truncate2(h.method ?? "\u2014", METHOD_MAX2),
|
|
12932
13235
|
highlight(s, h.snippet, needle)
|
|
12933
13236
|
]);
|
|
12934
|
-
return renderTable(s,
|
|
13237
|
+
return renderTable(s, COLUMNS3, body);
|
|
12935
13238
|
}
|
|
12936
13239
|
function highlight(s, snippet, needle) {
|
|
12937
13240
|
if (!s.enabled || needle.length === 0) return snippet;
|
|
@@ -12953,7 +13256,7 @@ function truncate2(s, max) {
|
|
|
12953
13256
|
if (s.length <= max) return s;
|
|
12954
13257
|
return s.slice(0, Math.max(1, max - 1)) + "\u2026";
|
|
12955
13258
|
}
|
|
12956
|
-
var SNIPPET_LEN, METHOD_MAX2,
|
|
13259
|
+
var SNIPPET_LEN, METHOD_MAX2, COLUMNS3;
|
|
12957
13260
|
var init_search = __esm({
|
|
12958
13261
|
"src/commands/search.ts"() {
|
|
12959
13262
|
"use strict";
|
|
@@ -12962,7 +13265,7 @@ var init_search = __esm({
|
|
|
12962
13265
|
init_table();
|
|
12963
13266
|
SNIPPET_LEN = 80;
|
|
12964
13267
|
METHOD_MAX2 = 32;
|
|
12965
|
-
|
|
13268
|
+
COLUMNS3 = [
|
|
12966
13269
|
{ title: "LOC", align: "left" },
|
|
12967
13270
|
{ title: "METHOD", align: "left" },
|
|
12968
13271
|
{ title: "MATCH", align: "left" }
|
|
@@ -13150,6 +13453,139 @@ var init_session_info = __esm({
|
|
|
13150
13453
|
}
|
|
13151
13454
|
});
|
|
13152
13455
|
|
|
13456
|
+
// src/commands/setup.ts
|
|
13457
|
+
import { mkdirSync as mkdirSync6, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "fs";
|
|
13458
|
+
import { dirname as dirname5 } from "path";
|
|
13459
|
+
function fail(message, code) {
|
|
13460
|
+
process.stderr.write(`acp-devtools: ${message}
|
|
13461
|
+
`);
|
|
13462
|
+
process.exit(code);
|
|
13463
|
+
}
|
|
13464
|
+
function rerunCommand(editor, target, opts) {
|
|
13465
|
+
const parts = ["acp-devtools setup", `--editor ${editor}`, "--write"];
|
|
13466
|
+
if (opts.name) parts.push(`--name ${JSON.stringify(opts.name)}`);
|
|
13467
|
+
if (opts.configPath) parts.push(`--config-path ${opts.configPath}`);
|
|
13468
|
+
if (target.length === 1) {
|
|
13469
|
+
parts.push(target[0]);
|
|
13470
|
+
} else if (target.length > 1) {
|
|
13471
|
+
parts.push("--", ...target);
|
|
13472
|
+
}
|
|
13473
|
+
return parts.join(" ");
|
|
13474
|
+
}
|
|
13475
|
+
function printInstallHint(plan, s) {
|
|
13476
|
+
if (plan.isCustom) return;
|
|
13477
|
+
if (plan.requiresExternalInstall) {
|
|
13478
|
+
process.stdout.write(`
|
|
13479
|
+
${s.yellow("!")} ${plan.agentDescription}
|
|
13480
|
+
`);
|
|
13481
|
+
} else {
|
|
13482
|
+
process.stdout.write(`
|
|
13483
|
+
${s.dim("Installs automatically via npx on first run.")}
|
|
13484
|
+
`);
|
|
13485
|
+
}
|
|
13486
|
+
}
|
|
13487
|
+
function printGuidance(plan, target, opts, configPath, s) {
|
|
13488
|
+
const block = renderConfigBlock(plan);
|
|
13489
|
+
process.stdout.write(
|
|
13490
|
+
`
|
|
13491
|
+
${s.bold(plan.displayName)} ${s.dim("\u2192")} ${s.bold(plan.editor.label)}
|
|
13492
|
+
|
|
13493
|
+
`
|
|
13494
|
+
);
|
|
13495
|
+
process.stdout.write(` ${plan.editor.placement}:
|
|
13496
|
+
`);
|
|
13497
|
+
process.stdout.write(` ${s.cyan(configPath)}
|
|
13498
|
+
|
|
13499
|
+
`);
|
|
13500
|
+
process.stdout.write(`${block}
|
|
13501
|
+
`);
|
|
13502
|
+
printInstallHint(plan, s);
|
|
13503
|
+
process.stdout.write(`
|
|
13504
|
+
Then ${plan.editor.restart}.
|
|
13505
|
+
`);
|
|
13506
|
+
process.stdout.write(
|
|
13507
|
+
`
|
|
13508
|
+
${s.dim("Or let ACP Devtools edit the file for you:")}
|
|
13509
|
+
${rerunCommand(opts.editor, target, opts)}
|
|
13510
|
+
|
|
13511
|
+
`
|
|
13512
|
+
);
|
|
13513
|
+
}
|
|
13514
|
+
function doWrite(plan, target, opts, configPath, s) {
|
|
13515
|
+
let existing = null;
|
|
13516
|
+
try {
|
|
13517
|
+
existing = readFileSync5(configPath, "utf8");
|
|
13518
|
+
} catch (err) {
|
|
13519
|
+
if (err.code !== "ENOENT") {
|
|
13520
|
+
fail(`cannot read ${configPath}: ${err.message}`, 1);
|
|
13521
|
+
}
|
|
13522
|
+
}
|
|
13523
|
+
let merged;
|
|
13524
|
+
try {
|
|
13525
|
+
merged = mergeIntoConfig(existing, plan.displayName, plan.entry);
|
|
13526
|
+
} catch {
|
|
13527
|
+
process.stderr.write(
|
|
13528
|
+
`${s.red("\u2717")} ${configPath} isn't valid JSON \u2014 leaving it untouched.
|
|
13529
|
+
Paste this block in by hand:
|
|
13530
|
+
`
|
|
13531
|
+
);
|
|
13532
|
+
process.stdout.write(`
|
|
13533
|
+
${renderConfigBlock(plan)}
|
|
13534
|
+
|
|
13535
|
+
`);
|
|
13536
|
+
process.exit(1);
|
|
13537
|
+
}
|
|
13538
|
+
try {
|
|
13539
|
+
mkdirSync6(dirname5(configPath), { recursive: true });
|
|
13540
|
+
writeFileSync3(configPath, merged.text);
|
|
13541
|
+
} catch (err) {
|
|
13542
|
+
fail(`cannot write ${configPath}: ${err.message}`, 1);
|
|
13543
|
+
}
|
|
13544
|
+
const verb = merged.replaced ? "updated" : "wrote";
|
|
13545
|
+
process.stdout.write(
|
|
13546
|
+
`
|
|
13547
|
+
${s.green("\u2713")} ${verb} ${s.bold(JSON.stringify(plan.displayName))} in ${s.cyan(configPath)}
|
|
13548
|
+
`
|
|
13549
|
+
);
|
|
13550
|
+
printInstallHint(plan, s);
|
|
13551
|
+
process.stdout.write(`
|
|
13552
|
+
Then ${plan.editor.restart}.
|
|
13553
|
+
|
|
13554
|
+
`);
|
|
13555
|
+
process.exit(0);
|
|
13556
|
+
}
|
|
13557
|
+
function registerSetupCommand(program) {
|
|
13558
|
+
program.command("setup [target...]").description("Generate an editor config that runs an agent through ACP Devtools").option("--editor <name>", `target editor (${EDITORS.join(" | ")})`).option("--name <label>", "display name for the agent entry").option("--config-path <path>", "override the editor config file location").option("--write", "merge the entry into the editor config instead of printing it", false).option("--no-color", "disable ANSI colour output").action((target, opts) => {
|
|
13559
|
+
if (!opts.editor) {
|
|
13560
|
+
fail(`--editor is required (${EDITORS.join(" | ")})`, 2);
|
|
13561
|
+
}
|
|
13562
|
+
if (!isEditor(opts.editor)) {
|
|
13563
|
+
fail(`unknown editor "${opts.editor}" (expected ${EDITORS.join(" | ")})`, 2);
|
|
13564
|
+
}
|
|
13565
|
+
const selfPath = process.argv[1] ?? "acp-devtools";
|
|
13566
|
+
const plan = buildSetupPlan({
|
|
13567
|
+
target,
|
|
13568
|
+
editor: opts.editor,
|
|
13569
|
+
selfPath,
|
|
13570
|
+
name: opts.name
|
|
13571
|
+
});
|
|
13572
|
+
const configPath = opts.configPath ?? editorInfo(opts.editor).configPath;
|
|
13573
|
+
const s = createStyler(opts.color && colorEnabled(process.stdout));
|
|
13574
|
+
if (opts.write) {
|
|
13575
|
+
doWrite(plan, target, opts, configPath, s);
|
|
13576
|
+
}
|
|
13577
|
+
printGuidance(plan, target, opts, configPath, s);
|
|
13578
|
+
process.exit(0);
|
|
13579
|
+
});
|
|
13580
|
+
}
|
|
13581
|
+
var init_setup = __esm({
|
|
13582
|
+
"src/commands/setup.ts"() {
|
|
13583
|
+
"use strict";
|
|
13584
|
+
init_style();
|
|
13585
|
+
init_setup_config();
|
|
13586
|
+
}
|
|
13587
|
+
});
|
|
13588
|
+
|
|
13153
13589
|
// src/commands/stats.ts
|
|
13154
13590
|
function registerStatsCommand(program) {
|
|
13155
13591
|
program.command("stats").description(
|
|
@@ -13444,11 +13880,11 @@ var init_stats = __esm({
|
|
|
13444
13880
|
// src/commands/ui.ts
|
|
13445
13881
|
import { createReadStream, existsSync as existsSync7, statSync as statSync3 } from "fs";
|
|
13446
13882
|
import { createServer } from "http";
|
|
13447
|
-
import { dirname as
|
|
13883
|
+
import { dirname as dirname6, extname, join as join5, normalize, resolve, sep } from "path";
|
|
13448
13884
|
import { fileURLToPath } from "url";
|
|
13449
13885
|
import { spawn as spawn2 } from "child_process";
|
|
13450
13886
|
function uiDistDir() {
|
|
13451
|
-
const here =
|
|
13887
|
+
const here = dirname6(fileURLToPath(import.meta.url));
|
|
13452
13888
|
return resolve(here, "ui");
|
|
13453
13889
|
}
|
|
13454
13890
|
function contentTypeFor(path) {
|
|
@@ -13462,7 +13898,7 @@ function serveStatic(req, res, rootDir) {
|
|
|
13462
13898
|
}
|
|
13463
13899
|
const urlPath = decodeURIComponent((req.url ?? "/").split("?")[0] ?? "/");
|
|
13464
13900
|
const relative = urlPath === "/" || urlPath === "" ? "/index.html" : urlPath;
|
|
13465
|
-
const candidate = normalize(
|
|
13901
|
+
const candidate = normalize(join5(rootDir, relative));
|
|
13466
13902
|
if (!candidate.startsWith(rootDir + sep) && candidate !== rootDir) {
|
|
13467
13903
|
res.statusCode = 403;
|
|
13468
13904
|
res.end();
|
|
@@ -13470,7 +13906,7 @@ function serveStatic(req, res, rootDir) {
|
|
|
13470
13906
|
}
|
|
13471
13907
|
let filePath = candidate;
|
|
13472
13908
|
if (!existsSync7(filePath) || !statSync3(filePath).isFile()) {
|
|
13473
|
-
filePath =
|
|
13909
|
+
filePath = join5(rootDir, "index.html");
|
|
13474
13910
|
if (!existsSync7(filePath)) {
|
|
13475
13911
|
res.statusCode = 404;
|
|
13476
13912
|
res.setHeader("content-type", "text/plain; charset=utf-8");
|
|
@@ -13513,7 +13949,7 @@ function registerUiCommand(program) {
|
|
|
13513
13949
|
process.exit(2);
|
|
13514
13950
|
}
|
|
13515
13951
|
const rootDir = uiDistDir();
|
|
13516
|
-
if (!existsSync7(
|
|
13952
|
+
if (!existsSync7(join5(rootDir, "index.html"))) {
|
|
13517
13953
|
process.stderr.write(
|
|
13518
13954
|
`acp-devtools: UI bundle missing at ${rootDir}
|
|
13519
13955
|
Run \`npm run build:full\` in the monorepo, or reinstall the published package.
|
|
@@ -13726,7 +14162,7 @@ function renderViolations(s, violations) {
|
|
|
13726
14162
|
s.cyan(truncate3(v.path, PATH_MAX)),
|
|
13727
14163
|
s.red(v.message)
|
|
13728
14164
|
]);
|
|
13729
|
-
return renderTable(s,
|
|
14165
|
+
return renderTable(s, COLUMNS4, body);
|
|
13730
14166
|
}
|
|
13731
14167
|
function renderAdvisories(s, advisories) {
|
|
13732
14168
|
const heading5 = s.yellow(`${advisories.length} advisor${advisories.length === 1 ? "y" : "ies"}`) + s.dim(" \u2014 valid today, but a future ACP version will require these fields") + "\n";
|
|
@@ -13743,7 +14179,7 @@ function truncate3(s, max) {
|
|
|
13743
14179
|
if (s.length <= max) return s;
|
|
13744
14180
|
return s.slice(0, Math.max(1, max - 1)) + "\u2026";
|
|
13745
14181
|
}
|
|
13746
|
-
var METHOD_MAX4, SCHEMA_MAX, PATH_MAX,
|
|
14182
|
+
var METHOD_MAX4, SCHEMA_MAX, PATH_MAX, COLUMNS4, ADVISORY_COLUMNS;
|
|
13747
14183
|
var init_validate2 = __esm({
|
|
13748
14184
|
"src/commands/validate.ts"() {
|
|
13749
14185
|
"use strict";
|
|
@@ -13754,7 +14190,7 @@ var init_validate2 = __esm({
|
|
|
13754
14190
|
METHOD_MAX4 = 28;
|
|
13755
14191
|
SCHEMA_MAX = 28;
|
|
13756
14192
|
PATH_MAX = 38;
|
|
13757
|
-
|
|
14193
|
+
COLUMNS4 = [
|
|
13758
14194
|
{ title: "SEQ", align: "right" },
|
|
13759
14195
|
{ title: "METHOD", align: "left" },
|
|
13760
14196
|
{ title: "SCHEMA", align: "left" },
|
|
@@ -13772,8 +14208,8 @@ var init_validate2 = __esm({
|
|
|
13772
14208
|
});
|
|
13773
14209
|
|
|
13774
14210
|
// src/lib/help.ts
|
|
13775
|
-
import { homedir as
|
|
13776
|
-
function tidyHome(text, home =
|
|
14211
|
+
import { homedir as homedir5 } from "os";
|
|
14212
|
+
function tidyHome(text, home = homedir5()) {
|
|
13777
14213
|
if (!home) return text;
|
|
13778
14214
|
const escapedHome = home.replace(/\\/g, "\\\\");
|
|
13779
14215
|
const collapsed = text.split(escapedHome).join("~").split(home).join("~");
|
|
@@ -13935,7 +14371,7 @@ var init_help = __esm({
|
|
|
13935
14371
|
},
|
|
13936
14372
|
{ title: "View", commands: ["ui", "replay"] },
|
|
13937
14373
|
{ title: "Manage", commands: ["export", "import", "delete", "backfill-metadata"] },
|
|
13938
|
-
{ title: "Setup", commands: ["doctor", "mcp"] }
|
|
14374
|
+
{ title: "Setup", commands: ["setup", "agents", "doctor", "mcp"] }
|
|
13939
14375
|
];
|
|
13940
14376
|
SUMMARIES = {
|
|
13941
14377
|
proxy: "Capture an agent's traffic through a proxy",
|
|
@@ -13954,6 +14390,8 @@ var init_help = __esm({
|
|
|
13954
14390
|
import: "Import a JSON export into the store",
|
|
13955
14391
|
delete: "Delete saved sessions permanently",
|
|
13956
14392
|
"backfill-metadata": "Recompute session metadata columns",
|
|
14393
|
+
setup: "Generate an editor config for an agent",
|
|
14394
|
+
agents: "List the built-in agent shortcuts",
|
|
13957
14395
|
doctor: "Diagnose setup and report issues",
|
|
13958
14396
|
mcp: "Expose captures to Claude over MCP"
|
|
13959
14397
|
};
|
|
@@ -14012,6 +14450,17 @@ var init_help = __esm({
|
|
|
14012
14450
|
replay: ["acp-devtools replay 12", "acp-devtools replay --file session-12.json"],
|
|
14013
14451
|
validate: ["acp-devtools validate 12"],
|
|
14014
14452
|
"session-info": ["acp-devtools session-info 12"],
|
|
14453
|
+
setup: [
|
|
14454
|
+
"# See which agent shortcuts exist",
|
|
14455
|
+
"acp-devtools agents",
|
|
14456
|
+
"",
|
|
14457
|
+
"# Print a Zed config block for a registry agent",
|
|
14458
|
+
"acp-devtools setup junie --editor zed",
|
|
14459
|
+
"",
|
|
14460
|
+
"# Wrap a custom agent and write it straight into the JetBrains config",
|
|
14461
|
+
"acp-devtools setup --editor jetbrains --write -- npx -y @your-scope/your-acp"
|
|
14462
|
+
],
|
|
14463
|
+
agents: ["acp-devtools agents", "", "# Machine-readable", "acp-devtools agents --json"],
|
|
14015
14464
|
doctor: ["acp-devtools doctor"],
|
|
14016
14465
|
mcp: ["# Read-only MCP server over stdio (wire into .claude/mcp_servers.json)", "acp-devtools mcp"],
|
|
14017
14466
|
"backfill-metadata": [
|
|
@@ -14048,6 +14497,8 @@ function buildProgram() {
|
|
|
14048
14497
|
registerInspectCommand(program);
|
|
14049
14498
|
registerSearchCommand(program);
|
|
14050
14499
|
registerSessionInfoCommand(program);
|
|
14500
|
+
registerSetupCommand(program);
|
|
14501
|
+
registerAgentsCommand(program);
|
|
14051
14502
|
registerStatsCommand(program);
|
|
14052
14503
|
registerBackfillMetadataCommand(program);
|
|
14053
14504
|
registerMcpCommand(program);
|
|
@@ -14059,6 +14510,7 @@ function buildProgram() {
|
|
|
14059
14510
|
var init_program = __esm({
|
|
14060
14511
|
"src/program.ts"() {
|
|
14061
14512
|
"use strict";
|
|
14513
|
+
init_agents2();
|
|
14062
14514
|
init_backfill_metadata();
|
|
14063
14515
|
init_delete();
|
|
14064
14516
|
init_diff();
|
|
@@ -14074,6 +14526,7 @@ var init_program = __esm({
|
|
|
14074
14526
|
init_replay2();
|
|
14075
14527
|
init_search();
|
|
14076
14528
|
init_session_info();
|
|
14529
|
+
init_setup();
|
|
14077
14530
|
init_stats();
|
|
14078
14531
|
init_ui();
|
|
14079
14532
|
init_validate2();
|
|
@@ -14178,6 +14631,8 @@ var KNOWN_SUBCOMMANDS = /* @__PURE__ */ new Set([
|
|
|
14178
14631
|
"inspect",
|
|
14179
14632
|
"search",
|
|
14180
14633
|
"session-info",
|
|
14634
|
+
"setup",
|
|
14635
|
+
"agents",
|
|
14181
14636
|
"stats",
|
|
14182
14637
|
"validate",
|
|
14183
14638
|
"backfill-metadata",
|