@moxt-ai/mobius 0.0.152 → 0.0.153

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
@@ -3381,7 +3381,7 @@ var program = new Command();
3381
3381
  // package.json
3382
3382
  var package_default = {
3383
3383
  name: "@moxt-ai/mobius",
3384
- version: "0.0.152",
3384
+ version: "0.0.153",
3385
3385
  description: "Mobius CLI for pairing and running local AI agent services.",
3386
3386
  type: "module",
3387
3387
  bin: {
@@ -3416,7 +3416,9 @@ var package_default = {
3416
3416
  dev: "node --watch src/cli.ts",
3417
3417
  prepack: "pnpm build",
3418
3418
  start: "node dist/cli.js",
3419
- typecheck: "tsc --project tsconfig.json"
3419
+ typecheck: "tsc --project tsconfig.json && tsc --project tests/tsconfig.json",
3420
+ "test:controlled": "vitest run tests/sessions tests/runtime --maxWorkers=4",
3421
+ "test:agents": "vitest run tests/agents --maxWorkers=2"
3420
3422
  },
3421
3423
  dependencies: {
3422
3424
  "@agentclientprotocol/sdk": "^1.4.0",
@@ -3430,7 +3432,12 @@ var package_default = {
3430
3432
  "@types/better-sqlite3": "7.6.13",
3431
3433
  "@types/node": "^24.13.5",
3432
3434
  "drizzle-orm": "^0.45.2",
3433
- esbuild: "0.28.2"
3435
+ esbuild: "0.28.2",
3436
+ "@moxt-ai/mobius-sdk": "workspace:*",
3437
+ "@moxt-ai/mobius-test": "workspace:*",
3438
+ valibot: "1.5.0",
3439
+ ws: "^8.21.3",
3440
+ "@types/ws": "^8.18.1"
3434
3441
  },
3435
3442
  main: "dist/index.js",
3436
3443
  keywords: [],
@@ -29554,6 +29561,11 @@ var assistantHistoryMessageSchema = external_exports.strictObject({
29554
29561
  }).readonly();
29555
29562
  var historyMessage = external_exports.discriminatedUnion("role", [userHistoryMessage, assistantHistoryMessageSchema]);
29556
29563
  var availableSessionHistoryObjectSchema = external_exports.strictObject({
29564
+ streamPosition: external_exports.strictObject({
29565
+ commandId: identifierStringSchema,
29566
+ epoch: identifierStringSchema,
29567
+ sequence: external_exports.number().int().nonnegative()
29568
+ }).readonly().optional(),
29557
29569
  status: external_exports.literal("available"),
29558
29570
  messages: external_exports.array(historyMessage).max(SESSION_HISTORY_MESSAGE_LIMIT).readonly(),
29559
29571
  truncated: external_exports.boolean(),
@@ -42587,6 +42599,7 @@ var ActiveDaemonTurn = class {
42587
42599
  commandId: decodeIdentifier(this.command.commandId),
42588
42600
  epoch: this.#epoch,
42589
42601
  messages: this.timelineMessages(),
42602
+ sequence: this.#sequence,
42590
42603
  state: "running",
42591
42604
  truncated: false
42592
42605
  };
@@ -42614,7 +42627,7 @@ var ActiveDaemonTurn = class {
42614
42627
  };
42615
42628
 
42616
42629
  // src/daemon-turn-registry.ts
42617
- var COMPLETED_TURN_RECOVERY_LIMIT = 32;
42630
+ var MAX_SESSIONS_WITH_COMPLETED_RECOVERY = 32;
42618
42631
  var waitForTurnCompletion = (turn, waitSignal) => {
42619
42632
  waitSignal.throwIfAborted();
42620
42633
  return new Promise((resolve9, reject) => {
@@ -42640,46 +42653,46 @@ var waitForTurnCompletion = (turn, waitSignal) => {
42640
42653
  });
42641
42654
  };
42642
42655
  var DaemonTurnRegistry = class {
42643
- #turns = /* @__PURE__ */ new Map();
42644
- #completed = /* @__PURE__ */ new Map();
42656
+ #inFlightByCommandId = /* @__PURE__ */ new Map();
42657
+ #latestCompletedBySessionId = /* @__PURE__ */ new Map();
42645
42658
  #operations;
42646
42659
  constructor(operations) {
42647
42660
  this.#operations = operations;
42648
42661
  }
42649
42662
  start = (command, attemptId) => {
42650
42663
  const turn = new ActiveDaemonTurn(command, attemptId);
42651
- this.#turns.set(command.commandId, turn);
42664
+ this.#inFlightByCommandId.set(command.commandId, turn);
42652
42665
  return turn;
42653
42666
  };
42654
- get = (commandId) => this.#turns.get(commandId);
42667
+ get = (commandId) => this.#inFlightByCommandId.get(commandId);
42655
42668
  finish = (turn) => {
42656
42669
  const recovery = turn.recovery();
42657
- this.#turns.delete(turn.command.commandId);
42670
+ this.#inFlightByCommandId.delete(turn.command.commandId);
42658
42671
  if (recovery !== null) {
42659
- this.#completed.delete(turn.command.sessionId);
42660
- this.#completed.set(turn.command.sessionId, {
42661
- command: turn.command,
42662
- recovery: { ...recovery, state: "completed" }
42663
- });
42664
- while (this.#completed.size > COMPLETED_TURN_RECOVERY_LIMIT) {
42665
- const oldestSessionId = this.#completed.keys().next().value;
42666
- if (oldestSessionId === void 0) {
42667
- break;
42668
- }
42669
- this.#completed.delete(oldestSessionId);
42670
- }
42672
+ this.retainLatestCompletedRecovery(turn.command, { ...recovery, state: "completed" });
42671
42673
  }
42672
42674
  turn.finish();
42673
42675
  };
42676
+ retainLatestCompletedRecovery = (command, recovery) => {
42677
+ this.#latestCompletedBySessionId.delete(command.sessionId);
42678
+ this.#latestCompletedBySessionId.set(command.sessionId, { command, recovery });
42679
+ while (this.#latestCompletedBySessionId.size > MAX_SESSIONS_WITH_COMPLETED_RECOVERY) {
42680
+ const oldestSessionId = this.#latestCompletedBySessionId.keys().next().value;
42681
+ if (oldestSessionId === void 0) {
42682
+ break;
42683
+ }
42684
+ this.#latestCompletedBySessionId.delete(oldestSessionId);
42685
+ }
42686
+ };
42674
42687
  recordEvent = (event) => {
42675
42688
  if ("commandId" in event) {
42676
- const turn = this.#turns.get(event.commandId);
42689
+ const turn = this.#inFlightByCommandId.get(event.commandId);
42677
42690
  if (turn !== void 0 && turn.command.sessionId === event.sessionId) {
42678
42691
  return turn.recordEvent(event);
42679
42692
  }
42680
42693
  }
42681
42694
  if (event.kind === SESSION_PERMISSION_RESOLVED_KIND || event.kind === SESSION_ELICITATION_RESOLVED_KIND) {
42682
- for (const turn of this.#turns.values()) {
42695
+ for (const turn of this.#inFlightByCommandId.values()) {
42683
42696
  if (turn.matchesInteraction(event.interactionId, event.sessionId)) {
42684
42697
  return turn.recordEvent(event);
42685
42698
  }
@@ -42688,17 +42701,17 @@ var DaemonTurnRegistry = class {
42688
42701
  return event;
42689
42702
  };
42690
42703
  recordSteeringPrompt = (command) => {
42691
- const target = this.#turns.get(command.targetCommandId);
42704
+ const target = this.#inFlightByCommandId.get(command.targetCommandId);
42692
42705
  return target?.recordSteeringPrompt(command) ?? false;
42693
42706
  };
42694
42707
  executionSnapshot = async (matches) => {
42695
42708
  const matching = [];
42696
- for (const turn of this.#turns.values()) {
42709
+ for (const turn of this.#inFlightByCommandId.values()) {
42697
42710
  if (await matches(turn.command)) {
42698
42711
  matching.push(turn);
42699
42712
  }
42700
42713
  }
42701
- const current = matching.filter((turn) => this.#turns.get(turn.command.commandId) === turn);
42714
+ const current = matching.filter((turn) => this.#inFlightByCommandId.get(turn.command.commandId) === turn);
42702
42715
  return {
42703
42716
  turn: current.map((turn) => turn.snapshot()).find((snapshot) => snapshot !== null) ?? null,
42704
42717
  queued: current.filter((turn) => turn.isQueued()).map(({ command }) => ({
@@ -42709,7 +42722,7 @@ var DaemonTurnRegistry = class {
42709
42722
  };
42710
42723
  };
42711
42724
  snapshot = (matches) => {
42712
- for (const turn of this.#turns.values()) {
42725
+ for (const turn of this.#inFlightByCommandId.values()) {
42713
42726
  if (!matches(turn.command)) {
42714
42727
  continue;
42715
42728
  }
@@ -42721,7 +42734,7 @@ var DaemonTurnRegistry = class {
42721
42734
  return null;
42722
42735
  };
42723
42736
  recovery = (matches) => {
42724
- for (const turn of this.#turns.values()) {
42737
+ for (const turn of this.#inFlightByCommandId.values()) {
42725
42738
  if (!matches(turn.command)) {
42726
42739
  continue;
42727
42740
  }
@@ -42730,7 +42743,7 @@ var DaemonTurnRegistry = class {
42730
42743
  return recovery;
42731
42744
  }
42732
42745
  }
42733
- for (const completed of this.#completed.values()) {
42746
+ for (const completed of this.#latestCompletedBySessionId.values()) {
42734
42747
  if (matches(completed.command)) {
42735
42748
  return completed.recovery;
42736
42749
  }
@@ -42738,17 +42751,17 @@ var DaemonTurnRegistry = class {
42738
42751
  return null;
42739
42752
  };
42740
42753
  close = async () => {
42741
- const turns = [...this.#turns.values()];
42754
+ const turns = [...this.#inFlightByCommandId.values()];
42742
42755
  for (const turn of turns) {
42743
42756
  turn.abortDaemon();
42744
42757
  }
42745
42758
  await Promise.all(turns.map((turn) => turn.completion));
42746
- this.#completed.clear();
42759
+ this.#latestCompletedBySessionId.clear();
42747
42760
  };
42748
42761
  admitAndWait = async (turn, waitSignal, onQueued) => {
42749
42762
  const command = turn.command;
42750
42763
  waitSignal.throwIfAborted();
42751
- const head = () => [...this.#turns.values()].find(
42764
+ const head = () => [...this.#inFlightByCommandId.values()].find(
42752
42765
  (turn2) => turn2.command.sessionId === command.sessionId && turn2.command.disposition !== SessionPromptDisposition.Steer
42753
42766
  );
42754
42767
  if (command.disposition === SessionPromptDisposition.Queue) {
@@ -45318,6 +45331,7 @@ function paginateActiveTurn(history, activeTurn, sessionId, endIndex, limit) {
45318
45331
  historicalCharacterLimit
45319
45332
  ) : null;
45320
45333
  return {
45334
+ streamPosition: { commandId: activeTurn.commandId, epoch: activeTurn.epoch, sequence: activeTurn.sequence },
45321
45335
  coveredCommandIds: historical?.coveredCommandIds ?? [],
45322
45336
  coveredMessageIds: [
45323
45337
  ...historical?.coveredMessageIds ?? [],
@@ -45350,6 +45364,7 @@ function mergeLiveSessionHistory(history, activeTurn, sessionId) {
45350
45364
  }
45351
45365
  return {
45352
45366
  coveredCommandIds: page.coveredCommandIds,
45367
+ ...page.streamPosition === void 0 ? {} : { streamPosition: page.streamPosition },
45353
45368
  coveredMessageIds: page.coveredMessageIds,
45354
45369
  messages: page.messages,
45355
45370
  status: "available",