@moxt-ai/mobius 0.0.12 → 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 +566 -513
- package/dist/cli.js.map +4 -4
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +2 -1
- package/dist/config.js.map +1 -1
- package/dist/index.js +719 -666
- package/dist/index.js.map +4 -4
- package/dist/pairing/pair-local-machine.d.ts.map +1 -1
- package/dist/pairing/pair-local-machine.js +3 -2
- package/dist/pairing/pair-local-machine.js.map +1 -1
- package/dist/run-daemon.d.ts.map +1 -1
- package/dist/run-daemon.js +34 -5
- package/dist/run-daemon.js.map +1 -1
- package/package.json +1 -1
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: () =>
|
|
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: () =>
|
|
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
|
|
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
|
|
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
|
-
|
|
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 =
|
|
7829
|
+
const depth = open5.length;
|
|
8293
7830
|
const result = base(payload, ctx);
|
|
8294
7831
|
handoff = void 0;
|
|
8295
|
-
const entry =
|
|
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: () =>
|
|
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
|
|
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
|
|
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(
|
|
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
|
|
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
|
|
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 (!
|
|
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 (!
|
|
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 (!
|
|
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
|
|
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(
|
|
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
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
23631
|
-
|
|
23632
|
-
|
|
23633
|
-
|
|
23634
|
-
|
|
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
|
-
|
|
23638
|
-
|
|
23639
|
-
|
|
23640
|
-
|
|
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
|
|
@@ -29570,6 +29593,28 @@ function waitForRelayRetry(signal, timer) {
|
|
|
29570
29593
|
signal.addEventListener("abort", finish, { once: true });
|
|
29571
29594
|
});
|
|
29572
29595
|
}
|
|
29596
|
+
async function publishAgentCatalogUntilAvailable(config2, signal, timer) {
|
|
29597
|
+
try {
|
|
29598
|
+
await publishAgentCatalog(config2, signal);
|
|
29599
|
+
return;
|
|
29600
|
+
} catch {
|
|
29601
|
+
if (signal.aborted) {
|
|
29602
|
+
return;
|
|
29603
|
+
}
|
|
29604
|
+
console.warn("Mobius daemon is waiting to publish its Agent catalog");
|
|
29605
|
+
}
|
|
29606
|
+
while (!signal.aborted) {
|
|
29607
|
+
await waitForRelayRetry(signal, timer);
|
|
29608
|
+
try {
|
|
29609
|
+
await publishAgentCatalog(config2, signal);
|
|
29610
|
+
return;
|
|
29611
|
+
} catch {
|
|
29612
|
+
if (signal.aborted) {
|
|
29613
|
+
return;
|
|
29614
|
+
}
|
|
29615
|
+
}
|
|
29616
|
+
}
|
|
29617
|
+
}
|
|
29573
29618
|
async function runRelayConnection(config2, directories, audit, sessions, installations, installationObserver, nativeSessions, outbox, onConnected, signal, timer) {
|
|
29574
29619
|
const relayUrl = new URL(config2.relayUrl);
|
|
29575
29620
|
relayUrl.searchParams.set("liveness", "1");
|
|
@@ -30027,10 +30072,14 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
|
|
|
30027
30072
|
`
|
|
30028
30073
|
);
|
|
30029
30074
|
};
|
|
30075
|
+
const catalogPublication = publishAgentCatalogUntilAvailable(
|
|
30076
|
+
config2,
|
|
30077
|
+
signal,
|
|
30078
|
+
timer
|
|
30079
|
+
);
|
|
30030
30080
|
try {
|
|
30031
30081
|
while (!signal.aborted) {
|
|
30032
30082
|
try {
|
|
30033
|
-
await publishAgentCatalog(config2, signal);
|
|
30034
30083
|
await runRelayConnection(
|
|
30035
30084
|
config2,
|
|
30036
30085
|
directories,
|
|
@@ -30058,15 +30107,19 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
|
|
|
30058
30107
|
}
|
|
30059
30108
|
} finally {
|
|
30060
30109
|
try {
|
|
30061
|
-
await
|
|
30110
|
+
await catalogPublication;
|
|
30062
30111
|
} finally {
|
|
30063
30112
|
try {
|
|
30064
|
-
await
|
|
30113
|
+
await installations.close();
|
|
30065
30114
|
} finally {
|
|
30066
30115
|
try {
|
|
30067
|
-
|
|
30116
|
+
await sessions.close();
|
|
30068
30117
|
} finally {
|
|
30069
|
-
|
|
30118
|
+
try {
|
|
30119
|
+
sessionStore.close();
|
|
30120
|
+
} finally {
|
|
30121
|
+
outbox.close();
|
|
30122
|
+
}
|
|
30070
30123
|
}
|
|
30071
30124
|
}
|
|
30072
30125
|
}
|