@moxt-ai/mobius 0.0.7 → 0.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -20988,7 +20988,7 @@ var AcpActivity = class _AcpActivity {
20988
20988
  toolKind;
20989
20989
  content;
20990
20990
  detail;
20991
- constructor(activityId, activityType, input2, locations, name, output2, sequence, status, title, toolKind, content = [], detail = captureActivityDetail(
20991
+ constructor(activityId, activityType, input2, locations, name, output2, sequence, status, title2, toolKind, content = [], detail = captureActivityDetail(
20992
20992
  content,
20993
20993
  input2,
20994
20994
  output2
@@ -21001,7 +21001,7 @@ var AcpActivity = class _AcpActivity {
21001
21001
  this.output = output2;
21002
21002
  this.sequence = sequence;
21003
21003
  this.status = status;
21004
- this.title = title;
21004
+ this.title = title2;
21005
21005
  this.toolKind = toolKind;
21006
21006
  this.content = content;
21007
21007
  this.detail = detail;
@@ -21217,8 +21217,8 @@ function normalizeToolStatus(status, fallback) {
21217
21217
  }
21218
21218
  return fallback;
21219
21219
  }
21220
- function normalizeTitle(title, fallback) {
21221
- const normalized = title.trim();
21220
+ function normalizeTitle(title2, fallback) {
21221
+ const normalized = title2.trim();
21222
21222
  return truncate(normalized.length === 0 ? fallback : normalized, 500);
21223
21223
  }
21224
21224
  function formatPlanEntries(entries) {
@@ -21464,12 +21464,13 @@ var AcpActivityTracker = class {
21464
21464
 
21465
21465
  // src/acp/native-session.ts
21466
21466
  var path = external_exports.string().min(1).max(2048).refine((value) => !value.includes("\0"));
21467
+ var title = external_exports.string().transform((value) => value.slice(0, 500));
21467
21468
  var nativeSessionIdSchema = external_exports.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,255}$/);
21468
21469
  var nativeSessionInfoSchema = external_exports.object({
21469
21470
  sessionId: nativeSessionIdSchema,
21470
21471
  cwd: path,
21471
21472
  additionalDirectories: external_exports.array(path).max(16).default([]).readonly(),
21472
- title: external_exports.string().max(500).nullish(),
21473
+ title: title.nullish(),
21473
21474
  updatedAt: external_exports.iso.datetime({ offset: true }).nullish()
21474
21475
  }).readonly();
21475
21476
  var nativeSessionPageSchema = external_exports.object({
@@ -21792,6 +21793,12 @@ var AcpExecutionError = class extends Error {
21792
21793
  this.name = "AcpExecutionError";
21793
21794
  }
21794
21795
  };
21796
+ var RetryableAcpInitializationError = class extends AcpExecutionError {
21797
+ constructor(cause) {
21798
+ super("ACP agent initialization failed", { cause });
21799
+ this.name = "RetryableAcpInitializationError";
21800
+ }
21801
+ };
21795
21802
  function readableWebStream(input2) {
21796
21803
  let streamOpen = true;
21797
21804
  return new ReadableStream({
@@ -22421,42 +22428,63 @@ var AcpProcessSession = class _AcpProcessSession {
22421
22428
  );
22422
22429
  this.#connection = createAcpClient(this).connect(stream);
22423
22430
  }
22424
- static start = async (options, getObserver, store) => {
22425
- options.signal.throwIfAborted();
22426
- const [adapterUnchanged, agentUnchanged] = await Promise.all([
22427
- revalidateExecutable(options.agent.adapterIdentity),
22428
- revalidateExecutable(options.agent.agentIdentity)
22429
- ]);
22430
- options.signal.throwIfAborted();
22431
- if (!adapterUnchanged || !agentUnchanged) {
22432
- throw new AcpExecutionError(
22433
- "The local Agent runtime changed; restart Mobius before starting a new conversation",
22434
- {},
22435
- "agent_runtime_changed"
22436
- );
22437
- }
22438
- const runtime = new _AcpProcessSession(
22439
- options.agent,
22440
- options.cwd,
22441
- options.additionalDirectories,
22442
- options.sessionId,
22443
- getObserver,
22444
- store
22445
- );
22446
- try {
22447
- await runtime.initialize(options.signal, options.origin);
22448
- return runtime;
22449
- } catch (error61) {
22450
- await runtime.closeProcess();
22431
+ static async #start(options, getObserver, store, initialize) {
22432
+ for (let attempt = 1; attempt <= 2; attempt += 1) {
22451
22433
  options.signal.throwIfAborted();
22452
- if (error61 instanceof AcpExecutionError) {
22453
- throw error61;
22434
+ const [adapterUnchanged, agentUnchanged] = await Promise.all([
22435
+ revalidateExecutable(options.agent.adapterIdentity),
22436
+ revalidateExecutable(options.agent.agentIdentity)
22437
+ ]);
22438
+ options.signal.throwIfAborted();
22439
+ if (!adapterUnchanged || !agentUnchanged) {
22440
+ throw new AcpExecutionError(
22441
+ "The local Agent runtime changed; restart Mobius before starting a new conversation",
22442
+ {},
22443
+ "agent_runtime_changed"
22444
+ );
22445
+ }
22446
+ const runtime = new _AcpProcessSession(
22447
+ options.agent,
22448
+ options.cwd,
22449
+ options.additionalDirectories,
22450
+ options.sessionId,
22451
+ getObserver,
22452
+ store
22453
+ );
22454
+ try {
22455
+ await initialize(runtime);
22456
+ return runtime;
22457
+ } catch (error61) {
22458
+ await runtime.closeProcess();
22459
+ options.signal.throwIfAborted();
22460
+ if (error61 instanceof RetryableAcpInitializationError && attempt === 1) {
22461
+ console.warn(
22462
+ `[${options.agent.id}-acp] ACP agent initialization failed; retrying once`
22463
+ );
22464
+ continue;
22465
+ }
22466
+ if (error61 instanceof AcpExecutionError) {
22467
+ throw error61;
22468
+ }
22469
+ throw new AcpExecutionError("ACP agent initialization failed", {
22470
+ cause: error61
22471
+ });
22454
22472
  }
22455
- throw new AcpExecutionError("ACP agent initialization failed", {
22456
- cause: error61
22457
- });
22458
22473
  }
22459
- };
22474
+ throw new AcpExecutionError("ACP agent initialization failed");
22475
+ }
22476
+ static start = async (options, getObserver, store) => await _AcpProcessSession.#start(
22477
+ options,
22478
+ getObserver,
22479
+ store,
22480
+ async (runtime) => await runtime.initialize(options.signal, options.origin)
22481
+ );
22482
+ static startNativeSessionBrowser = async (options, getObserver, store) => await _AcpProcessSession.#start(
22483
+ options,
22484
+ getObserver,
22485
+ store,
22486
+ async (runtime) => await runtime.#initializeAgent(options.signal)
22487
+ );
22460
22488
  belongsTo = (agentId, cwd, additionalDirectories) => this.#agentId === agentId && this.#cwd === cwd && arraysEqual(this.#additionalDirectories, additionalDirectories);
22461
22489
  canRebind = () => !this.#prompted && !this.#turn.running;
22462
22490
  prepared = () => new AcpPreparedSession(
@@ -22493,7 +22521,7 @@ var AcpProcessSession = class _AcpProcessSession {
22493
22521
  this.#replay = { kind: "idle" };
22494
22522
  }
22495
22523
  };
22496
- initialize = async (signal, origin) => {
22524
+ async #initializeAgent(signal) {
22497
22525
  const initialized = await this.race(
22498
22526
  this.#connection.agent.request(
22499
22527
  methods2.agent.initialize,
@@ -22510,7 +22538,10 @@ var AcpProcessSession = class _AcpProcessSession {
22510
22538
  ),
22511
22539
  "ACP agent exited during initialization",
22512
22540
  signal
22513
- );
22541
+ ).catch((cause) => {
22542
+ signal.throwIfAborted();
22543
+ throw new RetryableAcpInitializationError(cause);
22544
+ });
22514
22545
  if (initialized.protocolVersion !== PROTOCOL_VERSION) {
22515
22546
  throw new AcpExecutionError(
22516
22547
  "ACP agent selected an unsupported protocol version",
@@ -22525,7 +22556,10 @@ var AcpProcessSession = class _AcpProcessSession {
22525
22556
  255
22526
22557
  );
22527
22558
  this.#agentVersion = truncate2(initialized.agentInfo?.version ?? "", 128);
22528
- const stored = origin?.kind === "import" ? new FoundAcpStoredSession(
22559
+ }
22560
+ initialize = async (signal, origin) => {
22561
+ await this.#initializeAgent(signal);
22562
+ let stored = origin?.kind === "import" ? new FoundAcpStoredSession(
22529
22563
  new AcpStoredSession(
22530
22564
  this.#mobiusSessionId,
22531
22565
  this.#agentId,
@@ -22535,6 +22569,10 @@ var AcpProcessSession = class _AcpProcessSession {
22535
22569
  true
22536
22570
  )
22537
22571
  ) : this.#store.read(this.#mobiusSessionId);
22572
+ if (stored instanceof FoundAcpStoredSession && !stored.session.prompted) {
22573
+ this.#store.remove(this.#mobiusSessionId);
22574
+ stored = this.#store.read(this.#mobiusSessionId);
22575
+ }
22538
22576
  if (stored instanceof DeletedAcpStoredSession)
22539
22577
  throw new AcpExecutionError(
22540
22578
  "The native Agent session was deleted. Start a new chat.",
@@ -22650,6 +22688,15 @@ var AcpProcessSession = class _AcpProcessSession {
22650
22688
  );
22651
22689
  this.#nativeSessionId = created.sessionId;
22652
22690
  lifecycleResponse = created;
22691
+ }
22692
+ const lifecycleRecord = isRecord3(lifecycleResponse) ? lifecycleResponse : {};
22693
+ this.#configOptions = normalizeConfigOptions(
22694
+ lifecycleRecord["configOptions"],
22695
+ lifecycleRecord["modes"]
22696
+ );
22697
+ await this.#updateTail;
22698
+ signal.throwIfAborted();
22699
+ if (this.#prompted) {
22653
22700
  this.#store.write(
22654
22701
  new AcpStoredSession(
22655
22702
  this.#mobiusSessionId,
@@ -22657,27 +22704,10 @@ var AcpProcessSession = class _AcpProcessSession {
22657
22704
  this.#nativeSessionId,
22658
22705
  this.#cwd,
22659
22706
  this.#additionalDirectories,
22660
- false
22707
+ true
22661
22708
  )
22662
22709
  );
22663
22710
  }
22664
- const lifecycleRecord = isRecord3(lifecycleResponse) ? lifecycleResponse : {};
22665
- this.#configOptions = normalizeConfigOptions(
22666
- lifecycleRecord["configOptions"],
22667
- lifecycleRecord["modes"]
22668
- );
22669
- await this.#updateTail;
22670
- signal.throwIfAborted();
22671
- this.#store.write(
22672
- new AcpStoredSession(
22673
- this.#mobiusSessionId,
22674
- this.#agentId,
22675
- this.#nativeSessionId,
22676
- this.#cwd,
22677
- this.#additionalDirectories,
22678
- this.#prompted
22679
- )
22680
- );
22681
22711
  };
22682
22712
  listNativeSessions = async (cursor, signal) => {
22683
22713
  if (!this.#capabilities.listSessions)
@@ -23349,6 +23379,10 @@ var AcpProcessSession = class _AcpProcessSession {
23349
23379
  };
23350
23380
  var AcpSessionManager = class {
23351
23381
  #nativeOperations = /* @__PURE__ */ new Set();
23382
+ #nativeBrowserObserver = new NullAcpSessionObserver();
23383
+ #nativeBrowserPreparing = /* @__PURE__ */ new Map();
23384
+ #nativeBrowserSessions = /* @__PURE__ */ new Map();
23385
+ #nativeBrowserStore = new MemoryAcpSessionStore();
23352
23386
  #activeSessionIds = /* @__PURE__ */ new Set();
23353
23387
  #cancellationRequests = /* @__PURE__ */ new Set();
23354
23388
  #preparing = /* @__PURE__ */ new Map();
@@ -23362,6 +23396,43 @@ var AcpSessionManager = class {
23362
23396
  setObserver = (observer) => {
23363
23397
  this.#observer = observer;
23364
23398
  };
23399
+ async #startNativeBrowserPreparation(options) {
23400
+ const operation = (async () => {
23401
+ try {
23402
+ const runtime = await AcpProcessSession.startNativeSessionBrowser(
23403
+ options,
23404
+ () => this.#nativeBrowserObserver,
23405
+ this.#nativeBrowserStore
23406
+ );
23407
+ this.#nativeBrowserSessions.set(options.sessionId, runtime);
23408
+ return runtime;
23409
+ } finally {
23410
+ this.#nativeBrowserPreparing.delete(options.sessionId);
23411
+ }
23412
+ })();
23413
+ this.#nativeBrowserPreparing.set(options.sessionId, operation);
23414
+ return await operation;
23415
+ }
23416
+ async #replaceNativeBrowserPreparation(existing, options) {
23417
+ const operation = (async () => {
23418
+ try {
23419
+ this.#nativeBrowserSessions.delete(options.sessionId);
23420
+ await existing.close();
23421
+ this.#nativeBrowserStore.remove(options.sessionId);
23422
+ const runtime = await AcpProcessSession.startNativeSessionBrowser(
23423
+ options,
23424
+ () => this.#nativeBrowserObserver,
23425
+ this.#nativeBrowserStore
23426
+ );
23427
+ this.#nativeBrowserSessions.set(options.sessionId, runtime);
23428
+ return runtime;
23429
+ } finally {
23430
+ this.#nativeBrowserPreparing.delete(options.sessionId);
23431
+ }
23432
+ })();
23433
+ this.#nativeBrowserPreparing.set(options.sessionId, operation);
23434
+ return await operation;
23435
+ }
23365
23436
  async #startPreparation(options) {
23366
23437
  const operation = (async () => {
23367
23438
  try {
@@ -23449,6 +23520,44 @@ var AcpSessionManager = class {
23449
23520
  const runtime = await this.#startPreparation(options);
23450
23521
  return runtime.prepared();
23451
23522
  };
23523
+ prepareNativeSessionBrowser = async (options) => {
23524
+ const pending = this.#nativeBrowserPreparing.get(options.sessionId);
23525
+ if (pending !== void 0) {
23526
+ const runtime2 = await pending;
23527
+ if (runtime2.belongsTo(
23528
+ options.agent.id,
23529
+ options.cwd,
23530
+ options.additionalDirectories
23531
+ )) {
23532
+ return runtime2.prepared();
23533
+ }
23534
+ return await this.prepareNativeSessionBrowser(options);
23535
+ }
23536
+ const existing = this.#nativeBrowserSessions.get(options.sessionId);
23537
+ if (existing !== void 0) {
23538
+ if (existing.belongsTo(
23539
+ options.agent.id,
23540
+ options.cwd,
23541
+ options.additionalDirectories
23542
+ )) {
23543
+ return existing.prepared();
23544
+ }
23545
+ if (!existing.canRebind()) {
23546
+ throw new AcpExecutionError(
23547
+ "The agent or workspace cannot change after a conversation has started",
23548
+ {},
23549
+ "session_identity_mismatch"
23550
+ );
23551
+ }
23552
+ const runtime2 = await this.#replaceNativeBrowserPreparation(
23553
+ existing,
23554
+ options
23555
+ );
23556
+ return runtime2.prepared();
23557
+ }
23558
+ const runtime = await this.#startNativeBrowserPreparation(options);
23559
+ return runtime.prepared();
23560
+ };
23452
23561
  configureSession = async (options) => {
23453
23562
  const runtime = await this.ensureSession(options);
23454
23563
  return await runtime.configure(options);
@@ -23537,8 +23646,14 @@ var AcpSessionManager = class {
23537
23646
  };
23538
23647
  close = async () => {
23539
23648
  const sessions = [...this.#sessions.values()];
23649
+ const nativeBrowserSessions = [...this.#nativeBrowserSessions.values()];
23540
23650
  this.#sessions.clear();
23541
- await Promise.all(sessions.map(async (session) => await session.close()));
23651
+ this.#nativeBrowserSessions.clear();
23652
+ await Promise.all(
23653
+ [...sessions, ...nativeBrowserSessions].map(
23654
+ async (session) => await session.close()
23655
+ )
23656
+ );
23542
23657
  };
23543
23658
  ensureSession = async (options) => {
23544
23659
  const existing = this.#sessions.get(options.sessionId);
@@ -23563,7 +23678,30 @@ var AcpSessionManager = class {
23563
23678
  }
23564
23679
  return started;
23565
23680
  };
23566
- listNativeSessions = async (options, cursor) => await (await this.ensureSession(options)).listNativeSessions(
23681
+ async #ensureNativeSessionBrowser(options) {
23682
+ const existing = this.#nativeBrowserSessions.get(options.sessionId);
23683
+ if (existing !== void 0) {
23684
+ if (!existing.belongsTo(
23685
+ options.agent.id,
23686
+ options.cwd,
23687
+ options.additionalDirectories
23688
+ )) {
23689
+ throw new AcpExecutionError(
23690
+ "The agent or workspace cannot change after a conversation has started",
23691
+ {},
23692
+ "session_identity_mismatch"
23693
+ );
23694
+ }
23695
+ return existing;
23696
+ }
23697
+ await this.prepareNativeSessionBrowser(options);
23698
+ const started = this.#nativeBrowserSessions.get(options.sessionId);
23699
+ if (started === void 0) {
23700
+ throw new AcpExecutionError("ACP native session browser did not start");
23701
+ }
23702
+ return started;
23703
+ }
23704
+ listNativeSessions = async (options, cursor) => await (await this.#ensureNativeSessionBrowser(options)).listNativeSessions(
23567
23705
  cursor,
23568
23706
  options.signal
23569
23707
  );
@@ -23646,7 +23784,7 @@ var AcpSessionManager = class {
23646
23784
  }
23647
23785
  };
23648
23786
  deleteNativeSession = async (options, nativeSessionId) => {
23649
- const runtime = await this.ensureSession(options);
23787
+ const runtime = await this.#ensureNativeSessionBrowser(options);
23650
23788
  const key = `${options.agent.id}:${nativeSessionId}`;
23651
23789
  const linked = this.#store.findNative(options.agent.id, nativeSessionId);
23652
23790
  if (this.#nativeOperations.has(key) || linked.some(
@@ -23673,7 +23811,8 @@ var AcpSessionManager = class {
23673
23811
  nativeSessionId
23674
23812
  );
23675
23813
  if (runtime.nativeSessionId() === nativeSessionId) {
23676
- this.#sessions.delete(options.sessionId);
23814
+ this.#nativeBrowserSessions.delete(options.sessionId);
23815
+ this.#nativeBrowserStore.remove(options.sessionId);
23677
23816
  await runtime.close();
23678
23817
  }
23679
23818
  return deleted;
@@ -26693,7 +26832,7 @@ var NativeSessionService = class {
26693
26832
  sessionId: command.sessionId,
26694
26833
  signal
26695
26834
  };
26696
- const prepared = await this.#sessions.prepareSession(options);
26835
+ const prepared = await this.#sessions.prepareNativeSessionBrowser(options);
26697
26836
  if (!prepared.capabilities.listSessions)
26698
26837
  throw new AcpExecutionError(
26699
26838
  "This Agent does not support native session listing",
@@ -27755,6 +27894,15 @@ async function executeSessionPrepare(outbox, socket, command, config2, directori
27755
27894
  })
27756
27895
  );
27757
27896
  } catch (error61) {
27897
+ audit.record({
27898
+ commandId: command.requestId,
27899
+ details: {
27900
+ agentId: command.agentId,
27901
+ code: operationErrorCode(error61)
27902
+ },
27903
+ event: "session_prepare_failed",
27904
+ sessionId: command.sessionId
27905
+ });
27758
27906
  reportOperationFailure(socket, command.requestId, command.sessionId, error61);
27759
27907
  }
27760
27908
  }