@wrongstack/acp 1.0.29 → 1.0.33

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/agent.js CHANGED
@@ -236,6 +236,10 @@ async function handleSessionNewOp(ctx, id, params) {
236
236
  }
237
237
  const skipped = [];
238
238
  const mcpServers = parseMcpServers(p.mcpServers, (reason) => skipped.push(reason));
239
+ if (ctx.sessions.size >= ctx.maxSessions) {
240
+ await ctx.sendError(id, -32e3, `active session limit reached (${ctx.maxSessions})`);
241
+ return false;
242
+ }
239
243
  const sessionId = `sess_${ctx.allocId()}`;
240
244
  const now = (/* @__PURE__ */ new Date()).toISOString();
241
245
  const state = {
@@ -286,6 +290,9 @@ async function handleSessionLoadOp(ctx, id, params, replayHistory = true) {
286
290
  if (!existing && sessionId && ctx.store) {
287
291
  const persisted = await ctx.store.load(sessionId);
288
292
  if (persisted) {
293
+ if (ctx.sessions.has(sessionId)) {
294
+ return handleSessionLoadOp(ctx, id, params, replayHistory);
295
+ }
289
296
  if (ctx.sessions.size >= ctx.maxSessions) {
290
297
  await ctx.sendError(id, -32e3, `active session limit reached (${ctx.maxSessions})`);
291
298
  return false;
@@ -296,6 +303,13 @@ async function handleSessionLoadOp(ctx, id, params, replayHistory = true) {
296
303
  }
297
304
  const candidateCwd = loadCwd ?? persisted.cwd ?? ctx.defaultCwd;
298
305
  const restoredCwd = await resolveSessionCwd(candidateCwd) ?? ctx.defaultCwd;
306
+ if (ctx.sessions.has(sessionId)) {
307
+ return handleSessionLoadOp(ctx, id, params, replayHistory);
308
+ }
309
+ if (ctx.sessions.size >= ctx.maxSessions) {
310
+ await ctx.sendError(id, -32e3, `active session limit reached (${ctx.maxSessions})`);
311
+ return false;
312
+ }
299
313
  const restored = {
300
314
  id: sessionId,
301
315
  cwd: restoredCwd,
@@ -399,9 +413,17 @@ async function handleSessionForkOp(ctx, id, params) {
399
413
  }
400
414
  forkCwd = resolved;
401
415
  }
416
+ if (ctx.sessions.get(sourceId) !== source) {
417
+ await ctx.sendError(id, -32e3, `session not found: ${sourceId}`);
418
+ return false;
419
+ }
402
420
  const forkSkipped = [];
403
421
  const forkRequested = parseMcpServers(p.mcpServers, (reason) => forkSkipped.push(reason));
404
422
  const forkMcpServers = forkRequested.length > 0 ? forkRequested : source.mcpServers;
423
+ if (ctx.sessions.size >= ctx.maxSessions) {
424
+ await ctx.sendError(id, -32e3, `active session limit reached (${ctx.maxSessions})`);
425
+ return false;
426
+ }
405
427
  const now = (/* @__PURE__ */ new Date()).toISOString();
406
428
  const sessionId = `sess_${ctx.allocId()}`;
407
429
  const forked = {
@@ -1511,20 +1533,24 @@ var ACPSessionStore = class {
1511
1533
  const tmp = `${target}.${process.pid}.${Date.now()}.${++this.writeSeq}.tmp`;
1512
1534
  let renamed = false;
1513
1535
  try {
1514
- await fsp2.writeFile(
1515
- tmp,
1516
- JSON.stringify({
1517
- id: state.id,
1518
- cwd: state.cwd,
1519
- modeId: state.modeId,
1520
- configOptions: state.configOptions,
1521
- createdAt: state.createdAt,
1522
- updatedAt: state.updatedAt,
1523
- title: state.title,
1524
- ...history && history.length > 0 ? { history } : {}
1525
- }),
1526
- "utf8"
1527
- );
1536
+ const data = JSON.stringify({
1537
+ id: state.id,
1538
+ cwd: state.cwd,
1539
+ modeId: state.modeId,
1540
+ configOptions: state.configOptions,
1541
+ createdAt: state.createdAt,
1542
+ updatedAt: state.updatedAt,
1543
+ title: state.title,
1544
+ ...history && history.length > 0 ? { history } : {}
1545
+ });
1546
+ try {
1547
+ await fsp2.writeFile(tmp, data, "utf8");
1548
+ } catch (err) {
1549
+ if (err.code !== "ENOENT") throw err;
1550
+ this.initialized = false;
1551
+ await this.init();
1552
+ await fsp2.writeFile(tmp, data, "utf8");
1553
+ }
1528
1554
  await fsp2.rename(tmp, target);
1529
1555
  renamed = true;
1530
1556
  } finally {
@@ -1548,13 +1574,15 @@ var ACPSessionStore = class {
1548
1574
  }
1549
1575
  /** List all persisted sessions. */
1550
1576
  async list() {
1551
- const indexEntries = await this.readIndex();
1552
- if (indexEntries !== null) {
1553
- return indexEntries.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
1554
- }
1555
- const sessions = await this.scanForSessions();
1556
- void this.writeIndex(sessions).catch(() => void 0);
1557
- return sessions;
1577
+ return this.withIndexLock(async () => {
1578
+ const indexEntries = await this.readIndex();
1579
+ if (indexEntries !== null) {
1580
+ return indexEntries.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
1581
+ }
1582
+ const sessions = await this.scanForSessions();
1583
+ await this.writeIndex(sessions).catch(() => void 0);
1584
+ return sessions;
1585
+ });
1558
1586
  }
1559
1587
  /**
1560
1588
  * Walk `<dir>` and parse every session file into `{id, updatedAt}`
@@ -1579,7 +1607,7 @@ var ACPSessionStore = class {
1579
1607
  try {
1580
1608
  const data = await fsp2.readFile(path2.join(this.dir, file), "utf8");
1581
1609
  const parsed = JSON.parse(data);
1582
- if (parsed.id) {
1610
+ if (parsed && typeof parsed.id === "string" && parsed.id !== "" && (parsed.updatedAt === void 0 || typeof parsed.updatedAt === "string")) {
1583
1611
  sessions.push({ id: parsed.id, updatedAt: parsed.updatedAt ?? "" });
1584
1612
  }
1585
1613
  } catch {
@@ -1963,7 +1991,7 @@ function toACPInputSchema(src) {
1963
1991
  if (typeof s.maximum === "number") out.maximum = s.maximum;
1964
1992
  if (s.items) out.items = toACPInputSchema(s.items);
1965
1993
  if (s.properties && typeof s.properties === "object") {
1966
- const props = {};
1994
+ const props = /* @__PURE__ */ Object.create(null);
1967
1995
  for (const [k, v] of Object.entries(s.properties)) {
1968
1996
  props[k] = toACPInputSchema(v);
1969
1997
  }
@@ -2319,6 +2347,7 @@ var WsBridgeTransport = class {
2319
2347
  receive(msg) {
2320
2348
  if (this.closed) return;
2321
2349
  for (const handler of [...this.handlers]) {
2350
+ if (this.closed) break;
2322
2351
  try {
2323
2352
  handler(msg);
2324
2353
  } catch {
@@ -0,0 +1,24 @@
1
+ import type { ACPMessage } from '../types/acp-messages.js';
2
+ import { type ACPCallbackOptions, type ACPResponseSender } from './acp-session-callbacks.js';
3
+ import type { ACPProgressEvent } from './acp-session-types.js';
4
+ export interface AcpSessionMessagesHost {
5
+ sendResult: (id: string | number, result: unknown) => Promise<void>;
6
+ sendErrorResponse: (id: string | number, code: number, message: string) => Promise<void>;
7
+ promptCallbackAbort: AbortController | null;
8
+ callbackAbort: AbortController;
9
+ pending: Map<string | number, import('./acp-request-state.js').PendingRequest>;
10
+ sessionId: import('../types/acp-v1.js').SessionId | null;
11
+ scratch: import('./acp-session-updates.js').ACPSessionScratch;
12
+ emitProgress: (event: import('./acp-session-types.js').ACPProgressEvent) => void;
13
+ permissionPolicy: import('./permission.js').PermissionPolicy;
14
+ responseSender: () => import('./acp-session-callbacks.js').ACPResponseSender;
15
+ callbackOptions: () => import('./acp-session-callbacks.js').ACPCallbackOptions;
16
+ fileServer: import('./file-server.js').FileServer;
17
+ terminalServer: import('./terminal-server.js').TerminalServer;
18
+ progressHandler: import('./acp-session-types.js').ACPProgressHandler | null;
19
+ }
20
+ export declare function responseSender(this: AcpSessionMessagesHost): ACPResponseSender;
21
+ export declare function callbackOptions(this: AcpSessionMessagesHost): ACPCallbackOptions;
22
+ export declare function handleMessage(this: AcpSessionMessagesHost, msg: ACPMessage): void;
23
+ export declare function emitProgress(this: AcpSessionMessagesHost, event: ACPProgressEvent): void;
24
+ //# sourceMappingURL=acp-session-messages.d.ts.map
@@ -139,5 +139,6 @@ export declare class ACPSession {
139
139
  private scratch;
140
140
  private resetScratch;
141
141
  private acpSessionAuthHost;
142
+ private acpSessionMessagesHost;
142
143
  }
143
144
  //# sourceMappingURL=acp-session.d.ts.map