@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/cli.js CHANGED
@@ -22338,7 +22338,7 @@ var AcpActivity = class _AcpActivity {
22338
22338
  toolKind;
22339
22339
  content;
22340
22340
  detail;
22341
- constructor(activityId, activityType, input2, locations, name, output2, sequence, status, title, toolKind, content = [], detail = captureActivityDetail(
22341
+ constructor(activityId, activityType, input2, locations, name, output2, sequence, status, title2, toolKind, content = [], detail = captureActivityDetail(
22342
22342
  content,
22343
22343
  input2,
22344
22344
  output2
@@ -22351,7 +22351,7 @@ var AcpActivity = class _AcpActivity {
22351
22351
  this.output = output2;
22352
22352
  this.sequence = sequence;
22353
22353
  this.status = status;
22354
- this.title = title;
22354
+ this.title = title2;
22355
22355
  this.toolKind = toolKind;
22356
22356
  this.content = content;
22357
22357
  this.detail = detail;
@@ -22567,8 +22567,8 @@ function normalizeToolStatus(status, fallback) {
22567
22567
  }
22568
22568
  return fallback;
22569
22569
  }
22570
- function normalizeTitle(title, fallback) {
22571
- const normalized = title.trim();
22570
+ function normalizeTitle(title2, fallback) {
22571
+ const normalized = title2.trim();
22572
22572
  return truncate(normalized.length === 0 ? fallback : normalized, 500);
22573
22573
  }
22574
22574
  function formatPlanEntries(entries) {
@@ -22814,12 +22814,13 @@ var AcpActivityTracker = class {
22814
22814
 
22815
22815
  // src/acp/native-session.ts
22816
22816
  var path = external_exports.string().min(1).max(2048).refine((value) => !value.includes("\0"));
22817
+ var title = external_exports.string().transform((value) => value.slice(0, 500));
22817
22818
  var nativeSessionIdSchema = external_exports.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,255}$/);
22818
22819
  var nativeSessionInfoSchema = external_exports.object({
22819
22820
  sessionId: nativeSessionIdSchema,
22820
22821
  cwd: path,
22821
22822
  additionalDirectories: external_exports.array(path).max(16).default([]).readonly(),
22822
- title: external_exports.string().max(500).nullish(),
22823
+ title: title.nullish(),
22823
22824
  updatedAt: external_exports.iso.datetime({ offset: true }).nullish()
22824
22825
  }).readonly();
22825
22826
  var nativeSessionPageSchema = external_exports.object({
@@ -23142,6 +23143,12 @@ var AcpExecutionError = class extends Error {
23142
23143
  this.name = "AcpExecutionError";
23143
23144
  }
23144
23145
  };
23146
+ var RetryableAcpInitializationError = class extends AcpExecutionError {
23147
+ constructor(cause) {
23148
+ super("ACP agent initialization failed", { cause });
23149
+ this.name = "RetryableAcpInitializationError";
23150
+ }
23151
+ };
23145
23152
  function readableWebStream(input2) {
23146
23153
  let streamOpen = true;
23147
23154
  return new ReadableStream({
@@ -23771,42 +23778,63 @@ var AcpProcessSession = class _AcpProcessSession {
23771
23778
  );
23772
23779
  this.#connection = createAcpClient(this).connect(stream);
23773
23780
  }
23774
- static start = async (options, getObserver, store) => {
23775
- options.signal.throwIfAborted();
23776
- const [adapterUnchanged, agentUnchanged] = await Promise.all([
23777
- revalidateExecutable(options.agent.adapterIdentity),
23778
- revalidateExecutable(options.agent.agentIdentity)
23779
- ]);
23780
- options.signal.throwIfAborted();
23781
- if (!adapterUnchanged || !agentUnchanged) {
23782
- throw new AcpExecutionError(
23783
- "The local Agent runtime changed; restart Mobius before starting a new conversation",
23784
- {},
23785
- "agent_runtime_changed"
23786
- );
23787
- }
23788
- const runtime = new _AcpProcessSession(
23789
- options.agent,
23790
- options.cwd,
23791
- options.additionalDirectories,
23792
- options.sessionId,
23793
- getObserver,
23794
- store
23795
- );
23796
- try {
23797
- await runtime.initialize(options.signal, options.origin);
23798
- return runtime;
23799
- } catch (error61) {
23800
- await runtime.closeProcess();
23781
+ static async #start(options, getObserver, store, initialize) {
23782
+ for (let attempt = 1; attempt <= 2; attempt += 1) {
23801
23783
  options.signal.throwIfAborted();
23802
- if (error61 instanceof AcpExecutionError) {
23803
- throw error61;
23784
+ const [adapterUnchanged, agentUnchanged] = await Promise.all([
23785
+ revalidateExecutable(options.agent.adapterIdentity),
23786
+ revalidateExecutable(options.agent.agentIdentity)
23787
+ ]);
23788
+ options.signal.throwIfAborted();
23789
+ if (!adapterUnchanged || !agentUnchanged) {
23790
+ throw new AcpExecutionError(
23791
+ "The local Agent runtime changed; restart Mobius before starting a new conversation",
23792
+ {},
23793
+ "agent_runtime_changed"
23794
+ );
23795
+ }
23796
+ const runtime = new _AcpProcessSession(
23797
+ options.agent,
23798
+ options.cwd,
23799
+ options.additionalDirectories,
23800
+ options.sessionId,
23801
+ getObserver,
23802
+ store
23803
+ );
23804
+ try {
23805
+ await initialize(runtime);
23806
+ return runtime;
23807
+ } catch (error61) {
23808
+ await runtime.closeProcess();
23809
+ options.signal.throwIfAborted();
23810
+ if (error61 instanceof RetryableAcpInitializationError && attempt === 1) {
23811
+ console.warn(
23812
+ `[${options.agent.id}-acp] ACP agent initialization failed; retrying once`
23813
+ );
23814
+ continue;
23815
+ }
23816
+ if (error61 instanceof AcpExecutionError) {
23817
+ throw error61;
23818
+ }
23819
+ throw new AcpExecutionError("ACP agent initialization failed", {
23820
+ cause: error61
23821
+ });
23804
23822
  }
23805
- throw new AcpExecutionError("ACP agent initialization failed", {
23806
- cause: error61
23807
- });
23808
23823
  }
23809
- };
23824
+ throw new AcpExecutionError("ACP agent initialization failed");
23825
+ }
23826
+ static start = async (options, getObserver, store) => await _AcpProcessSession.#start(
23827
+ options,
23828
+ getObserver,
23829
+ store,
23830
+ async (runtime) => await runtime.initialize(options.signal, options.origin)
23831
+ );
23832
+ static startNativeSessionBrowser = async (options, getObserver, store) => await _AcpProcessSession.#start(
23833
+ options,
23834
+ getObserver,
23835
+ store,
23836
+ async (runtime) => await runtime.#initializeAgent(options.signal)
23837
+ );
23810
23838
  belongsTo = (agentId, cwd, additionalDirectories) => this.#agentId === agentId && this.#cwd === cwd && arraysEqual(this.#additionalDirectories, additionalDirectories);
23811
23839
  canRebind = () => !this.#prompted && !this.#turn.running;
23812
23840
  prepared = () => new AcpPreparedSession(
@@ -23843,7 +23871,7 @@ var AcpProcessSession = class _AcpProcessSession {
23843
23871
  this.#replay = { kind: "idle" };
23844
23872
  }
23845
23873
  };
23846
- initialize = async (signal, origin) => {
23874
+ async #initializeAgent(signal) {
23847
23875
  const initialized = await this.race(
23848
23876
  this.#connection.agent.request(
23849
23877
  methods3.agent.initialize,
@@ -23860,7 +23888,10 @@ var AcpProcessSession = class _AcpProcessSession {
23860
23888
  ),
23861
23889
  "ACP agent exited during initialization",
23862
23890
  signal
23863
- );
23891
+ ).catch((cause) => {
23892
+ signal.throwIfAborted();
23893
+ throw new RetryableAcpInitializationError(cause);
23894
+ });
23864
23895
  if (initialized.protocolVersion !== PROTOCOL_VERSION2) {
23865
23896
  throw new AcpExecutionError(
23866
23897
  "ACP agent selected an unsupported protocol version",
@@ -23875,7 +23906,10 @@ var AcpProcessSession = class _AcpProcessSession {
23875
23906
  255
23876
23907
  );
23877
23908
  this.#agentVersion = truncate2(initialized.agentInfo?.version ?? "", 128);
23878
- const stored = origin?.kind === "import" ? new FoundAcpStoredSession(
23909
+ }
23910
+ initialize = async (signal, origin) => {
23911
+ await this.#initializeAgent(signal);
23912
+ let stored = origin?.kind === "import" ? new FoundAcpStoredSession(
23879
23913
  new AcpStoredSession(
23880
23914
  this.#mobiusSessionId,
23881
23915
  this.#agentId,
@@ -23885,6 +23919,10 @@ var AcpProcessSession = class _AcpProcessSession {
23885
23919
  true
23886
23920
  )
23887
23921
  ) : this.#store.read(this.#mobiusSessionId);
23922
+ if (stored instanceof FoundAcpStoredSession && !stored.session.prompted) {
23923
+ this.#store.remove(this.#mobiusSessionId);
23924
+ stored = this.#store.read(this.#mobiusSessionId);
23925
+ }
23888
23926
  if (stored instanceof DeletedAcpStoredSession)
23889
23927
  throw new AcpExecutionError(
23890
23928
  "The native Agent session was deleted. Start a new chat.",
@@ -24000,6 +24038,15 @@ var AcpProcessSession = class _AcpProcessSession {
24000
24038
  );
24001
24039
  this.#nativeSessionId = created.sessionId;
24002
24040
  lifecycleResponse = created;
24041
+ }
24042
+ const lifecycleRecord = isRecord6(lifecycleResponse) ? lifecycleResponse : {};
24043
+ this.#configOptions = normalizeConfigOptions(
24044
+ lifecycleRecord["configOptions"],
24045
+ lifecycleRecord["modes"]
24046
+ );
24047
+ await this.#updateTail;
24048
+ signal.throwIfAborted();
24049
+ if (this.#prompted) {
24003
24050
  this.#store.write(
24004
24051
  new AcpStoredSession(
24005
24052
  this.#mobiusSessionId,
@@ -24007,27 +24054,10 @@ var AcpProcessSession = class _AcpProcessSession {
24007
24054
  this.#nativeSessionId,
24008
24055
  this.#cwd,
24009
24056
  this.#additionalDirectories,
24010
- false
24057
+ true
24011
24058
  )
24012
24059
  );
24013
24060
  }
24014
- const lifecycleRecord = isRecord6(lifecycleResponse) ? lifecycleResponse : {};
24015
- this.#configOptions = normalizeConfigOptions(
24016
- lifecycleRecord["configOptions"],
24017
- lifecycleRecord["modes"]
24018
- );
24019
- await this.#updateTail;
24020
- signal.throwIfAborted();
24021
- this.#store.write(
24022
- new AcpStoredSession(
24023
- this.#mobiusSessionId,
24024
- this.#agentId,
24025
- this.#nativeSessionId,
24026
- this.#cwd,
24027
- this.#additionalDirectories,
24028
- this.#prompted
24029
- )
24030
- );
24031
24061
  };
24032
24062
  listNativeSessions = async (cursor, signal) => {
24033
24063
  if (!this.#capabilities.listSessions)
@@ -24699,6 +24729,10 @@ var AcpProcessSession = class _AcpProcessSession {
24699
24729
  };
24700
24730
  var AcpSessionManager = class {
24701
24731
  #nativeOperations = /* @__PURE__ */ new Set();
24732
+ #nativeBrowserObserver = new NullAcpSessionObserver();
24733
+ #nativeBrowserPreparing = /* @__PURE__ */ new Map();
24734
+ #nativeBrowserSessions = /* @__PURE__ */ new Map();
24735
+ #nativeBrowserStore = new MemoryAcpSessionStore();
24702
24736
  #activeSessionIds = /* @__PURE__ */ new Set();
24703
24737
  #cancellationRequests = /* @__PURE__ */ new Set();
24704
24738
  #preparing = /* @__PURE__ */ new Map();
@@ -24712,6 +24746,43 @@ var AcpSessionManager = class {
24712
24746
  setObserver = (observer) => {
24713
24747
  this.#observer = observer;
24714
24748
  };
24749
+ async #startNativeBrowserPreparation(options) {
24750
+ const operation = (async () => {
24751
+ try {
24752
+ const runtime = await AcpProcessSession.startNativeSessionBrowser(
24753
+ options,
24754
+ () => this.#nativeBrowserObserver,
24755
+ this.#nativeBrowserStore
24756
+ );
24757
+ this.#nativeBrowserSessions.set(options.sessionId, runtime);
24758
+ return runtime;
24759
+ } finally {
24760
+ this.#nativeBrowserPreparing.delete(options.sessionId);
24761
+ }
24762
+ })();
24763
+ this.#nativeBrowserPreparing.set(options.sessionId, operation);
24764
+ return await operation;
24765
+ }
24766
+ async #replaceNativeBrowserPreparation(existing, options) {
24767
+ const operation = (async () => {
24768
+ try {
24769
+ this.#nativeBrowserSessions.delete(options.sessionId);
24770
+ await existing.close();
24771
+ this.#nativeBrowserStore.remove(options.sessionId);
24772
+ const runtime = await AcpProcessSession.startNativeSessionBrowser(
24773
+ options,
24774
+ () => this.#nativeBrowserObserver,
24775
+ this.#nativeBrowserStore
24776
+ );
24777
+ this.#nativeBrowserSessions.set(options.sessionId, runtime);
24778
+ return runtime;
24779
+ } finally {
24780
+ this.#nativeBrowserPreparing.delete(options.sessionId);
24781
+ }
24782
+ })();
24783
+ this.#nativeBrowserPreparing.set(options.sessionId, operation);
24784
+ return await operation;
24785
+ }
24715
24786
  async #startPreparation(options) {
24716
24787
  const operation = (async () => {
24717
24788
  try {
@@ -24799,6 +24870,44 @@ var AcpSessionManager = class {
24799
24870
  const runtime = await this.#startPreparation(options);
24800
24871
  return runtime.prepared();
24801
24872
  };
24873
+ prepareNativeSessionBrowser = async (options) => {
24874
+ const pending = this.#nativeBrowserPreparing.get(options.sessionId);
24875
+ if (pending !== void 0) {
24876
+ const runtime2 = await pending;
24877
+ if (runtime2.belongsTo(
24878
+ options.agent.id,
24879
+ options.cwd,
24880
+ options.additionalDirectories
24881
+ )) {
24882
+ return runtime2.prepared();
24883
+ }
24884
+ return await this.prepareNativeSessionBrowser(options);
24885
+ }
24886
+ const existing = this.#nativeBrowserSessions.get(options.sessionId);
24887
+ if (existing !== void 0) {
24888
+ if (existing.belongsTo(
24889
+ options.agent.id,
24890
+ options.cwd,
24891
+ options.additionalDirectories
24892
+ )) {
24893
+ return existing.prepared();
24894
+ }
24895
+ if (!existing.canRebind()) {
24896
+ throw new AcpExecutionError(
24897
+ "The agent or workspace cannot change after a conversation has started",
24898
+ {},
24899
+ "session_identity_mismatch"
24900
+ );
24901
+ }
24902
+ const runtime2 = await this.#replaceNativeBrowserPreparation(
24903
+ existing,
24904
+ options
24905
+ );
24906
+ return runtime2.prepared();
24907
+ }
24908
+ const runtime = await this.#startNativeBrowserPreparation(options);
24909
+ return runtime.prepared();
24910
+ };
24802
24911
  configureSession = async (options) => {
24803
24912
  const runtime = await this.ensureSession(options);
24804
24913
  return await runtime.configure(options);
@@ -24887,8 +24996,14 @@ var AcpSessionManager = class {
24887
24996
  };
24888
24997
  close = async () => {
24889
24998
  const sessions = [...this.#sessions.values()];
24999
+ const nativeBrowserSessions = [...this.#nativeBrowserSessions.values()];
24890
25000
  this.#sessions.clear();
24891
- await Promise.all(sessions.map(async (session) => await session.close()));
25001
+ this.#nativeBrowserSessions.clear();
25002
+ await Promise.all(
25003
+ [...sessions, ...nativeBrowserSessions].map(
25004
+ async (session) => await session.close()
25005
+ )
25006
+ );
24892
25007
  };
24893
25008
  ensureSession = async (options) => {
24894
25009
  const existing = this.#sessions.get(options.sessionId);
@@ -24913,7 +25028,30 @@ var AcpSessionManager = class {
24913
25028
  }
24914
25029
  return started;
24915
25030
  };
24916
- listNativeSessions = async (options, cursor) => await (await this.ensureSession(options)).listNativeSessions(
25031
+ async #ensureNativeSessionBrowser(options) {
25032
+ const existing = this.#nativeBrowserSessions.get(options.sessionId);
25033
+ if (existing !== void 0) {
25034
+ if (!existing.belongsTo(
25035
+ options.agent.id,
25036
+ options.cwd,
25037
+ options.additionalDirectories
25038
+ )) {
25039
+ throw new AcpExecutionError(
25040
+ "The agent or workspace cannot change after a conversation has started",
25041
+ {},
25042
+ "session_identity_mismatch"
25043
+ );
25044
+ }
25045
+ return existing;
25046
+ }
25047
+ await this.prepareNativeSessionBrowser(options);
25048
+ const started = this.#nativeBrowserSessions.get(options.sessionId);
25049
+ if (started === void 0) {
25050
+ throw new AcpExecutionError("ACP native session browser did not start");
25051
+ }
25052
+ return started;
25053
+ }
25054
+ listNativeSessions = async (options, cursor) => await (await this.#ensureNativeSessionBrowser(options)).listNativeSessions(
24917
25055
  cursor,
24918
25056
  options.signal
24919
25057
  );
@@ -24996,7 +25134,7 @@ var AcpSessionManager = class {
24996
25134
  }
24997
25135
  };
24998
25136
  deleteNativeSession = async (options, nativeSessionId) => {
24999
- const runtime = await this.ensureSession(options);
25137
+ const runtime = await this.#ensureNativeSessionBrowser(options);
25000
25138
  const key = `${options.agent.id}:${nativeSessionId}`;
25001
25139
  const linked = this.#store.findNative(options.agent.id, nativeSessionId);
25002
25140
  if (this.#nativeOperations.has(key) || linked.some(
@@ -25023,7 +25161,8 @@ var AcpSessionManager = class {
25023
25161
  nativeSessionId
25024
25162
  );
25025
25163
  if (runtime.nativeSessionId() === nativeSessionId) {
25026
- this.#sessions.delete(options.sessionId);
25164
+ this.#nativeBrowserSessions.delete(options.sessionId);
25165
+ this.#nativeBrowserStore.remove(options.sessionId);
25027
25166
  await runtime.close();
25028
25167
  }
25029
25168
  return deleted;
@@ -26712,7 +26851,7 @@ var NativeSessionService = class {
26712
26851
  sessionId: command.sessionId,
26713
26852
  signal
26714
26853
  };
26715
- const prepared = await this.#sessions.prepareSession(options);
26854
+ const prepared = await this.#sessions.prepareNativeSessionBrowser(options);
26716
26855
  if (!prepared.capabilities.listSessions)
26717
26856
  throw new AcpExecutionError(
26718
26857
  "This Agent does not support native session listing",
@@ -27774,6 +27913,15 @@ async function executeSessionPrepare(outbox, socket, command, config2, directori
27774
27913
  })
27775
27914
  );
27776
27915
  } catch (error61) {
27916
+ audit.record({
27917
+ commandId: command.requestId,
27918
+ details: {
27919
+ agentId: command.agentId,
27920
+ code: operationErrorCode(error61)
27921
+ },
27922
+ event: "session_prepare_failed",
27923
+ sessionId: command.sessionId
27924
+ });
27777
27925
  reportOperationFailure(socket, command.requestId, command.sessionId, error61);
27778
27926
  }
27779
27927
  }