@moxt-ai/mobius 0.0.13 → 0.0.14

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
@@ -2732,469 +2732,6 @@ var AuditStore = class {
2732
2732
 
2733
2733
  // src/config.ts
2734
2734
  import { join as join12 } from "node:path";
2735
- function loadDefaultWorkspace() {
2736
- const { MOBIUS_DEFAULT_WORKSPACE: configuredWorkspace } = process.env;
2737
- return configuredWorkspace ?? join12(readStateDirectory(), "workspace");
2738
- }
2739
- function createDaemonConfig(connection, agents = [], installableAgents = []) {
2740
- return {
2741
- agents,
2742
- defaultWorkspace: connection.defaultWorkspace,
2743
- auditDatabasePath: connection.auditDatabasePath,
2744
- bindingId: "workspace",
2745
- catalog: new LocalAgentCatalog(agents, installableAgents),
2746
- channelId: connection.channelId,
2747
- installableAgents,
2748
- relayUrl: connection.relayUrl
2749
- };
2750
- }
2751
-
2752
- // src/pairing/pair-local-machine.ts
2753
- import { randomUUID } from "node:crypto";
2754
- import {
2755
- mkdir as mkdir3,
2756
- open as open5,
2757
- realpath as realpath5,
2758
- rename as rename3,
2759
- stat as stat5,
2760
- writeFile as writeFile2
2761
- } from "node:fs/promises";
2762
- import { hostname } from "node:os";
2763
- import { basename, join as join13, resolve as resolve3 } from "node:path";
2764
- import { fetch as fetch2 } from "undici";
2765
- var PAIRING_TIMEOUT_MILLISECONDS = 2e4;
2766
- var PAIRING_CODE_PATTERN = /^[A-HJ-NP-Z2-9]{4}(?:-[A-HJ-NP-Z2-9]{4}){4}$/;
2767
- var IDENTIFIER_PATTERN = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
2768
- var TOKEN_PATTERN = /^[a-zA-Z0-9_-]{32,256}$/;
2769
- var MAX_CONNECTION_FILE_LENGTH = 16 * 1024;
2770
- var CLAIM_RESPONSE_KEYS = [
2771
- "channelId",
2772
- "daemonToken",
2773
- "runtimeId"
2774
- ];
2775
- var SAVED_CONNECTION_KEYS = [
2776
- "defaultWorkspace",
2777
- "channelId",
2778
- "daemonToken",
2779
- "relayOrigin"
2780
- ];
2781
- var PairingClientError = class extends Error {
2782
- code;
2783
- constructor(code, message, options = {}) {
2784
- super(message, options);
2785
- this.code = code;
2786
- this.name = "PairingClientError";
2787
- }
2788
- };
2789
- function isRecord4(value) {
2790
- return typeof value === "object" && value !== null && !Array.isArray(value);
2791
- }
2792
- function hasExactKeys(value, expectedKeys) {
2793
- const keys = Object.keys(value);
2794
- return keys.length === expectedKeys.length && expectedKeys.every((key) => Object.hasOwn(value, key));
2795
- }
2796
- function readSingleOption(arguments_, option) {
2797
- const values = [];
2798
- for (let index = 0; index < arguments_.length; index += 1) {
2799
- if (arguments_[index] !== option) {
2800
- continue;
2801
- }
2802
- const value = arguments_[index + 1];
2803
- if (value === void 0 || value.startsWith("--")) {
2804
- throw new PairingClientError(
2805
- "invalid_arguments",
2806
- `${option} requires a value`
2807
- );
2808
- }
2809
- values.push(value);
2810
- index += 1;
2811
- }
2812
- if (values.length !== 1) {
2813
- throw new PairingClientError(
2814
- "invalid_arguments",
2815
- `${option} must be provided exactly once`
2816
- );
2817
- }
2818
- return values[0] ?? "";
2819
- }
2820
- function assertKnownArguments(arguments_) {
2821
- for (let index = 0; index < arguments_.length; index += 2) {
2822
- const option = arguments_[index];
2823
- if (option !== "--url" && option !== "--code" && option !== "--workspace") {
2824
- throw new PairingClientError(
2825
- "invalid_arguments",
2826
- `Unknown pairing option: ${option ?? "missing option"}`
2827
- );
2828
- }
2829
- }
2830
- }
2831
- function parseRelayOrigin(value) {
2832
- let url2;
2833
- try {
2834
- url2 = new URL(value);
2835
- } catch (error61) {
2836
- throw new PairingClientError(
2837
- "invalid_relay_url",
2838
- "The relay URL is invalid",
2839
- { cause: error61 }
2840
- );
2841
- }
2842
- if (url2.protocol !== "https:" && url2.protocol !== "http:") {
2843
- throw new PairingClientError(
2844
- "invalid_relay_url",
2845
- "The relay URL must use http or https"
2846
- );
2847
- }
2848
- if (url2.username.length > 0 || url2.password.length > 0) {
2849
- throw new PairingClientError(
2850
- "invalid_relay_url",
2851
- "The relay URL cannot contain credentials"
2852
- );
2853
- }
2854
- if (url2.protocol === "http:" && url2.hostname !== "127.0.0.1" && url2.hostname !== "localhost") {
2855
- throw new PairingClientError(
2856
- "invalid_relay_url",
2857
- "A remote relay must use https"
2858
- );
2859
- }
2860
- url2.hash = "";
2861
- url2.pathname = "/";
2862
- url2.search = "";
2863
- return url2;
2864
- }
2865
- function parsePairingCode(value) {
2866
- const code = value.trim().toUpperCase();
2867
- if (!PAIRING_CODE_PATTERN.test(code)) {
2868
- throw new PairingClientError(
2869
- "invalid_pairing_code",
2870
- "The pairing code must match the code shown in the browser"
2871
- );
2872
- }
2873
- return code;
2874
- }
2875
- function parsePairCommand(arguments_) {
2876
- assertKnownArguments(arguments_);
2877
- return {
2878
- code: parsePairingCode(readSingleOption(arguments_, "--code")),
2879
- relayOrigin: parseRelayOrigin(readSingleOption(arguments_, "--url")),
2880
- workspace: arguments_.includes("--workspace") ? readSingleOption(arguments_, "--workspace") : loadDefaultWorkspace()
2881
- };
2882
- }
2883
- function parseChannelArgument(arguments_) {
2884
- if (arguments_.length !== 2 || arguments_[0] !== "--channel") {
2885
- throw new PairingClientError(
2886
- "invalid_arguments",
2887
- "Usage: mobius start --channel <channel-id>"
2888
- );
2889
- }
2890
- const channelId = arguments_[1] ?? "";
2891
- if (!IDENTIFIER_PATTERN.test(channelId)) {
2892
- throw new PairingClientError(
2893
- "invalid_channel_id",
2894
- "The saved channel ID is invalid"
2895
- );
2896
- }
2897
- return channelId;
2898
- }
2899
- async function resolveDefaultWorkspace(path2) {
2900
- const requestedWorkspace = resolve3(path2);
2901
- try {
2902
- await mkdir3(requestedWorkspace, { recursive: true, mode: 448 });
2903
- const defaultWorkspace = await realpath5(requestedWorkspace);
2904
- const metadata = await stat5(defaultWorkspace);
2905
- if (!metadata.isDirectory()) {
2906
- throw new PairingClientError(
2907
- "invalid_workspace",
2908
- "The default workspace is not a directory"
2909
- );
2910
- }
2911
- return defaultWorkspace;
2912
- } catch (error61) {
2913
- if (error61 instanceof PairingClientError) {
2914
- throw error61;
2915
- }
2916
- throw new PairingClientError(
2917
- "invalid_workspace",
2918
- "The default workspace cannot be resolved",
2919
- { cause: error61 }
2920
- );
2921
- }
2922
- }
2923
- async function readJsonResponse(response) {
2924
- if (response.headers.get("cf-mitigated") === "challenge") {
2925
- throw new PairingClientError(
2926
- "relay_challenge",
2927
- "Cloudflare is protecting this temporary preview. Claim the deployment or use an authenticated deployment, then pair again"
2928
- );
2929
- }
2930
- const encoded = await response.text();
2931
- try {
2932
- return JSON.parse(encoded);
2933
- } catch (error61) {
2934
- throw new PairingClientError(
2935
- "invalid_relay_response",
2936
- "The relay returned an invalid response",
2937
- { cause: error61 }
2938
- );
2939
- }
2940
- }
2941
- function readRelayError(value) {
2942
- if (isRecord4(value)) {
2943
- const error61 = value["error"];
2944
- if (isRecord4(error61)) {
2945
- const code = error61["code"];
2946
- const message = error61["message"];
2947
- if (typeof code === "string" && typeof message === "string") {
2948
- return new PairingClientError(code, message);
2949
- }
2950
- }
2951
- }
2952
- return new PairingClientError(
2953
- "pairing_failed",
2954
- "The relay could not pair this machine"
2955
- );
2956
- }
2957
- function decodeClaimResponse(value) {
2958
- if (!isRecord4(value) || !hasExactKeys(value, CLAIM_RESPONSE_KEYS)) {
2959
- throw new PairingClientError(
2960
- "invalid_relay_response",
2961
- "The relay returned an invalid pairing response"
2962
- );
2963
- }
2964
- const channelId = value["channelId"];
2965
- const daemonToken = value["daemonToken"];
2966
- const runtimeId = value["runtimeId"];
2967
- if (typeof channelId !== "string" || !IDENTIFIER_PATTERN.test(channelId) || typeof daemonToken !== "string" || !TOKEN_PATTERN.test(daemonToken) || typeof runtimeId !== "string" || !IDENTIFIER_PATTERN.test(runtimeId)) {
2968
- throw new PairingClientError(
2969
- "invalid_relay_response",
2970
- "The relay returned an invalid pairing response"
2971
- );
2972
- }
2973
- return { channelId, daemonToken, runtimeId };
2974
- }
2975
- async function claimPairing(options, defaultWorkspace, localAgents, installableAgents, signal) {
2976
- const agents = localAgents.map((agent) => ({
2977
- id: agent.id,
2978
- label: agent.label
2979
- }));
2980
- const endpoint = new URL("/mobius/api/pairings/claim", options.relayOrigin);
2981
- let response;
2982
- try {
2983
- response = await fetch2(endpoint, {
2984
- body: JSON.stringify({
2985
- agents,
2986
- installableAgents: installableAgents.map((agent) => ({
2987
- id: agent.id,
2988
- label: agent.label,
2989
- requiresLocalApproval: agent.requiresLocalApproval
2990
- })),
2991
- machineName: hostname(),
2992
- pairingCode: options.code,
2993
- workspaceName: basename(defaultWorkspace) || "Local workspace"
2994
- }),
2995
- dispatcher: environmentProxyDispatcher,
2996
- headers: { "content-type": "application/json" },
2997
- method: "POST",
2998
- signal: AbortSignal.any([
2999
- signal,
3000
- AbortSignal.timeout(PAIRING_TIMEOUT_MILLISECONDS)
3001
- ])
3002
- });
3003
- } catch (error61) {
3004
- throw new PairingClientError(
3005
- "relay_unavailable",
3006
- "The pairing relay could not be reached",
3007
- { cause: error61 }
3008
- );
3009
- }
3010
- const value = await readJsonResponse(response);
3011
- if (!response.ok) {
3012
- throw readRelayError(value);
3013
- }
3014
- return decodeClaimResponse(value);
3015
- }
3016
- async function persistConnection(channelId, relayOrigin, daemonToken, defaultWorkspace) {
3017
- const connectionsDirectory = join13(readStateDirectory(), "connections");
3018
- await mkdir3(connectionsDirectory, { mode: 448, recursive: true });
3019
- const connectionPath = join13(connectionsDirectory, `${channelId}.json`);
3020
- const temporaryPath = join13(
3021
- connectionsDirectory,
3022
- `.${channelId}.${randomUUID()}.tmp`
3023
- );
3024
- await writeFile2(
3025
- temporaryPath,
3026
- `${JSON.stringify(
3027
- {
3028
- defaultWorkspace,
3029
- channelId,
3030
- daemonToken,
3031
- relayOrigin: relayOrigin.toString()
3032
- },
3033
- null,
3034
- 2
3035
- )}
3036
- `,
3037
- { flag: "wx", mode: 384 }
3038
- );
3039
- await rename3(temporaryPath, connectionPath);
3040
- return connectionPath;
3041
- }
3042
- function decodeSavedConnection(value, expectedChannelId) {
3043
- if (!isRecord4(value) || !hasExactKeys(value, SAVED_CONNECTION_KEYS)) {
3044
- throw new PairingClientError(
3045
- "invalid_connection",
3046
- "The saved connection is invalid"
3047
- );
3048
- }
3049
- const defaultWorkspace = value["defaultWorkspace"];
3050
- const channelId = value["channelId"];
3051
- const daemonToken = value["daemonToken"];
3052
- const relayOrigin = value["relayOrigin"];
3053
- if (typeof defaultWorkspace !== "string" || typeof channelId !== "string" || channelId !== expectedChannelId || !IDENTIFIER_PATTERN.test(channelId) || typeof daemonToken !== "string" || !TOKEN_PATTERN.test(daemonToken) || typeof relayOrigin !== "string") {
3054
- throw new PairingClientError(
3055
- "invalid_connection",
3056
- "The saved connection is invalid"
3057
- );
3058
- }
3059
- return {
3060
- defaultWorkspace,
3061
- channelId,
3062
- daemonToken,
3063
- relayOrigin: parseRelayOrigin(relayOrigin)
3064
- };
3065
- }
3066
- async function readSavedConnection(channelId) {
3067
- const connectionPath = join13(
3068
- readStateDirectory(),
3069
- "connections",
3070
- `${channelId}.json`
3071
- );
3072
- let encoded = "";
3073
- const handle = await open5(connectionPath, "r");
3074
- try {
3075
- const metadata = await handle.stat();
3076
- if (!metadata.isFile() || metadata.size > MAX_CONNECTION_FILE_LENGTH) {
3077
- throw new PairingClientError(
3078
- "invalid_connection",
3079
- "The saved connection is invalid"
3080
- );
3081
- }
3082
- encoded = await handle.readFile({ encoding: "utf8" });
3083
- } finally {
3084
- await handle.close();
3085
- }
3086
- let value;
3087
- try {
3088
- value = JSON.parse(encoded);
3089
- } catch (error61) {
3090
- throw new PairingClientError(
3091
- "invalid_connection",
3092
- "The saved connection is invalid",
3093
- { cause: error61 }
3094
- );
3095
- }
3096
- const connection = decodeSavedConnection(value, channelId);
3097
- return {
3098
- defaultWorkspace: await resolveDefaultWorkspace(
3099
- connection.defaultWorkspace
3100
- ),
3101
- channelId: connection.channelId,
3102
- daemonToken: connection.daemonToken,
3103
- relayOrigin: connection.relayOrigin
3104
- };
3105
- }
3106
- function assertInventoryUsable(inventory) {
3107
- if (inventory.available.length + inventory.installable.length === 0) {
3108
- throw new PairingClientError(
3109
- "no_supported_agent",
3110
- "No supported Agent is ready or safely installable on this machine"
3111
- );
3112
- }
3113
- }
3114
- function buildPairedDaemon(connection, connectionPath, inventory) {
3115
- assertInventoryUsable(inventory);
3116
- const relayUrl = new URL(
3117
- `/mobius/api/channels/${encodeURIComponent(connection.channelId)}/daemon`,
3118
- connection.relayOrigin
3119
- );
3120
- relayUrl.protocol = relayUrl.protocol === "https:" ? "wss:" : "ws:";
3121
- relayUrl.searchParams.set("token", connection.daemonToken);
3122
- const auditDatabasePath = join13(
3123
- readStateDirectory(),
3124
- "audit",
3125
- `${connection.channelId}.sqlite`
3126
- );
3127
- return {
3128
- channelUrl: new URL(
3129
- `/channels/${encodeURIComponent(connection.channelId)}`,
3130
- connection.relayOrigin
3131
- ).toString(),
3132
- config: createDaemonConfig(
3133
- {
3134
- defaultWorkspace: connection.defaultWorkspace,
3135
- auditDatabasePath,
3136
- channelId: connection.channelId,
3137
- relayUrl
3138
- },
3139
- inventory.readyAgents(),
3140
- inventory.installable
3141
- ),
3142
- connectionPath
3143
- };
3144
- }
3145
- async function pairLocalMachine(arguments_, signal = new AbortController().signal) {
3146
- const options = parsePairCommand(arguments_);
3147
- const defaultWorkspace = await resolveDefaultWorkspace(options.workspace);
3148
- const inventory = await discoverLocalAgentInventory({
3149
- defaultWorkspace,
3150
- environment: process.env,
3151
- signal
3152
- });
3153
- assertInventoryUsable(inventory);
3154
- const agents = inventory.readyAgents();
3155
- const claim2 = await claimPairing(
3156
- options,
3157
- defaultWorkspace,
3158
- agents,
3159
- inventory.installable,
3160
- signal
3161
- );
3162
- const connectionPath = await persistConnection(
3163
- claim2.channelId,
3164
- options.relayOrigin,
3165
- claim2.daemonToken,
3166
- defaultWorkspace
3167
- );
3168
- return buildPairedDaemon(
3169
- {
3170
- defaultWorkspace,
3171
- channelId: claim2.channelId,
3172
- daemonToken: claim2.daemonToken,
3173
- relayOrigin: options.relayOrigin
3174
- },
3175
- connectionPath,
3176
- inventory
3177
- );
3178
- }
3179
- async function resumeLocalMachine(arguments_, signal = new AbortController().signal) {
3180
- const channelId = parseChannelArgument(arguments_);
3181
- const connectionPath = join13(
3182
- readStateDirectory(),
3183
- "connections",
3184
- `${channelId}.json`
3185
- );
3186
- const connection = await readSavedConnection(channelId);
3187
- const inventory = await discoverLocalAgentInventory({
3188
- defaultWorkspace: connection.defaultWorkspace,
3189
- environment: process.env,
3190
- signal
3191
- });
3192
- return buildPairedDaemon(connection, connectionPath, inventory);
3193
- }
3194
-
3195
- // src/run-daemon.ts
3196
- import { basename as basename3 } from "node:path";
3197
- import { styleText } from "node:util";
3198
2735
 
3199
2736
  // ../../node_modules/.pnpm/zod@4.5.4/node_modules/zod/v4/classic/external.js
3200
2737
  var external_exports = {};
@@ -3336,7 +2873,7 @@ __export(external_exports, {
3336
2873
  guid: () => guid2,
3337
2874
  hash: () => hash,
3338
2875
  hex: () => hex2,
3339
- hostname: () => hostname3,
2876
+ hostname: () => hostname2,
3340
2877
  httpUrl: () => httpUrl,
3341
2878
  includes: () => _includes,
3342
2879
  input: () => input,
@@ -5082,7 +4619,7 @@ __export(regexes_exports, {
5082
4619
  extendedDuration: () => extendedDuration,
5083
4620
  guid: () => guid,
5084
4621
  hex: () => hex,
5085
- hostname: () => hostname2,
4622
+ hostname: () => hostname,
5086
4623
  html5Email: () => html5Email,
5087
4624
  httpProtocol: () => httpProtocol,
5088
4625
  idnEmail: () => idnEmail,
@@ -5164,7 +4701,7 @@ var cidrv4 = /^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(25[0-5]
5164
4701
  var cidrv6 = /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:))\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$/;
5165
4702
  var base64 = /^$|^(?:[0-9a-zA-Z+/]{4})*(?:(?:[0-9a-zA-Z+/]{2}==)|(?:[0-9a-zA-Z+/]{3}=))?$/;
5166
4703
  var base64url = /^[A-Za-z0-9_-]*$/;
5167
- var hostname2 = /^(?=.{1,253}\.?$)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[-0-9a-zA-Z]{0,61}[0-9a-zA-Z])?)*\.?$/;
4704
+ var hostname = /^(?=.{1,253}\.?$)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[-0-9a-zA-Z]{0,61}[0-9a-zA-Z])?)*\.?$/;
5168
4705
  var domain = /^(?=.{1,253}$)([a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,63}$/;
5169
4706
  var httpProtocol = /^https?$/;
5170
4707
  var e164 = /^\+[1-9]\d{6,14}$/;
@@ -8214,7 +7751,7 @@ function bucketFor(state, inst) {
8214
7751
  return bucket;
8215
7752
  }
8216
7753
  var handoff;
8217
- var open6 = [];
7754
+ var open5 = [];
8218
7755
  var memo = {
8219
7756
  alloc(_inst, payload, empty) {
8220
7757
  const bucket = handoff;
@@ -8223,7 +7760,7 @@ var memo = {
8223
7760
  handoff = void 0;
8224
7761
  const entry = { value: empty, issues: null };
8225
7762
  bucket.set(payload.value, entry);
8226
- open6.push(entry);
7763
+ open5.push(entry);
8227
7764
  return empty;
8228
7765
  },
8229
7766
  guard(inst) {
@@ -8289,10 +7826,10 @@ var memo = {
8289
7826
  return payload;
8290
7827
  }
8291
7828
  handoff = bucket;
8292
- const depth = open6.length;
7829
+ const depth = open5.length;
8293
7830
  const result = base(payload, ctx);
8294
7831
  handoff = void 0;
8295
- const entry = open6.length > depth ? open6.pop() : void 0;
7832
+ const entry = open5.length > depth ? open5.pop() : void 0;
8296
7833
  if (result instanceof Promise) {
8297
7834
  return result.then((r) => {
8298
7835
  if (entry)
@@ -19676,7 +19213,7 @@ __export(schemas_exports2, {
19676
19213
  guid: () => guid2,
19677
19214
  hash: () => hash,
19678
19215
  hex: () => hex2,
19679
- hostname: () => hostname3,
19216
+ hostname: () => hostname2,
19680
19217
  httpUrl: () => httpUrl,
19681
19218
  instanceof: () => _instanceof,
19682
19219
  int: () => int,
@@ -20347,7 +19884,7 @@ var ZodCustomStringFormat = /* @__PURE__ */ $constructor("ZodCustomStringFormat"
20347
19884
  function stringFormat(format, fnOrRegex, _params = {}) {
20348
19885
  return _stringFormat(ZodCustomStringFormat, format, fnOrRegex, _params);
20349
19886
  }
20350
- function hostname3(_params) {
19887
+ function hostname2(_params) {
20351
19888
  return _stringFormat(ZodCustomStringFormat, "hostname", regexes_exports.hostname, _params);
20352
19889
  }
20353
19890
  function hex2(_params) {
@@ -22138,9 +21675,9 @@ var AGENT_INSTALL_PROGRESS_KIND = "agent.install.progress";
22138
21675
  var AGENT_INSTALL_COMPLETED_KIND = "agent.install.completed";
22139
21676
  var AGENT_INSTALL_FAILED_KIND = "agent.install.failed";
22140
21677
  var AGENT_INSTALL_CANCELLED_KIND = "agent.install.cancelled";
22141
- var IDENTIFIER_PATTERN2 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
21678
+ var IDENTIFIER_PATTERN = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
22142
21679
  var DIRECTORY_IDENTIFIER_PATTERN = /^[a-zA-Z0-9][a-zA-Z0-9_-]{0,2047}$/;
22143
- var IDENTIFIER = external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN2);
21680
+ var IDENTIFIER = external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN);
22144
21681
  var DIRECTORY_IDENTIFIER = external_exports.string().min(1).max(2048).regex(DIRECTORY_IDENTIFIER_PATTERN);
22145
21682
  var SHORT_TEXT = external_exports.string().max(500);
22146
21683
  var LONG_TEXT = external_exports.string().max(1e5);
@@ -22549,7 +22086,7 @@ var SESSION_COMPLETED_KIND = "session.completed";
22549
22086
  var SESSION_FAILED_KIND = "session.failed";
22550
22087
 
22551
22088
  // ../protocol/src/codecs/messages.ts
22552
- var IDENTIFIER_PATTERN3 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
22089
+ var IDENTIFIER_PATTERN2 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
22553
22090
  var DIRECTORY_IDENTIFIER_PATTERN2 = /^[a-zA-Z0-9][a-zA-Z0-9_-]{0,2047}$/;
22554
22091
  var MAX_PROMPT_LENGTH = 1e4;
22555
22092
  var MAX_PROMPT_ATTACHMENT_LENGTH = 6e6;
@@ -22581,7 +22118,7 @@ var ProtocolMessageError = class extends Error {
22581
22118
  this.name = "ProtocolMessageError";
22582
22119
  }
22583
22120
  };
22584
- function isRecord5(value) {
22121
+ function isRecord4(value) {
22585
22122
  return typeof value === "object" && value !== null && !Array.isArray(value);
22586
22123
  }
22587
22124
  function parseJson2(encoded) {
@@ -22593,7 +22130,7 @@ function parseJson2(encoded) {
22593
22130
  cause: error61
22594
22131
  });
22595
22132
  }
22596
- if (!isRecord5(value)) {
22133
+ if (!isRecord4(value)) {
22597
22134
  throw new ProtocolMessageError("Message must be a JSON object");
22598
22135
  }
22599
22136
  return value;
@@ -22677,7 +22214,7 @@ function readActivityContent(value) {
22677
22214
  }
22678
22215
  function readActivityDetail(value) {
22679
22216
  const field = value["detail"];
22680
- if (!isRecord5(field)) {
22217
+ if (!isRecord4(field)) {
22681
22218
  throw new ProtocolMessageError("Invalid activity detail field");
22682
22219
  }
22683
22220
  const kind = readString(field, "kind", 32);
@@ -22724,7 +22261,7 @@ function readActivityDetail(value) {
22724
22261
  }
22725
22262
  function readIdentifier(value, key) {
22726
22263
  const field = readString(value, key, 128);
22727
- if (!IDENTIFIER_PATTERN3.test(field)) {
22264
+ if (!IDENTIFIER_PATTERN2.test(field)) {
22728
22265
  throw new ProtocolMessageError(`Invalid identifier field: ${key}`);
22729
22266
  }
22730
22267
  return field;
@@ -22924,6 +22461,29 @@ function encodeSessionFailedEvent(message) {
22924
22461
  return JSON.stringify(decodeSessionFailedEvent(JSON.stringify(message)));
22925
22462
  }
22926
22463
 
22464
+ // ../protocol/src/mobius-api.ts
22465
+ var MOBIUS_API_PREFIX = "/mobius/api";
22466
+ var API_PREFIX_PATTERN = /^\/[a-zA-Z0-9._~-]+(?:\/[a-zA-Z0-9._~-]+)*$/;
22467
+ var MobiusApiConfigurationError = class extends Error {
22468
+ code = "invalid_api_prefix";
22469
+ constructor() {
22470
+ super("The Mobius API prefix must be an absolute path without parameters");
22471
+ this.name = "MobiusApiConfigurationError";
22472
+ }
22473
+ };
22474
+ function parseMobiusApiPrefix(value) {
22475
+ if (typeof value !== "string" || !API_PREFIX_PATTERN.test(value)) {
22476
+ throw new MobiusApiConfigurationError();
22477
+ }
22478
+ return value;
22479
+ }
22480
+ function mobiusApiPath(resourcePath, apiPrefix = MOBIUS_API_PREFIX) {
22481
+ return `${parseMobiusApiPrefix(apiPrefix)}${resourcePath}`;
22482
+ }
22483
+ function mobiusApiUrl(origin, resourcePath, apiPrefix = MOBIUS_API_PREFIX) {
22484
+ return new URL(mobiusApiPath(resourcePath, apiPrefix), origin);
22485
+ }
22486
+
22927
22487
  // ../protocol/src/session-history.ts
22928
22488
  var SESSION_HISTORY_CHARACTER_LIMIT = 256e3;
22929
22489
  var SESSION_HISTORY_MESSAGE_LIMIT = 1e3;
@@ -23083,10 +22643,10 @@ var encodeNativeSessionResult = (value) => JSON.stringify(nativeSessionResultSch
23083
22643
  var decodeNativeSessionCancel = (encoded) => decode4(nativeSessionCancelSchema, encoded);
23084
22644
 
23085
22645
  // ../protocol/src/resource-model.ts
23086
- var IDENTIFIER_PATTERN4 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
22646
+ var IDENTIFIER_PATTERN3 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
23087
22647
  var DECIMAL_SEQUENCE_PATTERN = /^(?:0|[1-9][0-9]*)$/;
23088
22648
  var SHA256_PATTERN = /^[a-f0-9]{64}$/;
23089
- var identifierSchema = external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN4);
22649
+ var identifierSchema = external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN3);
23090
22650
  var timestampSchema = external_exports.string().datetime({ offset: true });
23091
22651
  var decimalSequenceSchema = external_exports.string().min(1).max(40).regex(DECIMAL_SEQUENCE_PATTERN);
23092
22652
  var digestSchema = external_exports.string().length(64).regex(SHA256_PATTERN);
@@ -23572,13 +23132,13 @@ var commandReceiptSchema = external_exports.strictObject({
23572
23132
  var SESSION_EVENT_KIND = "session.event";
23573
23133
  var SESSION_EVENT_ACK_KIND = "session.event.ack";
23574
23134
  var SESSION_EVENT_COMMITTED_KIND = "session.event.committed";
23575
- var IDENTIFIER_PATTERN5 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
23135
+ var IDENTIFIER_PATTERN4 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
23576
23136
  var CURSOR_PATTERN = /^[A-Za-z0-9_-]{1,512}$/;
23577
23137
  var MAX_RECORDED_EVENT_LENGTH = 8 * 1024 * 1024;
23578
23138
  var DECIMAL_SEQUENCE_PATTERN2 = /^(?:0|[1-9][0-9]*)$/;
23579
23139
  var eventSourceSchema = external_exports.discriminatedUnion("kind", [
23580
23140
  external_exports.strictObject({
23581
- attemptId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN5),
23141
+ attemptId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN4),
23582
23142
  kind: external_exports.literal("attempt"),
23583
23143
  sourceSeq: external_exports.string().min(1).max(40).regex(DECIMAL_SEQUENCE_PATTERN2)
23584
23144
  }).readonly(),
@@ -23588,58 +23148,521 @@ var eventSourceSchema = external_exports.discriminatedUnion("kind", [
23588
23148
  }).readonly()
23589
23149
  ]);
23590
23150
  var eventEnvelopeSchema = external_exports.strictObject({
23591
- eventId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN5),
23151
+ eventId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN4),
23592
23152
  kind: external_exports.literal(SESSION_EVENT_KIND),
23593
23153
  payload: external_exports.string().min(2).max(MAX_RECORDED_EVENT_LENGTH),
23594
- sessionId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN5),
23154
+ sessionId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN4),
23595
23155
  source: eventSourceSchema
23596
23156
  }).readonly();
23597
23157
  var committedEventSchema = external_exports.strictObject({
23598
23158
  cursor: external_exports.string().min(1).max(512).regex(CURSOR_PATTERN),
23599
- eventId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN5),
23159
+ eventId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN4),
23600
23160
  kind: external_exports.literal(SESSION_EVENT_COMMITTED_KIND),
23601
23161
  payload: external_exports.string().min(2).max(MAX_RECORDED_EVENT_LENGTH),
23602
23162
  recordedAt: external_exports.string().datetime({ offset: true }),
23603
23163
  sequence: external_exports.string().min(1).max(40).regex(DECIMAL_SEQUENCE_PATTERN2),
23604
- sessionId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN5),
23164
+ sessionId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN4),
23605
23165
  source: eventSourceSchema
23606
23166
  }).readonly();
23607
23167
  var eventAcknowledgementSchema = external_exports.strictObject({
23608
23168
  cursor: external_exports.string().min(1).max(512).regex(CURSOR_PATTERN),
23609
23169
  duplicate: external_exports.boolean(),
23610
- eventId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN5),
23170
+ eventId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN4),
23611
23171
  kind: external_exports.literal(SESSION_EVENT_ACK_KIND),
23612
23172
  sequence: external_exports.string().min(1).max(40).regex(DECIMAL_SEQUENCE_PATTERN2),
23613
- sessionId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN5)
23173
+ sessionId: external_exports.string().min(1).max(128).regex(IDENTIFIER_PATTERN4)
23614
23174
  }).readonly();
23615
23175
  function decode5(encoded, schema) {
23616
23176
  let value;
23617
23177
  try {
23618
23178
  value = JSON.parse(encoded);
23619
- } catch (cause) {
23620
- throw new ProtocolMessageError("Message is not valid JSON", { cause });
23621
- }
23622
- const decoded = schema.safeParse(value);
23623
- if (!decoded.success) {
23624
- throw new ProtocolMessageError("Message does not match its schema", {
23625
- cause: decoded.error
23626
- });
23179
+ } catch (cause) {
23180
+ throw new ProtocolMessageError("Message is not valid JSON", { cause });
23181
+ }
23182
+ const decoded = schema.safeParse(value);
23183
+ if (!decoded.success) {
23184
+ throw new ProtocolMessageError("Message does not match its schema", {
23185
+ cause: decoded.error
23186
+ });
23187
+ }
23188
+ return decoded.data;
23189
+ }
23190
+ var encode4 = (message, schema) => {
23191
+ const decoded = schema.safeParse(message);
23192
+ if (!decoded.success) {
23193
+ throw new ProtocolMessageError("Message does not match its schema", {
23194
+ cause: decoded.error
23195
+ });
23196
+ }
23197
+ return JSON.stringify(decoded.data);
23198
+ };
23199
+ var encodeSessionEventEnvelope = (message) => encode4(message, eventEnvelopeSchema);
23200
+ var decodeSessionEventAcknowledgement = (encoded) => decode5(encoded, eventAcknowledgementSchema);
23201
+
23202
+ // src/config.ts
23203
+ function loadDefaultWorkspace() {
23204
+ const { MOBIUS_DEFAULT_WORKSPACE: configuredWorkspace } = process.env;
23205
+ return configuredWorkspace ?? join12(readStateDirectory(), "workspace");
23206
+ }
23207
+ function createDaemonConfig(connection, agents = [], installableAgents = []) {
23208
+ return {
23209
+ agents,
23210
+ defaultWorkspace: connection.defaultWorkspace,
23211
+ auditDatabasePath: connection.auditDatabasePath,
23212
+ bindingId: "workspace",
23213
+ catalog: new LocalAgentCatalog(agents, installableAgents),
23214
+ channelId: connection.channelId,
23215
+ installableAgents,
23216
+ relayUrl: connection.relayUrl
23217
+ };
23218
+ }
23219
+
23220
+ // src/pairing/pair-local-machine.ts
23221
+ import { randomUUID } from "node:crypto";
23222
+ import {
23223
+ mkdir as mkdir3,
23224
+ open as open6,
23225
+ realpath as realpath5,
23226
+ rename as rename3,
23227
+ stat as stat5,
23228
+ writeFile as writeFile2
23229
+ } from "node:fs/promises";
23230
+ import { hostname as hostname3 } from "node:os";
23231
+ import { basename, join as join13, resolve as resolve3 } from "node:path";
23232
+ import { fetch as fetch2 } from "undici";
23233
+ var PAIRING_TIMEOUT_MILLISECONDS = 2e4;
23234
+ var PAIRING_CODE_PATTERN = /^[A-HJ-NP-Z2-9]{4}(?:-[A-HJ-NP-Z2-9]{4}){4}$/;
23235
+ var IDENTIFIER_PATTERN5 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
23236
+ var TOKEN_PATTERN = /^[a-zA-Z0-9_-]{32,256}$/;
23237
+ var MAX_CONNECTION_FILE_LENGTH = 16 * 1024;
23238
+ var CLAIM_RESPONSE_KEYS = [
23239
+ "channelId",
23240
+ "daemonToken",
23241
+ "runtimeId"
23242
+ ];
23243
+ var SAVED_CONNECTION_KEYS = [
23244
+ "defaultWorkspace",
23245
+ "channelId",
23246
+ "daemonToken",
23247
+ "relayOrigin"
23248
+ ];
23249
+ var PairingClientError = class extends Error {
23250
+ code;
23251
+ constructor(code, message, options = {}) {
23252
+ super(message, options);
23253
+ this.code = code;
23254
+ this.name = "PairingClientError";
23255
+ }
23256
+ };
23257
+ function isRecord5(value) {
23258
+ return typeof value === "object" && value !== null && !Array.isArray(value);
23259
+ }
23260
+ function hasExactKeys(value, expectedKeys) {
23261
+ const keys = Object.keys(value);
23262
+ return keys.length === expectedKeys.length && expectedKeys.every((key) => Object.hasOwn(value, key));
23263
+ }
23264
+ function readSingleOption(arguments_, option) {
23265
+ const values = [];
23266
+ for (let index = 0; index < arguments_.length; index += 1) {
23267
+ if (arguments_[index] !== option) {
23268
+ continue;
23269
+ }
23270
+ const value = arguments_[index + 1];
23271
+ if (value === void 0 || value.startsWith("--")) {
23272
+ throw new PairingClientError(
23273
+ "invalid_arguments",
23274
+ `${option} requires a value`
23275
+ );
23276
+ }
23277
+ values.push(value);
23278
+ index += 1;
23279
+ }
23280
+ if (values.length !== 1) {
23281
+ throw new PairingClientError(
23282
+ "invalid_arguments",
23283
+ `${option} must be provided exactly once`
23284
+ );
23285
+ }
23286
+ return values[0] ?? "";
23287
+ }
23288
+ function assertKnownArguments(arguments_) {
23289
+ for (let index = 0; index < arguments_.length; index += 2) {
23290
+ const option = arguments_[index];
23291
+ if (option !== "--url" && option !== "--code" && option !== "--workspace") {
23292
+ throw new PairingClientError(
23293
+ "invalid_arguments",
23294
+ `Unknown pairing option: ${option ?? "missing option"}`
23295
+ );
23296
+ }
23297
+ }
23298
+ }
23299
+ function parseRelayOrigin(value) {
23300
+ let url2;
23301
+ try {
23302
+ url2 = new URL(value);
23303
+ } catch (error61) {
23304
+ throw new PairingClientError(
23305
+ "invalid_relay_url",
23306
+ "The relay URL is invalid",
23307
+ { cause: error61 }
23308
+ );
23309
+ }
23310
+ if (url2.protocol !== "https:" && url2.protocol !== "http:") {
23311
+ throw new PairingClientError(
23312
+ "invalid_relay_url",
23313
+ "The relay URL must use http or https"
23314
+ );
23315
+ }
23316
+ if (url2.username.length > 0 || url2.password.length > 0) {
23317
+ throw new PairingClientError(
23318
+ "invalid_relay_url",
23319
+ "The relay URL cannot contain credentials"
23320
+ );
23321
+ }
23322
+ if (url2.protocol === "http:" && url2.hostname !== "127.0.0.1" && url2.hostname !== "localhost") {
23323
+ throw new PairingClientError(
23324
+ "invalid_relay_url",
23325
+ "A remote relay must use https"
23326
+ );
23327
+ }
23328
+ url2.hash = "";
23329
+ url2.pathname = "/";
23330
+ url2.search = "";
23331
+ return url2;
23332
+ }
23333
+ function parsePairingCode(value) {
23334
+ const code = value.trim().toUpperCase();
23335
+ if (!PAIRING_CODE_PATTERN.test(code)) {
23336
+ throw new PairingClientError(
23337
+ "invalid_pairing_code",
23338
+ "The pairing code must match the code shown in the browser"
23339
+ );
23340
+ }
23341
+ return code;
23342
+ }
23343
+ function parsePairCommand(arguments_) {
23344
+ assertKnownArguments(arguments_);
23345
+ return {
23346
+ code: parsePairingCode(readSingleOption(arguments_, "--code")),
23347
+ relayOrigin: parseRelayOrigin(readSingleOption(arguments_, "--url")),
23348
+ workspace: arguments_.includes("--workspace") ? readSingleOption(arguments_, "--workspace") : loadDefaultWorkspace()
23349
+ };
23350
+ }
23351
+ function parseChannelArgument(arguments_) {
23352
+ if (arguments_.length !== 2 || arguments_[0] !== "--channel") {
23353
+ throw new PairingClientError(
23354
+ "invalid_arguments",
23355
+ "Usage: mobius start --channel <channel-id>"
23356
+ );
23357
+ }
23358
+ const channelId = arguments_[1] ?? "";
23359
+ if (!IDENTIFIER_PATTERN5.test(channelId)) {
23360
+ throw new PairingClientError(
23361
+ "invalid_channel_id",
23362
+ "The saved channel ID is invalid"
23363
+ );
23364
+ }
23365
+ return channelId;
23366
+ }
23367
+ async function resolveDefaultWorkspace(path2) {
23368
+ const requestedWorkspace = resolve3(path2);
23369
+ try {
23370
+ await mkdir3(requestedWorkspace, { recursive: true, mode: 448 });
23371
+ const defaultWorkspace = await realpath5(requestedWorkspace);
23372
+ const metadata = await stat5(defaultWorkspace);
23373
+ if (!metadata.isDirectory()) {
23374
+ throw new PairingClientError(
23375
+ "invalid_workspace",
23376
+ "The default workspace is not a directory"
23377
+ );
23378
+ }
23379
+ return defaultWorkspace;
23380
+ } catch (error61) {
23381
+ if (error61 instanceof PairingClientError) {
23382
+ throw error61;
23383
+ }
23384
+ throw new PairingClientError(
23385
+ "invalid_workspace",
23386
+ "The default workspace cannot be resolved",
23387
+ { cause: error61 }
23388
+ );
23389
+ }
23390
+ }
23391
+ async function readJsonResponse(response) {
23392
+ if (response.headers.get("cf-mitigated") === "challenge") {
23393
+ throw new PairingClientError(
23394
+ "relay_challenge",
23395
+ "Cloudflare is protecting this temporary preview. Claim the deployment or use an authenticated deployment, then pair again"
23396
+ );
23397
+ }
23398
+ const encoded = await response.text();
23399
+ try {
23400
+ return JSON.parse(encoded);
23401
+ } catch (error61) {
23402
+ throw new PairingClientError(
23403
+ "invalid_relay_response",
23404
+ "The relay returned an invalid response",
23405
+ { cause: error61 }
23406
+ );
23407
+ }
23408
+ }
23409
+ function readRelayError(value) {
23410
+ if (isRecord5(value)) {
23411
+ const error61 = value["error"];
23412
+ if (isRecord5(error61)) {
23413
+ const code = error61["code"];
23414
+ const message = error61["message"];
23415
+ if (typeof code === "string" && typeof message === "string") {
23416
+ return new PairingClientError(code, message);
23417
+ }
23418
+ }
23419
+ }
23420
+ return new PairingClientError(
23421
+ "pairing_failed",
23422
+ "The relay could not pair this machine"
23423
+ );
23424
+ }
23425
+ function decodeClaimResponse(value) {
23426
+ if (!isRecord5(value) || !hasExactKeys(value, CLAIM_RESPONSE_KEYS)) {
23427
+ throw new PairingClientError(
23428
+ "invalid_relay_response",
23429
+ "The relay returned an invalid pairing response"
23430
+ );
23431
+ }
23432
+ const channelId = value["channelId"];
23433
+ const daemonToken = value["daemonToken"];
23434
+ const runtimeId = value["runtimeId"];
23435
+ if (typeof channelId !== "string" || !IDENTIFIER_PATTERN5.test(channelId) || typeof daemonToken !== "string" || !TOKEN_PATTERN.test(daemonToken) || typeof runtimeId !== "string" || !IDENTIFIER_PATTERN5.test(runtimeId)) {
23436
+ throw new PairingClientError(
23437
+ "invalid_relay_response",
23438
+ "The relay returned an invalid pairing response"
23439
+ );
23440
+ }
23441
+ return { channelId, daemonToken, runtimeId };
23442
+ }
23443
+ async function claimPairing(options, defaultWorkspace, localAgents, installableAgents, signal) {
23444
+ const agents = localAgents.map((agent) => ({
23445
+ id: agent.id,
23446
+ label: agent.label
23447
+ }));
23448
+ const endpoint = mobiusApiUrl(options.relayOrigin, "/pairings/claim");
23449
+ let response;
23450
+ try {
23451
+ response = await fetch2(endpoint, {
23452
+ body: JSON.stringify({
23453
+ agents,
23454
+ installableAgents: installableAgents.map((agent) => ({
23455
+ id: agent.id,
23456
+ label: agent.label,
23457
+ requiresLocalApproval: agent.requiresLocalApproval
23458
+ })),
23459
+ machineName: hostname3(),
23460
+ pairingCode: options.code,
23461
+ workspaceName: basename(defaultWorkspace) || "Local workspace"
23462
+ }),
23463
+ dispatcher: environmentProxyDispatcher,
23464
+ headers: { "content-type": "application/json" },
23465
+ method: "POST",
23466
+ signal: AbortSignal.any([
23467
+ signal,
23468
+ AbortSignal.timeout(PAIRING_TIMEOUT_MILLISECONDS)
23469
+ ])
23470
+ });
23471
+ } catch (error61) {
23472
+ throw new PairingClientError(
23473
+ "relay_unavailable",
23474
+ "The pairing relay could not be reached",
23475
+ { cause: error61 }
23476
+ );
23477
+ }
23478
+ const value = await readJsonResponse(response);
23479
+ if (!response.ok) {
23480
+ throw readRelayError(value);
23481
+ }
23482
+ return decodeClaimResponse(value);
23483
+ }
23484
+ async function persistConnection(channelId, relayOrigin, daemonToken, defaultWorkspace) {
23485
+ const connectionsDirectory = join13(readStateDirectory(), "connections");
23486
+ await mkdir3(connectionsDirectory, { mode: 448, recursive: true });
23487
+ const connectionPath = join13(connectionsDirectory, `${channelId}.json`);
23488
+ const temporaryPath = join13(
23489
+ connectionsDirectory,
23490
+ `.${channelId}.${randomUUID()}.tmp`
23491
+ );
23492
+ await writeFile2(
23493
+ temporaryPath,
23494
+ `${JSON.stringify(
23495
+ {
23496
+ defaultWorkspace,
23497
+ channelId,
23498
+ daemonToken,
23499
+ relayOrigin: relayOrigin.toString()
23500
+ },
23501
+ null,
23502
+ 2
23503
+ )}
23504
+ `,
23505
+ { flag: "wx", mode: 384 }
23506
+ );
23507
+ await rename3(temporaryPath, connectionPath);
23508
+ return connectionPath;
23509
+ }
23510
+ function decodeSavedConnection(value, expectedChannelId) {
23511
+ if (!isRecord5(value) || !hasExactKeys(value, SAVED_CONNECTION_KEYS)) {
23512
+ throw new PairingClientError(
23513
+ "invalid_connection",
23514
+ "The saved connection is invalid"
23515
+ );
23516
+ }
23517
+ const defaultWorkspace = value["defaultWorkspace"];
23518
+ const channelId = value["channelId"];
23519
+ const daemonToken = value["daemonToken"];
23520
+ const relayOrigin = value["relayOrigin"];
23521
+ if (typeof defaultWorkspace !== "string" || typeof channelId !== "string" || channelId !== expectedChannelId || !IDENTIFIER_PATTERN5.test(channelId) || typeof daemonToken !== "string" || !TOKEN_PATTERN.test(daemonToken) || typeof relayOrigin !== "string") {
23522
+ throw new PairingClientError(
23523
+ "invalid_connection",
23524
+ "The saved connection is invalid"
23525
+ );
23526
+ }
23527
+ return {
23528
+ defaultWorkspace,
23529
+ channelId,
23530
+ daemonToken,
23531
+ relayOrigin: parseRelayOrigin(relayOrigin)
23532
+ };
23533
+ }
23534
+ async function readSavedConnection(channelId) {
23535
+ const connectionPath = join13(
23536
+ readStateDirectory(),
23537
+ "connections",
23538
+ `${channelId}.json`
23539
+ );
23540
+ let encoded = "";
23541
+ const handle = await open6(connectionPath, "r");
23542
+ try {
23543
+ const metadata = await handle.stat();
23544
+ if (!metadata.isFile() || metadata.size > MAX_CONNECTION_FILE_LENGTH) {
23545
+ throw new PairingClientError(
23546
+ "invalid_connection",
23547
+ "The saved connection is invalid"
23548
+ );
23549
+ }
23550
+ encoded = await handle.readFile({ encoding: "utf8" });
23551
+ } finally {
23552
+ await handle.close();
23553
+ }
23554
+ let value;
23555
+ try {
23556
+ value = JSON.parse(encoded);
23557
+ } catch (error61) {
23558
+ throw new PairingClientError(
23559
+ "invalid_connection",
23560
+ "The saved connection is invalid",
23561
+ { cause: error61 }
23562
+ );
23627
23563
  }
23628
- return decoded.data;
23564
+ const connection = decodeSavedConnection(value, channelId);
23565
+ return {
23566
+ defaultWorkspace: await resolveDefaultWorkspace(
23567
+ connection.defaultWorkspace
23568
+ ),
23569
+ channelId: connection.channelId,
23570
+ daemonToken: connection.daemonToken,
23571
+ relayOrigin: connection.relayOrigin
23572
+ };
23629
23573
  }
23630
- var encode4 = (message, schema) => {
23631
- const decoded = schema.safeParse(message);
23632
- if (!decoded.success) {
23633
- throw new ProtocolMessageError("Message does not match its schema", {
23634
- cause: decoded.error
23635
- });
23574
+ function assertInventoryUsable(inventory) {
23575
+ if (inventory.available.length + inventory.installable.length === 0) {
23576
+ throw new PairingClientError(
23577
+ "no_supported_agent",
23578
+ "No supported Agent is ready or safely installable on this machine"
23579
+ );
23636
23580
  }
23637
- return JSON.stringify(decoded.data);
23638
- };
23639
- var encodeSessionEventEnvelope = (message) => encode4(message, eventEnvelopeSchema);
23640
- var decodeSessionEventAcknowledgement = (encoded) => decode5(encoded, eventAcknowledgementSchema);
23581
+ }
23582
+ function buildPairedDaemon(connection, connectionPath, inventory) {
23583
+ assertInventoryUsable(inventory);
23584
+ const relayUrl = mobiusApiUrl(
23585
+ connection.relayOrigin,
23586
+ `/channels/${encodeURIComponent(connection.channelId)}/daemon`
23587
+ );
23588
+ relayUrl.protocol = relayUrl.protocol === "https:" ? "wss:" : "ws:";
23589
+ relayUrl.searchParams.set("token", connection.daemonToken);
23590
+ const auditDatabasePath = join13(
23591
+ readStateDirectory(),
23592
+ "audit",
23593
+ `${connection.channelId}.sqlite`
23594
+ );
23595
+ return {
23596
+ channelUrl: new URL(
23597
+ `/channels/${encodeURIComponent(connection.channelId)}`,
23598
+ connection.relayOrigin
23599
+ ).toString(),
23600
+ config: createDaemonConfig(
23601
+ {
23602
+ defaultWorkspace: connection.defaultWorkspace,
23603
+ auditDatabasePath,
23604
+ channelId: connection.channelId,
23605
+ relayUrl
23606
+ },
23607
+ inventory.readyAgents(),
23608
+ inventory.installable
23609
+ ),
23610
+ connectionPath
23611
+ };
23612
+ }
23613
+ async function pairLocalMachine(arguments_, signal = new AbortController().signal) {
23614
+ const options = parsePairCommand(arguments_);
23615
+ const defaultWorkspace = await resolveDefaultWorkspace(options.workspace);
23616
+ const inventory = await discoverLocalAgentInventory({
23617
+ defaultWorkspace,
23618
+ environment: process.env,
23619
+ signal
23620
+ });
23621
+ assertInventoryUsable(inventory);
23622
+ const agents = inventory.readyAgents();
23623
+ const claim2 = await claimPairing(
23624
+ options,
23625
+ defaultWorkspace,
23626
+ agents,
23627
+ inventory.installable,
23628
+ signal
23629
+ );
23630
+ const connectionPath = await persistConnection(
23631
+ claim2.channelId,
23632
+ options.relayOrigin,
23633
+ claim2.daemonToken,
23634
+ defaultWorkspace
23635
+ );
23636
+ return buildPairedDaemon(
23637
+ {
23638
+ defaultWorkspace,
23639
+ channelId: claim2.channelId,
23640
+ daemonToken: claim2.daemonToken,
23641
+ relayOrigin: options.relayOrigin
23642
+ },
23643
+ connectionPath,
23644
+ inventory
23645
+ );
23646
+ }
23647
+ async function resumeLocalMachine(arguments_, signal = new AbortController().signal) {
23648
+ const channelId = parseChannelArgument(arguments_);
23649
+ const connectionPath = join13(
23650
+ readStateDirectory(),
23651
+ "connections",
23652
+ `${channelId}.json`
23653
+ );
23654
+ const connection = await readSavedConnection(channelId);
23655
+ const inventory = await discoverLocalAgentInventory({
23656
+ defaultWorkspace: connection.defaultWorkspace,
23657
+ environment: process.env,
23658
+ signal
23659
+ });
23660
+ return buildPairedDaemon(connection, connectionPath, inventory);
23661
+ }
23641
23662
 
23642
23663
  // src/run-daemon.ts
23664
+ import { basename as basename3 } from "node:path";
23665
+ import { styleText } from "node:util";
23643
23666
  import { WebSocket as WebSocket2 } from "undici";
23644
23667
 
23645
23668
  // src/acp/session-manager.ts