@victor-software-house/pi-acp 0.17.0 → 0.17.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 CHANGED
@@ -62,6 +62,11 @@ Active development. ACP compliance is improving steadily. Development is centere
62
62
  - `local` (default) / `overlay` — ACP `params.cwd` used as session cwd; manifest roots compose
63
63
  - `none` — pi-acp mints an ephemeral tmpdir under `os.tmpdir()/pi-acp-session-*`, cleaned up at session dispose. For one-shot Q&A sessions that shouldn't pollute any project directory.
64
64
  - **ACP-FS `read` delegation** (PRD-002 §FR-6) — When the client advertises `clientCapabilities.fs.readTextFile`, pi-acp routes pi's built-in `read` tool through `connection.fs.readTextFile` instead of local disk. Lets Zed Remote read the actual remote workspace files (the ones the user is editing) while pi runs locally.
65
+ - **ACP terminal delegation** (PRD-002 §FR-6.5) — When the client advertises `clientCapabilities.terminal`, pi-acp overrides pi's built-in `bash` tool with an ACP `createTerminal`-backed implementation. Commands run on the client's machine via `terminal/*` lifecycle, so Zed Remote workflows execute `bash` on the remote workspace where the user actually edits. Pairs with `read` delegation so the full read/bash pair lands consistently remote.
66
+ - **ACP provider config** — `agentCapabilities.providers = {}` advertises `providers/list`, `providers/set`, `providers/disable`. Soft-disable on top of pi's `unregisterProvider`. Per-process; no `models.json` writer.
67
+ - **ACP logout** — `agentCapabilities.auth.logout = {}` advertises `logout`. Clears every provider's credentials from the shared `AuthStorage` in one call.
68
+ - **ACP session delete** — implemented but DISABLED by default (see Limitations). Direct invocation returns `methodNotFound`; capability not advertised. Flip `PiAcpAgent.SESSION_DELETE_ENABLED` to enable.
69
+ - **ACP `extMethod` / `extNotification`** — dispatcher under the `pi-acp/` namespace. Built-ins: `pi-acp/ping`, `pi-acp/runtime-info`.
65
70
 
66
71
  ## Resource composition (`.pi-acp.yaml`)
67
72
 
@@ -208,7 +213,7 @@ bun run dev # run from src
208
213
  bun run build # tsdown -> dist/index.mjs
209
214
  bun run typecheck # tsc --noEmit
210
215
  bun run lint # biome + oxlint
211
- bun test # 277 tests
216
+ bun test # 308 tests
212
217
  ```
213
218
 
214
219
  Project layout:
@@ -249,7 +254,17 @@ test/
249
254
 
250
255
  - **`agent_plan`** -- plan updates not emitted before tool execution. pi has no equivalent planning surface.
251
256
  - **ACP filesystem `write` delegation** (`fs/write_text_file`) -- pi writes locally. Not advertised. `fs/read_text_file` IS routed through ACP when the client advertises the capability (see Features → ACP-FS `read` delegation).
252
- - **ACP terminal delegation** (`terminal/*`) -- pi executes commands locally. Not advertised.
257
+ - **ACP terminal delegation** (`terminal/*`) -- DELEGATED. When the client advertises `clientCapabilities.terminal`, pi-acp overrides pi's built-in `bash` tool with an ACP `createTerminal`-backed implementation so commands run on the client's machine (Zed Remote routes `terminal/*` to the remote workspace). See Features → ACP terminal delegation.
258
+
259
+ ### ACP optional methods implemented (substrate completion at v0.16.0+)
260
+
261
+ - **`providers/list` / `providers/set` / `providers/disable`** -- advertised via `agentCapabilities.providers = {}`. Operates on every live `ModelRegistry`. Soft-disable is layered on top of pi's destructive `unregisterProvider`. Mutations are per-process (no models.json writer in pi).
262
+ - **`logout`** -- advertised via `agentCapabilities.auth.logout = {}`. Clears every provider's credentials from the shared AuthStorage. Sessions stay live; subsequent prompts may surface `auth_required`.
263
+ - **`extMethod` / `extNotification`** -- dispatcher under the `pi-acp/` method-name namespace. Built-in handlers: `pi-acp/ping`, `pi-acp/runtime-info`. Unknown methods → `methodNotFound`.
264
+
265
+ ### Implemented but DISABLED by default
266
+
267
+ - **`session/delete`** -- the implementation (release-from-daemon → `fs.rmSync` → cache purge) is in place, but the capability is NOT advertised in `initialize()` and direct invocations return `methodNotFound`. Gated behind `PiAcpAgent.SESSION_DELETE_ENABLED = false`. Rationale: ACP `session/delete` takes a single sessionId, has no confirmation surface, no trash, no recovery — easy to misfire from a UI button or a mistaken script. Re-enable only after a client-layer confirmation flow exists.
253
268
 
254
269
  ### Design decisions
255
270
 
@@ -2195,7 +2195,7 @@ var SshBackend = class {
2195
2195
  //#endregion
2196
2196
  //#region package.json
2197
2197
  var name = "@victor-software-house/pi-acp";
2198
- var version = "0.17.0";
2198
+ var version = "0.17.1";
2199
2199
  //#endregion
2200
2200
  //#region src/acp/agent.ts
2201
2201
  /** Builtin ACP slash commands handled directly by the adapter. */
