@openma/deepseek-harness-acp 0.4.10 → 0.4.13

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/bridge.js CHANGED
@@ -9,8 +9,8 @@ var __esm = (fn, res, err) => function __init() {
9
9
  }
10
10
  };
11
11
  var __export = (target, all) => {
12
- for (var name3 in all)
13
- __defProp(target, name3, { get: all[name3], enumerable: true });
12
+ for (var name5 in all)
13
+ __defProp(target, name5, { get: all[name5], enumerable: true });
14
14
  };
15
15
 
16
16
  // src/bridge/self-harness.ts
@@ -52,11 +52,11 @@ import { Readable as Readable2, Writable as Writable2 } from "node:stream";
52
52
  var bridge_exports = {};
53
53
  __export(bridge_exports, {
54
54
  answerFromElicitation: () => answerFromElicitation,
55
- apply: () => apply,
55
+ apply: () => apply3,
56
56
  askUserQuestionsOverAcp: () => askUserQuestionsOverAcp,
57
- inject: () => inject,
57
+ inject: () => inject3,
58
58
  installAcpUserQuestionProvider: () => installAcpUserQuestionProvider,
59
- name: () => name,
59
+ name: () => name3,
60
60
  questionsToElicitation: () => questionsToElicitation
61
61
  });
62
62
  import { randomUUID } from "node:crypto";
@@ -147,11 +147,11 @@ function apiKeyAuthMethods(providers) {
147
147
  }
148
148
  return providers.map((provider) => apiKeyAuthMethod(provider.id, provider.name, false));
149
149
  }
