@codeagentswarm/cas-cloud 0.0.6 → 0.0.15
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/README.md +14 -1
- package/dist/cas.js +523 -98
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -22,6 +22,19 @@ bundled CodeAgentSwarm MCP. It also installs the guarded global instructions
|
|
|
22
22
|
that publish each session's title, activity and work-phase status. Run
|
|
23
23
|
`cas-cli setup` to perform that same setup explicitly.
|
|
24
24
|
|
|
25
|
+
To connect this host to CodeAgentSwarm Desktop, keep `serve` running and ask it
|
|
26
|
+
for a temporary Desktop link:
|
|
27
|
+
|
|
28
|
+
```sh
|
|
29
|
+
cas-cli connect
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Open the printed link on the Mac, or paste it into **Remote devices**. Desktop
|
|
33
|
+
reviews and saves the host; its projects and open sessions then appear in the
|
|
34
|
+
normal Agents list and New Agent launcher while the VPS is online. The link is
|
|
35
|
+
single-use, expires after five minutes, uses the existing encrypted relay and
|
|
36
|
+
does not open an inbound VPS port.
|
|
37
|
+
|
|
25
38
|
To let a Cloud session read or start work on your Mac, enable **Session
|
|
26
39
|
communication** on the Mac, create a Mobile Connect pairing code, and keep the
|
|
27
40
|
Cloud service running while you link it:
|
|
@@ -38,7 +51,7 @@ list eligible Mac sessions, read a bounded user/assistant transcript, or list an
|
|
|
38
51
|
opaque project and start one new Mac session with a prompt when you explicitly
|
|
39
52
|
ask. Only assistant prose returns; paths, reasoning and tool output do not.
|
|
40
53
|
|
|
41
|
-
Desktop
|
|
54
|
+
The Desktop connection created by `cas-cli connect` provides the reverse direction. With both
|
|
42
55
|
links approved, a Mac session can perform the same explicit read, remote start,
|
|
43
56
|
or focused request/response exchange with an eligible CAS Cloud session. Those
|
|
44
57
|
messages stay end-to-end encrypted and are not retained for replay by the relay.
|
package/dist/cas.js
CHANGED
|
@@ -8393,6 +8393,9 @@ var require_mcp_entry_ownership = __commonJS({
|
|
|
8393
8393
|
function hasStaleSourceCheckoutRuntime(text) {
|
|
8394
8394
|
const candidates = [text.trim(), ...[...text.matchAll(/["']([^"']+)["']/g)].map((match) => match[1])];
|
|
8395
8395
|
return candidates.some((candidate) => {
|
|
8396
|
+
if (candidate.includes(WORKTREE_MARKER)) return false;
|
|
8397
|
+
const ownedPaths = [OWNED_SOURCE_RUNTIME, OWNED_SOURCE_LAUNCHER].map(normalizeRuntimePath);
|
|
8398
|
+
if (ownedPaths.some((owned) => candidate !== owned && candidate.includes(owned))) return false;
|
|
8396
8399
|
if (!SOURCE_CHECKOUT_SUFFIXES.some((suffix) => candidate.endsWith(suffix))) return false;
|
|
8397
8400
|
if (!/^(?:[a-z]:\/|\/)/i.test(candidate)) return false;
|
|
8398
8401
|
const withoutRoot = candidate.replace(/^[a-z]:\//i, "").replace(/^\/+/, "");
|
|
@@ -18501,10 +18504,144 @@ var require_jsonrpc_line_parser = __commonJS({
|
|
|
18501
18504
|
}
|
|
18502
18505
|
});
|
|
18503
18506
|
|
|
18507
|
+
// src/shared/provider-error-presentation.js
|
|
18508
|
+
var require_provider_error_presentation = __commonJS({
|
|
18509
|
+
"src/shared/provider-error-presentation.js"(exports2, module2) {
|
|
18510
|
+
var MODEL_USAGE_LIMIT_CODE = "model_usage_limit_reached";
|
|
18511
|
+
var MODEL_USAGE_LIMIT_MESSAGE = "This model's usage limit has been reached. Switch models or try again after the limit resets.";
|
|
18512
|
+
var USAGE_LIMIT_CODES = /* @__PURE__ */ new Set([
|
|
18513
|
+
"billinghardlimitreached",
|
|
18514
|
+
"creditsexhausted",
|
|
18515
|
+
"insufficientquota",
|
|
18516
|
+
"modelusagelimitreached",
|
|
18517
|
+
"quotaexhausted",
|
|
18518
|
+
"ratelimit",
|
|
18519
|
+
"ratelimited",
|
|
18520
|
+
"ratelimiterror",
|
|
18521
|
+
"ratelimitreached",
|
|
18522
|
+
"resourceexhausted",
|
|
18523
|
+
"usagelimit",
|
|
18524
|
+
"usagelimitexceeded",
|
|
18525
|
+
"workspaceownerusagelimitreached",
|
|
18526
|
+
"workspacememberusagelimitreached"
|
|
18527
|
+
]);
|
|
18528
|
+
var USAGE_LIMIT_MESSAGE_PATTERN = /(?:credit balance is too low|credits? (?:have been )?exhausted|insufficient[ _-]quota|too many requests|(?:model|rate|usage) limit (?:has been )?(?:exceeded|reached)|(?:hit|reached|exceeded) (?:(?:your|the) )?(?:model|rate|usage) limit|quota (?:has been )?(?:exceeded|exhausted|reached)|resource[ _-]exhausted)/i;
|
|
18529
|
+
function structuredErrorInfoValues(value) {
|
|
18530
|
+
if (!value || typeof value !== "object") return [value];
|
|
18531
|
+
return Object.entries(value).flatMap(([kind, detail]) => [
|
|
18532
|
+
kind,
|
|
18533
|
+
typeof detail === "string" || typeof detail === "number" ? detail : void 0,
|
|
18534
|
+
detail == null ? void 0 : detail.httpStatusCode,
|
|
18535
|
+
detail == null ? void 0 : detail.statusCode,
|
|
18536
|
+
detail == null ? void 0 : detail.http_status
|
|
18537
|
+
]);
|
|
18538
|
+
}
|
|
18539
|
+
function errorSignalValues(event) {
|
|
18540
|
+
var _a, _b;
|
|
18541
|
+
const payload = (event == null ? void 0 : event.payload) || {};
|
|
18542
|
+
const payloadErrorData = payload.errorData || {};
|
|
18543
|
+
const detail = payload.detail || {};
|
|
18544
|
+
const detailError = detail.error || {};
|
|
18545
|
+
const detailData = detail.data || {};
|
|
18546
|
+
const detailErrorData = detailError.data || {};
|
|
18547
|
+
const rawPayload = ((_a = event == null ? void 0 : event.raw) == null ? void 0 : _a.payload) || {};
|
|
18548
|
+
const rawError = rawPayload.error || ((_b = rawPayload.turn) == null ? void 0 : _b.error) || {};
|
|
18549
|
+
return [
|
|
18550
|
+
payload.message,
|
|
18551
|
+
payload.errorMessage,
|
|
18552
|
+
...structuredErrorInfoValues(payload.code),
|
|
18553
|
+
...structuredErrorInfoValues(payload.errorCode),
|
|
18554
|
+
payloadErrorData,
|
|
18555
|
+
payloadErrorData.message,
|
|
18556
|
+
payloadErrorData.code,
|
|
18557
|
+
payloadErrorData.errorCode,
|
|
18558
|
+
payloadErrorData.httpStatusCode,
|
|
18559
|
+
payloadErrorData.statusCode,
|
|
18560
|
+
payloadErrorData.http_status,
|
|
18561
|
+
payloadErrorData.reason,
|
|
18562
|
+
payloadErrorData.stopReason,
|
|
18563
|
+
detail.code,
|
|
18564
|
+
detail.message,
|
|
18565
|
+
detail.errorCode,
|
|
18566
|
+
detail.httpStatusCode,
|
|
18567
|
+
detail.statusCode,
|
|
18568
|
+
detail.http_status,
|
|
18569
|
+
...structuredErrorInfoValues(detail.codexErrorInfo),
|
|
18570
|
+
detail.stopReason,
|
|
18571
|
+
detailError.code,
|
|
18572
|
+
detailError.message,
|
|
18573
|
+
detailError.errorCode,
|
|
18574
|
+
detailError.httpStatusCode,
|
|
18575
|
+
detailError.statusCode,
|
|
18576
|
+
detailError.http_status,
|
|
18577
|
+
...structuredErrorInfoValues(detailError.codexErrorInfo),
|
|
18578
|
+
detailData.code,
|
|
18579
|
+
detailData.message,
|
|
18580
|
+
detailData.errorCode,
|
|
18581
|
+
detailData.httpStatusCode,
|
|
18582
|
+
detailData.statusCode,
|
|
18583
|
+
detailData.http_status,
|
|
18584
|
+
detailData.reason,
|
|
18585
|
+
detailData.stopReason,
|
|
18586
|
+
detailErrorData.code,
|
|
18587
|
+
detailErrorData.message,
|
|
18588
|
+
detailErrorData.errorCode,
|
|
18589
|
+
detailErrorData.httpStatusCode,
|
|
18590
|
+
detailErrorData.statusCode,
|
|
18591
|
+
detailErrorData.http_status,
|
|
18592
|
+
detailErrorData.reason,
|
|
18593
|
+
detailErrorData.stopReason,
|
|
18594
|
+
rawPayload.stopReason,
|
|
18595
|
+
rawError.message,
|
|
18596
|
+
rawError.code,
|
|
18597
|
+
rawError.errorCode,
|
|
18598
|
+
rawError.httpStatusCode,
|
|
18599
|
+
rawError.statusCode,
|
|
18600
|
+
rawError.http_status,
|
|
18601
|
+
...structuredErrorInfoValues(rawError.codexErrorInfo)
|
|
18602
|
+
];
|
|
18603
|
+
}
|
|
18604
|
+
function isModelUsageLimitError(event) {
|
|
18605
|
+
const values = errorSignalValues(event);
|
|
18606
|
+
if (values.some((value) => typeof value === "string" && USAGE_LIMIT_MESSAGE_PATTERN.test(value))) {
|
|
18607
|
+
return true;
|
|
18608
|
+
}
|
|
18609
|
+
if (values.some((value) => typeof value === "string" && USAGE_LIMIT_CODES.has(value.toLowerCase().replace(/[^a-z0-9]/g, "")))) return true;
|
|
18610
|
+
if (values.some((value) => Number(value) === 429)) return true;
|
|
18611
|
+
return (event == null ? void 0 : event.provider) === "grok" && values.some((value) => Number(value) === -32003);
|
|
18612
|
+
}
|
|
18613
|
+
function normalizeProviderErrorEvent(event) {
|
|
18614
|
+
if (!event || !["runtime.error", "turn.completed", "session.exited"].includes(event.type)) {
|
|
18615
|
+
return event;
|
|
18616
|
+
}
|
|
18617
|
+
if (!isModelUsageLimitError(event)) return event;
|
|
18618
|
+
const payload = { ...event.payload || {}, code: MODEL_USAGE_LIMIT_CODE };
|
|
18619
|
+
if (event.type === "runtime.error") {
|
|
18620
|
+
payload.message = MODEL_USAGE_LIMIT_MESSAGE;
|
|
18621
|
+
payload.class = "usage_limit";
|
|
18622
|
+
} else if (event.type === "turn.completed") {
|
|
18623
|
+
payload.errorMessage = MODEL_USAGE_LIMIT_MESSAGE;
|
|
18624
|
+
payload.errorCode = MODEL_USAGE_LIMIT_CODE;
|
|
18625
|
+
} else {
|
|
18626
|
+
payload.reason = MODEL_USAGE_LIMIT_MESSAGE;
|
|
18627
|
+
payload.errorCode = MODEL_USAGE_LIMIT_CODE;
|
|
18628
|
+
}
|
|
18629
|
+
return { ...event, payload };
|
|
18630
|
+
}
|
|
18631
|
+
module2.exports = {
|
|
18632
|
+
MODEL_USAGE_LIMIT_CODE,
|
|
18633
|
+
MODEL_USAGE_LIMIT_MESSAGE,
|
|
18634
|
+
isModelUsageLimitError,
|
|
18635
|
+
normalizeProviderErrorEvent
|
|
18636
|
+
};
|
|
18637
|
+
}
|
|
18638
|
+
});
|
|
18639
|
+
|
|
18504
18640
|
// src/infrastructure/agent-drivers/provider-events.js
|
|
18505
18641
|
var require_provider_events = __commonJS({
|
|
18506
18642
|
"src/infrastructure/agent-drivers/provider-events.js"(exports2, module2) {
|
|
18507
18643
|
var crypto = require("crypto");
|
|
18644
|
+
var { normalizeProviderErrorEvent } = require_provider_error_presentation();
|
|
18508
18645
|
var PROVIDER_EVENT_TYPES = Object.freeze([
|
|
18509
18646
|
"session.state.changed",
|
|
18510
18647
|
"session.config.updated",
|
|
@@ -18596,7 +18733,7 @@ var require_provider_events = __commonJS({
|
|
|
18596
18733
|
if (bare.itemId !== void 0) event.itemId = bare.itemId;
|
|
18597
18734
|
if (bare.requestId !== void 0) event.requestId = bare.requestId;
|
|
18598
18735
|
if (bare.raw !== void 0) event.raw = bare.raw;
|
|
18599
|
-
return event;
|
|
18736
|
+
return normalizeProviderErrorEvent(event);
|
|
18600
18737
|
}
|
|
18601
18738
|
function normalizeExecutionOrigin(value) {
|
|
18602
18739
|
return EXECUTION_ORIGINS.includes(value) ? value : "unknown";
|
|
@@ -18674,6 +18811,7 @@ var require_provider_auth = __commonJS({
|
|
|
18674
18811
|
/\bunauthenticated\b/i,
|
|
18675
18812
|
/\bauthentication required\b/i,
|
|
18676
18813
|
/\bplease (?:run|use) [^\n]*(?:login|log in|sign in)\b/i,
|
|
18814
|
+
/\brun [^\n]*(?:login|log in|sign in)\b/i,
|
|
18677
18815
|
/\b(?:login|log in|sign in) (?:is )?required\b/i,
|
|
18678
18816
|
/\bmissing (?:an? )?(?:api key|access token|auth token|credentials?)\b/i,
|
|
18679
18817
|
/\b(?:invalid|expired) (?:api key|access token|auth token|credentials?)\b/i,
|
|
@@ -20864,17 +21002,19 @@ ${text}`;
|
|
|
20864
21002
|
}];
|
|
20865
21003
|
},
|
|
20866
21004
|
"turn/completed": ({ method, params }) => {
|
|
20867
|
-
var _a;
|
|
21005
|
+
var _a, _b;
|
|
20868
21006
|
const turn = params == null ? void 0 : params.turn;
|
|
20869
21007
|
if (!(turn == null ? void 0 : turn.id)) return [];
|
|
20870
21008
|
const errorMessage = (_a = turn.error) == null ? void 0 : _a.message;
|
|
21009
|
+
const errorCode = (_b = turn.error) == null ? void 0 : _b.codexErrorInfo;
|
|
20871
21010
|
return [{
|
|
20872
21011
|
type: "turn.completed",
|
|
20873
21012
|
threadId: params.threadId,
|
|
20874
21013
|
turnId: turn.id,
|
|
20875
21014
|
payload: {
|
|
20876
21015
|
state: mapTurnStatus(turn.status),
|
|
20877
|
-
...errorMessage ? { errorMessage } : {}
|
|
21016
|
+
...errorMessage ? { errorMessage } : {},
|
|
21017
|
+
...errorCode ? { errorCode } : {}
|
|
20878
21018
|
},
|
|
20879
21019
|
raw: buildRaw(method, params)
|
|
20880
21020
|
}];
|
|
@@ -20992,8 +21132,9 @@ ${text}`;
|
|
|
20992
21132
|
raw: buildRaw(method, params)
|
|
20993
21133
|
}],
|
|
20994
21134
|
error: ({ method, params }) => {
|
|
20995
|
-
var _a;
|
|
21135
|
+
var _a, _b;
|
|
20996
21136
|
const message = (_a = params == null ? void 0 : params.error) == null ? void 0 : _a.message;
|
|
21137
|
+
const code = (_b = params == null ? void 0 : params.error) == null ? void 0 : _b.codexErrorInfo;
|
|
20997
21138
|
const base = {
|
|
20998
21139
|
threadId: params == null ? void 0 : params.threadId,
|
|
20999
21140
|
turnId: params == null ? void 0 : params.turnId,
|
|
@@ -21005,7 +21146,7 @@ ${text}`;
|
|
|
21005
21146
|
return [{
|
|
21006
21147
|
...base,
|
|
21007
21148
|
type: "runtime.error",
|
|
21008
|
-
payload: { message, class: "provider_error", detail: params }
|
|
21149
|
+
payload: { message, class: "provider_error", ...code ? { code } : {}, detail: params }
|
|
21009
21150
|
}];
|
|
21010
21151
|
}
|
|
21011
21152
|
});
|
|
@@ -25778,12 +25919,15 @@ var require_acp_agent_driver = __commonJS({
|
|
|
25778
25919
|
try {
|
|
25779
25920
|
const result = await prompt;
|
|
25780
25921
|
const stopReason = result && result.stopReason;
|
|
25781
|
-
completion = {
|
|
25782
|
-
state: stopReason === "cancelled" ? "cancelled" : "completed"
|
|
25783
|
-
};
|
|
25922
|
+
completion = stopReason === "rate_limit" ? { state: "failed", errorMessage: "Rate limit reached", errorCode: "rate_limit" } : { state: stopReason === "cancelled" ? "cancelled" : "completed" };
|
|
25784
25923
|
} catch (error) {
|
|
25785
25924
|
if (this._stopping || this._state === "stopped") return;
|
|
25786
|
-
completion = {
|
|
25925
|
+
completion = {
|
|
25926
|
+
state: "failed",
|
|
25927
|
+
errorMessage: error.message,
|
|
25928
|
+
...error.rpcCode !== void 0 ? { errorCode: error.rpcCode } : {},
|
|
25929
|
+
...error.rpcData !== void 0 ? { errorData: error.rpcData } : {}
|
|
25930
|
+
};
|
|
25787
25931
|
} finally {
|
|
25788
25932
|
this._promptsInFlight = Math.max(0, this._promptsInFlight - 1);
|
|
25789
25933
|
}
|
|
@@ -25792,7 +25936,11 @@ var require_acp_agent_driver = __commonJS({
|
|
|
25792
25936
|
this._emit({
|
|
25793
25937
|
type: "runtime.error",
|
|
25794
25938
|
turnId,
|
|
25795
|
-
payload: {
|
|
25939
|
+
payload: {
|
|
25940
|
+
message: completion.errorMessage,
|
|
25941
|
+
...completion.errorCode !== void 0 ? { code: completion.errorCode } : {},
|
|
25942
|
+
...completion.errorData !== void 0 ? { detail: { data: completion.errorData } } : {}
|
|
25943
|
+
}
|
|
25796
25944
|
});
|
|
25797
25945
|
}
|
|
25798
25946
|
return;
|
|
@@ -34806,7 +34954,18 @@ var require_mobile_runtime = __commonJS({
|
|
|
34806
34954
|
} = require_chat_history_pagination();
|
|
34807
34955
|
var PROTOCOL_VERSION = 2;
|
|
34808
34956
|
var SESSION_SUBSCRIPTIONS_FEATURE = "session-subscriptions";
|
|
34809
|
-
var SUBSCRIPTION_ONLY_EVENT_TYPES = /* @__PURE__ */ new Set([
|
|
34957
|
+
var SUBSCRIPTION_ONLY_EVENT_TYPES = /* @__PURE__ */ new Set([
|
|
34958
|
+
"session.config.updated",
|
|
34959
|
+
"session.commands.updated",
|
|
34960
|
+
"thread.started",
|
|
34961
|
+
"thread.token-usage.updated",
|
|
34962
|
+
"turn.diff.updated",
|
|
34963
|
+
"item.started",
|
|
34964
|
+
"item.updated",
|
|
34965
|
+
"item.completed",
|
|
34966
|
+
"content.delta",
|
|
34967
|
+
"account.rate-limits.updated"
|
|
34968
|
+
]);
|
|
34810
34969
|
var STREAM_METRICS_INTERVAL_MS = 6e4;
|
|
34811
34970
|
var MAX_MESSAGE_BYTES = 1024 * 1024;
|
|
34812
34971
|
var MAX_ITEMS_PER_SESSION = 500;
|
|
@@ -36453,9 +36612,17 @@ var require_mobile_runtime = __commonJS({
|
|
|
36453
36612
|
}
|
|
36454
36613
|
if (command.type === "project.clone") {
|
|
36455
36614
|
if (typeof this.cloneProject !== "function") throw new Error("Remote project cloning is unavailable");
|
|
36456
|
-
exactPayload(["rootId", "url", "relativePath", "requestId"]);
|
|
36615
|
+
exactPayload(["rootId", "url", "relativePath", "displayName", "color", "icon", "requestId"]);
|
|
36457
36616
|
if (typeof payload.requestId !== "string" || !payload.requestId) throw new Error("A clone requestId is required");
|
|
36458
|
-
return this.cloneProject({
|
|
36617
|
+
return this.cloneProject({
|
|
36618
|
+
rootId: payload.rootId,
|
|
36619
|
+
url: payload.url,
|
|
36620
|
+
relativePath: payload.relativePath,
|
|
36621
|
+
displayName: payload.displayName,
|
|
36622
|
+
color: payload.color,
|
|
36623
|
+
icon: payload.icon,
|
|
36624
|
+
requestId: payload.requestId
|
|
36625
|
+
});
|
|
36459
36626
|
}
|
|
36460
36627
|
if (command.type === "project.clone.cancel") {
|
|
36461
36628
|
if (typeof this.cancelProjectClone !== "function") throw new Error("Remote clone cancellation is unavailable");
|
|
@@ -36980,7 +37147,8 @@ var require_mobile_runtime = __commonJS({
|
|
|
36980
37147
|
await this.manager.interruptTurn(sessionId);
|
|
36981
37148
|
return { interrupted: true };
|
|
36982
37149
|
case "session.stop": {
|
|
36983
|
-
const session = this.
|
|
37150
|
+
const session = this.sessions.get(sessionId);
|
|
37151
|
+
if (!session || session.state === "stopped") return { stopped: true };
|
|
36984
37152
|
let result;
|
|
36985
37153
|
if (typeof this.closeSession === "function") {
|
|
36986
37154
|
const closed = await this.closeSession({
|
|
@@ -37296,7 +37464,7 @@ var require_mobile_relay_client = __commonJS({
|
|
|
37296
37464
|
var PEER_BATCH_MAX_BYTES = 5 * 1024 * 1024;
|
|
37297
37465
|
var PEER_BATCH_ITEM_MAX_BYTES = 256 * 1024;
|
|
37298
37466
|
var PEER_METRICS_INTERVAL_MS = 6e4;
|
|
37299
|
-
var
|
|
37467
|
+
var BATCHABLE_RUNTIME_KINDS = /* @__PURE__ */ new Set(["session.event", "cursor.advanced"]);
|
|
37300
37468
|
var COMPRESSION_THRESHOLD_BYTES = 4096;
|
|
37301
37469
|
var ID_PATTERN = /^[A-Za-z0-9._:-]{1,128}$/;
|
|
37302
37470
|
var RELAY_GROUP_PATTERN = /^[A-Za-z0-9_-]{43}$/;
|
|
@@ -37340,7 +37508,7 @@ var require_mobile_relay_client = __commonJS({
|
|
|
37340
37508
|
this.acceptsDeflate = false;
|
|
37341
37509
|
}
|
|
37342
37510
|
send(raw) {
|
|
37343
|
-
var _a
|
|
37511
|
+
var _a;
|
|
37344
37512
|
if (this.readyState !== 1) return;
|
|
37345
37513
|
const json = String(raw);
|
|
37346
37514
|
const bytes = Buffer.byteLength(json);
|
|
@@ -37357,7 +37525,7 @@ var require_mobile_relay_client = __commonJS({
|
|
|
37357
37525
|
deviceId: this.device.id,
|
|
37358
37526
|
...codec ? { codec } : {},
|
|
37359
37527
|
box: encryptJson(payload, this.client.keyPair.secretKey, this.device.publicKey, codec)
|
|
37360
|
-
},
|
|
37528
|
+
}, BATCHABLE_RUNTIME_KINDS.has(payload.kind));
|
|
37361
37529
|
}
|
|
37362
37530
|
receive(box) {
|
|
37363
37531
|
if (this.readyState !== 1) return;
|
|
@@ -38097,7 +38265,7 @@ var require_mobile_relay_client = __commonJS({
|
|
|
38097
38265
|
});
|
|
38098
38266
|
return;
|
|
38099
38267
|
}
|
|
38100
|
-
if (
|
|
38268
|
+
if (["peer.message", "peer.offline", "peer.online"].includes(message.kind)) {
|
|
38101
38269
|
if (message.kind === "peer.offline") {
|
|
38102
38270
|
this.emit("diagnostic", { event: "peer.route_offline", peer: logRef(message.targetRuntimeId) });
|
|
38103
38271
|
}
|
|
@@ -38356,6 +38524,7 @@ var require_remote_runtime_client = __commonJS({
|
|
|
38356
38524
|
"session.identity.updated",
|
|
38357
38525
|
"projects.updated",
|
|
38358
38526
|
"projects.operation.updated",
|
|
38527
|
+
"project.icon.generated",
|
|
38359
38528
|
"tasks.changed",
|
|
38360
38529
|
"provider.login.event",
|
|
38361
38530
|
"provider.operation.updated",
|
|
@@ -38415,6 +38584,8 @@ var require_remote_runtime_client = __commonJS({
|
|
|
38415
38584
|
"session.resume",
|
|
38416
38585
|
"history.older",
|
|
38417
38586
|
"projects.list",
|
|
38587
|
+
"project.directories.list",
|
|
38588
|
+
"project.update",
|
|
38418
38589
|
"project.register",
|
|
38419
38590
|
"project.clone",
|
|
38420
38591
|
"project.clone.cancel",
|
|
@@ -38446,6 +38617,7 @@ var require_remote_runtime_client = __commonJS({
|
|
|
38446
38617
|
"coordination.transcript",
|
|
38447
38618
|
"coordination.message",
|
|
38448
38619
|
"projects.list",
|
|
38620
|
+
"project.directories.list",
|
|
38449
38621
|
"tasks.list",
|
|
38450
38622
|
"providers.list",
|
|
38451
38623
|
"provider.login.describe",
|
|
@@ -38511,15 +38683,20 @@ var require_remote_runtime_client = __commonJS({
|
|
|
38511
38683
|
assertPublicPayload(child, depth + 1);
|
|
38512
38684
|
}
|
|
38513
38685
|
}
|
|
38514
|
-
function stripPathFields(value, depth = 0) {
|
|
38686
|
+
function stripPathFields(value, depth = 0, preserveRelativePaths = false) {
|
|
38515
38687
|
if (depth > 40) throw new Error("Remote runtime payload is too deeply nested");
|
|
38516
|
-
if (Array.isArray(value)) return value.map((item) => stripPathFields(item, depth + 1));
|
|
38688
|
+
if (Array.isArray(value)) return value.map((item) => stripPathFields(item, depth + 1, preserveRelativePaths));
|
|
38517
38689
|
if (!value || typeof value !== "object") return value;
|
|
38518
38690
|
const clean = {};
|
|
38519
38691
|
for (const [key, child] of Object.entries(value)) {
|
|
38520
38692
|
const normalized = normalizedKey(key);
|
|
38521
|
-
if (PATH_KEYS.has(normalized) || normalized.endsWith("path"))
|
|
38522
|
-
|
|
38693
|
+
if (PATH_KEYS.has(normalized) || normalized.endsWith("path")) {
|
|
38694
|
+
if (preserveRelativePaths && (child === null || isSafeRelativePath(child))) {
|
|
38695
|
+
clean[key] = typeof child === "string" ? child.replace(/\\/g, "/") : null;
|
|
38696
|
+
}
|
|
38697
|
+
continue;
|
|
38698
|
+
}
|
|
38699
|
+
clean[key] = stripPathFields(child, depth + 1, preserveRelativePaths);
|
|
38523
38700
|
}
|
|
38524
38701
|
return clean;
|
|
38525
38702
|
}
|
|
@@ -39064,7 +39241,7 @@ var require_remote_runtime_client = __commonJS({
|
|
|
39064
39241
|
}
|
|
39065
39242
|
if (command.payload !== void 0) {
|
|
39066
39243
|
assertPublicPayload(command.payload);
|
|
39067
|
-
assertPathlessCommand(command.payload, 0, command.type === "project.register" || command.type === "project.clone" || command.type.startsWith("workspace.files."));
|
|
39244
|
+
assertPathlessCommand(command.payload, 0, command.type === "project.directories.list" || command.type === "project.register" || command.type === "project.clone" || command.type.startsWith("workspace.files."));
|
|
39068
39245
|
wire.payload = clone(command.payload);
|
|
39069
39246
|
}
|
|
39070
39247
|
return wire;
|
|
@@ -39316,12 +39493,12 @@ var require_remote_runtime_client = __commonJS({
|
|
|
39316
39493
|
if (this.runtimeOnline) this._sendRuntimeHello();
|
|
39317
39494
|
}
|
|
39318
39495
|
_handleRuntimeEnvelope(envelope) {
|
|
39319
|
-
var _a, _b;
|
|
39496
|
+
var _a, _b, _c, _d, _e;
|
|
39320
39497
|
let safe;
|
|
39321
39498
|
let bytes;
|
|
39322
39499
|
try {
|
|
39323
39500
|
bytes = Buffer.byteLength(JSON.stringify(envelope));
|
|
39324
|
-
if (!envelope || typeof envelope !== "object" || bytes > MAX_RUNTIME_MESSAGE_BYTES
|
|
39501
|
+
if (!envelope || typeof envelope !== "object" || bytes > MAX_RUNTIME_MESSAGE_BYTES) {
|
|
39325
39502
|
throw new Error("Invalid runtime envelope");
|
|
39326
39503
|
}
|
|
39327
39504
|
assertPublicPayload(envelope);
|
|
@@ -39330,9 +39507,11 @@ var require_remote_runtime_client = __commonJS({
|
|
|
39330
39507
|
throw new Error("Invalid runtime snapshot");
|
|
39331
39508
|
}
|
|
39332
39509
|
}
|
|
39333
|
-
|
|
39510
|
+
const commandType = envelope.kind === "command.result" ? (_c = (_b = (_a = this.pendingCommands.get(envelope.commandId)) == null ? void 0 : _a.message) == null ? void 0 : _b.command) == null ? void 0 : _c.type : null;
|
|
39511
|
+
safe = stripPathFields(envelope, 0, commandType === "project.directories.list");
|
|
39334
39512
|
} catch {
|
|
39335
|
-
|
|
39513
|
+
const kind = typeof (envelope == null ? void 0 : envelope.kind) === "string" && /^[a-z][a-z0-9.]{0,63}$/.test(envelope.kind) ? envelope.kind : void 0;
|
|
39514
|
+
this._diagnostic("remote.runtime_rejected", { reason: "invalid_envelope", kind });
|
|
39336
39515
|
return this._protocolFailure(this.socket);
|
|
39337
39516
|
}
|
|
39338
39517
|
if (safe.kind === "command.accepted") {
|
|
@@ -39383,8 +39562,8 @@ var require_remote_runtime_client = __commonJS({
|
|
|
39383
39562
|
totalMs: this.connectTrace ? this.now() - this.connectTrace.startedAt : void 0,
|
|
39384
39563
|
reset: safe.reset === true,
|
|
39385
39564
|
bytes,
|
|
39386
|
-
sessions: Array.isArray((
|
|
39387
|
-
projects: Array.isArray((
|
|
39565
|
+
sessions: Array.isArray((_d = safe.snapshot) == null ? void 0 : _d.sessions) ? safe.snapshot.sessions.length : void 0,
|
|
39566
|
+
projects: Array.isArray((_e = safe.snapshot) == null ? void 0 : _e.projects) ? safe.snapshot.projects.length : void 0
|
|
39388
39567
|
});
|
|
39389
39568
|
this.connectTrace = null;
|
|
39390
39569
|
this._emitEnvelope(safe);
|
|
@@ -39410,6 +39589,15 @@ var require_remote_runtime_client = __commonJS({
|
|
|
39410
39589
|
return;
|
|
39411
39590
|
}
|
|
39412
39591
|
if (seq <= cursor.seq) return;
|
|
39592
|
+
if (!RUNTIME_KINDS.has(safe.kind)) {
|
|
39593
|
+
this._diagnostic("remote.runtime_ignored", { kind: safe.kind, seq });
|
|
39594
|
+
this._setState({
|
|
39595
|
+
...this.state,
|
|
39596
|
+
cursor: { runtimeId: cursor.runtimeId, seq },
|
|
39597
|
+
error: null
|
|
39598
|
+
});
|
|
39599
|
+
return;
|
|
39600
|
+
}
|
|
39413
39601
|
this._setState({
|
|
39414
39602
|
...this.state,
|
|
39415
39603
|
cursor: { runtimeId: cursor.runtimeId, seq },
|
|
@@ -39871,6 +40059,83 @@ var require_remote_runtime_store = __commonJS({
|
|
|
39871
40059
|
}
|
|
39872
40060
|
});
|
|
39873
40061
|
|
|
40062
|
+
// src/infrastructure/mobile/desktop-connection-link.js
|
|
40063
|
+
var require_desktop_connection_link = __commonJS({
|
|
40064
|
+
"src/infrastructure/mobile/desktop-connection-link.js"(exports2, module2) {
|
|
40065
|
+
var DEFAULT_CONNECT_ORIGIN = "https://codeagentswarm-connect.elcaminodelprogramadorweb.workers.dev";
|
|
40066
|
+
var PUBLIC_CONNECT_ORIGIN = "https://connect.codeagentswarm.com";
|
|
40067
|
+
var PAIRING_CODE = /^[A-HJ-NP-Z2-9]{8}$/;
|
|
40068
|
+
function secureOrigin(value) {
|
|
40069
|
+
try {
|
|
40070
|
+
const url = new URL(value);
|
|
40071
|
+
const local = ["localhost", "127.0.0.1", "[::1]"].includes(url.hostname);
|
|
40072
|
+
if (url.protocol !== "https:" && !(url.protocol === "http:" && local) || url.username || url.password || url.origin !== value) return null;
|
|
40073
|
+
return url.origin;
|
|
40074
|
+
} catch (_) {
|
|
40075
|
+
return null;
|
|
40076
|
+
}
|
|
40077
|
+
}
|
|
40078
|
+
function normalizeCode(value) {
|
|
40079
|
+
const compact = String(value || "").trim().toUpperCase().replace(/[\s-]/g, "");
|
|
40080
|
+
return PAIRING_CODE.test(compact) ? `${compact.slice(0, 4)}-${compact.slice(4)}` : null;
|
|
40081
|
+
}
|
|
40082
|
+
function configuredOrigin() {
|
|
40083
|
+
const value = process.env.CAS_PAIRING_CODE_ORIGIN || DEFAULT_CONNECT_ORIGIN;
|
|
40084
|
+
const origin = secureOrigin(value);
|
|
40085
|
+
if (!origin) throw new Error("The pairing service is not secure");
|
|
40086
|
+
return origin;
|
|
40087
|
+
}
|
|
40088
|
+
function codeFromInput(raw) {
|
|
40089
|
+
const direct = normalizeCode(raw);
|
|
40090
|
+
if (direct) return { code: direct, origin: configuredOrigin() };
|
|
40091
|
+
let url;
|
|
40092
|
+
try {
|
|
40093
|
+
url = new URL(String(raw || "").trim());
|
|
40094
|
+
} catch (_) {
|
|
40095
|
+
return null;
|
|
40096
|
+
}
|
|
40097
|
+
if (["codeagentswarm:", "codeagentswarm-dev:"].includes(url.protocol) && url.hostname === "connect") {
|
|
40098
|
+
const code2 = normalizeCode(url.searchParams.get("code"));
|
|
40099
|
+
if (!code2) throw new Error("This pairing code is not valid");
|
|
40100
|
+
return { code: code2, origin: configuredOrigin() };
|
|
40101
|
+
}
|
|
40102
|
+
if (!/^\/(?:connect|c)\/[^/]+\/?$/.test(url.pathname)) return null;
|
|
40103
|
+
const trusted = /* @__PURE__ */ new Set([DEFAULT_CONNECT_ORIGIN, PUBLIC_CONNECT_ORIGIN, configuredOrigin()]);
|
|
40104
|
+
if (!trusted.has(url.origin) || url.search || url.hash) throw new Error("This pairing code is not valid");
|
|
40105
|
+
const code = normalizeCode(url.pathname.split("/").filter(Boolean).at(-1));
|
|
40106
|
+
if (!code) throw new Error("This pairing code is not valid");
|
|
40107
|
+
return { code, origin: url.origin };
|
|
40108
|
+
}
|
|
40109
|
+
async function resolvePairingInput(raw, fetchImpl = globalThis.fetch) {
|
|
40110
|
+
const connection = codeFromInput(raw);
|
|
40111
|
+
if (!connection) return String(raw || "").trim();
|
|
40112
|
+
try {
|
|
40113
|
+
const response = await fetchImpl(`${connection.origin}/api/mobile/pairing-code/${encodeURIComponent(connection.code)}`, {
|
|
40114
|
+
headers: { Accept: "application/json" },
|
|
40115
|
+
signal: AbortSignal.timeout(1e4)
|
|
40116
|
+
});
|
|
40117
|
+
if (!response.ok) throw new Error();
|
|
40118
|
+
const body = await response.json();
|
|
40119
|
+
if (typeof body.pairingUri !== "string") throw new Error();
|
|
40120
|
+
return body.pairingUri;
|
|
40121
|
+
} catch (_) {
|
|
40122
|
+
throw new Error("This pairing code is invalid or has expired");
|
|
40123
|
+
}
|
|
40124
|
+
}
|
|
40125
|
+
function desktopConnectionLink(pairing) {
|
|
40126
|
+
const code = normalizeCode(pairing == null ? void 0 : pairing.pairingCode);
|
|
40127
|
+
if (!code) throw new Error("CAS Cloud did not return a valid pairing code");
|
|
40128
|
+
return `${configuredOrigin()}/connect/${code}`;
|
|
40129
|
+
}
|
|
40130
|
+
module2.exports = {
|
|
40131
|
+
DEFAULT_CONNECT_ORIGIN,
|
|
40132
|
+
desktopConnectionLink,
|
|
40133
|
+
normalizeCode,
|
|
40134
|
+
resolvePairingInput
|
|
40135
|
+
};
|
|
40136
|
+
}
|
|
40137
|
+
});
|
|
40138
|
+
|
|
39874
40139
|
// src/infrastructure/mobile/peer-runtime-network.js
|
|
39875
40140
|
var require_peer_runtime_network = __commonJS({
|
|
39876
40141
|
"src/infrastructure/mobile/peer-runtime-network.js"(exports2, module2) {
|
|
@@ -39883,6 +40148,7 @@ var require_peer_runtime_network = __commonJS({
|
|
|
39883
40148
|
var MAX_PEERS = 32;
|
|
39884
40149
|
var PEER_ACCESS_TTL_MS = 7 * 24 * 60 * 6e4;
|
|
39885
40150
|
var PEER_HANDSHAKE_TIMEOUT_MS = 5e3;
|
|
40151
|
+
var PEER_DENIAL_FEATURE = "peer-denial";
|
|
39886
40152
|
function peerRef(value) {
|
|
39887
40153
|
return value ? crypto.createHash("sha256").update(String(value)).digest("hex").slice(0, 10) : void 0;
|
|
39888
40154
|
}
|
|
@@ -39921,7 +40187,18 @@ var require_peer_runtime_network = __commonJS({
|
|
|
39921
40187
|
return;
|
|
39922
40188
|
}
|
|
39923
40189
|
if (message.kind === "runtime.message" && message.box) {
|
|
39924
|
-
|
|
40190
|
+
let box = message.box;
|
|
40191
|
+
try {
|
|
40192
|
+
const payload = decryptJson(box, this.network.keyPair.secretKey, this.peer.publicKey);
|
|
40193
|
+
if ((payload == null ? void 0 : payload.kind) === "hello" && !(Array.isArray(payload.features) && payload.features.includes(PEER_DENIAL_FEATURE))) {
|
|
40194
|
+
box = encryptJson({
|
|
40195
|
+
...payload,
|
|
40196
|
+
features: [...Array.isArray(payload.features) ? payload.features : [], PEER_DENIAL_FEATURE]
|
|
40197
|
+
}, this.network.keyPair.secretKey, this.peer.publicKey);
|
|
40198
|
+
}
|
|
40199
|
+
} catch {
|
|
40200
|
+
}
|
|
40201
|
+
if (!this.network.relay.sendPeerMessage(this.peer.runtimeId, box, "to-runtime")) {
|
|
39925
40202
|
this.network._diagnostic("peer.route_failed", { peer: peerRef(this.peer.runtimeId), stream: "to-runtime" });
|
|
39926
40203
|
this.offline();
|
|
39927
40204
|
} else if (this.readyState === 1 && !this.handshakeComplete && !this.handshakeTimer) {
|
|
@@ -39931,11 +40208,17 @@ var require_peer_runtime_network = __commonJS({
|
|
|
39931
40208
|
}
|
|
39932
40209
|
receive(box) {
|
|
39933
40210
|
if (this.readyState !== 1) return;
|
|
40211
|
+
let payload;
|
|
39934
40212
|
try {
|
|
39935
|
-
decryptJson(box, this.network.keyPair.secretKey, this.peer.publicKey);
|
|
40213
|
+
payload = decryptJson(box, this.network.keyPair.secretKey, this.peer.publicKey);
|
|
39936
40214
|
this.network.relay.emit("diagnostic", { event: "peer.response_verified", stream: "to-client" });
|
|
39937
40215
|
} catch {
|
|
39938
40216
|
this.network.relay.emit("diagnostic", { event: "peer.response_rejected", reason: "decrypt_failed" });
|
|
40217
|
+
return;
|
|
40218
|
+
}
|
|
40219
|
+
if ((payload == null ? void 0 : payload.kind) === "peer.denied") {
|
|
40220
|
+
this.network._denyPeer(this.peer.runtimeId);
|
|
40221
|
+
return;
|
|
39939
40222
|
}
|
|
39940
40223
|
this.handshakeComplete = true;
|
|
39941
40224
|
if (this.handshakeTimer) clearTimeout(this.handshakeTimer);
|
|
@@ -39974,6 +40257,8 @@ var require_peer_runtime_network = __commonJS({
|
|
|
39974
40257
|
this.loadRosters = loadRosters;
|
|
39975
40258
|
this.saveRosters = saveRosters;
|
|
39976
40259
|
this.rosters = /* @__PURE__ */ new Map();
|
|
40260
|
+
this.revokedPeers = /* @__PURE__ */ new Set();
|
|
40261
|
+
this.deniedPeers = /* @__PURE__ */ new Set();
|
|
39977
40262
|
this.peers = /* @__PURE__ */ new Map();
|
|
39978
40263
|
this.clients = /* @__PURE__ */ new Map();
|
|
39979
40264
|
this.clientSockets = /* @__PURE__ */ new Map();
|
|
@@ -39987,7 +40272,11 @@ var require_peer_runtime_network = __commonJS({
|
|
|
39987
40272
|
if (this.started) return;
|
|
39988
40273
|
this.started = true;
|
|
39989
40274
|
const saved = this.loadRosters() || {};
|
|
39990
|
-
|
|
40275
|
+
const savedRosters = saved.version === 1 && saved.rosters && typeof saved.rosters === "object" ? saved.rosters : saved;
|
|
40276
|
+
if (saved.version === 1 && Array.isArray(saved.revoked)) {
|
|
40277
|
+
this.revokedPeers = new Set(saved.revoked.filter((runtimeId) => ID_PATTERN.test(runtimeId || "") && runtimeId !== this.runtimeId));
|
|
40278
|
+
}
|
|
40279
|
+
for (const [deviceId, peers] of Object.entries(savedRosters)) {
|
|
39991
40280
|
if (!ID_PATTERN.test(deviceId) || !Array.isArray(peers)) continue;
|
|
39992
40281
|
this.rosters.set(deviceId, peers.slice(0, MAX_PEERS).filter((peer) => validPeer(peer, this.runtimeId)));
|
|
39993
40282
|
}
|
|
@@ -40017,9 +40306,15 @@ var require_peer_runtime_network = __commonJS({
|
|
|
40017
40306
|
publicKey: peer.publicKey,
|
|
40018
40307
|
name: peer.name.trim().slice(0, 200) || "Connected host"
|
|
40019
40308
|
}])).values()];
|
|
40309
|
+
for (const peer of unique) this.deniedPeers.delete(peer.runtimeId);
|
|
40020
40310
|
if (unique.length) this.rosters.set(deviceId, unique);
|
|
40021
40311
|
else this.rosters.delete(deviceId);
|
|
40022
|
-
|
|
40312
|
+
for (const runtimeId of this.revokedPeers) {
|
|
40313
|
+
if (![...this.rosters.values()].some((roster) => roster.some((peer) => peer.runtimeId === runtimeId))) {
|
|
40314
|
+
this.revokedPeers.delete(runtimeId);
|
|
40315
|
+
}
|
|
40316
|
+
}
|
|
40317
|
+
this._saveState();
|
|
40023
40318
|
this._rebuildPeers();
|
|
40024
40319
|
this._diagnostic("peer.roster_replaced", {
|
|
40025
40320
|
rosters: this.rosters.size,
|
|
@@ -40029,6 +40324,15 @@ var require_peer_runtime_network = __commonJS({
|
|
|
40029
40324
|
});
|
|
40030
40325
|
return { peers: unique.length };
|
|
40031
40326
|
}
|
|
40327
|
+
removePeer(runtimeId) {
|
|
40328
|
+
if (!ID_PATTERN.test(runtimeId || "")) return false;
|
|
40329
|
+
if (![...this.rosters.values()].some((roster) => roster.some((peer) => peer.runtimeId === runtimeId))) return false;
|
|
40330
|
+
this.revokedPeers.add(runtimeId);
|
|
40331
|
+
this._saveState();
|
|
40332
|
+
this._rebuildPeers();
|
|
40333
|
+
this._diagnostic("peer.removed_by_user", { peer: peerRef(runtimeId) });
|
|
40334
|
+
return true;
|
|
40335
|
+
}
|
|
40032
40336
|
getClients() {
|
|
40033
40337
|
return [...this.clients.values()];
|
|
40034
40338
|
}
|
|
@@ -40047,6 +40351,7 @@ var require_peer_runtime_network = __commonJS({
|
|
|
40047
40351
|
const next = /* @__PURE__ */ new Map();
|
|
40048
40352
|
for (const roster of this.rosters.values()) {
|
|
40049
40353
|
for (const peer of roster) {
|
|
40354
|
+
if (this.revokedPeers.has(peer.runtimeId)) continue;
|
|
40050
40355
|
const existing = next.get(peer.runtimeId);
|
|
40051
40356
|
if (existing && existing.publicKey !== peer.publicKey) continue;
|
|
40052
40357
|
next.set(peer.runtimeId, peer);
|
|
@@ -40056,14 +40361,22 @@ var require_peer_runtime_network = __commonJS({
|
|
|
40056
40361
|
const previous = this.peers.get(runtimeId);
|
|
40057
40362
|
const current = next.get(runtimeId);
|
|
40058
40363
|
if ((current == null ? void 0 : current.publicKey) === previous.publicKey) continue;
|
|
40364
|
+
this.deniedPeers.delete(runtimeId);
|
|
40059
40365
|
this._removePeer(runtimeId);
|
|
40060
40366
|
}
|
|
40061
40367
|
this.peers = next;
|
|
40062
40368
|
for (const peer of this.peers.values()) {
|
|
40063
|
-
if (!this.clients.has(peer.runtimeId)) this._addPeer(peer);
|
|
40369
|
+
if (!this.deniedPeers.has(peer.runtimeId) && !this.clients.has(peer.runtimeId)) this._addPeer(peer);
|
|
40064
40370
|
}
|
|
40065
40371
|
this._notifyClients();
|
|
40066
40372
|
}
|
|
40373
|
+
_saveState() {
|
|
40374
|
+
this.saveRosters({
|
|
40375
|
+
version: 1,
|
|
40376
|
+
rosters: Object.fromEntries(this.rosters),
|
|
40377
|
+
revoked: [...this.revokedPeers]
|
|
40378
|
+
});
|
|
40379
|
+
}
|
|
40067
40380
|
_addPeer(peer) {
|
|
40068
40381
|
const network = this;
|
|
40069
40382
|
let connection = {
|
|
@@ -40118,7 +40431,8 @@ var require_peer_runtime_network = __commonJS({
|
|
|
40118
40431
|
...details,
|
|
40119
40432
|
scope: "peer",
|
|
40120
40433
|
peer: peerRef(peer.runtimeId)
|
|
40121
|
-
})
|
|
40434
|
+
}),
|
|
40435
|
+
timeouts: { reconnectMax: 5 * 6e4 }
|
|
40122
40436
|
});
|
|
40123
40437
|
client.subscribeEnvelopes((envelope) => {
|
|
40124
40438
|
for (const listener of this.envelopeListeners) listener(peer.runtimeId, envelope, client);
|
|
@@ -40137,8 +40451,34 @@ var require_peer_runtime_network = __commonJS({
|
|
|
40137
40451
|
this.serverSockets.delete(runtimeId);
|
|
40138
40452
|
this._diagnostic("peer.removed", { peer: peerRef(runtimeId) });
|
|
40139
40453
|
}
|
|
40454
|
+
_denyPeer(runtimeId) {
|
|
40455
|
+
if (!this.peers.has(runtimeId)) return;
|
|
40456
|
+
this.deniedPeers.add(runtimeId);
|
|
40457
|
+
this._removePeer(runtimeId);
|
|
40458
|
+
this._diagnostic("peer.connection_denied", { peer: peerRef(runtimeId) });
|
|
40459
|
+
this._notifyClients();
|
|
40460
|
+
}
|
|
40461
|
+
_rosterPeer(runtimeId) {
|
|
40462
|
+
let found = null;
|
|
40463
|
+
for (const roster of this.rosters.values()) {
|
|
40464
|
+
for (const peer of roster) {
|
|
40465
|
+
if (peer.runtimeId !== runtimeId) continue;
|
|
40466
|
+
if (found && found.publicKey !== peer.publicKey) return null;
|
|
40467
|
+
found = peer;
|
|
40468
|
+
}
|
|
40469
|
+
}
|
|
40470
|
+
return found;
|
|
40471
|
+
}
|
|
40140
40472
|
_handleRelayEvent(event) {
|
|
40141
40473
|
var _a, _b, _c;
|
|
40474
|
+
if ((event == null ? void 0 : event.kind) === "peer.online" && ID_PATTERN.test(event.targetRuntimeId || "")) {
|
|
40475
|
+
const client = this.clients.get(event.targetRuntimeId);
|
|
40476
|
+
if (client && client.getState().phase !== "online") {
|
|
40477
|
+
this._diagnostic("peer.online", { peer: peerRef(event.targetRuntimeId) });
|
|
40478
|
+
client.reconnectNow();
|
|
40479
|
+
}
|
|
40480
|
+
return;
|
|
40481
|
+
}
|
|
40142
40482
|
if ((event == null ? void 0 : event.kind) === "peer.offline" && ID_PATTERN.test(event.targetRuntimeId || "")) {
|
|
40143
40483
|
this._diagnostic("peer.offline", { peer: peerRef(event.targetRuntimeId) });
|
|
40144
40484
|
(_a = this.clientSockets.get(event.targetRuntimeId)) == null ? void 0 : _a.offline();
|
|
@@ -40149,6 +40489,20 @@ var require_peer_runtime_network = __commonJS({
|
|
|
40149
40489
|
if ((event == null ? void 0 : event.kind) !== "peer.message" || !ID_PATTERN.test(event.sourceRuntimeId || "") || !KEY_PATTERN.test(event.sourcePublicKey || "")) return;
|
|
40150
40490
|
const peer = this.peers.get(event.sourceRuntimeId);
|
|
40151
40491
|
if (!peer || peer.publicKey !== event.sourcePublicKey) {
|
|
40492
|
+
const revokedPeer = this.revokedPeers.has(event.sourceRuntimeId) ? this._rosterPeer(event.sourceRuntimeId) : null;
|
|
40493
|
+
if ((revokedPeer == null ? void 0 : revokedPeer.publicKey) === event.sourcePublicKey && event.stream === "to-runtime") {
|
|
40494
|
+
let payload2;
|
|
40495
|
+
try {
|
|
40496
|
+
payload2 = decryptJson(event.box, this.keyPair.secretKey, revokedPeer.publicKey);
|
|
40497
|
+
} catch {
|
|
40498
|
+
}
|
|
40499
|
+
if ((payload2 == null ? void 0 : payload2.kind) === "hello" && Array.isArray(payload2.features) && payload2.features.includes(PEER_DENIAL_FEATURE)) {
|
|
40500
|
+
const box = encryptJson({ kind: "peer.denied" }, this.keyPair.secretKey, revokedPeer.publicKey);
|
|
40501
|
+
if (this.relay.sendPeerMessage(revokedPeer.runtimeId, box, "to-client")) {
|
|
40502
|
+
this._diagnostic("peer.denial_sent", { peer: peerRef(revokedPeer.runtimeId) });
|
|
40503
|
+
}
|
|
40504
|
+
}
|
|
40505
|
+
}
|
|
40152
40506
|
this._diagnostic("peer.message_rejected", {
|
|
40153
40507
|
reason: peer ? "key_mismatch" : "not_introduced",
|
|
40154
40508
|
peer: peerRef(event.sourceRuntimeId)
|
|
@@ -40341,7 +40695,7 @@ var require_headless_session_bridge = __commonJS({
|
|
|
40341
40695
|
};
|
|
40342
40696
|
}
|
|
40343
40697
|
var HeadlessSessionBridge = class {
|
|
40344
|
-
constructor({ runtime, remoteClient, peerRuntimeNetwork = null, dataPath, deliverMessage, randomBytes = crypto.randomBytes } = {}) {
|
|
40698
|
+
constructor({ runtime, remoteClient, peerRuntimeNetwork = null, dataPath, deliverMessage, createPairingLink = null, randomBytes = crypto.randomBytes } = {}) {
|
|
40345
40699
|
if (!runtime || !remoteClient || typeof deliverMessage !== "function" || !path.isAbsolute(dataPath || "")) {
|
|
40346
40700
|
throw new Error("CAS Cloud session bridge configuration is invalid");
|
|
40347
40701
|
}
|
|
@@ -40350,6 +40704,7 @@ var require_headless_session_bridge = __commonJS({
|
|
|
40350
40704
|
this.peerRuntimeNetwork = peerRuntimeNetwork;
|
|
40351
40705
|
this.dataPath = dataPath;
|
|
40352
40706
|
this.deliverMessage = deliverMessage;
|
|
40707
|
+
this.createPairingLink = createPairingLink;
|
|
40353
40708
|
this.adminToken = randomBytes(32).toString("hex");
|
|
40354
40709
|
this.sessionSecret = randomBytes(32);
|
|
40355
40710
|
this.server = null;
|
|
@@ -40534,6 +40889,15 @@ var require_headless_session_bridge = __commonJS({
|
|
|
40534
40889
|
if (request.method === "GET" && url.pathname === "/admin/remote-runtime") {
|
|
40535
40890
|
return sendJson(response, 200, publicRemoteState(this.remoteClient));
|
|
40536
40891
|
}
|
|
40892
|
+
if (request.method === "POST" && url.pathname === "/admin/pairing-link") {
|
|
40893
|
+
if (typeof this.createPairingLink !== "function") return sendJson(response, 503, { error: "Pairing is unavailable" });
|
|
40894
|
+
try {
|
|
40895
|
+
const result = await this.createPairingLink();
|
|
40896
|
+
return sendJson(response, 201, { url: result.url, expiresAt: result.expiresAt });
|
|
40897
|
+
} catch (_) {
|
|
40898
|
+
return sendJson(response, 503, { error: "Could not create a connection link" });
|
|
40899
|
+
}
|
|
40900
|
+
}
|
|
40537
40901
|
if (request.method === "POST" && url.pathname === "/admin/remote-runtime/pair") {
|
|
40538
40902
|
const body = await readJson(request);
|
|
40539
40903
|
if (typeof body.pairing !== "string" || !body.pairing.trim()) {
|
|
@@ -41126,6 +41490,19 @@ var require_headless_project_registry = __commonJS({
|
|
|
41126
41490
|
const result = this._registerPath(resolved, root ? this._rootByPath(root.rootPath).root_id : null, { legacy: true });
|
|
41127
41491
|
if (result.changed) changed = true;
|
|
41128
41492
|
}
|
|
41493
|
+
for (const row of this.db.prepare("SELECT project_id, path FROM runtime_projects WHERE registered = 1").all()) {
|
|
41494
|
+
let resolved;
|
|
41495
|
+
try {
|
|
41496
|
+
resolved = fs.realpathSync(row.path);
|
|
41497
|
+
} catch (_) {
|
|
41498
|
+
continue;
|
|
41499
|
+
}
|
|
41500
|
+
if (resolved === row.path) continue;
|
|
41501
|
+
const canonical = this.db.prepare("SELECT project_id FROM runtime_projects WHERE path = ? AND registered = 1").get(resolved);
|
|
41502
|
+
if (!canonical || canonical.project_id === row.project_id) continue;
|
|
41503
|
+
this.db.prepare("UPDATE runtime_projects SET registered = 0, updated_at = CURRENT_TIMESTAMP WHERE project_id = ?").run(row.project_id);
|
|
41504
|
+
changed = true;
|
|
41505
|
+
}
|
|
41129
41506
|
return changed;
|
|
41130
41507
|
}
|
|
41131
41508
|
_resolveDirectory(candidate, label) {
|
|
@@ -41393,12 +41770,20 @@ var require_headless_project_registry = __commonJS({
|
|
|
41393
41770
|
const revision = this._bumpRevision();
|
|
41394
41771
|
return this._recordRequest(requestId, hash, { projectId: project.projectId, revision, updated: true });
|
|
41395
41772
|
}
|
|
41396
|
-
clone({ rootId, url, relativePath, requestId }) {
|
|
41773
|
+
clone({ rootId, url, relativePath, displayName, color, icon, requestId }) {
|
|
41397
41774
|
const normalizedUrl = validateGitUrl(url);
|
|
41398
41775
|
const root = this._root(rootId);
|
|
41399
41776
|
this._assertSecureCloneRoot(root);
|
|
41400
41777
|
const normalizedRelative = validateCloneChildName(relativePath || cloneDirectoryName(normalizedUrl));
|
|
41401
|
-
const
|
|
41778
|
+
const appearance = {
|
|
41779
|
+
...displayName !== void 0 ? { displayName: String(displayName || "").trim().slice(0, 120) } : {},
|
|
41780
|
+
...color !== void 0 ? { color: String(color || "").trim().slice(0, 32) } : {},
|
|
41781
|
+
...icon !== void 0 ? { icon } : {}
|
|
41782
|
+
};
|
|
41783
|
+
if (appearance.displayName !== void 0 && !appearance.displayName || appearance.icon !== void 0 && appearance.icon !== null && (typeof appearance.icon !== "string" || !ICON_PATTERN.test(appearance.icon))) {
|
|
41784
|
+
throw runtimeError("invalid_project_update", "Project changes are invalid");
|
|
41785
|
+
}
|
|
41786
|
+
const hash = requestHash("clone", { rootId, url: normalizedUrl, relativePath: normalizedRelative, ...appearance });
|
|
41402
41787
|
const duplicate = this._request(requestId, hash);
|
|
41403
41788
|
if (duplicate) return duplicate;
|
|
41404
41789
|
const destinationInfo = this._cloneDestination(root, normalizedRelative, normalizedUrl);
|
|
@@ -41415,6 +41800,7 @@ var require_headless_project_registry = __commonJS({
|
|
|
41415
41800
|
requestId,
|
|
41416
41801
|
rootId,
|
|
41417
41802
|
url: normalizedUrl,
|
|
41803
|
+
appearance,
|
|
41418
41804
|
destination: destinationInfo.destination,
|
|
41419
41805
|
temporaryDestination: null,
|
|
41420
41806
|
temporaryIdentity: null,
|
|
@@ -41552,7 +41938,17 @@ var require_headless_project_registry = __commonJS({
|
|
|
41552
41938
|
return this._finish(operation, "failed", "path_symlink_escape");
|
|
41553
41939
|
}
|
|
41554
41940
|
const registered = this._registerPath(resolved, root.root_id);
|
|
41555
|
-
|
|
41941
|
+
if (Object.keys(operation.appearance).length) {
|
|
41942
|
+
this.db.prepare(`UPDATE runtime_projects
|
|
41943
|
+
SET display_name = COALESCE(?, display_name), color = COALESCE(?, color), icon = ?, updated_at = CURRENT_TIMESTAMP
|
|
41944
|
+
WHERE project_id = ?`).run(
|
|
41945
|
+
operation.appearance.displayName ?? null,
|
|
41946
|
+
operation.appearance.color ?? null,
|
|
41947
|
+
operation.appearance.icon === void 0 ? registered.row.icon || null : operation.appearance.icon,
|
|
41948
|
+
registered.row.project_id
|
|
41949
|
+
);
|
|
41950
|
+
}
|
|
41951
|
+
const revision = registered.changed || Object.keys(operation.appearance).length ? this._bumpRevision() : this.getRevision();
|
|
41556
41952
|
this.db.prepare(`UPDATE runtime_project_operations SET state = 'succeeded', project_id = ?, error = NULL, updated_at = CURRENT_TIMESTAMP WHERE operation_id = ?`).run(registered.row.project_id, operation.operationId);
|
|
41557
41953
|
this.running.delete(operation.operationId);
|
|
41558
41954
|
this.destinations.delete(operation.destination);
|
|
@@ -48824,12 +49220,15 @@ var require_headless_runtime = __commonJS({
|
|
|
48824
49220
|
var os = require("os");
|
|
48825
49221
|
var path = require("path");
|
|
48826
49222
|
var { DriverChatManager, SESSION_EVENT } = require_driver_chat_manager();
|
|
49223
|
+
var { CHAT_PERMISSION_MODES } = require_chat_permission_modes();
|
|
49224
|
+
var { classifyProviderStartupError } = require_provider_auth();
|
|
48827
49225
|
var { boundedConversationMessages } = require_chat_history_pagination();
|
|
48828
49226
|
var { MobileRuntime } = require_mobile_runtime();
|
|
48829
49227
|
var { MobileRelayClient } = require_mobile_relay_client();
|
|
48830
49228
|
var { createKeyPair } = require_mobile_crypto();
|
|
48831
49229
|
var { RemoteRuntimeClient } = require_remote_runtime_client();
|
|
48832
49230
|
var { RemoteRuntimeStore } = require_remote_runtime_store();
|
|
49231
|
+
var { desktopConnectionLink } = require_desktop_connection_link();
|
|
48833
49232
|
var { PeerRuntimeNetwork } = require_peer_runtime_network();
|
|
48834
49233
|
var { HeadlessSessionBridge } = require_headless_session_bridge();
|
|
48835
49234
|
var { createHeadlessChatPreferences } = require_headless_chat_preferences();
|
|
@@ -48896,18 +49295,11 @@ var require_headless_runtime = __commonJS({
|
|
|
48896
49295
|
"workspace.git.switch",
|
|
48897
49296
|
"workspace.git.create"
|
|
48898
49297
|
]);
|
|
48899
|
-
var FINAL_COORDINATION_STATUSES = /* @__PURE__ */ new Set(["done", "pushed", "completed", "finished"]);
|
|
48900
|
-
var COORDINATION_IDLE_MS = 30 * 6e4;
|
|
48901
49298
|
var COORDINATION_COMPLETION_GRACE_MS = 5e3;
|
|
48902
|
-
function isCoordinatedSessionEligible(session
|
|
48903
|
-
|
|
48904
|
-
|
|
48905
|
-
|
|
48906
|
-
if (FINAL_COORDINATION_STATUSES.has(status)) return false;
|
|
48907
|
-
if (((_a = session.currentTurn) == null ? void 0 : _a.state) === "running" || status === "needs_input" || status === "working") return true;
|
|
48908
|
-
const lastActivity = Number(session.lastActivityAt) || Date.parse(session.lastActivityAt);
|
|
48909
|
-
if (Number.isFinite(lastActivity) && now - lastActivity > COORDINATION_IDLE_MS) return false;
|
|
48910
|
-
return Array.from(((_c = (_b = session.items) == null ? void 0 : _b.values) == null ? void 0 : _c.call(_b)) || []).some((item) => (item == null ? void 0 : item.itemType) === "user_message" || (item == null ? void 0 : item.itemType) === "assistant_message");
|
|
49299
|
+
function isCoordinatedSessionEligible(session) {
|
|
49300
|
+
return Boolean(
|
|
49301
|
+
session && session.state !== "stopped" && typeof session.terminalUuid === "string" && session.terminalUuid
|
|
49302
|
+
);
|
|
48911
49303
|
}
|
|
48912
49304
|
function appDataPath({ env = process.env, platform = process.platform, home = os.homedir() } = {}) {
|
|
48913
49305
|
if (platform === "linux") {
|
|
@@ -49163,7 +49555,8 @@ var require_headless_runtime = __commonJS({
|
|
|
49163
49555
|
quotaService: suppliedQuotaService = null,
|
|
49164
49556
|
generateConversationTitle: generateConversationTitleFn = generateConversationTitle,
|
|
49165
49557
|
forkConversation: forkConversationFn = forkConversation,
|
|
49166
|
-
spawnImpl
|
|
49558
|
+
spawnImpl,
|
|
49559
|
+
getuid = typeof process.getuid === "function" ? () => process.getuid() : null
|
|
49167
49560
|
} = {}) {
|
|
49168
49561
|
if (typeof getToken !== "function") throw new Error("CAS CLI requires an access token provider");
|
|
49169
49562
|
if (!validIdentity(identity)) throw new Error("CAS CLI identity is invalid");
|
|
@@ -49205,7 +49598,17 @@ var require_headless_runtime = __commonJS({
|
|
|
49205
49598
|
const startSessionWithPreferences = async (options) => {
|
|
49206
49599
|
const launchOptions = chatPreferences.apply(options.agent, options);
|
|
49207
49600
|
if (launchOptions.permissionMode === void 0) launchOptions.permissionMode = "default";
|
|
49208
|
-
|
|
49601
|
+
if (options.agent === "claude" && launchOptions.permissionMode === CHAT_PERMISSION_MODES.FULL_ACCESS && (getuid == null ? void 0 : getuid()) === 0) launchOptions.permissionMode = "default";
|
|
49602
|
+
let started;
|
|
49603
|
+
try {
|
|
49604
|
+
started = await manager.startSession(launchOptions);
|
|
49605
|
+
} catch (error) {
|
|
49606
|
+
const status = classifyProviderStartupError(options.agent, error);
|
|
49607
|
+
if (status) {
|
|
49608
|
+
error.code = status.state === "not_installed" ? "provider_not_installed" : "provider_unauthenticated";
|
|
49609
|
+
}
|
|
49610
|
+
throw error;
|
|
49611
|
+
}
|
|
49209
49612
|
chatPreferences.write(started.agent || options.agent, {
|
|
49210
49613
|
permissionMode: started.permissionMode,
|
|
49211
49614
|
effort: started.effort
|
|
@@ -49652,10 +50055,8 @@ ${message}`;
|
|
|
49652
50055
|
handoffSession,
|
|
49653
50056
|
sessionAction,
|
|
49654
50057
|
closeSession: async ({ sessionId }) => {
|
|
49655
|
-
|
|
49656
|
-
return {
|
|
49657
|
-
success: ((_a = await manager.stopSession(sessionId)) == null ? void 0 : _a.stopped) === true
|
|
49658
|
-
};
|
|
50058
|
+
await manager.stopSession(sessionId);
|
|
50059
|
+
return { success: true };
|
|
49659
50060
|
},
|
|
49660
50061
|
minimizeSession: ({ sessionId }) => updateIdentity(sessionId, { minimized: true }),
|
|
49661
50062
|
restoreSession: ({ sessionId }) => updateIdentity(sessionId, { minimized: false }),
|
|
@@ -49712,7 +50113,11 @@ ${message}`;
|
|
|
49712
50113
|
remoteClient: remoteRuntimeClient,
|
|
49713
50114
|
peerRuntimeNetwork,
|
|
49714
50115
|
dataPath: resolvedDataPath,
|
|
49715
|
-
deliverMessage: deliverCoordinatedMessage
|
|
50116
|
+
deliverMessage: deliverCoordinatedMessage,
|
|
50117
|
+
createPairingLink: async () => {
|
|
50118
|
+
const pairing = await relay.createPairing();
|
|
50119
|
+
return { url: desktopConnectionLink(pairing), expiresAt: pairing.expiresAt };
|
|
50120
|
+
}
|
|
49716
50121
|
});
|
|
49717
50122
|
return {
|
|
49718
50123
|
identity,
|
|
@@ -49755,7 +50160,7 @@ ${message}`;
|
|
|
49755
50160
|
}
|
|
49756
50161
|
terminalOrder = Math.max(terminalOrder, saved.terminalOrder || 0);
|
|
49757
50162
|
try {
|
|
49758
|
-
const started = await
|
|
50163
|
+
const started = await startSessionWithPreferences({
|
|
49759
50164
|
agent: saved.agent,
|
|
49760
50165
|
...saved.accountId && saved.accountId !== "current" ? { accountId: saved.accountId } : {},
|
|
49761
50166
|
cwd: saved.cwd,
|
|
@@ -50163,6 +50568,9 @@ var require_mobile_pairing_ipc = __commonJS({
|
|
|
50163
50568
|
"src/infrastructure/mobile/mobile-pairing-ipc.js"(exports2, module2) {
|
|
50164
50569
|
var MOBILE_PAIRING_EVENT = "mobile-pairing:event";
|
|
50165
50570
|
var { PRODUCTION_MOBILE_WEB_ORIGIN } = require_mobile_build_channel();
|
|
50571
|
+
var WARM_PAIRING_MIN_REMAINING_MS = 2 * 6e4;
|
|
50572
|
+
var WARM_PAIRING_CHECK_INTERVAL_MS = 3e4;
|
|
50573
|
+
var WARM_PAIRING_SERVE_MIN_REMAINING_MS = 15e3;
|
|
50166
50574
|
function pairingPayload(pairing, mobileWebOrigin = PRODUCTION_MOBILE_WEB_ORIGIN) {
|
|
50167
50575
|
const credentials = new URL("codeagentswarm://pair");
|
|
50168
50576
|
credentials.searchParams.set("relay", new URL(pairing.relayOrigin).origin);
|
|
@@ -50184,13 +50592,49 @@ var require_mobile_pairing_ipc = __commonJS({
|
|
|
50184
50592
|
setKeepAvailable = () => false,
|
|
50185
50593
|
createQrDataUrl = (payload, options) => require("qrcode").toDataURL(payload, options)
|
|
50186
50594
|
}) {
|
|
50595
|
+
var _a;
|
|
50187
50596
|
const broadcast = (message) => {
|
|
50188
50597
|
for (const window2 of BrowserWindow.getAllWindows()) {
|
|
50189
50598
|
if (!window2.isDestroyed()) window2.webContents.send(MOBILE_PAIRING_EVENT, message);
|
|
50190
50599
|
}
|
|
50191
50600
|
};
|
|
50192
|
-
|
|
50193
|
-
|
|
50601
|
+
const buildPairing = async () => {
|
|
50602
|
+
const pairing = await relayClient.createPairing();
|
|
50603
|
+
const qrDataUrl = await createQrDataUrl(
|
|
50604
|
+
pairingPayload(pairing, mobileWebOrigin),
|
|
50605
|
+
{
|
|
50606
|
+
scale: 8,
|
|
50607
|
+
margin: 4,
|
|
50608
|
+
errorCorrectionLevel: "L",
|
|
50609
|
+
color: { dark: "#111827", light: "#ffffff" }
|
|
50610
|
+
}
|
|
50611
|
+
);
|
|
50612
|
+
return { expiresAt: pairing.expiresAt, pairingCode: pairing.pairingCode, qrDataUrl };
|
|
50613
|
+
};
|
|
50614
|
+
let warm = null;
|
|
50615
|
+
let warming = null;
|
|
50616
|
+
const warmPairing = () => {
|
|
50617
|
+
if (warming || relayClient.status !== "online") return warming;
|
|
50618
|
+
const remaining = warm ? warm.expiresAt - Date.now() : 0;
|
|
50619
|
+
if (warm && (warm.served ? remaining > 0 : remaining > WARM_PAIRING_MIN_REMAINING_MS)) return null;
|
|
50620
|
+
warming = buildPairing().then((result) => {
|
|
50621
|
+
warm = result;
|
|
50622
|
+
}, () => {
|
|
50623
|
+
}).finally(() => {
|
|
50624
|
+
warming = null;
|
|
50625
|
+
});
|
|
50626
|
+
return warming;
|
|
50627
|
+
};
|
|
50628
|
+
const warmTimer = setInterval(warmPairing, WARM_PAIRING_CHECK_INTERVAL_MS);
|
|
50629
|
+
(_a = warmTimer.unref) == null ? void 0 : _a.call(warmTimer);
|
|
50630
|
+
relayClient.on("status", (status) => {
|
|
50631
|
+
broadcast({ type: "status", status });
|
|
50632
|
+
if ((status == null ? void 0 : status.status) === "online") void warmPairing();
|
|
50633
|
+
});
|
|
50634
|
+
relayClient.on("event", (event) => {
|
|
50635
|
+
if ((event == null ? void 0 : event.kind) === "pair.scanned") warm = null;
|
|
50636
|
+
broadcast({ type: "relay", event });
|
|
50637
|
+
});
|
|
50194
50638
|
ipcMain.handle("mobile-pairing:status", () => ({
|
|
50195
50639
|
success: true,
|
|
50196
50640
|
...relayClient.getStatus(),
|
|
@@ -50222,23 +50666,16 @@ var require_mobile_pairing_ipc = __commonJS({
|
|
|
50222
50666
|
ipcMain.handle("mobile-pairing:create", async () => {
|
|
50223
50667
|
try {
|
|
50224
50668
|
if (getKeepAvailable() == null) setKeepAvailable(true);
|
|
50225
|
-
|
|
50226
|
-
|
|
50227
|
-
|
|
50228
|
-
{
|
|
50229
|
-
scale: 8,
|
|
50230
|
-
margin: 4,
|
|
50231
|
-
errorCorrectionLevel: "L",
|
|
50232
|
-
color: { dark: "#111827", light: "#ffffff" }
|
|
50233
|
-
}
|
|
50234
|
-
);
|
|
50669
|
+
if (warming) await warming;
|
|
50670
|
+
if (!warm || warm.expiresAt - Date.now() < WARM_PAIRING_SERVE_MIN_REMAINING_MS) warm = await buildPairing();
|
|
50671
|
+
warm.served = true;
|
|
50235
50672
|
return {
|
|
50236
50673
|
success: true,
|
|
50237
|
-
expiresAt:
|
|
50238
|
-
pairingCode:
|
|
50674
|
+
expiresAt: warm.expiresAt,
|
|
50675
|
+
pairingCode: warm.pairingCode,
|
|
50239
50676
|
webUrl: mobileWebOrigin,
|
|
50240
50677
|
keepAvailable: getKeepAvailable() === true,
|
|
50241
|
-
qrDataUrl
|
|
50678
|
+
qrDataUrl: warm.qrDataUrl
|
|
50242
50679
|
};
|
|
50243
50680
|
} catch (error) {
|
|
50244
50681
|
return { success: false, error: error.message };
|
|
@@ -50274,6 +50711,7 @@ var require_cas = __commonJS({
|
|
|
50274
50711
|
var { pairingPayload } = require_mobile_pairing_ipc();
|
|
50275
50712
|
var { mobileWebOrigin } = require_mobile_build_channel();
|
|
50276
50713
|
var { requestHeadlessBridge } = require_headless_session_bridge();
|
|
50714
|
+
var { resolvePairingInput } = require_desktop_connection_link();
|
|
50277
50715
|
var {
|
|
50278
50716
|
DEFAULT_BACKEND_URL,
|
|
50279
50717
|
appDataPath,
|
|
@@ -50282,8 +50720,7 @@ var require_cas = __commonJS({
|
|
|
50282
50720
|
loadIdentity,
|
|
50283
50721
|
resolveProject
|
|
50284
50722
|
} = require_headless_runtime();
|
|
50285
|
-
var version = true ? "0.0.
|
|
50286
|
-
var DEFAULT_PAIRING_CODE_ORIGIN = "https://codeagentswarm-connect.elcaminodelprogramadorweb.workers.dev";
|
|
50723
|
+
var version = true ? "0.0.15" : JSON.parse(fs.readFileSync(path.join(__dirname, "..", "..", "package.json"), "utf8")).version;
|
|
50287
50724
|
function help() {
|
|
50288
50725
|
return `CAS CLI ${version}
|
|
50289
50726
|
|
|
@@ -50293,6 +50730,7 @@ Usage:
|
|
|
50293
50730
|
cas-cli setup
|
|
50294
50731
|
cas-cli doctor
|
|
50295
50732
|
cas-cli update
|
|
50733
|
+
cas-cli connect
|
|
50296
50734
|
cas-cli link PAIRING_CODE
|
|
50297
50735
|
cas-cli remote-status
|
|
50298
50736
|
cas-cli unlink
|
|
@@ -50319,7 +50757,7 @@ host-local configuration; either repeatable flag may be omitted.
|
|
|
50319
50757
|
});
|
|
50320
50758
|
const requestedCommand = parsed.positionals.shift() || "serve";
|
|
50321
50759
|
const command = requestedCommand === "cloud" ? "serve" : requestedCommand;
|
|
50322
|
-
if (!["serve", "setup", "doctor", "update", "help", "link", "remote-status", "unlink"].includes(command)) {
|
|
50760
|
+
if (!["serve", "setup", "doctor", "update", "help", "connect", "link", "remote-status", "unlink"].includes(command)) {
|
|
50323
50761
|
throw new Error(`Unknown command: ${command}`);
|
|
50324
50762
|
}
|
|
50325
50763
|
const pairingInput = command === "link" ? parsed.positionals.shift() : null;
|
|
@@ -50331,28 +50769,6 @@ host-local configuration; either repeatable flag may be omitted.
|
|
|
50331
50769
|
const { ["projects-root"]: projectsRoot, ...values } = parsed.values;
|
|
50332
50770
|
return { command, ...values, projectsRoot, ...pairingInput ? { pairingInput } : {} };
|
|
50333
50771
|
}
|
|
50334
|
-
async function resolvePairingInput(raw, fetchImpl = globalThis.fetch) {
|
|
50335
|
-
const compact = String(raw || "").trim().toUpperCase().replace(/[\s-]/g, "");
|
|
50336
|
-
if (!/^[A-HJ-NP-Z2-9]{8}$/.test(compact)) throw new Error("This pairing code is not valid");
|
|
50337
|
-
const code = `${compact.slice(0, 4)}-${compact.slice(4)}`;
|
|
50338
|
-
const origin = new URL(process.env.CAS_PAIRING_CODE_ORIGIN || DEFAULT_PAIRING_CODE_ORIGIN);
|
|
50339
|
-
const local = ["localhost", "127.0.0.1", "[::1]"].includes(origin.hostname);
|
|
50340
|
-
if (origin.protocol !== "https:" && !(origin.protocol === "http:" && local) || origin.username || origin.password) {
|
|
50341
|
-
throw new Error("The pairing service is not secure");
|
|
50342
|
-
}
|
|
50343
|
-
try {
|
|
50344
|
-
const response = await fetchImpl(`${origin.origin}/api/mobile/pairing-code/${encodeURIComponent(code)}`, {
|
|
50345
|
-
headers: { Accept: "application/json" },
|
|
50346
|
-
signal: AbortSignal.timeout(1e4)
|
|
50347
|
-
});
|
|
50348
|
-
if (!response.ok) throw new Error();
|
|
50349
|
-
const body = await response.json();
|
|
50350
|
-
if (typeof body.pairingUri !== "string") throw new Error();
|
|
50351
|
-
return body.pairingUri;
|
|
50352
|
-
} catch (_) {
|
|
50353
|
-
throw new Error("This pairing code is invalid or has expired");
|
|
50354
|
-
}
|
|
50355
|
-
}
|
|
50356
50772
|
async function linkRemoteRuntime(pairingInput, { output = console.log, request = requestHeadlessBridge } = {}) {
|
|
50357
50773
|
var _a, _b;
|
|
50358
50774
|
const pairing = await resolvePairingInput(pairingInput);
|
|
@@ -50374,6 +50790,13 @@ host-local configuration; either repeatable flag may be omitted.
|
|
|
50374
50790
|
}
|
|
50375
50791
|
throw new Error("Pairing timed out before it was confirmed on the Mac");
|
|
50376
50792
|
}
|
|
50793
|
+
async function createDesktopConnectionLink({ output = console.log, request = requestHeadlessBridge } = {}) {
|
|
50794
|
+
const result = await request(appDataPath(), "POST", "/admin/pairing-link");
|
|
50795
|
+
output("Open this link on the Mac running CodeAgentSwarm Desktop:");
|
|
50796
|
+
output(result.url);
|
|
50797
|
+
output("The link is single-use and expires in 5 minutes.");
|
|
50798
|
+
return result;
|
|
50799
|
+
}
|
|
50377
50800
|
async function printRemoteStatus({ output = console.log, request = requestHeadlessBridge } = {}) {
|
|
50378
50801
|
var _a, _b;
|
|
50379
50802
|
const state = await request(appDataPath(), "GET", "/admin/remote-runtime");
|
|
@@ -50538,6 +50961,7 @@ CAS Cloud is serving ${host.projects.length} registered project${host.projects.l
|
|
|
50538
50961
|
if (options.command === "doctor") return doctor();
|
|
50539
50962
|
if (options.command === "setup") return setupCloud();
|
|
50540
50963
|
if (options.command === "update") return updateInstallation();
|
|
50964
|
+
if (options.command === "connect") return createDesktopConnectionLink();
|
|
50541
50965
|
if (options.command === "link") return linkRemoteRuntime(options.pairingInput);
|
|
50542
50966
|
if (options.command === "remote-status") return printRemoteStatus();
|
|
50543
50967
|
if (options.command === "unlink") return unlinkRemoteRuntime();
|
|
@@ -50552,6 +50976,7 @@ CAS Cloud is serving ${host.projects.length} registered project${host.projects.l
|
|
|
50552
50976
|
module2.exports = {
|
|
50553
50977
|
AGENT_BINARIES,
|
|
50554
50978
|
doctor,
|
|
50979
|
+
createDesktopConnectionLink,
|
|
50555
50980
|
help,
|
|
50556
50981
|
linkRemoteRuntime,
|
|
50557
50982
|
main,
|
package/package.json
CHANGED