@moxt-ai/mobius 0.0.29 → 0.0.30

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/runtime.js CHANGED
@@ -27969,6 +27969,18 @@ import { createHash as createHash3, randomUUID } from "node:crypto";
27969
27969
  import { stat as stat7 } from "node:fs/promises";
27970
27970
  import { DatabaseSync as DatabaseSync3 } from "node:sqlite";
27971
27971
  var LOCAL_BOT_GRANT_LIFETIME_MILLISECONDS = 90 * 24 * 60 * 60 * 1e3;
27972
+ var identifier2 = external_exports.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/);
27973
+ var savedApprovalSchema = external_exports.object({
27974
+ local_grant_id: identifier2,
27975
+ bot_id: identifier2,
27976
+ binding_id: identifier2,
27977
+ binding_revision: external_exports.number().int().positive(),
27978
+ agent_ref: identifier2,
27979
+ workspace_ref: external_exports.string().min(1).max(2048),
27980
+ revocation_epoch: external_exports.number().int().nonnegative(),
27981
+ agent_identity_digest: external_exports.string().regex(/^[a-f0-9]{64}$/),
27982
+ workspace_identity_digest: external_exports.string().regex(/^[a-f0-9]{64}$/)
27983
+ }).readonly();
27972
27984
  var LocalBotAuthorizationError = class extends Error {
27973
27985
  code;
27974
27986
  constructor(code, message, options = {}) {
@@ -28073,6 +28085,17 @@ function parseTargets(encoded) {
28073
28085
  }
28074
28086
  var LocalBotGrantStore = class {
28075
28087
  #database;
28088
+ static containsBot = (path2, botId) => {
28089
+ const database = new DatabaseSync3(path2, { readOnly: true });
28090
+ try {
28091
+ if (database.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name = 'local_bot_grants'").get() === void 0) {
28092
+ return false;
28093
+ }
28094
+ return database.prepare("SELECT local_grant_id FROM local_bot_grants WHERE bot_id = ? LIMIT 1").get(botId) !== void 0;
28095
+ } finally {
28096
+ database.close();
28097
+ }
28098
+ };
28076
28099
  constructor(path2) {
28077
28100
  this.#database = new DatabaseSync3(path2);
28078
28101
  this.#database.exec(`
@@ -28106,6 +28129,78 @@ var LocalBotGrantStore = class {
28106
28129
  ) STRICT;
28107
28130
  `);
28108
28131
  }
28132
+ /** Only the local CLI may invoke this explicit approval transition. */
28133
+ reapprove = async (botId, catalog, directories, bindingAuthorityId, now, signal) => {
28134
+ signal.throwIfAborted();
28135
+ if (!identifier2.safeParse(botId).success) {
28136
+ throw new LocalBotAuthorizationError("invalid_request", "The Bot ID is invalid");
28137
+ }
28138
+ const row = this.#database.prepare("SELECT * FROM local_bot_grants WHERE bot_id = ? ORDER BY binding_revision DESC LIMIT 1").get(botId);
28139
+ if (row === void 0) {
28140
+ throw new LocalBotAuthorizationError("bot_not_found", "This machine has no saved approval for that Bot");
28141
+ }
28142
+ const parsed = savedApprovalSchema.safeParse(row);
28143
+ if (!parsed.success) {
28144
+ throw new LocalBotAuthorizationError("local_grant_invalid", "The saved Bot approval is invalid", {
28145
+ cause: parsed.error
28146
+ });
28147
+ }
28148
+ const saved = parsed.data;
28149
+ const agent = catalog.find(saved.agent_ref);
28150
+ if (!agent.capabilities.embeddedContextPrompt) {
28151
+ throw new LocalBotAuthorizationError("binding_incompatible", "The local Agent cannot apply Bot context");
28152
+ }
28153
+ const [adapterUnchanged, agentUnchanged] = await Promise.all([
28154
+ revalidateExecutable(agent.adapterIdentity),
28155
+ revalidateExecutable(agent.agentIdentity)
28156
+ ]);
28157
+ signal.throwIfAborted();
28158
+ if (!adapterUnchanged || !agentUnchanged) {
28159
+ throw new LocalBotAuthorizationError(
28160
+ "binding_incompatible",
28161
+ "The local Agent executable changed before approval"
28162
+ );
28163
+ }
28164
+ const workspacePath = await directories.resolve(bindingAuthorityId, saved.workspace_ref, signal);
28165
+ const workspaceIdentityDigest = await workspaceDigest(workspacePath);
28166
+ signal.throwIfAborted();
28167
+ this.#database.exec("BEGIN IMMEDIATE");
28168
+ try {
28169
+ const result = this.#database.prepare(`UPDATE local_bot_grants
28170
+ SET agent_identity_digest = ?, workspace_identity_digest = ?, workspace_path = ?,
28171
+ revoked_at = NULL, expires_at = ?, revocation_epoch = revocation_epoch + 1
28172
+ WHERE local_grant_id = ? AND revocation_epoch = ?
28173
+ AND agent_identity_digest = ? AND workspace_identity_digest = ?
28174
+ AND binding_revision = (SELECT MAX(binding_revision) FROM local_bot_grants WHERE bot_id = ?)`).run(
28175
+ agentDigest(agent),
28176
+ workspaceIdentityDigest,
28177
+ workspacePath,
28178
+ now + LOCAL_BOT_GRANT_LIFETIME_MILLISECONDS,
28179
+ saved.local_grant_id,
28180
+ saved.revocation_epoch,
28181
+ saved.agent_identity_digest,
28182
+ saved.workspace_identity_digest,
28183
+ botId
28184
+ );
28185
+ if (result.changes !== 1) {
28186
+ throw new LocalBotAuthorizationError(
28187
+ "binding_not_approved",
28188
+ "The Bot binding changed during approval; run the command again"
28189
+ );
28190
+ }
28191
+ this.#database.prepare(`INSERT INTO audit_events (recorded_at, event, command_id, session_id, details_json)
28192
+ VALUES (?, 'bot_binding_locally_reapproved', ?, '', ?)`).run(
28193
+ new Date(now).toISOString(),
28194
+ saved.binding_id,
28195
+ JSON.stringify({ botId, bindingId: saved.binding_id, agentRef: saved.agent_ref })
28196
+ );
28197
+ this.#database.exec("COMMIT");
28198
+ } catch (cause) {
28199
+ this.#database.exec("ROLLBACK");
28200
+ throw cause;
28201
+ }
28202
+ return { bindingId: saved.binding_id, workspacePath, agentRef: saved.agent_ref };
28203
+ };
28109
28204
  approve = async (request, catalog, directories, bindingAuthorityId, now, signal) => {
28110
28205
  signal.throwIfAborted();
28111
28206
  const existing = this.#database.prepare(
@@ -31149,7 +31244,7 @@ async function executeSessionConfigure(publisher, socket, command, config2, dire
31149
31244
  reportOperationFailure(socket, command.requestId, command.sessionId, error61);
31150
31245
  }
31151
31246
  }
31152
- async function executePrompt(outbox, publisher, command, config2, directories, audit, sessions, attemptId, timer, signal) {
31247
+ async function executePrompt(outbox, publisher, command, config2, directories, audit, sessions, attemptId, activateAttempt, timer, signal) {
31153
31248
  const activities = new CoalescingDaemonActivityPublisher(timer, (activity) => {
31154
31249
  publisher.recordAttempt(command.sessionId, encodeDaemonActivity(command, activity), attemptId);
31155
31250
  });
@@ -31178,6 +31273,7 @@ async function executePrompt(outbox, publisher, command, config2, directories, a
31178
31273
  }),
31179
31274
  attemptId
31180
31275
  );
31276
+ activateAttempt();
31181
31277
  const attachments = await resolvePromptArtifacts(config2, command, signal);
31182
31278
  let stopReason;
31183
31279
  if (command.disposition === SessionPromptDisposition.Steer) {
@@ -31289,7 +31385,7 @@ function botExecutionAgent(agent, contextHandle, socketPath) {
31289
31385
  agent.capabilities
31290
31386
  );
31291
31387
  }
31292
- async function executeBotPrompt(outbox, publisher, command, config2, directories, audit, sessions, grants, contexts, applicator, ipc, attemptId, timer, signal) {
31388
+ async function executeBotPrompt(outbox, publisher, command, config2, directories, audit, sessions, grants, contexts, applicator, ipc, attemptId, activateAttempt, timer, signal) {
31293
31389
  const activities = new CoalescingDaemonActivityPublisher(timer, (activity) => {
31294
31390
  publisher.recordAttempt(command.sessionId, encodeDaemonActivity(command, activity), attemptId);
31295
31391
  });
@@ -31370,6 +31466,7 @@ async function executeBotPrompt(outbox, publisher, command, config2, directories
31370
31466
  }),
31371
31467
  attemptId
31372
31468
  );
31469
+ activateAttempt();
31373
31470
  const result = await sessions.runPrompt({
31374
31471
  additionalDirectories: resolved.additionalDirectories,
31375
31472
  agent,
@@ -31563,11 +31660,13 @@ async function runRelayConnection(config2, directories, audit, sessions, install
31563
31660
  }
31564
31661
  const turn = new ActiveDaemonTurn(command, receipt.attemptId);
31565
31662
  activeTurns.set(command.commandId, turn);
31566
- if (trackActiveAttempt) {
31567
- activeAttemptIds.set(command.sessionId, receipt.attemptId);
31568
- }
31663
+ const activateAttempt = () => {
31664
+ if (trackActiveAttempt) {
31665
+ activeAttemptIds.set(command.sessionId, receipt.attemptId);
31666
+ }
31667
+ };
31569
31668
  try {
31570
- await execute(receipt.attemptId, turn.signal);
31669
+ await execute(receipt.attemptId, activateAttempt, turn.signal);
31571
31670
  } finally {
31572
31671
  activeTurns.delete(command.commandId);
31573
31672
  if (activeAttemptIds.get(command.sessionId) === receipt.attemptId) {
@@ -31652,7 +31751,7 @@ async function runRelayConnection(config2, directories, audit, sessions, install
31652
31751
  delivery,
31653
31752
  command,
31654
31753
  true,
31655
- (attemptId, executionSignal) => executeBotPrompt(
31754
+ (attemptId, activateAttempt, executionSignal) => executeBotPrompt(
31656
31755
  outbox,
31657
31756
  publisher,
31658
31757
  command,
@@ -31665,6 +31764,7 @@ async function runRelayConnection(config2, directories, audit, sessions, install
31665
31764
  applicator,
31666
31765
  ipc,
31667
31766
  attemptId,
31767
+ activateAttempt,
31668
31768
  timer,
31669
31769
  executionSignal
31670
31770
  )
@@ -31677,7 +31777,7 @@ async function runRelayConnection(config2, directories, audit, sessions, install
31677
31777
  delivery,
31678
31778
  command,
31679
31779
  command.disposition !== SessionPromptDisposition.Steer,
31680
- (attemptId, executionSignal) => executePrompt(
31780
+ (attemptId, activateAttempt, executionSignal) => executePrompt(
31681
31781
  outbox,
31682
31782
  publisher,
31683
31783
  command,
@@ -31686,6 +31786,7 @@ async function runRelayConnection(config2, directories, audit, sessions, install
31686
31786
  audit,
31687
31787
  sessions,
31688
31788
  attemptId,
31789
+ activateAttempt,
31689
31790
  timer,
31690
31791
  executionSignal
31691
31792
  )
@@ -32187,7 +32288,6 @@ async function runRelayConnection(config2, directories, audit, sessions, install
32187
32288
  }
32188
32289
  const turn2 = new ActiveDaemonTurn(command2, receipt2.attemptId);
32189
32290
  activeTurns.set(command2.commandId, turn2);
32190
- activeAttemptIds.set(command2.sessionId, receipt2.attemptId);
32191
32291
  void executeBotPrompt(
32192
32292
  outbox,
32193
32293
  publisher,
@@ -32201,6 +32301,7 @@ async function runRelayConnection(config2, directories, audit, sessions, install
32201
32301
  applicator,
32202
32302
  ipc,
32203
32303
  receipt2.attemptId,
32304
+ () => activeAttemptIds.set(command2.sessionId, receipt2.attemptId),
32204
32305
  timer,
32205
32306
  turn2.signal
32206
32307
  ).catch((error61) => {
@@ -32227,9 +32328,6 @@ async function runRelayConnection(config2, directories, audit, sessions, install
32227
32328
  }
32228
32329
  const turn = new ActiveDaemonTurn(command, receipt.attemptId);
32229
32330
  activeTurns.set(command.commandId, turn);
32230
- if (command.disposition !== SessionPromptDisposition.Steer) {
32231
- activeAttemptIds.set(command.sessionId, receipt.attemptId);
32232
- }
32233
32331
  void executePrompt(
32234
32332
  outbox,
32235
32333
  publisher,
@@ -32239,6 +32337,11 @@ async function runRelayConnection(config2, directories, audit, sessions, install
32239
32337
  audit,
32240
32338
  sessions,
32241
32339
  receipt.attemptId,
32340
+ () => {
32341
+ if (command.disposition !== SessionPromptDisposition.Steer) {
32342
+ activeAttemptIds.set(command.sessionId, receipt.attemptId);
32343
+ }
32344
+ },
32242
32345
  timer,
32243
32346
  turn.signal
32244
32347
  ).catch((error61) => {