@moxt-ai/mobius 0.0.28 → 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.
Files changed (59) hide show
  1. package/dist/agent-catalog/acp-readiness-probe.d.ts.map +1 -1
  2. package/dist/agent-catalog/acp-readiness-probe.js +2 -2
  3. package/dist/agent-catalog/acp-readiness-probe.js.map +1 -1
  4. package/dist/agent-catalog/agent-specification.d.ts +3 -0
  5. package/dist/agent-catalog/agent-specification.d.ts.map +1 -1
  6. package/dist/agent-catalog/agent-specification.js +3 -0
  7. package/dist/agent-catalog/agent-specification.js.map +1 -1
  8. package/dist/agent-catalog/agents/copilot-cli-agent.d.ts +18 -0
  9. package/dist/agent-catalog/agents/copilot-cli-agent.d.ts.map +1 -0
  10. package/dist/agent-catalog/agents/copilot-cli-agent.js +29 -0
  11. package/dist/agent-catalog/agents/copilot-cli-agent.js.map +1 -0
  12. package/dist/agent-catalog/agents/gemini-cli-agent.d.ts +14 -0
  13. package/dist/agent-catalog/agents/gemini-cli-agent.d.ts.map +1 -0
  14. package/dist/agent-catalog/agents/gemini-cli-agent.js +30 -0
  15. package/dist/agent-catalog/agents/gemini-cli-agent.js.map +1 -0
  16. package/dist/agent-catalog/agents/hermes-agent.d.ts +18 -0
  17. package/dist/agent-catalog/agents/hermes-agent.d.ts.map +1 -0
  18. package/dist/agent-catalog/agents/hermes-agent.js +32 -0
  19. package/dist/agent-catalog/agents/hermes-agent.js.map +1 -0
  20. package/dist/agent-catalog/agents/resolve-user-local-executable.d.ts +4 -0
  21. package/dist/agent-catalog/agents/resolve-user-local-executable.d.ts.map +1 -0
  22. package/dist/agent-catalog/agents/resolve-user-local-executable.js +14 -0
  23. package/dist/agent-catalog/agents/resolve-user-local-executable.js.map +1 -0
  24. package/dist/agent-catalog/agents/supported-agent-specifications.d.ts.map +1 -1
  25. package/dist/agent-catalog/agents/supported-agent-specifications.js +6 -0
  26. package/dist/agent-catalog/agents/supported-agent-specifications.js.map +1 -1
  27. package/dist/agent-catalog/discover-agent.d.ts.map +1 -1
  28. package/dist/agent-catalog/discover-agent.js +2 -2
  29. package/dist/agent-catalog/discover-agent.js.map +1 -1
  30. package/dist/agent-catalog/discover-local-agents.d.ts +3 -0
  31. package/dist/agent-catalog/discover-local-agents.d.ts.map +1 -1
  32. package/dist/agent-catalog/discover-local-agents.js +3 -0
  33. package/dist/agent-catalog/discover-local-agents.js.map +1 -1
  34. package/dist/agent-catalog/executable-discovery.d.ts +1 -2
  35. package/dist/agent-catalog/executable-discovery.d.ts.map +1 -1
  36. package/dist/agent-catalog/executable-discovery.js +4 -6
  37. package/dist/agent-catalog/executable-discovery.js.map +1 -1
  38. package/dist/agent-catalog/version-output.d.ts +2 -0
  39. package/dist/agent-catalog/version-output.d.ts.map +1 -0
  40. package/dist/agent-catalog/version-output.js +4 -0
  41. package/dist/agent-catalog/version-output.js.map +1 -0
  42. package/dist/bots/bot-approve-command.d.ts +2 -0
  43. package/dist/bots/bot-approve-command.d.ts.map +1 -0
  44. package/dist/bots/bot-approve-command.js +78 -0
  45. package/dist/bots/bot-approve-command.js.map +1 -0
  46. package/dist/bots/local-bot-grant-store.d.ts +7 -0
  47. package/dist/bots/local-bot-grant-store.d.ts.map +1 -1
  48. package/dist/bots/local-bot-grant-store.js +89 -0
  49. package/dist/bots/local-bot-grant-store.js.map +1 -1
  50. package/dist/cli.js +1300 -941
  51. package/dist/cli.js.map +4 -4
  52. package/dist/index.js +476 -236
  53. package/dist/index.js.map +4 -4
  54. package/dist/run-daemon.d.ts.map +1 -1
  55. package/dist/run-daemon.js +18 -14
  56. package/dist/run-daemon.js.map +1 -1
  57. package/dist/runtime.js +488 -246
  58. package/dist/runtime.js.map +4 -4
  59. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -18903,6 +18903,28 @@ function date4(params) {
18903
18903
 
18904
18904
  // ../protocol/src/prompt-usage.ts
18905
18905
  var TOKEN_COUNT = external_exports.number().int().nonnegative();
18906
+ function normalizeQuotaTokenCount(value) {
18907
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
18908
+ return value;
18909
+ }
18910
+ if (Reflect.has(value, "inputTokens") || Reflect.has(value, "outputTokens") || Reflect.has(value, "totalTokens")) {
18911
+ return value;
18912
+ }
18913
+ if (!Reflect.has(value, "input_tokens") && !Reflect.has(value, "output_tokens")) {
18914
+ return value;
18915
+ }
18916
+ const inputTokens = Reflect.get(value, "input_tokens");
18917
+ const outputTokens = Reflect.get(value, "output_tokens");
18918
+ const reportedTotal = Reflect.get(value, "total_tokens");
18919
+ return {
18920
+ cachedInputTokens: Reflect.get(value, "cached_input_tokens"),
18921
+ cachedWriteTokens: Reflect.get(value, "cached_write_tokens"),
18922
+ inputTokens,
18923
+ outputTokens,
18924
+ reasoningOutputTokens: Reflect.get(value, "reasoning_output_tokens"),
18925
+ totalTokens: reportedTotal === void 0 && typeof inputTokens === "number" && typeof outputTokens === "number" ? inputTokens + outputTokens : reportedTotal
18926
+ };
18927
+ }
18906
18928
  var promptUsageSchema = external_exports.object({
18907
18929
  cachedReadTokens: TOKEN_COUNT.nullish(),
18908
18930
  cachedWriteTokens: TOKEN_COUNT.nullish(),
@@ -18911,14 +18933,17 @@ var promptUsageSchema = external_exports.object({
18911
18933
  thoughtTokens: TOKEN_COUNT.nullish(),
18912
18934
  totalTokens: TOKEN_COUNT
18913
18935
  }).readonly();
18914
- var quotaTokenCountSchema = external_exports.object({
18915
- cachedInputTokens: TOKEN_COUNT,
18916
- cachedWriteTokens: TOKEN_COUNT.optional(),
18917
- inputTokens: TOKEN_COUNT,
18918
- outputTokens: TOKEN_COUNT,
18919
- reasoningOutputTokens: TOKEN_COUNT,
18920
- totalTokens: TOKEN_COUNT
18921
- }).readonly();
18936
+ var quotaTokenCountSchema = external_exports.preprocess(
18937
+ normalizeQuotaTokenCount,
18938
+ external_exports.object({
18939
+ cachedInputTokens: TOKEN_COUNT.optional(),
18940
+ cachedWriteTokens: TOKEN_COUNT.optional(),
18941
+ inputTokens: TOKEN_COUNT,
18942
+ outputTokens: TOKEN_COUNT,
18943
+ reasoningOutputTokens: TOKEN_COUNT.optional(),
18944
+ totalTokens: TOKEN_COUNT
18945
+ }).readonly()
18946
+ );
18922
18947
  var promptMetadataSchema = external_exports.object({
18923
18948
  quota: external_exports.object({
18924
18949
  model_usage: external_exports.array(
@@ -24926,6 +24951,18 @@ import { createHash, randomUUID } from "node:crypto";
24926
24951
  import { stat as stat3 } from "node:fs/promises";
24927
24952
  import { DatabaseSync as DatabaseSync3 } from "node:sqlite";
24928
24953
  var LOCAL_BOT_GRANT_LIFETIME_MILLISECONDS = 90 * 24 * 60 * 60 * 1e3;
24954
+ var identifier2 = external_exports.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/);
24955
+ var savedApprovalSchema = external_exports.object({
24956
+ local_grant_id: identifier2,
24957
+ bot_id: identifier2,
24958
+ binding_id: identifier2,
24959
+ binding_revision: external_exports.number().int().positive(),
24960
+ agent_ref: identifier2,
24961
+ workspace_ref: external_exports.string().min(1).max(2048),
24962
+ revocation_epoch: external_exports.number().int().nonnegative(),
24963
+ agent_identity_digest: external_exports.string().regex(/^[a-f0-9]{64}$/),
24964
+ workspace_identity_digest: external_exports.string().regex(/^[a-f0-9]{64}$/)
24965
+ }).readonly();
24929
24966
  var LocalBotAuthorizationError = class extends Error {
24930
24967
  code;
24931
24968
  constructor(code, message, options = {}) {
@@ -25030,6 +25067,17 @@ function parseTargets(encoded) {
25030
25067
  }
25031
25068
  var LocalBotGrantStore = class {
25032
25069
  #database;
25070
+ static containsBot = (path2, botId) => {
25071
+ const database = new DatabaseSync3(path2, { readOnly: true });
25072
+ try {
25073
+ if (database.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name = 'local_bot_grants'").get() === void 0) {
25074
+ return false;
25075
+ }
25076
+ return database.prepare("SELECT local_grant_id FROM local_bot_grants WHERE bot_id = ? LIMIT 1").get(botId) !== void 0;
25077
+ } finally {
25078
+ database.close();
25079
+ }
25080
+ };
25033
25081
  constructor(path2) {
25034
25082
  this.#database = new DatabaseSync3(path2);
25035
25083
  this.#database.exec(`
@@ -25063,6 +25111,78 @@ var LocalBotGrantStore = class {
25063
25111
  ) STRICT;
25064
25112
  `);
25065
25113
  }
25114
+ /** Only the local CLI may invoke this explicit approval transition. */
25115
+ reapprove = async (botId, catalog, directories, bindingAuthorityId, now, signal) => {
25116
+ signal.throwIfAborted();
25117
+ if (!identifier2.safeParse(botId).success) {
25118
+ throw new LocalBotAuthorizationError("invalid_request", "The Bot ID is invalid");
25119
+ }
25120
+ const row = this.#database.prepare("SELECT * FROM local_bot_grants WHERE bot_id = ? ORDER BY binding_revision DESC LIMIT 1").get(botId);
25121
+ if (row === void 0) {
25122
+ throw new LocalBotAuthorizationError("bot_not_found", "This machine has no saved approval for that Bot");
25123
+ }
25124
+ const parsed = savedApprovalSchema.safeParse(row);
25125
+ if (!parsed.success) {
25126
+ throw new LocalBotAuthorizationError("local_grant_invalid", "The saved Bot approval is invalid", {
25127
+ cause: parsed.error
25128
+ });
25129
+ }
25130
+ const saved = parsed.data;
25131
+ const agent = catalog.find(saved.agent_ref);
25132
+ if (!agent.capabilities.embeddedContextPrompt) {
25133
+ throw new LocalBotAuthorizationError("binding_incompatible", "The local Agent cannot apply Bot context");
25134
+ }
25135
+ const [adapterUnchanged, agentUnchanged] = await Promise.all([
25136
+ revalidateExecutable(agent.adapterIdentity),
25137
+ revalidateExecutable(agent.agentIdentity)
25138
+ ]);
25139
+ signal.throwIfAborted();
25140
+ if (!adapterUnchanged || !agentUnchanged) {
25141
+ throw new LocalBotAuthorizationError(
25142
+ "binding_incompatible",
25143
+ "The local Agent executable changed before approval"
25144
+ );
25145
+ }
25146
+ const workspacePath = await directories.resolve(bindingAuthorityId, saved.workspace_ref, signal);
25147
+ const workspaceIdentityDigest = await workspaceDigest(workspacePath);
25148
+ signal.throwIfAborted();
25149
+ this.#database.exec("BEGIN IMMEDIATE");
25150
+ try {
25151
+ const result = this.#database.prepare(`UPDATE local_bot_grants
25152
+ SET agent_identity_digest = ?, workspace_identity_digest = ?, workspace_path = ?,
25153
+ revoked_at = NULL, expires_at = ?, revocation_epoch = revocation_epoch + 1
25154
+ WHERE local_grant_id = ? AND revocation_epoch = ?
25155
+ AND agent_identity_digest = ? AND workspace_identity_digest = ?
25156
+ AND binding_revision = (SELECT MAX(binding_revision) FROM local_bot_grants WHERE bot_id = ?)`).run(
25157
+ agentDigest(agent),
25158
+ workspaceIdentityDigest,
25159
+ workspacePath,
25160
+ now + LOCAL_BOT_GRANT_LIFETIME_MILLISECONDS,
25161
+ saved.local_grant_id,
25162
+ saved.revocation_epoch,
25163
+ saved.agent_identity_digest,
25164
+ saved.workspace_identity_digest,
25165
+ botId
25166
+ );
25167
+ if (result.changes !== 1) {
25168
+ throw new LocalBotAuthorizationError(
25169
+ "binding_not_approved",
25170
+ "The Bot binding changed during approval; run the command again"
25171
+ );
25172
+ }
25173
+ this.#database.prepare(`INSERT INTO audit_events (recorded_at, event, command_id, session_id, details_json)
25174
+ VALUES (?, 'bot_binding_locally_reapproved', ?, '', ?)`).run(
25175
+ new Date(now).toISOString(),
25176
+ saved.binding_id,
25177
+ JSON.stringify({ botId, bindingId: saved.binding_id, agentRef: saved.agent_ref })
25178
+ );
25179
+ this.#database.exec("COMMIT");
25180
+ } catch (cause) {
25181
+ this.#database.exec("ROLLBACK");
25182
+ throw cause;
25183
+ }
25184
+ return { bindingId: saved.binding_id, workspacePath, agentRef: saved.agent_ref };
25185
+ };
25066
25186
  approve = async (request, catalog, directories, bindingAuthorityId, now, signal) => {
25067
25187
  signal.throwIfAborted();
25068
25188
  const existing = this.#database.prepare(
@@ -25759,7 +25879,7 @@ var BotOutboundIpcServer = class {
25759
25879
  import { randomUUID as randomUUID3 } from "node:crypto";
25760
25880
  import { mkdir as mkdir4, open as open4, realpath as realpath7, rename as rename3, stat as stat7, writeFile as writeFile2 } from "node:fs/promises";
25761
25881
  import { hostname as hostname3 } from "node:os";
25762
- import { basename as basename2, join as join14, resolve as resolve3 } from "node:path";
25882
+ import { basename as basename2, join as join15, resolve as resolve3 } from "node:path";
25763
25883
  import { fetch as fetch3 } from "undici";
25764
25884
 
25765
25885
  // src/agent-catalog/agent-discovery.ts
@@ -26189,6 +26309,13 @@ var ManagedNpmPackageInstaller = class {
26189
26309
 
26190
26310
  // src/agent-catalog/agent-specification.ts
26191
26311
  import { join as join5 } from "node:path";
26312
+
26313
+ // src/agent-catalog/version-output.ts
26314
+ function normalizeVersionOutput(output2) {
26315
+ return output2.trim().split(/\r?\n/, 1)[0]?.trim().slice(0, 128) ?? "";
26316
+ }
26317
+
26318
+ // src/agent-catalog/agent-specification.ts
26192
26319
  var VERSION_PROBE_TIMEOUT_MILLISECONDS = 3e3;
26193
26320
  var ACP_PROBE_TIMEOUT_MILLISECONDS = 5e3;
26194
26321
  var DEFAULT_PROMPT_TIMEOUT_MILLISECONDS = 30 * 60 * 1e3;
@@ -26197,6 +26324,8 @@ var LocalAgentSpecification = class {
26197
26324
  authenticationCommand = () => "";
26198
26325
  adapterVersionArguments = ["--version"];
26199
26326
  agentVersionArguments = ["--version"];
26327
+ normalizeAdapterVersion = normalizeVersionOutput;
26328
+ normalizeAgentVersion = normalizeVersionOutput;
26200
26329
  promptTimeoutMilliseconds = DEFAULT_PROMPT_TIMEOUT_MILLISECONDS;
26201
26330
  versionProbeTimeoutMilliseconds = VERSION_PROBE_TIMEOUT_MILLISECONDS;
26202
26331
  resolveManagedAgent = async (stateDirectory, platform, signal) => {
@@ -26308,6 +26437,20 @@ var AgentProbeError = class extends Error {
26308
26437
  }
26309
26438
  };
26310
26439
 
26440
+ // src/agent-catalog/agents/resolve-user-local-executable.ts
26441
+ import { isAbsolute as isAbsolute4, join as join6 } from "node:path";
26442
+ async function resolveUserLocalExecutable(executableName, context) {
26443
+ context.signal.throwIfAborted();
26444
+ const platform = context.platform ?? process.platform;
26445
+ const homeDirectory = context.environment["HOME"];
26446
+ if (platform === "win32" || homeDirectory === void 0 || !isAbsolute4(homeDirectory)) {
26447
+ return [];
26448
+ }
26449
+ const executable = await resolveExecutablePath(join6(homeDirectory, ".local", "bin", executableName), platform);
26450
+ context.signal.throwIfAborted();
26451
+ return executable === null ? [] : [executable];
26452
+ }
26453
+
26311
26454
  // src/agent-catalog/agents/verify-session-creation.ts
26312
26455
  import { methods as methods4 } from "@agentclientprotocol/sdk";
26313
26456
  async function verifySessionCreation(connection, capabilities, defaultWorkspace, signal, label) {
@@ -26332,6 +26475,37 @@ async function verifySessionCreation(connection, capabilities, defaultWorkspace,
26332
26475
  }
26333
26476
  }
26334
26477
 
26478
+ // src/agent-catalog/agents/copilot-cli-agent.ts
26479
+ var COPILOT_CLI_TESTED_VERSION = "1.0.83";
26480
+ var CopilotCliAgentSpecification = class extends DirectAcpAgentDefinition {
26481
+ acpProbeTimeoutMilliseconds = 2e4;
26482
+ adapterVersion = COPILOT_CLI_TESTED_VERSION;
26483
+ authenticationCommand = () => "copilot login";
26484
+ agentExecutable = "copilot";
26485
+ id = "github-copilot-cli";
26486
+ label = "GitHub Copilot CLI";
26487
+ versionProbeTimeoutMilliseconds = 1e4;
26488
+ constructor() {
26489
+ super(
26490
+ "MOBIUS_COPILOT_PATH",
26491
+ ["--no-auto-update", "--acp", "--stdio"],
26492
+ ["agents", "github-copilot-cli", COPILOT_CLI_TESTED_VERSION, "bin", "copilot"]
26493
+ );
26494
+ }
26495
+ createLaunchEnvironment = async (_agent, _context) => Object.freeze({ COPILOT_AUTO_UPDATE: "false" });
26496
+ resolveInstalledAgentExecutables = async (context) => await resolveUserLocalExecutable(this.agentExecutable, context);
26497
+ verifyAcp = async (connection, initialized, defaultWorkspace, signal) => {
26498
+ const capabilities = initialized.agentCapabilities ?? {};
26499
+ if (capabilities.loadSession !== true || capabilities.sessionCapabilities?.list == null || (initialized.authMethods ?? []).length === 0) {
26500
+ throw new AgentProbeError(
26501
+ "acp_incompatible",
26502
+ "GitHub Copilot CLI reported an unsupported ACP capability set"
26503
+ );
26504
+ }
26505
+ await verifySessionCreation(connection, capabilities, defaultWorkspace, signal, this.label);
26506
+ };
26507
+ };
26508
+
26335
26509
  // src/agent-catalog/agents/cursor-cli-agent.ts
26336
26510
  var CURSOR_CLI_TESTED_VERSION = "2026.09.02-c22c1a3";
26337
26511
  var CursorCliAgentSpecification = class extends DirectAcpAgentDefinition {
@@ -26358,7 +26532,7 @@ var CursorCliAgentSpecification = class extends DirectAcpAgentDefinition {
26358
26532
 
26359
26533
  // src/agent-catalog/agents/deepseek-harness-agent.ts
26360
26534
  import { realpath as realpath4, stat as stat5 } from "node:fs/promises";
26361
- import { isAbsolute as isAbsolute4, join as join6, normalize as normalize2 } from "node:path";
26535
+ import { isAbsolute as isAbsolute5, join as join7, normalize as normalize2 } from "node:path";
26362
26536
 
26363
26537
  // src/agent-installation/deepseek-managed-package.ts
26364
26538
  var DeepSeekHarnessManagedPackage = class extends SriManagedNpmPackageDefinition {
@@ -26376,7 +26550,7 @@ var DEEPSEEK_HARNESS_PACKAGE = new DeepSeekHarnessManagedPackage(
26376
26550
 
26377
26551
  // src/agent-catalog/agents/deepseek-harness-agent.ts
26378
26552
  async function validateAgentHome(path2) {
26379
- if (!isAbsolute4(path2) || normalize2(path2) !== path2) {
26553
+ if (!isAbsolute5(path2) || normalize2(path2) !== path2) {
26380
26554
  throw new AgentProbeError("agent_environment_invalid", "The configured Agent home is invalid");
26381
26555
  }
26382
26556
  try {
@@ -26426,7 +26600,7 @@ var DeepSeekHarnessAgentSpecification = class extends DirectAcpAgentDefinition {
26426
26600
  context.signal
26427
26601
  );
26428
26602
  if (managed.path === agent.path) {
26429
- selectedHome = join6(readStateDirectory(context.environment), "agents", this.id, "home");
26603
+ selectedHome = join7(readStateDirectory(context.environment), "agents", this.id, "home");
26430
26604
  }
26431
26605
  } catch {
26432
26606
  context.signal.throwIfAborted();
@@ -26442,7 +26616,7 @@ var DeepSeekHarnessAgentSpecification = class extends DirectAcpAgentDefinition {
26442
26616
  resolveManagedAgent = async (stateDirectory, _platform, signal) => {
26443
26617
  signal.throwIfAborted();
26444
26618
  const executable = await validateManagedNpmPackage(
26445
- join6(stateDirectory, "agents", this.id, DEEPSEEK_HARNESS_PACKAGE.version),
26619
+ join7(stateDirectory, "agents", this.id, DEEPSEEK_HARNESS_PACKAGE.version),
26446
26620
  DEEPSEEK_HARNESS_PACKAGE
26447
26621
  );
26448
26622
  signal.throwIfAborted();
@@ -26462,9 +26636,41 @@ var DeepSeekHarnessAgentSpecification = class extends DirectAcpAgentDefinition {
26462
26636
  };
26463
26637
  };
26464
26638
 
26639
+ // src/agent-catalog/agents/gemini-cli-agent.ts
26640
+ var GEMINI_CLI_TESTED_VERSION = "0.59.0";
26641
+ var GeminiCliAgentSpecification = class extends DirectAcpAgentDefinition {
26642
+ acpProbeTimeoutMilliseconds = 2e4;
26643
+ adapterVersion = GEMINI_CLI_TESTED_VERSION;
26644
+ authenticationCommand = () => "gemini";
26645
+ agentExecutable = "gemini";
26646
+ id = "gemini-cli";
26647
+ label = "Gemini CLI";
26648
+ versionProbeTimeoutMilliseconds = 1e4;
26649
+ constructor() {
26650
+ super(
26651
+ "MOBIUS_GEMINI_PATH",
26652
+ ["--acp"],
26653
+ [
26654
+ "agents",
26655
+ "gemini-cli",
26656
+ GEMINI_CLI_TESTED_VERSION,
26657
+ "bin",
26658
+ process.platform === "win32" ? "gemini.cmd" : "gemini"
26659
+ ]
26660
+ );
26661
+ }
26662
+ verifyAcp = async (connection, initialized, defaultWorkspace, signal) => {
26663
+ const capabilities = initialized.agentCapabilities ?? {};
26664
+ if (capabilities.loadSession !== true || (initialized.authMethods ?? []).length === 0) {
26665
+ throw new AgentProbeError("acp_incompatible", "Gemini CLI reported an unsupported ACP capability set");
26666
+ }
26667
+ await verifySessionCreation(connection, capabilities, defaultWorkspace, signal, this.label);
26668
+ };
26669
+ };
26670
+
26465
26671
  // src/agent-catalog/agents/grok-build-agent.ts
26466
26672
  import { realpath as realpath5 } from "node:fs/promises";
26467
- import { isAbsolute as isAbsolute5, join as join7, relative as relative3, sep as sep3 } from "node:path";
26673
+ import { isAbsolute as isAbsolute6, join as join8, relative as relative3, sep as sep3 } from "node:path";
26468
26674
 
26469
26675
  // src/agent-installation/grok-managed-package.ts
26470
26676
  var GROK_BUILD_MANAGED_VERSION = "1.0.21";
@@ -26527,7 +26733,7 @@ function grokBuildManagedPackage(platform, architecture) {
26527
26733
  // src/agent-catalog/agents/grok-build-agent.ts
26528
26734
  function isContainedPath2(root, candidate) {
26529
26735
  const difference = relative3(root, candidate);
26530
- return difference.length > 0 && difference !== ".." && !difference.startsWith(`..${sep3}`) && !isAbsolute5(difference);
26736
+ return difference.length > 0 && difference !== ".." && !difference.startsWith(`..${sep3}`) && !isAbsolute6(difference);
26531
26737
  }
26532
26738
  var GrokBuildAgentSpecification = class extends DirectAcpAgentDefinition {
26533
26739
  adapterVersion = GROK_BUILD_MANAGED_VERSION;
@@ -26555,7 +26761,7 @@ var GrokBuildAgentSpecification = class extends DirectAcpAgentDefinition {
26555
26761
  if (managed.path === agent.path) {
26556
26762
  return Object.freeze({
26557
26763
  GROK_HOME: await realpath5(
26558
- join7(stateDirectory, "agents", this.id, GROK_BUILD_MANAGED_VERSION, "home")
26764
+ join8(stateDirectory, "agents", this.id, GROK_BUILD_MANAGED_VERSION, "home")
26559
26765
  )
26560
26766
  });
26561
26767
  }
@@ -26566,9 +26772,9 @@ var GrokBuildAgentSpecification = class extends DirectAcpAgentDefinition {
26566
26772
  };
26567
26773
  resolveManagedAgent = async (stateDirectory, platform, signal) => {
26568
26774
  signal.throwIfAborted();
26569
- const versionRoot = await realpath5(join7(stateDirectory, "agents", this.id, GROK_BUILD_MANAGED_VERSION));
26570
- await validateManagedNpmPackage(join7(versionRoot, "package"), grokBuildManagedPackage(platform, process.arch));
26571
- const executable = await resolveExecutablePath(join7(versionRoot, "home", "bin", "grok"), platform);
26775
+ const versionRoot = await realpath5(join8(stateDirectory, "agents", this.id, GROK_BUILD_MANAGED_VERSION));
26776
+ await validateManagedNpmPackage(join8(versionRoot, "package"), grokBuildManagedPackage(platform, process.arch));
26777
+ const executable = await resolveExecutablePath(join8(versionRoot, "home", "bin", "grok"), platform);
26572
26778
  signal.throwIfAborted();
26573
26779
  if (executable === null || !isContainedPath2(versionRoot, executable.path)) {
26574
26780
  throw new AgentProbeError("managed_agent_invalid", "The managed Grok Build executable is invalid");
@@ -26585,14 +26791,39 @@ var GrokBuildAgentSpecification = class extends DirectAcpAgentDefinition {
26585
26791
  };
26586
26792
  };
26587
26793
 
26794
+ // src/agent-catalog/agents/hermes-agent.ts
26795
+ var HERMES_TESTED_VERSION = "0.21.1";
26796
+ var HermesAgentSpecification = class extends DirectAcpAgentDefinition {
26797
+ acpProbeTimeoutMilliseconds = 2e4;
26798
+ adapterVersion = HERMES_TESTED_VERSION;
26799
+ adapterVersionArguments = ["acp", "--version"];
26800
+ authenticationCommand = () => "hermes acp --setup";
26801
+ agentExecutable = "hermes";
26802
+ agentVersionArguments = ["acp", "--version"];
26803
+ id = "hermes";
26804
+ label = "Hermes Agent";
26805
+ constructor() {
26806
+ super("MOBIUS_HERMES_PATH", ["acp"], ["agents", "hermes", HERMES_TESTED_VERSION, "bin", "hermes"]);
26807
+ }
26808
+ resolveInstalledAgentExecutables = async (context) => await resolveUserLocalExecutable(this.agentExecutable, context);
26809
+ verifyAcp = async (connection, initialized, defaultWorkspace, signal) => {
26810
+ const capabilities = initialized.agentCapabilities ?? {};
26811
+ const session = capabilities.sessionCapabilities;
26812
+ if (capabilities.loadSession !== true || session?.fork == null || session.list == null || session.resume == null || (initialized.authMethods ?? []).length === 0) {
26813
+ throw new AgentProbeError("acp_incompatible", "Hermes Agent reported an unsupported ACP capability set");
26814
+ }
26815
+ await verifySessionCreation(connection, capabilities, defaultWorkspace, signal, this.label);
26816
+ };
26817
+ };
26818
+
26588
26819
  // src/agent-catalog/agents/opencode-agent.ts
26589
- import { join as join9 } from "node:path";
26820
+ import { join as join10 } from "node:path";
26590
26821
 
26591
26822
  // src/agent-installation/managed-agent-archive.ts
26592
26823
  import { createHash as createHash2 } from "node:crypto";
26593
26824
  import { createReadStream } from "node:fs";
26594
26825
  import { chmod as chmod2, copyFile, mkdir as mkdir3, mkdtemp as mkdtemp2, open as open3, realpath as realpath6, rename as rename2, rm as rm2, stat as stat6, writeFile } from "node:fs/promises";
26595
- import { dirname as dirname5, isAbsolute as isAbsolute6, join as join8, relative as relative4, sep as sep4 } from "node:path";
26826
+ import { dirname as dirname5, isAbsolute as isAbsolute7, join as join9, relative as relative4, sep as sep4 } from "node:path";
26596
26827
 
26597
26828
  // src/agent-installation/verified-download.ts
26598
26829
  import { fetch as fetch2 } from "undici";
@@ -26698,7 +26929,7 @@ function isRecord10(value) {
26698
26929
  }
26699
26930
  function isContainedPath3(root, candidate) {
26700
26931
  const difference = relative4(root, candidate);
26701
- return difference.length > 0 && difference !== ".." && !difference.startsWith(`..${sep4}`) && !isAbsolute6(difference);
26932
+ return difference.length > 0 && difference !== ".." && !difference.startsWith(`..${sep4}`) && !isAbsolute7(difference);
26702
26933
  }
26703
26934
  async function hashFile(path2, signal) {
26704
26935
  signal.throwIfAborted();
@@ -26777,11 +27008,11 @@ async function validateManagedAgentArchive(root, definition, signal) {
26777
27008
  if (!rootMetadata.isDirectory() || typeof process.getuid === "function" && rootMetadata.uid !== process.getuid()) {
26778
27009
  throw new Error("Managed Agent root is not user-owned");
26779
27010
  }
26780
- const manifest = await readManifest(join8(rootPath, "archive.json"));
27011
+ const manifest = await readManifest(join9(rootPath, "archive.json"));
26781
27012
  if (manifest["archiveSha256"] !== definition.archiveSha256 || manifest["archiveUrl"] !== definition.archiveUrl.toString() || manifest["version"] !== definition.version || typeof manifest["executableSha256"] !== "string") {
26782
27013
  throw new Error("Managed Agent archive identity is invalid");
26783
27014
  }
26784
- const executable = await resolveExecutablePath(join8(rootPath, "bin", definition.executableName));
27015
+ const executable = await resolveExecutablePath(join9(rootPath, "bin", definition.executableName));
26785
27016
  if (executable === null || !isContainedPath3(rootPath, executable.path) || await hashFile(executable.path, signal) !== manifest["executableSha256"]) {
26786
27017
  throw new Error("Managed Agent executable is invalid");
26787
27018
  }
@@ -26873,7 +27104,7 @@ var OpenCodeAgentSpecification = class extends DirectAcpAgentDefinition {
26873
27104
  }
26874
27105
  createLaunchEnvironment = async (_agent, _context) => Object.freeze({ OPENCODE_DISABLE_AUTOUPDATE: "1" });
26875
27106
  resolveManagedAgent = async (stateDirectory, platform, signal) => await validateManagedAgentArchive(
26876
- join9(stateDirectory, "agents", this.id, OPENCODE_MANAGED_VERSION),
27107
+ join10(stateDirectory, "agents", this.id, OPENCODE_MANAGED_VERSION),
26877
27108
  openCodeManagedArchive(platform, process.arch),
26878
27109
  signal
26879
27110
  );
@@ -26891,7 +27122,7 @@ var OpenCodeAgentSpecification = class extends DirectAcpAgentDefinition {
26891
27122
  };
26892
27123
 
26893
27124
  // src/agent-catalog/agents/pi-agent.ts
26894
- import { join as join10 } from "node:path";
27125
+ import { join as join11 } from "node:path";
26895
27126
  import {
26896
27127
  methods as methods5
26897
27128
  } from "@agentclientprotocol/sdk";
@@ -26950,7 +27181,7 @@ var PiAgentSpecification = class extends BridgedAcpAgentDefinition {
26950
27181
  resolveManagedAgent = async (stateDirectory, _platform, signal) => {
26951
27182
  signal.throwIfAborted();
26952
27183
  const executable = await validateManagedNpmPackage(
26953
- join10(stateDirectory, "agents", this.id, PI_AGENT_PACKAGE.version),
27184
+ join11(stateDirectory, "agents", this.id, PI_AGENT_PACKAGE.version),
26954
27185
  PI_AGENT_PACKAGE
26955
27186
  );
26956
27187
  signal.throwIfAborted();
@@ -26988,7 +27219,7 @@ var PiAgentSpecification = class extends BridgedAcpAgentDefinition {
26988
27219
  };
26989
27220
 
26990
27221
  // src/agent-catalog/agents/workbuddy-agent.ts
26991
- import { isAbsolute as isAbsolute7, join as join11 } from "node:path";
27222
+ import { isAbsolute as isAbsolute8, join as join12 } from "node:path";
26992
27223
 
26993
27224
  // src/agent-installation/workbuddy-managed-package.ts
26994
27225
  var WORKBUDDY_MANAGED_VERSION = "2.146.0";
@@ -27041,7 +27272,7 @@ var WorkBuddyAgentSpecification = class extends DirectAcpAgentDefinition {
27041
27272
  resolveManagedAgent = async (stateDirectory, _platform, signal) => {
27042
27273
  signal.throwIfAborted();
27043
27274
  const executable = await validateManagedNpmPackage(
27044
- join11(stateDirectory, "agents", this.id, WORKBUDDY_MANAGED_VERSION),
27275
+ join12(stateDirectory, "agents", this.id, WORKBUDDY_MANAGED_VERSION),
27045
27276
  WORKBUDDY_MANAGED_PACKAGE
27046
27277
  );
27047
27278
  signal.throwIfAborted();
@@ -27052,10 +27283,10 @@ var WorkBuddyAgentSpecification = class extends DirectAcpAgentDefinition {
27052
27283
  if ((context.platform ?? process.platform) !== "darwin") {
27053
27284
  return [];
27054
27285
  }
27055
- const requestedPaths = [join11("/Applications", ...WORKBUDDY_MACOS_EXECUTABLE_PATH)];
27286
+ const requestedPaths = [join12("/Applications", ...WORKBUDDY_MACOS_EXECUTABLE_PATH)];
27056
27287
  const homeDirectory = context.environment["HOME"];
27057
- if (homeDirectory !== void 0 && isAbsolute7(homeDirectory)) {
27058
- requestedPaths.unshift(join11(homeDirectory, "Applications", ...WORKBUDDY_MACOS_EXECUTABLE_PATH));
27288
+ if (homeDirectory !== void 0 && isAbsolute8(homeDirectory)) {
27289
+ requestedPaths.unshift(join12(homeDirectory, "Applications", ...WORKBUDDY_MACOS_EXECUTABLE_PATH));
27059
27290
  }
27060
27291
  const executables = [];
27061
27292
  for (const requestedPath of requestedPaths) {
@@ -27081,12 +27312,15 @@ function supportedLocalAgentSpecifications() {
27081
27312
  return Object.freeze([
27082
27313
  new CodexAgentSpecification(),
27083
27314
  new ClaudeCodeAgentSpecification(),
27315
+ new CopilotCliAgentSpecification(),
27084
27316
  new PiAgentSpecification(),
27085
27317
  new DeepSeekHarnessAgentSpecification(),
27318
+ new HermesAgentSpecification(),
27086
27319
  new OpenCodeAgentSpecification(),
27087
27320
  new CursorCliAgentSpecification(),
27088
27321
  new GrokBuildAgentSpecification(),
27089
- new WorkBuddyAgentSpecification()
27322
+ new WorkBuddyAgentSpecification(),
27323
+ new GeminiCliAgentSpecification()
27090
27324
  ]);
27091
27325
  }
27092
27326
 
@@ -27098,12 +27332,172 @@ import {
27098
27332
  PROTOCOL_VERSION as PROTOCOL_VERSION2,
27099
27333
  RequestError as RequestError2
27100
27334
  } from "@agentclientprotocol/sdk";
27335
+ var ACP_OUTPUT_LIMIT_BYTES = 1024 * 1024;
27336
+ var VerifiedAcpReadiness = class {
27337
+ adapterVersion;
27338
+ capabilities;
27339
+ constructor(adapterVersion, capabilities) {
27340
+ this.adapterVersion = adapterVersion;
27341
+ this.capabilities = capabilities;
27342
+ }
27343
+ };
27344
+ var DiscoveryAcpHandler = class {
27345
+ onElicitation = (_request, _signal) => Promise.reject(new Error("ACP probe does not accept elicitations"));
27346
+ onElicitationComplete = (_notification) => Promise.resolve();
27347
+ onPermission = (_request, _signal) => Promise.reject(new Error("ACP probe does not grant permissions"));
27348
+ onUpdate = (_notification) => Promise.resolve();
27349
+ };
27350
+ function readableAcpStream(input2) {
27351
+ let byteLength = 0;
27352
+ let open5 = true;
27353
+ return new ReadableStream({
27354
+ start(controller) {
27355
+ input2.on("data", (chunk) => {
27356
+ if (!open5) {
27357
+ return;
27358
+ }
27359
+ if (!(chunk instanceof Uint8Array)) {
27360
+ open5 = false;
27361
+ controller.error(new Error("ACP adapter produced invalid output"));
27362
+ return;
27363
+ }
27364
+ byteLength += chunk.byteLength;
27365
+ if (byteLength > ACP_OUTPUT_LIMIT_BYTES) {
27366
+ open5 = false;
27367
+ controller.error(new Error("ACP adapter output limit exceeded"));
27368
+ return;
27369
+ }
27370
+ controller.enqueue(new Uint8Array(chunk));
27371
+ });
27372
+ input2.once("end", () => {
27373
+ if (open5) {
27374
+ open5 = false;
27375
+ controller.close();
27376
+ }
27377
+ });
27378
+ input2.once("error", (error61) => {
27379
+ if (open5) {
27380
+ open5 = false;
27381
+ controller.error(error61);
27382
+ }
27383
+ });
27384
+ },
27385
+ cancel() {
27386
+ open5 = false;
27387
+ }
27388
+ });
27389
+ }
27390
+ function writableAcpStream(output2) {
27391
+ return new WritableStream({
27392
+ write(chunk) {
27393
+ return new Promise((resolveWrite, rejectWrite) => {
27394
+ output2.write(chunk, (error61) => {
27395
+ if (error61) {
27396
+ rejectWrite(error61);
27397
+ return;
27398
+ }
27399
+ resolveWrite();
27400
+ });
27401
+ });
27402
+ }
27403
+ });
27404
+ }
27405
+ async function probeAcpReadiness(specification, agent, environment, defaultWorkspace, signal) {
27406
+ signal.throwIfAborted();
27407
+ const controller = new AbortController();
27408
+ let timedOut = false;
27409
+ const timeout = setTimeout(() => {
27410
+ timedOut = true;
27411
+ controller.abort(new Error("ACP probe timed out"));
27412
+ }, specification.acpProbeTimeoutMilliseconds);
27413
+ const abort = () => controller.abort(signal.reason);
27414
+ signal.addEventListener("abort", abort, { once: true });
27415
+ if (signal.aborted) {
27416
+ abort();
27417
+ }
27418
+ const child = spawn3(agent.adapterPath, [...agent.arguments], {
27419
+ cwd: defaultWorkspace,
27420
+ detached: process.platform !== "win32",
27421
+ env: { ...environment, ...agent.environment },
27422
+ shell: false,
27423
+ stdio: ["pipe", "pipe", "pipe"]
27424
+ });
27425
+ const processExit = new Promise((_resolve, reject) => {
27426
+ const rejectExit = () => reject(new Error("ACP adapter exited during initialization"));
27427
+ child.once("error", reject);
27428
+ child.once("exit", rejectExit);
27429
+ if (child.exitCode !== null || child.signalCode !== null) {
27430
+ rejectExit();
27431
+ }
27432
+ });
27433
+ const stdin = child.stdin;
27434
+ const stdout = child.stdout;
27435
+ const stderr = child.stderr;
27436
+ if (stdin === null || stdout === null || stderr === null) {
27437
+ await stopProcessTree(child);
27438
+ throw new AgentProbeError("acp_incompatible", "ACP adapter streams are unavailable");
27439
+ }
27440
+ let stderrBytes = 0;
27441
+ const consumeStderr = (chunk) => {
27442
+ stderrBytes += chunk.byteLength;
27443
+ if (stderrBytes > ACP_OUTPUT_LIMIT_BYTES) {
27444
+ controller.abort(new Error("ACP adapter output limit exceeded"));
27445
+ }
27446
+ };
27447
+ stderr.on("data", consumeStderr);
27448
+ const connection = createAcpClient(new DiscoveryAcpHandler()).connect(
27449
+ ndJsonStream2(writableAcpStream(stdin), readableAcpStream(stdout))
27450
+ );
27451
+ try {
27452
+ const initialized = await Promise.race([
27453
+ connection.agent.request(
27454
+ methods6.agent.initialize,
27455
+ {
27456
+ clientCapabilities: {},
27457
+ clientInfo: { name: "mobius", version: "0.0.3" },
27458
+ protocolVersion: PROTOCOL_VERSION2
27459
+ },
27460
+ { cancellationSignal: controller.signal }
27461
+ ),
27462
+ processExit
27463
+ ]);
27464
+ if (initialized.protocolVersion !== PROTOCOL_VERSION2) {
27465
+ throw new AgentProbeError("acp_incompatible", "ACP adapter selected an unsupported protocol version");
27466
+ }
27467
+ await specification.verifyAcp(connection, initialized, defaultWorkspace, controller.signal);
27468
+ return new VerifiedAcpReadiness(
27469
+ normalizeVersionOutput(initialized.agentInfo?.version ?? ""),
27470
+ normalizeAcpCapabilities(initialized)
27471
+ );
27472
+ } catch (error61) {
27473
+ if (signal.aborted) {
27474
+ signal.throwIfAborted();
27475
+ }
27476
+ if (timedOut) {
27477
+ throw new AgentProbeError("adapter_probe_timeout", "ACP adapter probe timed out", { cause: error61 });
27478
+ }
27479
+ if (error61 instanceof AgentProbeError) {
27480
+ throw error61;
27481
+ }
27482
+ if (error61 instanceof RequestError2 && error61.code === -32e3 && specification.authenticationCommand().length > 0) {
27483
+ throw new AgentProbeError("authentication_required", "Agent authentication is required", { cause: error61 });
27484
+ }
27485
+ throw new AgentProbeError("acp_incompatible", "ACP adapter initialization failed", { cause: error61 });
27486
+ } finally {
27487
+ clearTimeout(timeout);
27488
+ signal.removeEventListener("abort", abort);
27489
+ connection.close();
27490
+ stdin.end();
27491
+ stderr.removeListener("data", consumeStderr);
27492
+ await stopProcessTree(child);
27493
+ }
27494
+ }
27101
27495
 
27102
27496
  // src/agent-catalog/executable-discovery.ts
27103
- import { isAbsolute as isAbsolute8, join as join13 } from "node:path";
27497
+ import { isAbsolute as isAbsolute9, join as join14 } from "node:path";
27104
27498
 
27105
27499
  // src/agent-installation/managed-adapter-installer.ts
27106
- import { join as join12 } from "node:path";
27500
+ import { join as join13 } from "node:path";
27107
27501
  var ManagedAdapterInstallError = class extends Error {
27108
27502
  code;
27109
27503
  constructor(code, message, options = {}) {
@@ -27160,7 +27554,7 @@ var ManagedAdapterInstaller = class {
27160
27554
  this.#stateDirectory = options.stateDirectory;
27161
27555
  }
27162
27556
  install = async (specification, signal) => {
27163
- const root = join12(this.#stateDirectory, "adapters", specification.id, specification.adapterVersion);
27557
+ const root = join13(this.#stateDirectory, "adapters", specification.id, specification.adapterVersion);
27164
27558
  try {
27165
27559
  return await this.#npmInstaller.install(
27166
27560
  root,
@@ -27194,7 +27588,7 @@ async function resolveManagedAdapterExecutable(specification, context) {
27194
27588
  let managed;
27195
27589
  try {
27196
27590
  managed = await validateManagedAdapter(
27197
- join13(readStateDirectory(context.environment), "adapters", specification.id, specification.adapterVersion),
27591
+ join14(readStateDirectory(context.environment), "adapters", specification.id, specification.adapterVersion),
27198
27592
  specification
27199
27593
  );
27200
27594
  } catch {
@@ -27205,7 +27599,7 @@ async function resolveManagedAdapterExecutable(specification, context) {
27205
27599
  async function resolveSpecificationExecutables(executableName, overrideVariable, resolveInstalled, resolveManaged, context) {
27206
27600
  const override = context.environment[overrideVariable];
27207
27601
  if (override !== void 0) {
27208
- if (override.length === 0 || !isAbsolute8(override)) {
27602
+ if (override.length === 0 || !isAbsolute9(override)) {
27209
27603
  return [];
27210
27604
  }
27211
27605
  const executable = await resolveExecutablePath(override, context.platform);
@@ -27259,10 +27653,7 @@ async function resolveAdapterExecutable(specification, context) {
27259
27653
  const executables = await resolveAdapterExecutables(specification, context);
27260
27654
  return executables[0] ?? null;
27261
27655
  }
27262
- function normalizedVersion(output2) {
27263
- return output2.trim().split(/\r?\n/, 1)[0]?.trim().slice(0, 128) ?? "";
27264
- }
27265
- async function probeVersion(executable, arguments_, environment, defaultWorkspace, signal, timeoutMilliseconds) {
27656
+ async function probeVersion(executable, arguments_, environment, defaultWorkspace, signal, timeoutMilliseconds, normalize4 = normalizeVersionOutput) {
27266
27657
  const result = await runBoundedProcess({
27267
27658
  arguments: arguments_,
27268
27659
  command: executable.path,
@@ -27271,7 +27662,7 @@ async function probeVersion(executable, arguments_, environment, defaultWorkspac
27271
27662
  signal,
27272
27663
  timeoutMilliseconds
27273
27664
  });
27274
- const version2 = normalizedVersion(result.stdout || result.stderr);
27665
+ const version2 = normalize4(result.stdout || result.stderr);
27275
27666
  if (version2.length === 0) {
27276
27667
  throw new ProcessExecutionError("process_exit_failed", "The executable did not report a version");
27277
27668
  }
@@ -27295,7 +27686,8 @@ async function findVerifiedAgentExecutable(specification, context) {
27295
27686
  context.environment,
27296
27687
  context.defaultWorkspace,
27297
27688
  context.signal,
27298
- specification.versionProbeTimeoutMilliseconds
27689
+ specification.versionProbeTimeoutMilliseconds,
27690
+ specification.normalizeAgentVersion
27299
27691
  );
27300
27692
  return new VerifiedAgentExecutable(executable, version2);
27301
27693
  } catch {
@@ -27307,168 +27699,6 @@ async function findVerifiedAgentExecutable(specification, context) {
27307
27699
  return null;
27308
27700
  }
27309
27701
 
27310
- // src/agent-catalog/acp-readiness-probe.ts
27311
- var ACP_OUTPUT_LIMIT_BYTES = 1024 * 1024;
27312
- var VerifiedAcpReadiness = class {
27313
- adapterVersion;
27314
- capabilities;
27315
- constructor(adapterVersion, capabilities) {
27316
- this.adapterVersion = adapterVersion;
27317
- this.capabilities = capabilities;
27318
- }
27319
- };
27320
- var DiscoveryAcpHandler = class {
27321
- onElicitation = (_request, _signal) => Promise.reject(new Error("ACP probe does not accept elicitations"));
27322
- onElicitationComplete = (_notification) => Promise.resolve();
27323
- onPermission = (_request, _signal) => Promise.reject(new Error("ACP probe does not grant permissions"));
27324
- onUpdate = (_notification) => Promise.resolve();
27325
- };
27326
- function readableAcpStream(input2) {
27327
- let byteLength = 0;
27328
- let open5 = true;
27329
- return new ReadableStream({
27330
- start(controller) {
27331
- input2.on("data", (chunk) => {
27332
- if (!open5) {
27333
- return;
27334
- }
27335
- if (!(chunk instanceof Uint8Array)) {
27336
- open5 = false;
27337
- controller.error(new Error("ACP adapter produced invalid output"));
27338
- return;
27339
- }
27340
- byteLength += chunk.byteLength;
27341
- if (byteLength > ACP_OUTPUT_LIMIT_BYTES) {
27342
- open5 = false;
27343
- controller.error(new Error("ACP adapter output limit exceeded"));
27344
- return;
27345
- }
27346
- controller.enqueue(new Uint8Array(chunk));
27347
- });
27348
- input2.once("end", () => {
27349
- if (open5) {
27350
- open5 = false;
27351
- controller.close();
27352
- }
27353
- });
27354
- input2.once("error", (error61) => {
27355
- if (open5) {
27356
- open5 = false;
27357
- controller.error(error61);
27358
- }
27359
- });
27360
- },
27361
- cancel() {
27362
- open5 = false;
27363
- }
27364
- });
27365
- }
27366
- function writableAcpStream(output2) {
27367
- return new WritableStream({
27368
- write(chunk) {
27369
- return new Promise((resolveWrite, rejectWrite) => {
27370
- output2.write(chunk, (error61) => {
27371
- if (error61) {
27372
- rejectWrite(error61);
27373
- return;
27374
- }
27375
- resolveWrite();
27376
- });
27377
- });
27378
- }
27379
- });
27380
- }
27381
- async function probeAcpReadiness(specification, agent, environment, defaultWorkspace, signal) {
27382
- signal.throwIfAborted();
27383
- const controller = new AbortController();
27384
- let timedOut = false;
27385
- const timeout = setTimeout(() => {
27386
- timedOut = true;
27387
- controller.abort(new Error("ACP probe timed out"));
27388
- }, specification.acpProbeTimeoutMilliseconds);
27389
- const abort = () => controller.abort(signal.reason);
27390
- signal.addEventListener("abort", abort, { once: true });
27391
- if (signal.aborted) {
27392
- abort();
27393
- }
27394
- const child = spawn3(agent.adapterPath, [...agent.arguments], {
27395
- cwd: defaultWorkspace,
27396
- detached: process.platform !== "win32",
27397
- env: { ...environment, ...agent.environment },
27398
- shell: false,
27399
- stdio: ["pipe", "pipe", "pipe"]
27400
- });
27401
- const processExit = new Promise((_resolve, reject) => {
27402
- const rejectExit = () => reject(new Error("ACP adapter exited during initialization"));
27403
- child.once("error", reject);
27404
- child.once("exit", rejectExit);
27405
- if (child.exitCode !== null || child.signalCode !== null) {
27406
- rejectExit();
27407
- }
27408
- });
27409
- const stdin = child.stdin;
27410
- const stdout = child.stdout;
27411
- const stderr = child.stderr;
27412
- if (stdin === null || stdout === null || stderr === null) {
27413
- await stopProcessTree(child);
27414
- throw new AgentProbeError("acp_incompatible", "ACP adapter streams are unavailable");
27415
- }
27416
- let stderrBytes = 0;
27417
- const consumeStderr = (chunk) => {
27418
- stderrBytes += chunk.byteLength;
27419
- if (stderrBytes > ACP_OUTPUT_LIMIT_BYTES) {
27420
- controller.abort(new Error("ACP adapter output limit exceeded"));
27421
- }
27422
- };
27423
- stderr.on("data", consumeStderr);
27424
- const connection = createAcpClient(new DiscoveryAcpHandler()).connect(
27425
- ndJsonStream2(writableAcpStream(stdin), readableAcpStream(stdout))
27426
- );
27427
- try {
27428
- const initialized = await Promise.race([
27429
- connection.agent.request(
27430
- methods6.agent.initialize,
27431
- {
27432
- clientCapabilities: {},
27433
- clientInfo: { name: "mobius", version: "0.0.3" },
27434
- protocolVersion: PROTOCOL_VERSION2
27435
- },
27436
- { cancellationSignal: controller.signal }
27437
- ),
27438
- processExit
27439
- ]);
27440
- if (initialized.protocolVersion !== PROTOCOL_VERSION2) {
27441
- throw new AgentProbeError("acp_incompatible", "ACP adapter selected an unsupported protocol version");
27442
- }
27443
- await specification.verifyAcp(connection, initialized, defaultWorkspace, controller.signal);
27444
- return new VerifiedAcpReadiness(
27445
- normalizedVersion(initialized.agentInfo?.version ?? ""),
27446
- normalizeAcpCapabilities(initialized)
27447
- );
27448
- } catch (error61) {
27449
- if (signal.aborted) {
27450
- signal.throwIfAborted();
27451
- }
27452
- if (timedOut) {
27453
- throw new AgentProbeError("adapter_probe_timeout", "ACP adapter probe timed out", { cause: error61 });
27454
- }
27455
- if (error61 instanceof AgentProbeError) {
27456
- throw error61;
27457
- }
27458
- if (error61 instanceof RequestError2 && error61.code === -32e3 && specification.authenticationCommand().length > 0) {
27459
- throw new AgentProbeError("authentication_required", "Agent authentication is required", { cause: error61 });
27460
- }
27461
- throw new AgentProbeError("acp_incompatible", "ACP adapter initialization failed", { cause: error61 });
27462
- } finally {
27463
- clearTimeout(timeout);
27464
- signal.removeEventListener("abort", abort);
27465
- connection.close();
27466
- stdin.end();
27467
- stderr.removeListener("data", consumeStderr);
27468
- await stopProcessTree(child);
27469
- }
27470
- }
27471
-
27472
27702
  // src/agent-catalog/discover-agent.ts
27473
27703
  function agentProbeFailure(specification, error61) {
27474
27704
  if (error61 instanceof AgentProbeError) {
@@ -27512,7 +27742,8 @@ async function discoverAgent(specification, context) {
27512
27742
  context.environment,
27513
27743
  context.defaultWorkspace,
27514
27744
  context.signal,
27515
- specification.versionProbeTimeoutMilliseconds
27745
+ specification.versionProbeTimeoutMilliseconds,
27746
+ specification.normalizeAgentVersion
27516
27747
  );
27517
27748
  } catch (error61) {
27518
27749
  if (context.signal.aborted) {
@@ -27548,7 +27779,8 @@ async function discoverAgent(specification, context) {
27548
27779
  },
27549
27780
  context.defaultWorkspace,
27550
27781
  context.signal,
27551
- specification.versionProbeTimeoutMilliseconds
27782
+ specification.versionProbeTimeoutMilliseconds,
27783
+ specification.normalizeAdapterVersion
27552
27784
  );
27553
27785
  }
27554
27786
  } catch (error61) {
@@ -27821,10 +28053,10 @@ async function claimPairing(options, defaultWorkspace, localAgents, installableA
27821
28053
  return options.pairingId.length > 0 ? decodePairingResponse(value, "runtimeCredential", REDEEM_RESPONSE_KEYS) : decodePairingResponse(value, "daemonToken", CLAIM_RESPONSE_KEYS);
27822
28054
  }
27823
28055
  async function persistConnection(channelId, relayOrigin, runtimeCredential2, defaultWorkspace, environment) {
27824
- const connectionsDirectory = join14(readStateDirectory(environment), "connections");
28056
+ const connectionsDirectory = join15(readStateDirectory(environment), "connections");
27825
28057
  await mkdir4(connectionsDirectory, { mode: 448, recursive: true });
27826
- const connectionPath = join14(connectionsDirectory, `${channelId}.json`);
27827
- const temporaryPath = join14(connectionsDirectory, `.${channelId}.${randomUUID3()}.tmp`);
28058
+ const connectionPath = join15(connectionsDirectory, `${channelId}.json`);
28059
+ const temporaryPath = join15(connectionsDirectory, `.${channelId}.${randomUUID3()}.tmp`);
27828
28060
  await writeFile2(
27829
28061
  temporaryPath,
27830
28062
  `${JSON.stringify(
@@ -27862,7 +28094,7 @@ function decodeSavedConnection(value, expectedChannelId) {
27862
28094
  };
27863
28095
  }
27864
28096
  async function readSavedConnection(channelId, environment) {
27865
- const connectionPath = join14(readStateDirectory(environment), "connections", `${channelId}.json`);
28097
+ const connectionPath = join15(readStateDirectory(environment), "connections", `${channelId}.json`);
27866
28098
  let encoded = "";
27867
28099
  const handle = await open4(connectionPath, "r");
27868
28100
  try {
@@ -27898,7 +28130,7 @@ function buildPairedDaemon(connection, connectionPath, inventory, environment) {
27898
28130
  const relayUrl = mobiusApiUrl(connection.relayOrigin, "/v1/runtimes/connect");
27899
28131
  relayUrl.protocol = relayUrl.protocol === "https:" ? "wss:" : "ws:";
27900
28132
  relayUrl.searchParams.set("token", connection.runtimeCredential);
27901
- const auditDatabasePath = join14(readStateDirectory(environment), "audit", `${connection.channelId}.sqlite`);
28133
+ const auditDatabasePath = join15(readStateDirectory(environment), "audit", `${connection.channelId}.sqlite`);
27902
28134
  return {
27903
28135
  channelUrl: new URL(`/channels/${encodeURIComponent(connection.channelId)}`, connection.relayOrigin).toString(),
27904
28136
  config: createDaemonConfig(
@@ -27960,7 +28192,7 @@ async function pairLocalMachine(arguments_, signal = new AbortController().signa
27960
28192
  }
27961
28193
  async function resumeMobiusRuntime(channelId, signal, environment = process.env) {
27962
28194
  const normalizedChannelId = validatePairingId(channelId);
27963
- const connectionPath = join14(readStateDirectory(environment), "connections", `${normalizedChannelId}.json`);
28195
+ const connectionPath = join15(readStateDirectory(environment), "connections", `${normalizedChannelId}.json`);
27964
28196
  const connection = await readSavedConnection(normalizedChannelId, environment);
27965
28197
  const inventory = await discoverLocalAgentInventory({
27966
28198
  defaultWorkspace: connection.defaultWorkspace,
@@ -27975,7 +28207,7 @@ async function resumeLocalMachine(arguments_, signal = new AbortController().sig
27975
28207
 
27976
28208
  // src/run-daemon.ts
27977
28209
  import { randomUUID as randomUUID6 } from "node:crypto";
27978
- import { basename as basename5, join as join16 } from "node:path";
28210
+ import { basename as basename5, join as join17 } from "node:path";
27979
28211
  import { styleText } from "node:util";
27980
28212
  import { fetch as fetch7, WebSocket as WebSocket2 } from "undici";
27981
28213
 
@@ -28919,7 +29151,7 @@ async function uploadRuntimeArtifact(config2, sessionId, image, signal) {
28919
29151
  // src/authorization/workspace-directory.ts
28920
29152
  import { readdir, realpath as realpath8, stat as stat8 } from "node:fs/promises";
28921
29153
  import { homedir as homedir2 } from "node:os";
28922
- import { basename as basename3, dirname as dirname6, isAbsolute as isAbsolute9, join as join15, normalize as normalize3, relative as relative5 } from "node:path";
29154
+ import { basename as basename3, dirname as dirname6, isAbsolute as isAbsolute10, join as join16, normalize as normalize3, relative as relative5 } from "node:path";
28923
29155
  var WorkspaceDirectoryListing = class {
28924
29156
  directoryId;
28925
29157
  directoryLabel;
@@ -28971,7 +29203,7 @@ var WorkspaceDirectoryService = class {
28971
29203
  }
28972
29204
  if (id.startsWith("path-")) {
28973
29205
  const path2 = decodePath(id, "path-");
28974
- if (isAbsolute9(path2)) {
29206
+ if (isAbsolute10(path2)) {
28975
29207
  return path2;
28976
29208
  }
28977
29209
  }
@@ -28979,7 +29211,7 @@ var WorkspaceDirectoryService = class {
28979
29211
  };
28980
29212
  resolvePath = async (requested, signal) => {
28981
29213
  signal.throwIfAborted();
28982
- if (!isAbsolute9(requested) || requested.includes("\0") || normalize3(requested) !== requested) {
29214
+ if (!isAbsolute10(requested) || requested.includes("\0") || normalize3(requested) !== requested) {
28983
29215
  throw new LocalAuthorizationError("The local directory path is invalid");
28984
29216
  }
28985
29217
  try {
@@ -28987,7 +29219,7 @@ var WorkspaceDirectoryService = class {
28987
29219
  signal.throwIfAborted();
28988
29220
  const metadata = await stat8(target);
28989
29221
  signal.throwIfAborted();
28990
- if (!isAbsolute9(target) || normalize3(target) !== target || !metadata.isDirectory()) {
29222
+ if (!isAbsolute10(target) || normalize3(target) !== target || !metadata.isDirectory()) {
28991
29223
  throw new LocalAuthorizationError("The selected location is not a directory");
28992
29224
  }
28993
29225
  return target;
@@ -29003,7 +29235,7 @@ var WorkspaceDirectoryService = class {
29003
29235
  };
29004
29236
  label = (path2) => {
29005
29237
  const suffix = relative5(homedir2(), path2);
29006
- return suffix === "" ? "~" : !isAbsolute9(suffix) && suffix !== ".." && !suffix.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) ? `~/${suffix.replaceAll("\\", "/")}` : path2;
29238
+ return suffix === "" ? "~" : !isAbsolute10(suffix) && suffix !== ".." && !suffix.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) ? `~/${suffix.replaceAll("\\", "/")}` : path2;
29007
29239
  };
29008
29240
  identify = async (bindingId, requestedPath, signal) => {
29009
29241
  this.authorizeMachine(bindingId);
@@ -29033,7 +29265,7 @@ var WorkspaceDirectoryService = class {
29033
29265
  continue;
29034
29266
  }
29035
29267
  try {
29036
- const path2 = await this.resolvePath(join15(target, child.name), signal);
29268
+ const path2 = await this.resolvePath(join16(target, child.name), signal);
29037
29269
  entries.push({ directoryId: encodePath(path2), name: child.name });
29038
29270
  } catch (cause) {
29039
29271
  signal.throwIfAborted();
@@ -30905,7 +31137,7 @@ function botIpcSocketPath() {
30905
31137
  if (process.platform === "win32") {
30906
31138
  return `\\\\.\\pipe\\mobius-bot-${randomUUID6()}`;
30907
31139
  }
30908
- return join16("/tmp", `mobius-bot-${randomUUID6()}.sock`);
31140
+ return join17("/tmp", `mobius-bot-${randomUUID6()}.sock`);
30909
31141
  }
30910
31142
  var DaemonAcpObserver = class {
30911
31143
  #config;
@@ -31575,7 +31807,7 @@ async function executeSessionConfigure(publisher, socket, command, config2, dire
31575
31807
  reportOperationFailure(socket, command.requestId, command.sessionId, error61);
31576
31808
  }
31577
31809
  }
31578
- async function executePrompt(outbox, publisher, command, config2, directories, audit, sessions, attemptId, timer, signal) {
31810
+ async function executePrompt(outbox, publisher, command, config2, directories, audit, sessions, attemptId, activateAttempt, timer, signal) {
31579
31811
  const activities = new CoalescingDaemonActivityPublisher(timer, (activity) => {
31580
31812
  publisher.recordAttempt(command.sessionId, encodeDaemonActivity(command, activity), attemptId);
31581
31813
  });
@@ -31604,6 +31836,7 @@ async function executePrompt(outbox, publisher, command, config2, directories, a
31604
31836
  }),
31605
31837
  attemptId
31606
31838
  );
31839
+ activateAttempt();
31607
31840
  const attachments = await resolvePromptArtifacts(config2, command, signal);
31608
31841
  let stopReason;
31609
31842
  if (command.disposition === SessionPromptDisposition.Steer) {
@@ -31715,7 +31948,7 @@ function botExecutionAgent(agent, contextHandle, socketPath) {
31715
31948
  agent.capabilities
31716
31949
  );
31717
31950
  }
31718
- async function executeBotPrompt(outbox, publisher, command, config2, directories, audit, sessions, grants, contexts, applicator, ipc, attemptId, timer, signal) {
31951
+ async function executeBotPrompt(outbox, publisher, command, config2, directories, audit, sessions, grants, contexts, applicator, ipc, attemptId, activateAttempt, timer, signal) {
31719
31952
  const activities = new CoalescingDaemonActivityPublisher(timer, (activity) => {
31720
31953
  publisher.recordAttempt(command.sessionId, encodeDaemonActivity(command, activity), attemptId);
31721
31954
  });
@@ -31796,6 +32029,7 @@ async function executeBotPrompt(outbox, publisher, command, config2, directories
31796
32029
  }),
31797
32030
  attemptId
31798
32031
  );
32032
+ activateAttempt();
31799
32033
  const result = await sessions.runPrompt({
31800
32034
  additionalDirectories: resolved.additionalDirectories,
31801
32035
  agent,
@@ -31989,11 +32223,13 @@ async function runRelayConnection(config2, directories, audit, sessions, install
31989
32223
  }
31990
32224
  const turn = new ActiveDaemonTurn(command, receipt.attemptId);
31991
32225
  activeTurns.set(command.commandId, turn);
31992
- if (trackActiveAttempt) {
31993
- activeAttemptIds.set(command.sessionId, receipt.attemptId);
31994
- }
32226
+ const activateAttempt = () => {
32227
+ if (trackActiveAttempt) {
32228
+ activeAttemptIds.set(command.sessionId, receipt.attemptId);
32229
+ }
32230
+ };
31995
32231
  try {
31996
- await execute(receipt.attemptId, turn.signal);
32232
+ await execute(receipt.attemptId, activateAttempt, turn.signal);
31997
32233
  } finally {
31998
32234
  activeTurns.delete(command.commandId);
31999
32235
  if (activeAttemptIds.get(command.sessionId) === receipt.attemptId) {
@@ -32078,7 +32314,7 @@ async function runRelayConnection(config2, directories, audit, sessions, install
32078
32314
  delivery,
32079
32315
  command,
32080
32316
  true,
32081
- (attemptId, executionSignal) => executeBotPrompt(
32317
+ (attemptId, activateAttempt, executionSignal) => executeBotPrompt(
32082
32318
  outbox,
32083
32319
  publisher,
32084
32320
  command,
@@ -32091,6 +32327,7 @@ async function runRelayConnection(config2, directories, audit, sessions, install
32091
32327
  applicator,
32092
32328
  ipc,
32093
32329
  attemptId,
32330
+ activateAttempt,
32094
32331
  timer,
32095
32332
  executionSignal
32096
32333
  )
@@ -32103,7 +32340,7 @@ async function runRelayConnection(config2, directories, audit, sessions, install
32103
32340
  delivery,
32104
32341
  command,
32105
32342
  command.disposition !== SessionPromptDisposition.Steer,
32106
- (attemptId, executionSignal) => executePrompt(
32343
+ (attemptId, activateAttempt, executionSignal) => executePrompt(
32107
32344
  outbox,
32108
32345
  publisher,
32109
32346
  command,
@@ -32112,6 +32349,7 @@ async function runRelayConnection(config2, directories, audit, sessions, install
32112
32349
  audit,
32113
32350
  sessions,
32114
32351
  attemptId,
32352
+ activateAttempt,
32115
32353
  timer,
32116
32354
  executionSignal
32117
32355
  )
@@ -32613,7 +32851,6 @@ async function runRelayConnection(config2, directories, audit, sessions, install
32613
32851
  }
32614
32852
  const turn2 = new ActiveDaemonTurn(command2, receipt2.attemptId);
32615
32853
  activeTurns.set(command2.commandId, turn2);
32616
- activeAttemptIds.set(command2.sessionId, receipt2.attemptId);
32617
32854
  void executeBotPrompt(
32618
32855
  outbox,
32619
32856
  publisher,
@@ -32627,6 +32864,7 @@ async function runRelayConnection(config2, directories, audit, sessions, install
32627
32864
  applicator,
32628
32865
  ipc,
32629
32866
  receipt2.attemptId,
32867
+ () => activeAttemptIds.set(command2.sessionId, receipt2.attemptId),
32630
32868
  timer,
32631
32869
  turn2.signal
32632
32870
  ).catch((error61) => {
@@ -32653,9 +32891,6 @@ async function runRelayConnection(config2, directories, audit, sessions, install
32653
32891
  }
32654
32892
  const turn = new ActiveDaemonTurn(command, receipt.attemptId);
32655
32893
  activeTurns.set(command.commandId, turn);
32656
- if (command.disposition !== SessionPromptDisposition.Steer) {
32657
- activeAttemptIds.set(command.sessionId, receipt.attemptId);
32658
- }
32659
32894
  void executePrompt(
32660
32895
  outbox,
32661
32896
  publisher,
@@ -32665,6 +32900,11 @@ async function runRelayConnection(config2, directories, audit, sessions, install
32665
32900
  audit,
32666
32901
  sessions,
32667
32902
  receipt.attemptId,
32903
+ () => {
32904
+ if (command.disposition !== SessionPromptDisposition.Steer) {
32905
+ activeAttemptIds.set(command.sessionId, receipt.attemptId);
32906
+ }
32907
+ },
32668
32908
  timer,
32669
32909
  turn.signal
32670
32910
  ).catch((error61) => {
@@ -32851,7 +33091,7 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
32851
33091
 
32852
33092
  // src/runtime.ts
32853
33093
  import { mkdir as mkdir5, realpath as realpath9, stat as stat9 } from "node:fs/promises";
32854
- import { dirname as dirname8, join as join17, resolve as resolve5 } from "node:path";
33094
+ import { dirname as dirname8, join as join18, resolve as resolve5 } from "node:path";
32855
33095
  var APP_CREDENTIAL_PATTERN = /^mapp_[a-zA-Z0-9_-]{22}_[a-zA-Z0-9_-]{43}$/;
32856
33096
  var CONVERSATION_CREDENTIAL_PATTERN = /^mconv_[a-zA-Z0-9_-]{22}_[a-zA-Z0-9_-]{43}$/;
32857
33097
  var IDENTIFIER_PATTERN9 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
@@ -32916,7 +33156,7 @@ function loadMobiusRuntimeConnection(environment = process.env) {
32916
33156
  throw new MobiusRuntimeConfigurationError("MOBIUS_CHANNEL_ID is invalid");
32917
33157
  }
32918
33158
  return Object.freeze({
32919
- auditDatabasePath: environment["MOBIUS_AUDIT_DATABASE"]?.trim() || join17(readStateDirectory(environment), "audit", `${channelId}.sqlite`),
33159
+ auditDatabasePath: environment["MOBIUS_AUDIT_DATABASE"]?.trim() || join18(readStateDirectory(environment), "audit", `${channelId}.sqlite`),
32920
33160
  channelId,
32921
33161
  defaultWorkspace: loadDefaultWorkspace(environment),
32922
33162
  relayUrl: requiredEnvironmentValue(environment, "MOBIUS_RELAY_URL"),