150
- function apiKeyAuthMethod(provider, name3, unscoped) {
150
+ function apiKeyAuthMethod(provider, name5, unscoped) {
151
151
  const scoped = !unscoped && provider !== void 0;
152
152
  return {
153
153
  id: scoped ? `api-key:${provider}` : "api-key",
154
- name: scoped ? `${name3 ?? provider} API key` : "API Key",
154
+ name: scoped ? `${name5 ?? provider} API key` : "API Key",
155
155
  description: LOGIN_DESCRIPTION,
156
156
  _meta: { "api-key": scoped ? { provider } : {} }
157
157
  };
@@ -339,7 +339,7 @@ function pathLocations(args) {
339
339
  }
340
340
  return locations;
341
341
  }
342
- function classifyToolCall(name3, rawArguments) {
342
+ function classifyToolCall(name5, rawArguments) {
343
343
  let args = {};
344
344
  try {
345
345
  const parsed = JSON.parse(rawArguments);
@@ -357,7 +357,7 @@ function classifyToolCall(name3, rawArguments) {
357
357
  locations,
358
358
  rawInput: args
359
359
  });
360
- switch (name3) {
360
+ switch (name5) {
361
361
  case "bash": {
362
362
  const command = asString(args["command"]);
363
363
  const restart = args["restart"] === true;
@@ -388,17 +388,17 @@ function classifyToolCall(name3, rawArguments) {
388
388
  default:
389
389
  break;
390
390
  }
391
- const lowered = name3.toLowerCase();
391
+ const lowered = name5.toLowerCase();
392
392
  if (/(^|_)(grep|glob|find|search|ls|list)($|_)/.test(lowered)) {
393
393
  const query = asString(args["query"]) ?? asString(args["pattern"]);
394
- return facts("search", query !== void 0 ? `Search for '${firstLine(query, 50)}'` : name3);
394
+ return facts("search", query !== void 0 ? `Search for '${firstLine(query, 50)}'` : name5);
395
395
  }
396
396
  if (/(fetch|web|http|browse)/.test(lowered)) {
397
397
  const url = asString(args["url"]) ?? asString(args["query"]);
398
- return facts("fetch", url !== void 0 ? `Fetch ${firstLine(url, 60)}` : name3);
398
+ return facts("fetch", url !== void 0 ? `Fetch ${firstLine(url, 60)}` : name5);
399
399
  }
400
- if (/(job|task|run|exec)/.test(lowered)) return facts("execute", name3);
401
- return facts("other", name3);
400
+ if (/(job|task|run|exec)/.test(lowered)) return facts("execute", name5);
401
+ return facts("other", name5);
402
402
  }
403
403
  function diffsFromToolMeta(meta) {
404
404
  if (meta === null || typeof meta !== "object") return [];
@@ -513,8 +513,8 @@ var TOOL_KINDS = /* @__PURE__ */ new Set([
513
513
  "switch_mode",
514
514
  "other"
515
515
  ]);
516
- function factsFromPresentCall(name3, rawArguments, presented) {
517
- const fallback = classifyToolCall(name3, rawArguments);
516
+ function factsFromPresentCall(name5, rawArguments, presented) {
517
+ const fallback = classifyToolCall(name5, rawArguments);
518
518
  const kind = presented.kind !== void 0 && TOOL_KINDS.has(presented.kind) ? presented.kind : fallback.kind;
519
519
  const title = presented.title !== void 0 && presented.title.length > 0 ? presented.title : fallback.title;
520
520
  const locations = presented.locations !== void 0 && presented.locations.length > 0 ? presented.locations.map(
@@ -783,7 +783,7 @@ var SessionProjection = class {
783
783
  }
784
784
  onToolCall(data) {
785
785
  const callId = asString(data["callId"]);
786
- const name3 = asString(data["name"]) ?? "tool";
786
+ const name5 = asString(data["name"]) ?? "tool";
787
787
  if (callId === void 0) return [];
788
788
  const rawArguments = typeof data["arguments"] === "string" ? data["arguments"] : "{}";
789
789
  let parsedArgs = {};
@@ -792,8 +792,8 @@ var SessionProjection = class {
792
792
  } catch {
793
793
  parsedArgs = { arguments: rawArguments };
794
794
  }
795
- const presented = this.presentCall?.(name3, parsedArgs);
796
- const facts = presented !== void 0 ? factsFromPresentCall(name3, rawArguments, presented) : classifyToolCall(name3, rawArguments);
795
+ const presented = this.presentCall?.(name5, parsedArgs);
796
+ const facts = presented !== void 0 ? factsFromPresentCall(name5, rawArguments, presented) : classifyToolCall(name5, rawArguments);
797
797
  this.toolCalls.set(callId, facts);
798
798
  const displayTerminal = this.terminalOutput && facts.kind === "execute";
799
799
  return [
@@ -801,7 +801,7 @@ var SessionProjection = class {
801
801
  sessionUpdate: "tool_call",
802
802
  toolCallId: callId,
803
803
  title: facts.title,
804
- name: name3,
804
+ name: name5,
805
805
  kind: facts.kind,
806
806
  status: "in_progress",
807
807
  rawInput: facts.rawInput,
@@ -1034,8 +1034,8 @@ function prepareImage(block) {
1034
1034
  throw new PromptImageError(`unsupported image media type: ${block.mimeType}`);
1035
1035
  }
1036
1036
  const data = decodeImageData(block.data);
1037
- const name3 = imageName(block.uri);
1038
- return name3 === void 0 ? { data, mediaType } : { data, mediaType, name: name3 };
1037
+ const name5 = imageName(block.uri);
1038
+ return name5 === void 0 ? { data, mediaType } : { data, mediaType, name: name5 };
1039
1039
  }
1040
1040
  function saveInput(image) {
1041
1041
  return image.name === void 0 ? { data: image.data, mediaType: image.mediaType } : { data: image.data, mediaType: image.mediaType, name: image.name };
@@ -1260,6 +1260,14 @@ function muxAcpStream(stream, rpc) {
1260
1260
  return { readable, writable: acpWritable };
1261
1261
  }
1262
1262
 
1263
+ // src/bridge/tui-client-plugin.ts
1264
+ var tui_client_plugin_exports = {};
1265
+ __export(tui_client_plugin_exports, {
1266
+ apply: () => apply,
1267
+ inject: () => inject,
1268
+ name: () => name
1269
+ });
1270
+
1263
1271
  // src/bridge/tui-client.ts
1264
1272
  function installTuiClientPlane(ctx, rpc, opts) {
1265
1273
  const { findAgent, advertisement } = opts;
@@ -1513,6 +1521,24 @@ function readProviders(params) {
1513
1521
  });
1514
1522
  }
1515
1523
 
1524
+ // src/bridge/tui-client-plugin.ts
1525
+ var name = "acp-tui-client-plane";
1526
+ var inject = [];
1527
+ function apply(ctx, config) {
1528
+ installTuiClientPlane(ctx, config.rpc, {
1529
+ findAgent: config.findAgent,
1530
+ advertisement: config.advertisement
1531
+ });
1532
+ }
1533
+
1534
+ // src/bridge/user-questions-plugin.ts
1535
+ var user_questions_plugin_exports = {};
1536
+ __export(user_questions_plugin_exports, {
1537
+ apply: () => apply2,
1538
+ inject: () => inject2,
1539
+ name: () => name2
1540
+ });
1541
+
1516
1542
  // src/bridge/user-questions.ts
1517
1543
  import { Service } from "@deepseek-ai/cordis";
1518
1544
  import {
@@ -1685,17 +1711,26 @@ function installAcpUserQuestionProvider(service, options) {
1685
1711
  };
1686
1712
  }
1687
1713
 
1714
+ // src/bridge/user-questions-plugin.ts
1715
+ var name2 = "acp-user-questions";
1716
+ var inject2 = ["userQuestions"];
1717
+ function apply2(ctx, config) {
1718
+ const service = ctx.userQuestions;
1719
+ const dispose = installAcpUserQuestionProvider(service, config);
1720
+ ctx.effect(() => dispose, "acp-user-questions.provider");
1721
+ }
1722
+
1688
1723
  // src/bridge/presets.ts
1689
1724
  function presetDisplayName(preset) {
1690
1725
  if (preset.id === "cordis") return "Creator";
1691
1726
  if (preset.id === "code") return "Code";
1692
- const name3 = preset.name?.trim();
1693
- return name3 !== void 0 && name3.length > 0 ? name3 : preset.id;
1727
+ const name5 = preset.name?.trim();
1728
+ return name5 !== void 0 && name5.length > 0 ? name5 : preset.id;
1694
1729
  }
1695
1730
 
1696
1731
  // src/bridge/index.ts
1697
- var name = "acp-bridge";
1698
- var inject = ["agents", "credentials", "llm", "agentDefaultModel", "sessionPersistence", "approval", "permissionPresets", "commands", "agentPresets", "skills", "subagents", "userQuestions"];
1732
+ var name3 = "acp-bridge";
1733
+ var inject3 = ["agents", "credentials", "llm", "agentDefaultModel", "sessionPersistence", "approval", "permissionPresets", "commands", "agentPresets", "skills", "subagents", "userQuestions"];
1699
1734
  function invalidParams(detail) {
1700
1735
  return RequestError.invalidParams(void 0, detail);
1701
1736
  }
@@ -1716,7 +1751,7 @@ var MODE_LABELS = {
1716
1751
  description: "No sandbox confinement and no permission prompts"
1717
1752
  }
1718
1753
  };
1719
- async function apply(ctx, config = {}) {
1754
+ async function apply3(ctx, config = {}) {
1720
1755
  const agents = ctx.agents;
1721
1756
  const credentials = ctx.credentials;
1722
1757
  const llm = ctx.llm;
@@ -1728,7 +1763,6 @@ async function apply(ctx, config = {}) {
1728
1763
  const agentPresets = ctx.agentPresets;
1729
1764
  const skillRegistry = ctx.skills;
1730
1765
  const subagents = ctx.subagents;
1731
- const userQuestions = ctx.userQuestions;
1732
1766
  const harness = config.harness ?? (await Promise.resolve().then(() => (init_self_harness(), self_harness_exports))).selfHarness();
1733
1767
  const { createUserMessage: createUserMessage2, errorChain: errorChain2, sessionId: SessionId2, foldSessionTitle: foldSessionTitle2, setSandboxMode: setSandboxMode2 } = harness;
1734
1768
  const SANDBOX_MODES2 = harness.sandboxModes;
@@ -1751,7 +1785,7 @@ async function apply(ctx, config = {}) {
1751
1785
  }
1752
1786
  return void 0;
1753
1787
  };
1754
- installTuiClientPlane(ctx, rpc, { findAgent, advertisement: tuiClient });
1788
+ await ctx.plugin(tui_client_plugin_exports, { rpc, findAgent, advertisement: tuiClient });
1755
1789
  const modelCandidates = () => {
1756
1790
  const seen = /* @__PURE__ */ new Set();
1757
1791
  if (config.model !== void 0) seen.add(config.model);
@@ -1944,8 +1978,8 @@ async function apply(ctx, config = {}) {
1944
1978
  if (!entry || typeof entry !== "object") return [];
1945
1979
  const id = entry.id;
1946
1980
  if (typeof id !== "string" || id.length === 0) return [];
1947
- const name3 = entry.name;
1948
- return [{ id, ...typeof name3 === "string" && name3.length > 0 ? { name: name3 } : {} }];
1981
+ const name5 = entry.name;
1982
+ return [{ id, ...typeof name5 === "string" && name5.length > 0 ? { name: name5 } : {} }];
1949
1983
  });
1950
1984
  } catch (error) {
1951
1985
  logDebug(`listProviders failed: ${String(error)}`);
@@ -1953,10 +1987,10 @@ async function apply(ctx, config = {}) {
1953
1987
  }
1954
1988
  };
1955
1989
  const credentialPresent = async (provider) => {
1956
- const names = credentialEnvNames(provider).filter((name3) => !name3.endsWith("_BASE_URL"));
1957
- for (const name3 of names) {
1990
+ const names = credentialEnvNames(provider).filter((name5) => !name5.endsWith("_BASE_URL"));
1991
+ for (const name5 of names) {
1958
1992
  try {
1959
- if (await credentials.resolve(credentialRef(name3)) !== void 0) return true;
1993
+ if (await credentials.resolve(credentialRef(name5)) !== void 0) return true;
1960
1994
  } catch (error) {
1961
1995
  logWarn(`credential lookup failed: ${String(error)}`);
1962
1996
  }
@@ -2165,9 +2199,9 @@ async function apply(ctx, config = {}) {
2165
2199
  if (permission.names.length > 0) {
2166
2200
  return {
2167
2201
  currentModeId: record.modeId,
2168
- availableModes: permission.names.map((name3) => {
2169
- const spec = permission.resolve(name3);
2170
- return { id: name3, name: spec.name, description: spec.description };
2202
+ availableModes: permission.names.map((name5) => {
2203
+ const spec = permission.resolve(name5);
2204
+ return { id: name5, name: spec.name, description: spec.description };
2171
2205
  })
2172
2206
  };
2173
2207
  }
@@ -2265,10 +2299,10 @@ async function apply(ctx, config = {}) {
2265
2299
  const modelChoices = async (record) => {
2266
2300
  const seen = /* @__PURE__ */ new Set();
2267
2301
  const options = [];
2268
- const push = (value, name3) => {
2302
+ const push = (value, name5) => {
2269
2303
  if (seen.has(value)) return;
2270
2304
  seen.add(value);
2271
- options.push({ value, name: name3 });
2305
+ options.push({ value, name: name5 });
2272
2306
  };
2273
2307
  const current = encodeChoice(
2274
2308
  record.provider,
@@ -2287,9 +2321,9 @@ async function apply(ctx, config = {}) {
2287
2321
  const result = [];
2288
2322
  {
2289
2323
  const permission = permissionService();
2290
- const levels = permission.names.length > 0 ? permission.names.map((name3) => {
2291
- const spec = permission.resolve(name3);
2292
- return { value: name3, name: spec.name, description: spec.description };
2324
+ const levels = permission.names.length > 0 ? permission.names.map((name5) => {
2325
+ const spec = permission.resolve(name5);
2326
+ return { value: name5, name: spec.name, description: spec.description };
2293
2327
  }) : SANDBOX_MODES2.map((mode) => {
2294
2328
  const label = MODE_LABELS[mode] ?? { name: mode, description: "" };
2295
2329
  return { value: mode, name: label.name, description: label.description };
@@ -2387,6 +2421,18 @@ async function apply(ctx, config = {}) {
2387
2421
  ];
2388
2422
  const availableCommandsFor = async (record) => {
2389
2423
  const list = [...BUILTIN_COMMANDS];
2424
+ if (tuiClient.advertised) {
2425
+ list.push({
2426
+ name: "plan-view",
2427
+ description: "Open the current ACP plan",
2428
+ _meta: {
2429
+ commandAction: {
2430
+ kind: "clientCommand",
2431
+ presentation: "view"
2432
+ }
2433
+ }
2434
+ });
2435
+ }
2390
2436
  const seen = new Set(list.map((command) => command.name));
2391
2437
  try {
2392
2438
  for (const descriptor of commandRuntime.list(record.agent)) {
@@ -2474,9 +2520,9 @@ async function apply(ctx, config = {}) {
2474
2520
  };
2475
2521
  const describeCredential = async (provider) => {
2476
2522
  const names = credentialEnvNames(provider).filter((candidate) => !candidate.endsWith("_BASE_URL"));
2477
- for (const name3 of names) {
2523
+ for (const name5 of names) {
2478
2524
  try {
2479
- const info = await credentials.describe(credentialRef(name3));
2525
+ const info = await credentials.describe(credentialRef(name5));
2480
2526
  if (info.configured) return info.source ?? "credential store";
2481
2527
  } catch (error) {
2482
2528
  logWarn(`credential describe failed: ${String(error)}`);
@@ -2723,9 +2769,9 @@ async function apply(ctx, config = {}) {
2723
2769
  assertOpen();
2724
2770
  const started = performance.now();
2725
2771
  let checkpoint = started;
2726
- const mark = (name3) => {
2772
+ const mark = (name5) => {
2727
2773
  const now = performance.now();
2728
- logDebug(`session/new ${name3}: ${(now - checkpoint).toFixed(1)}ms (+${(now - started).toFixed(1)}ms)`);
2774
+ logDebug(`session/new ${name5}: ${(now - checkpoint).toFixed(1)}ms (+${(now - started).toFixed(1)}ms)`);
2729
2775
  checkpoint = now;
2730
2776
  };
2731
2777
  await requireCredential(config.provider);
@@ -3102,7 +3148,7 @@ async function apply(ctx, config = {}) {
3102
3148
  );
3103
3149
  const stream = muxAcpStream(raw, rpc);
3104
3150
  conn = new AgentSideConnection(makeAgent, stream);
3105
- const disposeUserQuestions = installAcpUserQuestionProvider(userQuestions, {
3151
+ await ctx.plugin(user_questions_plugin_exports, {
3106
3152
  formSupported: () => clientElicitationForm,
3107
3153
  sessionIdForRequest: (request) => {
3108
3154
  if (request.agent === void 0) return void 0;
@@ -3149,28 +3195,27 @@ async function apply(ctx, config = {}) {
3149
3195
  logWarn(`connection-close teardown failed: ${String(error)}`);
3150
3196
  });
3151
3197
  ctx.effect(() => quiesce, "acp-bridge.connection");
3152
- ctx.effect(() => disposeUserQuestions, "acp-bridge.user-questions");
3153
3198
  }
3154
3199
 
3155
3200
  // src/bundle.ts
3156
3201
  init_self_harness();
3157
- var name2 = "acp-bridge";
3158
- var inject2 = inject;
3202
+ var name4 = "acp-bridge";
3203
+ var inject4 = inject3;
3159
3204
  function nodeAcpStream(input, output) {
3160
3205
  return ndJsonStream2(
3161
3206
  Writable2.toWeb(output),
3162
3207
  Readable2.toWeb(input)
3163
3208
  );
3164
3209
  }
3165
- function apply2(ctx, config = {}) {
3210
+ function apply4(ctx, config = {}) {
3166
3211
  const stream = nodeAcpStream(process.stdin, process.stdout);
3167
3212
  const server = ctx.get("acpServer");
3168
3213
  if (server !== void 0) return server.connect(stream);
3169
3214
  return ctx.plugin(bridge_exports, { ...config, stream, harness: selfHarness() });
3170
3215
  }
3171
3216
  export {
3172
- apply2 as apply,
3173
- inject2 as inject,
3174
- name2 as name,
3217
+ apply4 as apply,
3218
+ inject4 as inject,
3219
+ name4 as name,
3175
3220
  nodeAcpStream
3176
3221
  };
package/dist/plugin.js CHANGED
@@ -9,8 +9,8 @@ var __esm = (fn, res, err) => function __init() {
9
9
  }
10
10
  };
11
11
  var __export = (target, all) => {
12
- for (var name4 in all)
13
- __defProp(target, name4, { get: all[name4], enumerable: true });
12
+ for (var name6 in all)
13
+ __defProp(target, name6, { get: all[name6], enumerable: true });
14
14
  };
15
15
 
16
16
  // src/bridge/self-harness.ts
@@ -53,11 +53,11 @@ import { dirname, join } from "node:path";
53
53
  var bridge_exports = {};
54
54
  __export(bridge_exports, {
55
55
  answerFromElicitation: () => answerFromElicitation,
56
- apply: () => apply,
56
+ apply: () => apply3,
57
57
  askUserQuestionsOverAcp: () => askUserQuestionsOverAcp,
58
- inject: () => inject,
58
+ inject: () => inject3,
59
59
  installAcpUserQuestionProvider: () => installAcpUserQuestionProvider,
60
- name: () => name,
60
+ name: () => name3,
61
61
  questionsToElicitation: () => questionsToElicitation
62
62
  });
63
63
  import { randomUUID } from "node:crypto";
@@ -148,11 +148,11 @@ function apiKeyAuthMethods(providers) {
148
148
  }
149
149
  return providers.map((provider) => apiKeyAuthMethod(provider.id, provider.name, false));
150
150
  }
151
- function apiKeyAuthMethod(provider, name4, unscoped) {
151
+ function apiKeyAuthMethod(provider, name6, unscoped) {
152
152
  const scoped = !unscoped && provider !== void 0;
153
153
  return {
154
154
  id: scoped ? `api-key:${provider}` : "api-key",
155
- name: scoped ? `${name4 ?? provider} API key` : "API Key",
155
+ name: scoped ? `${name6 ?? provider} API key` : "API Key",
156
156
  description: LOGIN_DESCRIPTION,
157
157
  _meta: { "api-key": scoped ? { provider } : {} }
158
158
  };
@@ -340,7 +340,7 @@ function pathLocations(args) {
340
340
  }
341
341
  return locations;
342
342
  }
343
- function classifyToolCall(name4, rawArguments) {
343
+ function classifyToolCall(name6, rawArguments) {
344
344
  let args = {};
345
345
  try {
346
346
  const parsed = JSON.parse(rawArguments);
@@ -358,7 +358,7 @@ function classifyToolCall(name4, rawArguments) {
358
358
  locations,
359
359
  rawInput: args
360
360
  });
361
- switch (name4) {
361
+ switch (name6) {
362
362
  case "bash": {
363
363
  const command = asString(args["command"]);
364
364
  const restart = args["restart"] === true;
@@ -389,17 +389,17 @@ function classifyToolCall(name4, rawArguments) {
389
389
  default:
390
390
  break;
391
391
  }
392
- const lowered = name4.toLowerCase();
392
+ const lowered = name6.toLowerCase();
393
393
  if (/(^|_)(grep|glob|find|search|ls|list)($|_)/.test(lowered)) {
394
394
  const query = asString(args["query"]) ?? asString(args["pattern"]);
395
- return facts("search", query !== void 0 ? `Search for '${firstLine(query, 50)}'` : name4);
395
+ return facts("search", query !== void 0 ? `Search for '${firstLine(query, 50)}'` : name6);
396
396
  }
397
397
  if (/(fetch|web|http|browse)/.test(lowered)) {
398
398
  const url = asString(args["url"]) ?? asString(args["query"]);
399
- return facts("fetch", url !== void 0 ? `Fetch ${firstLine(url, 60)}` : name4);
399
+ return facts("fetch", url !== void 0 ? `Fetch ${firstLine(url, 60)}` : name6);
400
400
  }
401
- if (/(job|task|run|exec)/.test(lowered)) return facts("execute", name4);
402
- return facts("other", name4);
401
+ if (/(job|task|run|exec)/.test(lowered)) return facts("execute", name6);
402
+ return facts("other", name6);
403
403
  }
404
404
  function diffsFromToolMeta(meta) {
405
405
  if (meta === null || typeof meta !== "object") return [];
@@ -514,8 +514,8 @@ var TOOL_KINDS = /* @__PURE__ */ new Set([
514
514
  "switch_mode",
515
515
  "other"
516
516
  ]);
517
- function factsFromPresentCall(name4, rawArguments, presented) {
518
- const fallback = classifyToolCall(name4, rawArguments);
517
+ function factsFromPresentCall(name6, rawArguments, presented) {
518
+ const fallback = classifyToolCall(name6, rawArguments);
519
519
  const kind = presented.kind !== void 0 && TOOL_KINDS.has(presented.kind) ? presented.kind : fallback.kind;
520
520
  const title = presented.title !== void 0 && presented.title.length > 0 ? presented.title : fallback.title;
521
521
  const locations = presented.locations !== void 0 && presented.locations.length > 0 ? presented.locations.map(
@@ -784,7 +784,7 @@ var SessionProjection = class {
784
784
  }
785
785
  onToolCall(data) {
786
786
  const callId = asString(data["callId"]);
787
- const name4 = asString(data["name"]) ?? "tool";
787
+ const name6 = asString(data["name"]) ?? "tool";
788
788
  if (callId === void 0) return [];
789
789
  const rawArguments = typeof data["arguments"] === "string" ? data["arguments"] : "{}";
790
790
  let parsedArgs = {};
@@ -793,8 +793,8 @@ var SessionProjection = class {
793
793
  } catch {
794
794
  parsedArgs = { arguments: rawArguments };
795
795
  }
796
- const presented = this.presentCall?.(name4, parsedArgs);
797
- const facts = presented !== void 0 ? factsFromPresentCall(name4, rawArguments, presented) : classifyToolCall(name4, rawArguments);
796
+ const presented = this.presentCall?.(name6, parsedArgs);
797
+ const facts = presented !== void 0 ? factsFromPresentCall(name6, rawArguments, presented) : classifyToolCall(name6, rawArguments);
798
798
  this.toolCalls.set(callId, facts);
799
799
  const displayTerminal = this.terminalOutput && facts.kind === "execute";
800
800
  return [
@@ -802,7 +802,7 @@ var SessionProjection = class {
802
802
  sessionUpdate: "tool_call",
803
803
  toolCallId: callId,
804
804
  title: facts.title,
805
- name: name4,
805
+ name: name6,
806
806
  kind: facts.kind,
807
807
  status: "in_progress",
808
808
  rawInput: facts.rawInput,
@@ -1035,8 +1035,8 @@ function prepareImage(block) {
1035
1035
  throw new PromptImageError(`unsupported image media type: ${block.mimeType}`);
1036
1036
  }
1037
1037
  const data = decodeImageData(block.data);
1038
- const name4 = imageName(block.uri);
1039
- return name4 === void 0 ? { data, mediaType } : { data, mediaType, name: name4 };
1038
+ const name6 = imageName(block.uri);
1039
+ return name6 === void 0 ? { data, mediaType } : { data, mediaType, name: name6 };
1040
1040
  }
1041
1041
  function saveInput(image) {
1042
1042
  return image.name === void 0 ? { data: image.data, mediaType: image.mediaType } : { data: image.data, mediaType: image.mediaType, name: image.name };
@@ -1261,6 +1261,14 @@ function muxAcpStream(stream, rpc) {
1261
1261
  return { readable, writable: acpWritable };
1262
1262
  }
1263
1263
 
1264
+ // src/bridge/tui-client-plugin.ts
1265
+ var tui_client_plugin_exports = {};
1266
+ __export(tui_client_plugin_exports, {
1267
+ apply: () => apply,
1268
+ inject: () => inject,
1269
+ name: () => name
1270
+ });
1271
+
1264
1272
  // src/bridge/tui-client.ts
1265
1273
  function installTuiClientPlane(ctx, rpc, opts) {
1266
1274
  const { findAgent, advertisement } = opts;
@@ -1514,6 +1522,24 @@ function readProviders(params) {
1514
1522
  });
1515
1523
  }
1516
1524
 
1525
+ // src/bridge/tui-client-plugin.ts
1526
+ var name = "acp-tui-client-plane";
1527
+ var inject = [];
1528
+ function apply(ctx, config) {
1529
+ installTuiClientPlane(ctx, config.rpc, {
1530
+ findAgent: config.findAgent,
1531
+ advertisement: config.advertisement
1532
+ });
1533
+ }
1534
+
1535
+ // src/bridge/user-questions-plugin.ts
1536
+ var user_questions_plugin_exports = {};
1537
+ __export(user_questions_plugin_exports, {
1538
+ apply: () => apply2,
1539
+ inject: () => inject2,
1540
+ name: () => name2
1541
+ });
1542
+
1517
1543
  // src/bridge/user-questions.ts
1518
1544
  import { Service } from "@deepseek-ai/cordis";
1519
1545
  import {
@@ -1686,17 +1712,26 @@ function installAcpUserQuestionProvider(service, options) {
1686
1712
  };
1687
1713
  }
1688
1714
 
1715
+ // src/bridge/user-questions-plugin.ts
1716
+ var name2 = "acp-user-questions";
1717
+ var inject2 = ["userQuestions"];
1718
+ function apply2(ctx, config) {
1719
+ const service = ctx.userQuestions;
1720
+ const dispose = installAcpUserQuestionProvider(service, config);
1721
+ ctx.effect(() => dispose, "acp-user-questions.provider");
1722
+ }
1723
+
1689
1724
  // src/bridge/presets.ts
1690
1725
  function presetDisplayName(preset) {
1691
1726
  if (preset.id === "cordis") return "Creator";
1692
1727
  if (preset.id === "code") return "Code";
1693
- const name4 = preset.name?.trim();
1694
- return name4 !== void 0 && name4.length > 0 ? name4 : preset.id;
1728
+ const name6 = preset.name?.trim();
1729
+ return name6 !== void 0 && name6.length > 0 ? name6 : preset.id;
1695
1730
  }
1696
1731
 
1697
1732
  // src/bridge/index.ts
1698
- var name = "acp-bridge";
1699
- var inject = ["agents", "credentials", "llm", "agentDefaultModel", "sessionPersistence", "approval", "permissionPresets", "commands", "agentPresets", "skills", "subagents", "userQuestions"];
1733
+ var name3 = "acp-bridge";
1734
+ var inject3 = ["agents", "credentials", "llm", "agentDefaultModel", "sessionPersistence", "approval", "permissionPresets", "commands", "agentPresets", "skills", "subagents", "userQuestions"];
1700
1735
  function invalidParams(detail) {
1701
1736
  return RequestError.invalidParams(void 0, detail);
1702
1737
  }
@@ -1717,7 +1752,7 @@ var MODE_LABELS = {
1717
1752
  description: "No sandbox confinement and no permission prompts"
1718
1753
  }
1719
1754
  };
1720
- async function apply(ctx, config = {}) {
1755
+ async function apply3(ctx, config = {}) {
1721
1756
  const agents = ctx.agents;
1722
1757
  const credentials = ctx.credentials;
1723
1758
  const llm = ctx.llm;
@@ -1729,7 +1764,6 @@ async function apply(ctx, config = {}) {
1729
1764
  const agentPresets = ctx.agentPresets;
1730
1765
  const skillRegistry = ctx.skills;
1731
1766
  const subagents = ctx.subagents;
1732
- const userQuestions = ctx.userQuestions;
1733
1767
  const harness = config.harness ?? (await Promise.resolve().then(() => (init_self_harness(), self_harness_exports))).selfHarness();
1734
1768
  const { createUserMessage: createUserMessage2, errorChain: errorChain2, sessionId: SessionId2, foldSessionTitle: foldSessionTitle2, setSandboxMode: setSandboxMode2 } = harness;
1735
1769
  const SANDBOX_MODES2 = harness.sandboxModes;
@@ -1752,7 +1786,7 @@ async function apply(ctx, config = {}) {
1752
1786
  }
1753
1787
  return void 0;
1754
1788
  };
1755
- installTuiClientPlane(ctx, rpc, { findAgent, advertisement: tuiClient });
1789
+ await ctx.plugin(tui_client_plugin_exports, { rpc, findAgent, advertisement: tuiClient });
1756
1790
  const modelCandidates = () => {
1757
1791
  const seen = /* @__PURE__ */ new Set();
1758
1792
  if (config.model !== void 0) seen.add(config.model);
@@ -1945,8 +1979,8 @@ async function apply(ctx, config = {}) {
1945
1979
  if (!entry || typeof entry !== "object") return [];
1946
1980
  const id = entry.id;
1947
1981
  if (typeof id !== "string" || id.length === 0) return [];
1948
- const name4 = entry.name;
1949
- return [{ id, ...typeof name4 === "string" && name4.length > 0 ? { name: name4 } : {} }];
1982
+ const name6 = entry.name;
1983
+ return [{ id, ...typeof name6 === "string" && name6.length > 0 ? { name: name6 } : {} }];
1950
1984
  });
1951
1985
  } catch (error) {
1952
1986
  logDebug(`listProviders failed: ${String(error)}`);
@@ -1954,10 +1988,10 @@ async function apply(ctx, config = {}) {
1954
1988
  }
1955
1989
  };
1956
1990
  const credentialPresent = async (provider) => {
1957
- const names = credentialEnvNames(provider).filter((name4) => !name4.endsWith("_BASE_URL"));
1958
- for (const name4 of names) {
1991
+ const names = credentialEnvNames(provider).filter((name6) => !name6.endsWith("_BASE_URL"));
1992
+ for (const name6 of names) {
1959
1993
  try {
1960
- if (await credentials.resolve(credentialRef(name4)) !== void 0) return true;
1994
+ if (await credentials.resolve(credentialRef(name6)) !== void 0) return true;
1961
1995
  } catch (error) {
1962
1996
  logWarn(`credential lookup failed: ${String(error)}`);
1963
1997
  }
@@ -2166,9 +2200,9 @@ async function apply(ctx, config = {}) {
2166
2200
  if (permission.names.length > 0) {
2167
2201
  return {
2168
2202
  currentModeId: record.modeId,
2169
- availableModes: permission.names.map((name4) => {
2170
- const spec = permission.resolve(name4);
2171
- return { id: name4, name: spec.name, description: spec.description };
2203
+ availableModes: permission.names.map((name6) => {
2204
+ const spec = permission.resolve(name6);
2205
+ return { id: name6, name: spec.name, description: spec.description };
2172
2206
  })
2173
2207
  };
2174
2208
  }
@@ -2266,10 +2300,10 @@ async function apply(ctx, config = {}) {
2266
2300
  const modelChoices = async (record) => {
2267
2301
  const seen = /* @__PURE__ */ new Set();
2268
2302
  const options = [];
2269
- const push = (value, name4) => {
2303
+ const push = (value, name6) => {
2270
2304
  if (seen.has(value)) return;
2271
2305
  seen.add(value);
2272
- options.push({ value, name: name4 });
2306
+ options.push({ value, name: name6 });
2273
2307
  };
2274
2308
  const current = encodeChoice(
2275
2309
  record.provider,
@@ -2288,9 +2322,9 @@ async function apply(ctx, config = {}) {
2288
2322
  const result = [];
2289
2323
  {
2290
2324
  const permission = permissionService();
2291
- const levels = permission.names.length > 0 ? permission.names.map((name4) => {
2292
- const spec = permission.resolve(name4);
2293
- return { value: name4, name: spec.name, description: spec.description };
2325
+ const levels = permission.names.length > 0 ? permission.names.map((name6) => {
2326
+ const spec = permission.resolve(name6);
2327
+ return { value: name6, name: spec.name, description: spec.description };
2294
2328
  }) : SANDBOX_MODES2.map((mode) => {
2295
2329
  const label = MODE_LABELS[mode] ?? { name: mode, description: "" };
2296
2330
  return { value: mode, name: label.name, description: label.description };
@@ -2388,6 +2422,18 @@ async function apply(ctx, config = {}) {
2388
2422
  ];
2389
2423
  const availableCommandsFor = async (record) => {
2390
2424
  const list = [...BUILTIN_COMMANDS];
2425
+ if (tuiClient.advertised) {
2426
+ list.push({
2427
+ name: "plan-view",
2428
+ description: "Open the current ACP plan",
2429
+ _meta: {
2430
+ commandAction: {
2431
+ kind: "clientCommand",
2432
+ presentation: "view"
2433
+ }
2434
+ }
2435
+ });
2436
+ }
2391
2437
  const seen = new Set(list.map((command) => command.name));
2392
2438
  try {
2393
2439
  for (const descriptor of commandRuntime.list(record.agent)) {
@@ -2475,9 +2521,9 @@ async function apply(ctx, config = {}) {
2475
2521
  };
2476
2522
  const describeCredential = async (provider) => {
2477
2523
  const names = credentialEnvNames(provider).filter((candidate) => !candidate.endsWith("_BASE_URL"));
2478
- for (const name4 of names) {
2524
+ for (const name6 of names) {
2479
2525
  try {
2480
- const info = await credentials.describe(credentialRef(name4));
2526
+ const info = await credentials.describe(credentialRef(name6));
2481
2527
  if (info.configured) return info.source ?? "credential store";
2482
2528
  } catch (error) {
2483
2529
  logWarn(`credential describe failed: ${String(error)}`);
@@ -2724,9 +2770,9 @@ async function apply(ctx, config = {}) {
2724
2770
  assertOpen();
2725
2771
  const started = performance.now();
2726
2772
  let checkpoint = started;
2727
- const mark = (name4) => {
2773
+ const mark = (name6) => {
2728
2774
  const now = performance.now();
2729
- logDebug(`session/new ${name4}: ${(now - checkpoint).toFixed(1)}ms (+${(now - started).toFixed(1)}ms)`);
2775
+ logDebug(`session/new ${name6}: ${(now - checkpoint).toFixed(1)}ms (+${(now - started).toFixed(1)}ms)`);
2730
2776
  checkpoint = now;
2731
2777
  };
2732
2778
  await requireCredential(config.provider);
@@ -3103,7 +3149,7 @@ async function apply(ctx, config = {}) {
3103
3149
  );
3104
3150
  const stream = muxAcpStream(raw, rpc);
3105
3151
  conn = new AgentSideConnection(makeAgent, stream);
3106
- const disposeUserQuestions = installAcpUserQuestionProvider(userQuestions, {
3152
+ await ctx.plugin(user_questions_plugin_exports, {
3107
3153
  formSupported: () => clientElicitationForm,
3108
3154
  sessionIdForRequest: (request) => {
3109
3155
  if (request.agent === void 0) return void 0;
@@ -3150,20 +3196,19 @@ async function apply(ctx, config = {}) {
3150
3196
  logWarn(`connection-close teardown failed: ${String(error)}`);
3151
3197
  });
3152
3198
  ctx.effect(() => quiesce, "acp-bridge.connection");
3153
- ctx.effect(() => disposeUserQuestions, "acp-bridge.user-questions");
3154
3199
  }
3155
3200
 
3156
3201
  // src/server.ts
3157
3202
  var server_exports = {};
3158
3203
  __export(server_exports, {
3159
- apply: () => apply2,
3160
- inject: () => inject2,
3161
- name: () => name2
3204
+ apply: () => apply4,
3205
+ inject: () => inject4,
3206
+ name: () => name4
3162
3207
  });
3163
3208
  init_self_harness();
3164
- var name2 = "acp-server";
3165
- var inject2 = inject;
3166
- function apply2(ctx, config = {}) {
3209
+ var name4 = "acp-server";
3210
+ var inject4 = inject3;
3211
+ function apply4(ctx, config = {}) {
3167
3212
  if (ctx.get("acpServer") !== void 0) return;
3168
3213
  const harness = selfHarness();
3169
3214
  const server = {
@@ -3175,8 +3220,8 @@ function apply2(ctx, config = {}) {
3175
3220
  }
3176
3221
 
3177
3222
  // src/plugin.ts
3178
- var name3 = "dsh-acp-plugin";
3179
- var inject3 = [.../* @__PURE__ */ new Set([...inject.filter((service) => service !== "agentPresets"), "loader"])];
3223
+ var name5 = "dsh-acp-plugin";
3224
+ var inject5 = [.../* @__PURE__ */ new Set([...inject3.filter((service) => service !== "agentPresets"), "loader"])];
3180
3225
  function shippedPresetRoot(ctx) {
3181
3226
  const anchors = [ctx.baseUrl, import.meta.url].filter((value) => typeof value === "string");
3182
3227
  for (const anchor of anchors) {
@@ -3198,7 +3243,7 @@ async function mountService(ctx, service, specifier, config) {
3198
3243
  throw new Error(`dsh-acp-plugin: ${specifier} did not provide ${service}`);
3199
3244
  }
3200
3245
  }
3201
- async function apply3(ctx, config = {}) {
3246
+ async function apply5(ctx, config = {}) {
3202
3247
  if (ctx.get("acpServer") !== void 0) return;
3203
3248
  await mountService(ctx, "agentPresets", "@deepseek-ai/dsh-agent-presets", {
3204
3249
  default: "standard",
@@ -3211,7 +3256,7 @@ async function apply3(ctx, config = {}) {
3211
3256
  }
3212
3257
  }
3213
3258
  export {
3214
- apply3 as apply,
3215
- inject3 as inject,
3216
- name3 as name
3259
+ apply5 as apply,
3260
+ inject5 as inject,
3261
+ name5 as name
3217
3262
  };
package/dist/server.js CHANGED
@@ -9,8 +9,8 @@ var __esm = (fn, res, err) => function __init() {
9
9
  }
10
10
  };
11
11
  var __export = (target, all) => {
12
- for (var name3 in all)
13
- __defProp(target, name3, { get: all[name3], enumerable: true });
12
+ for (var name5 in all)
13
+ __defProp(target, name5, { get: all[name5], enumerable: true });
14
14
  };
15
15
 
16
16
  // src/bridge/self-harness.ts
@@ -48,11 +48,11 @@ var init_self_harness = __esm({
48
48
  var bridge_exports = {};
49
49
  __export(bridge_exports, {
50
50
  answerFromElicitation: () => answerFromElicitation,
51
- apply: () => apply,
51
+ apply: () => apply3,
52
52
  askUserQuestionsOverAcp: () => askUserQuestionsOverAcp,
53
- inject: () => inject,
53
+ inject: () => inject3,
54
54
  installAcpUserQuestionProvider: () => installAcpUserQuestionProvider,
55
- name: () => name,
55
+ name: () => name3,
56
56
  questionsToElicitation: () => questionsToElicitation
57
57
  });
58
58
  import { randomUUID } from "node:crypto";
@@ -143,11 +143,11 @@ function apiKeyAuthMethods(providers) {
143
143
  }
144
144
  return providers.map((provider) => apiKeyAuthMethod(provider.id, provider.name, false));
145
145
  }
146
- function apiKeyAuthMethod(provider, name3, unscoped) {
146
+ function apiKeyAuthMethod(provider, name5, unscoped) {
147
147
  const scoped = !unscoped && provider !== void 0;
148
148
  return {
149
149
  id: scoped ? `api-key:${provider}` : "api-key",
150
- name: scoped ? `${name3 ?? provider} API key` : "API Key",
150
+ name: scoped ? `${name5 ?? provider} API key` : "API Key",
151
151
  description: LOGIN_DESCRIPTION,
152
152
  _meta: { "api-key": scoped ? { provider } : {} }
153
153
  };
@@ -335,7 +335,7 @@ function pathLocations(args) {
335
335
  }
336
336
  return locations;
337
337
  }
338
- function classifyToolCall(name3, rawArguments) {
338
+ function classifyToolCall(name5, rawArguments) {
339
339
  let args = {};
340
340
  try {
341
341
  const parsed = JSON.parse(rawArguments);
@@ -353,7 +353,7 @@ function classifyToolCall(name3, rawArguments) {
353
353
  locations,
354
354
  rawInput: args
355
355
  });
356
- switch (name3) {
356
+ switch (name5) {
357
357
  case "bash": {
358
358
  const command = asString(args["command"]);
359
359
  const restart = args["restart"] === true;
@@ -384,17 +384,17 @@ function classifyToolCall(name3, rawArguments) {
384
384
  default:
385
385
  break;
386
386
  }
387
- const lowered = name3.toLowerCase();
387
+ const lowered = name5.toLowerCase();
388
388
  if (/(^|_)(grep|glob|find|search|ls|list)($|_)/.test(lowered)) {
389
389
  const query = asString(args["query"]) ?? asString(args["pattern"]);
390
- return facts("search", query !== void 0 ? `Search for '${firstLine(query, 50)}'` : name3);
390
+ return facts("search", query !== void 0 ? `Search for '${firstLine(query, 50)}'` : name5);
391
391
  }
392
392
  if (/(fetch|web|http|browse)/.test(lowered)) {
393
393
  const url = asString(args["url"]) ?? asString(args["query"]);
394
- return facts("fetch", url !== void 0 ? `Fetch ${firstLine(url, 60)}` : name3);
394
+ return facts("fetch", url !== void 0 ? `Fetch ${firstLine(url, 60)}` : name5);
395
395
  }
396
- if (/(job|task|run|exec)/.test(lowered)) return facts("execute", name3);
397
- return facts("other", name3);
396
+ if (/(job|task|run|exec)/.test(lowered)) return facts("execute", name5);
397
+ return facts("other", name5);
398
398
  }
399
399
  function diffsFromToolMeta(meta) {
400
400
  if (meta === null || typeof meta !== "object") return [];
@@ -509,8 +509,8 @@ var TOOL_KINDS = /* @__PURE__ */ new Set([
509
509
  "switch_mode",
510
510
  "other"
511
511
  ]);
512
- function factsFromPresentCall(name3, rawArguments, presented) {
513
- const fallback = classifyToolCall(name3, rawArguments);
512
+ function factsFromPresentCall(name5, rawArguments, presented) {
513
+ const fallback = classifyToolCall(name5, rawArguments);
514
514
  const kind = presented.kind !== void 0 && TOOL_KINDS.has(presented.kind) ? presented.kind : fallback.kind;
515
515
  const title = presented.title !== void 0 && presented.title.length > 0 ? presented.title : fallback.title;
516
516
  const locations = presented.locations !== void 0 && presented.locations.length > 0 ? presented.locations.map(
@@ -779,7 +779,7 @@ var SessionProjection = class {
779
779
  }
780
780
  onToolCall(data) {
781
781
  const callId = asString(data["callId"]);
782
- const name3 = asString(data["name"]) ?? "tool";
782
+ const name5 = asString(data["name"]) ?? "tool";
783
783
  if (callId === void 0) return [];
784
784
  const rawArguments = typeof data["arguments"] === "string" ? data["arguments"] : "{}";
785
785
  let parsedArgs = {};
@@ -788,8 +788,8 @@ var SessionProjection = class {
788
788
  } catch {
789
789
  parsedArgs = { arguments: rawArguments };
790
790
  }
791
- const presented = this.presentCall?.(name3, parsedArgs);
792
- const facts = presented !== void 0 ? factsFromPresentCall(name3, rawArguments, presented) : classifyToolCall(name3, rawArguments);
791
+ const presented = this.presentCall?.(name5, parsedArgs);
792
+ const facts = presented !== void 0 ? factsFromPresentCall(name5, rawArguments, presented) : classifyToolCall(name5, rawArguments);
793
793
  this.toolCalls.set(callId, facts);
794
794
  const displayTerminal = this.terminalOutput && facts.kind === "execute";
795
795
  return [
@@ -797,7 +797,7 @@ var SessionProjection = class {
797
797
  sessionUpdate: "tool_call",
798
798
  toolCallId: callId,
799
799
  title: facts.title,
800
- name: name3,
800
+ name: name5,
801
801
  kind: facts.kind,
802
802
  status: "in_progress",
803
803
  rawInput: facts.rawInput,
@@ -1030,8 +1030,8 @@ function prepareImage(block) {
1030
1030
  throw new PromptImageError(`unsupported image media type: ${block.mimeType}`);
1031
1031
  }
1032
1032
  const data = decodeImageData(block.data);
1033
- const name3 = imageName(block.uri);
1034
- return name3 === void 0 ? { data, mediaType } : { data, mediaType, name: name3 };
1033
+ const name5 = imageName(block.uri);
1034
+ return name5 === void 0 ? { data, mediaType } : { data, mediaType, name: name5 };
1035
1035
  }
1036
1036
  function saveInput(image) {
1037
1037
  return image.name === void 0 ? { data: image.data, mediaType: image.mediaType } : { data: image.data, mediaType: image.mediaType, name: image.name };
@@ -1256,6 +1256,14 @@ function muxAcpStream(stream, rpc) {
1256
1256
  return { readable, writable: acpWritable };
1257
1257
  }
1258
1258
 
1259
+ // src/bridge/tui-client-plugin.ts
1260
+ var tui_client_plugin_exports = {};
1261
+ __export(tui_client_plugin_exports, {
1262
+ apply: () => apply,
1263
+ inject: () => inject,
1264
+ name: () => name
1265
+ });
1266
+
1259
1267
  // src/bridge/tui-client.ts
1260
1268
  function installTuiClientPlane(ctx, rpc, opts) {
1261
1269
  const { findAgent, advertisement } = opts;
@@ -1509,6 +1517,24 @@ function readProviders(params) {
1509
1517
  });
1510
1518
  }
1511
1519
 
1520
+ // src/bridge/tui-client-plugin.ts
1521
+ var name = "acp-tui-client-plane";
1522
+ var inject = [];
1523
+ function apply(ctx, config) {
1524
+ installTuiClientPlane(ctx, config.rpc, {
1525
+ findAgent: config.findAgent,
1526
+ advertisement: config.advertisement
1527
+ });
1528
+ }
1529
+
1530
+ // src/bridge/user-questions-plugin.ts
1531
+ var user_questions_plugin_exports = {};
1532
+ __export(user_questions_plugin_exports, {
1533
+ apply: () => apply2,
1534
+ inject: () => inject2,
1535
+ name: () => name2
1536
+ });
1537
+
1512
1538
  // src/bridge/user-questions.ts
1513
1539
  import { Service } from "@deepseek-ai/cordis";
1514
1540
  import {
@@ -1681,17 +1707,26 @@ function installAcpUserQuestionProvider(service, options) {
1681
1707
  };
1682
1708
  }
1683
1709
 
1710
+ // src/bridge/user-questions-plugin.ts
1711
+ var name2 = "acp-user-questions";
1712
+ var inject2 = ["userQuestions"];
1713
+ function apply2(ctx, config) {
1714
+ const service = ctx.userQuestions;
1715
+ const dispose = installAcpUserQuestionProvider(service, config);
1716
+ ctx.effect(() => dispose, "acp-user-questions.provider");
1717
+ }
1718
+
1684
1719
  // src/bridge/presets.ts
1685
1720
  function presetDisplayName(preset) {
1686
1721
  if (preset.id === "cordis") return "Creator";
1687
1722
  if (preset.id === "code") return "Code";
1688
- const name3 = preset.name?.trim();
1689
- return name3 !== void 0 && name3.length > 0 ? name3 : preset.id;
1723
+ const name5 = preset.name?.trim();
1724
+ return name5 !== void 0 && name5.length > 0 ? name5 : preset.id;
1690
1725
  }
1691
1726
 
1692
1727
  // src/bridge/index.ts
1693
- var name = "acp-bridge";
1694
- var inject = ["agents", "credentials", "llm", "agentDefaultModel", "sessionPersistence", "approval", "permissionPresets", "commands", "agentPresets", "skills", "subagents", "userQuestions"];
1728
+ var name3 = "acp-bridge";
1729
+ var inject3 = ["agents", "credentials", "llm", "agentDefaultModel", "sessionPersistence", "approval", "permissionPresets", "commands", "agentPresets", "skills", "subagents", "userQuestions"];
1695
1730
  function invalidParams(detail) {
1696
1731
  return RequestError.invalidParams(void 0, detail);
1697
1732
  }
@@ -1712,7 +1747,7 @@ var MODE_LABELS = {
1712
1747
  description: "No sandbox confinement and no permission prompts"
1713
1748
  }
1714
1749
  };
1715
- async function apply(ctx, config = {}) {
1750
+ async function apply3(ctx, config = {}) {
1716
1751
  const agents = ctx.agents;
1717
1752
  const credentials = ctx.credentials;
1718
1753
  const llm = ctx.llm;
@@ -1724,7 +1759,6 @@ async function apply(ctx, config = {}) {
1724
1759
  const agentPresets = ctx.agentPresets;
1725
1760
  const skillRegistry = ctx.skills;
1726
1761
  const subagents = ctx.subagents;
1727
- const userQuestions = ctx.userQuestions;
1728
1762
  const harness = config.harness ?? (await Promise.resolve().then(() => (init_self_harness(), self_harness_exports))).selfHarness();
1729
1763
  const { createUserMessage: createUserMessage2, errorChain: errorChain2, sessionId: SessionId2, foldSessionTitle: foldSessionTitle2, setSandboxMode: setSandboxMode2 } = harness;
1730
1764
  const SANDBOX_MODES2 = harness.sandboxModes;
@@ -1747,7 +1781,7 @@ async function apply(ctx, config = {}) {
1747
1781
  }
1748
1782
  return void 0;
1749
1783
  };
1750
- installTuiClientPlane(ctx, rpc, { findAgent, advertisement: tuiClient });
1784
+ await ctx.plugin(tui_client_plugin_exports, { rpc, findAgent, advertisement: tuiClient });
1751
1785
  const modelCandidates = () => {
1752
1786
  const seen = /* @__PURE__ */ new Set();
1753
1787
  if (config.model !== void 0) seen.add(config.model);
@@ -1940,8 +1974,8 @@ async function apply(ctx, config = {}) {
1940
1974
  if (!entry || typeof entry !== "object") return [];
1941
1975
  const id = entry.id;
1942
1976
  if (typeof id !== "string" || id.length === 0) return [];
1943
- const name3 = entry.name;
1944
- return [{ id, ...typeof name3 === "string" && name3.length > 0 ? { name: name3 } : {} }];
1977
+ const name5 = entry.name;
1978
+ return [{ id, ...typeof name5 === "string" && name5.length > 0 ? { name: name5 } : {} }];
1945
1979
  });
1946
1980
  } catch (error) {
1947
1981
  logDebug(`listProviders failed: ${String(error)}`);
@@ -1949,10 +1983,10 @@ async function apply(ctx, config = {}) {
1949
1983
  }
1950
1984
  };
1951
1985
  const credentialPresent = async (provider) => {
1952
- const names = credentialEnvNames(provider).filter((name3) => !name3.endsWith("_BASE_URL"));
1953
- for (const name3 of names) {
1986
+ const names = credentialEnvNames(provider).filter((name5) => !name5.endsWith("_BASE_URL"));
1987
+ for (const name5 of names) {
1954
1988
  try {
1955
- if (await credentials.resolve(credentialRef(name3)) !== void 0) return true;
1989
+ if (await credentials.resolve(credentialRef(name5)) !== void 0) return true;
1956
1990
  } catch (error) {
1957
1991
  logWarn(`credential lookup failed: ${String(error)}`);
1958
1992
  }
@@ -2161,9 +2195,9 @@ async function apply(ctx, config = {}) {
2161
2195
  if (permission.names.length > 0) {
2162
2196
  return {
2163
2197
  currentModeId: record.modeId,
2164
- availableModes: permission.names.map((name3) => {
2165
- const spec = permission.resolve(name3);
2166
- return { id: name3, name: spec.name, description: spec.description };
2198
+ availableModes: permission.names.map((name5) => {
2199
+ const spec = permission.resolve(name5);
2200
+ return { id: name5, name: spec.name, description: spec.description };
2167
2201
  })
2168
2202
  };
2169
2203
  }
@@ -2261,10 +2295,10 @@ async function apply(ctx, config = {}) {
2261
2295
  const modelChoices = async (record) => {
2262
2296
  const seen = /* @__PURE__ */ new Set();
2263
2297
  const options = [];
2264
- const push = (value, name3) => {
2298
+ const push = (value, name5) => {
2265
2299
  if (seen.has(value)) return;
2266
2300
  seen.add(value);
2267
- options.push({ value, name: name3 });
2301
+ options.push({ value, name: name5 });
2268
2302
  };
2269
2303
  const current = encodeChoice(
2270
2304
  record.provider,
@@ -2283,9 +2317,9 @@ async function apply(ctx, config = {}) {
2283
2317
  const result = [];
2284
2318
  {
2285
2319
  const permission = permissionService();
2286
- const levels = permission.names.length > 0 ? permission.names.map((name3) => {
2287
- const spec = permission.resolve(name3);
2288
- return { value: name3, name: spec.name, description: spec.description };
2320
+ const levels = permission.names.length > 0 ? permission.names.map((name5) => {
2321
+ const spec = permission.resolve(name5);
2322
+ return { value: name5, name: spec.name, description: spec.description };
2289
2323
  }) : SANDBOX_MODES2.map((mode) => {
2290
2324
  const label = MODE_LABELS[mode] ?? { name: mode, description: "" };
2291
2325
  return { value: mode, name: label.name, description: label.description };
@@ -2383,6 +2417,18 @@ async function apply(ctx, config = {}) {
2383
2417
  ];
2384
2418
  const availableCommandsFor = async (record) => {
2385
2419
  const list = [...BUILTIN_COMMANDS];
2420
+ if (tuiClient.advertised) {
2421
+ list.push({
2422
+ name: "plan-view",
2423
+ description: "Open the current ACP plan",
2424
+ _meta: {
2425
+ commandAction: {
2426
+ kind: "clientCommand",
2427
+ presentation: "view"
2428
+ }
2429
+ }
2430
+ });
2431
+ }
2386
2432
  const seen = new Set(list.map((command) => command.name));
2387
2433
  try {
2388
2434
  for (const descriptor of commandRuntime.list(record.agent)) {
@@ -2470,9 +2516,9 @@ async function apply(ctx, config = {}) {
2470
2516
  };
2471
2517
  const describeCredential = async (provider) => {
2472
2518
  const names = credentialEnvNames(provider).filter((candidate) => !candidate.endsWith("_BASE_URL"));
2473
- for (const name3 of names) {
2519
+ for (const name5 of names) {
2474
2520
  try {
2475
- const info = await credentials.describe(credentialRef(name3));
2521
+ const info = await credentials.describe(credentialRef(name5));
2476
2522
  if (info.configured) return info.source ?? "credential store";
2477
2523
  } catch (error) {
2478
2524
  logWarn(`credential describe failed: ${String(error)}`);
@@ -2719,9 +2765,9 @@ async function apply(ctx, config = {}) {
2719
2765
  assertOpen();
2720
2766
  const started = performance.now();
2721
2767
  let checkpoint = started;
2722
- const mark = (name3) => {
2768
+ const mark = (name5) => {
2723
2769
  const now = performance.now();
2724
- logDebug(`session/new ${name3}: ${(now - checkpoint).toFixed(1)}ms (+${(now - started).toFixed(1)}ms)`);
2770
+ logDebug(`session/new ${name5}: ${(now - checkpoint).toFixed(1)}ms (+${(now - started).toFixed(1)}ms)`);
2725
2771
  checkpoint = now;
2726
2772
  };
2727
2773
  await requireCredential(config.provider);
@@ -3098,7 +3144,7 @@ async function apply(ctx, config = {}) {
3098
3144
  );
3099
3145
  const stream = muxAcpStream(raw, rpc);
3100
3146
  conn = new AgentSideConnection(makeAgent, stream);
3101
- const disposeUserQuestions = installAcpUserQuestionProvider(userQuestions, {
3147
+ await ctx.plugin(user_questions_plugin_exports, {
3102
3148
  formSupported: () => clientElicitationForm,
3103
3149
  sessionIdForRequest: (request) => {
3104
3150
  if (request.agent === void 0) return void 0;
@@ -3145,14 +3191,13 @@ async function apply(ctx, config = {}) {
3145
3191
  logWarn(`connection-close teardown failed: ${String(error)}`);
3146
3192
  });
3147
3193
  ctx.effect(() => quiesce, "acp-bridge.connection");
3148
- ctx.effect(() => disposeUserQuestions, "acp-bridge.user-questions");
3149
3194
  }
3150
3195
 
3151
3196
  // src/server.ts
3152
3197
  init_self_harness();
3153
- var name2 = "acp-server";
3154
- var inject2 = inject;
3155
- function apply2(ctx, config = {}) {
3198
+ var name4 = "acp-server";
3199
+ var inject4 = inject3;
3200
+ function apply4(ctx, config = {}) {
3156
3201
  if (ctx.get("acpServer") !== void 0) return;
3157
3202
  const harness = selfHarness();
3158
3203
  const server = {
@@ -3163,7 +3208,7 @@ function apply2(ctx, config = {}) {
3163
3208
  ctx.provide("acpServer", server);
3164
3209
  }
3165
3210
  export {
3166
- apply2 as apply,
3167
- inject2 as inject,
3168
- name2 as name
3211
+ apply4 as apply,
3212
+ inject4 as inject,
3213
+ name4 as name
3169
3214
  };
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.4.10",
6
+ "version": "0.4.13",
7
7
  "repository": {
8
8
  "type": "git",
9
9
  "url": "git+https://github.com/openma-ai/deepseek-harness-acp.git"
@@ -35,7 +35,8 @@
35
35
  "build": "node build.mjs",
36
36
  "start": "node --import tsx src/index.ts",
37
37
  "pretest": "npm run build",
38
- "test": "vitest run",
38
+ "test": "vitest run --exclude test/profile-install.test.ts",
39
+ "test:install": "vitest run test/profile-install.test.ts",
39
40
  "test:watch": "vitest",
40
41
  "typecheck": "tsc --noEmit",
41
42
  "pack:local": "npm run build && npm pack"
@@ -112,7 +113,8 @@
112
113
  "vitest": "^4.1.10"
113
114
  },
114
115
  "dependencies": {
115
- "@agentclientprotocol/sdk": "^1.3.0"
116
+ "@agentclientprotocol/sdk": "^1.3.0",
117
+ "zod": "^4.4.3"
116
118
  },
117
119
  "peerDependencies": {
118
120
  "@deepseek-ai/dsh": "^0.1.0-rc.6"