@@ -2275,7 +2275,7 @@ function truncateSessionTitle(text) {
2275
2275
  if (oneLine.length <= SESSION_TITLE_MAX) return oneLine;
2276
2276
  return `${oneLine.slice(0, SESSION_TITLE_MAX - 1)}…`;
2277
2277
  }
2278
- var PiAcpAgent = class {
2278
+ var PiAcpAgent = class PiAcpAgent {
2279
2279
  conn;
2280
2280
  sessions = new SessionManager$1();
2281
2281
  /** Cache of sessionId → file path, populated by listSessions and newSession. */
@@ -2299,6 +2299,19 @@ var PiAcpAgent = class {
2299
2299
  * report `current: null` per ACP spec even after disable.
2300
2300
  */
2301
2301
  disabledProviders = /* @__PURE__ */ new Set();
2302
+ /**
2303
+ * Master toggle for `session/delete` advertisement + method body.
2304
+ *
2305
+ * Disabled by default: the method irreversibly removes a session file
2306
+ * via fs.rmSync, and ACP clients invoke it with a single sessionId arg
2307
+ * — no confirmation surface, no trash. Easy to misfire from a UI or
2308
+ * an extension. Re-enable only when a confirmation flow exists at the
2309
+ * client layer or when the operator opts in via configuration.
2310
+ *
2311
+ * The implementation (release-from-daemon → fs.rmSync → cache purge)
2312
+ * is kept intact so re-enabling is a one-line flip plus a re-advertise.
2313
+ */
2314
+ static SESSION_DELETE_ENABLED = false;
2302
2315
  dispose() {
2303
2316
  if (this.daemonContext !== void 0) {
2304
2317
  const registry = this.daemonContext.sessionRegistry;
@@ -2567,7 +2580,7 @@ var PiAcpAgent = class {
2567
2580
  close: {},
2568
2581
  resume: {},
2569
2582
  fork: {},
2570
- delete: {}
2583
+ ...PiAcpAgent.SESSION_DELETE_ENABLED ? { delete: {} } : {}
2571
2584
  },
2572
2585
  providers: {}
2573
2586
  }
@@ -2944,21 +2957,27 @@ var PiAcpAgent = class {
2944
2957
  /**
2945
2958
  * Deletes a session's on-disk file + releases any live state.
2946
2959
  *
2947
- * Pi's SessionManager exposes no `delete()` method (verified against
2948
- * session-manager.d.ts) sessions are append-only JSONL files. We
2949
- * unlink the file directly via `fs.rmSync`. `resolveSessionFile`
2950
- * sources paths from `PiSessionManager.listAll`, so the unlinked path
2951
- * is always inside `~/.pi/agent/sessions/...`.
2960
+ * DISABLED by default via `PiAcpAgent.SESSION_DELETE_ENABLED = false`.
2961
+ * The capability is not advertised in initialize() and any direct call
2962
+ * is refused with `methodNotFound`. Rationale: ACP `session/delete`
2963
+ * carries only a sessionId no confirmation surface, no trash, no
2964
+ * recovery. Easy to misfire from a UI button or a mistaken script,
2965
+ * and the consequence is permanent loss of session history.
2966
+ *
2967
+ * When enabled: Pi's SessionManager exposes no `delete()` method
2968
+ * (verified against session-manager.d.ts) — sessions are append-only
2969
+ * JSONL files. We unlink the file directly via `fs.rmSync`.
2970
+ * `resolveSessionFile` sources paths from `PiSessionManager.listAll`,
2971
+ * so the unlinked path is always inside `~/.pi/agent/sessions/...`.
2952
2972
  *
2953
2973
  * Refuses to delete sessions owned by ANOTHER connection in the daemon
2954
2974
  * registry — security boundary: clients may only delete sessions they
2955
2975
  * own or sessions that are not currently live. Always releases the
2956
2976
  * daemon registry entry first so the live piSession is disposed
2957
2977
  * cleanly before the file disappears.
2958
- *
2959
- * Gated by `sessionCapabilities.delete = {}` (advertised in initialize).
2960
2978
  */
2961
2979
  async unstable_deleteSession(params) {
2980
+ if (!PiAcpAgent.SESSION_DELETE_ENABLED) throw RequestError.methodNotFound("session/delete");
2962
2981
  const sessionFile = await this.resolveSessionFile(params.sessionId);
2963
2982
  if (sessionFile === null) throw RequestError.invalidParams(`Unknown sessionId: ${params.sessionId}`);
2964
2983
  const live = this.daemonContext?.sessionRegistry.get(params.sessionId);
@@ -3717,4 +3736,4 @@ async function runDaemon() {
3717
3736
  //#endregion
3718
3737
  export { runDaemon };
3719
3738
 
3720
- //# sourceMappingURL=daemon-CTINLJUp.mjs.map
3739
+ //# sourceMappingURL=daemon-DTmhT4aC.mjs.map