@schoolai/shipyard 3.14.0 → 3.15.0-rc.20260616.1
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/capability-detector-worker.js +5 -5
- package/dist/{chunk-IWBDVGD2.js → chunk-4FVMGXFP.js} +2 -2
- package/dist/{chunk-T3OTZ66B.js → chunk-B7WZUKYX.js} +219 -86
- package/dist/chunk-B7WZUKYX.js.map +1 -0
- package/dist/{chunk-M3WBYTB3.js → chunk-FJXRLZZI.js} +20 -3
- package/dist/chunk-FJXRLZZI.js.map +1 -0
- package/dist/{chunk-WGS7ZW6N.js → chunk-L5FQEZ6Y.js} +3 -3
- package/dist/{chunk-OX3UY44R.js → chunk-URRNZGFO.js} +31 -42
- package/dist/chunk-URRNZGFO.js.map +1 -0
- package/dist/{chunk-BUAEJNUG.js → chunk-UZT6JIJ5.js} +3 -3
- package/dist/{chunk-BUAEJNUG.js.map → chunk-UZT6JIJ5.js.map} +1 -1
- package/dist/{chunk-3KE2VDKA.js → chunk-VKY7UXTP.js} +25 -3
- package/dist/chunk-VKY7UXTP.js.map +1 -0
- package/dist/{chunk-RCEAMZVG.js → chunk-WMD76UPS.js} +2 -2
- package/dist/{chunk-KUPHN3ZN.js → chunk-X3TOIQUD.js} +2 -2
- package/dist/cursor-runner.js +3 -3
- package/dist/electron-utility.js +2 -2
- package/dist/index.js +4 -4
- package/dist/{login-HRR3T4SZ.js → login-7YFYG2ZB.js} +3 -3
- package/dist/{mcp-servers-GUA5WOHO.js → mcp-servers-DSOX243C.js} +8 -2
- package/dist/{plan-backfill-QNJUWOYP.js → plan-backfill-DVXCXD3E.js} +4 -4
- package/dist/{serve-25I4ML7R.js → serve-IWMVSSNF.js} +536 -218
- package/dist/{serve-25I4ML7R.js.map → serve-IWMVSSNF.js.map} +1 -1
- package/dist/{start-O2DXLW23.js → start-ZCDMUS4U.js} +6 -6
- package/package.json +1 -1
- package/dist/chunk-3KE2VDKA.js.map +0 -1
- package/dist/chunk-M3WBYTB3.js.map +0 -1
- package/dist/chunk-OX3UY44R.js.map +0 -1
- package/dist/chunk-T3OTZ66B.js.map +0 -1
- /package/dist/{chunk-IWBDVGD2.js.map → chunk-4FVMGXFP.js.map} +0 -0
- /package/dist/{chunk-WGS7ZW6N.js.map → chunk-L5FQEZ6Y.js.map} +0 -0
- /package/dist/{chunk-RCEAMZVG.js.map → chunk-WMD76UPS.js.map} +0 -0
- /package/dist/{chunk-KUPHN3ZN.js.map → chunk-X3TOIQUD.js.map} +0 -0
- /package/dist/{login-HRR3T4SZ.js.map → login-7YFYG2ZB.js.map} +0 -0
- /package/dist/{mcp-servers-GUA5WOHO.js.map → mcp-servers-DSOX243C.js.map} +0 -0
- /package/dist/{plan-backfill-QNJUWOYP.js.map → plan-backfill-DVXCXD3E.js.map} +0 -0
- /package/dist/{start-O2DXLW23.js.map → start-ZCDMUS4U.js.map} +0 -0
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
detectCapabilities,
|
|
4
4
|
refreshMcpServers,
|
|
5
5
|
registerBuiltInProfiles
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-URRNZGFO.js";
|
|
7
7
|
import "./chunk-TUQTEWK3.js";
|
|
8
8
|
import {
|
|
9
9
|
getRepoMetadata
|
|
@@ -11,13 +11,13 @@ import {
|
|
|
11
11
|
import "./chunk-4T2OQAVL.js";
|
|
12
12
|
import {
|
|
13
13
|
MCPTokenStore
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-B7WZUKYX.js";
|
|
15
15
|
import "./chunk-RR6V6SNM.js";
|
|
16
16
|
import "./chunk-4MRKRVIQ.js";
|
|
17
17
|
import "./chunk-ZFKJAYAN.js";
|
|
18
|
-
import "./chunk-
|
|
19
|
-
import "./chunk-
|
|
20
|
-
import "./chunk-
|
|
18
|
+
import "./chunk-WMD76UPS.js";
|
|
19
|
+
import "./chunk-4FVMGXFP.js";
|
|
20
|
+
import "./chunk-FJXRLZZI.js";
|
|
21
21
|
import "./chunk-EHQITHQX.js";
|
|
22
22
|
import "./chunk-X3MULCV5.js";
|
|
23
23
|
import {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
PUBLISHED_PREVIEW_KINDS,
|
|
4
4
|
PUBLISH_TTL_CHOICES
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-FJXRLZZI.js";
|
|
6
6
|
import {
|
|
7
7
|
external_exports
|
|
8
8
|
} from "./chunk-JCEWPG3R.js";
|
|
@@ -28835,4 +28835,4 @@ export {
|
|
|
28835
28835
|
encodeDrain,
|
|
28836
28836
|
decodeFrame
|
|
28837
28837
|
};
|
|
28838
|
-
//# sourceMappingURL=chunk-
|
|
28838
|
+
//# sourceMappingURL=chunk-4FVMGXFP.js.map
|
|
@@ -14,10 +14,10 @@ import {
|
|
|
14
14
|
} from "./chunk-JCEWPG3R.js";
|
|
15
15
|
|
|
16
16
|
// src/shared/capabilities/mcp-servers.ts
|
|
17
|
-
import { readFile as
|
|
17
|
+
import { readFile as readFile4 } from "fs/promises";
|
|
18
18
|
import { homedir as homedir2 } from "os";
|
|
19
|
-
import {
|
|
20
|
-
import { parse as
|
|
19
|
+
import { join as join3, resolve } from "path";
|
|
20
|
+
import { parse as parseToml2 } from "toml";
|
|
21
21
|
|
|
22
22
|
// src/shared/mcp/claude-code-credentials.ts
|
|
23
23
|
import { execFile as execFileCb } from "child_process";
|
|
@@ -523,6 +523,84 @@ var MCPTokenStore = class {
|
|
|
523
523
|
}
|
|
524
524
|
};
|
|
525
525
|
|
|
526
|
+
// src/services/metrics/telemeter.ts
|
|
527
|
+
var TELEMETERED_EVENT_NAMES = [
|
|
528
|
+
"anthropic_login_failed",
|
|
529
|
+
"claudeai_integrations_fetch_failed",
|
|
530
|
+
"codex_spawn_failed",
|
|
531
|
+
"run_stall_timeout",
|
|
532
|
+
"request_task_state_replay_failed",
|
|
533
|
+
"loro_recovery_failed",
|
|
534
|
+
"mcp_server_connect_failed",
|
|
535
|
+
"mcp_server_needs_auth",
|
|
536
|
+
"mcp_reconnect_failed",
|
|
537
|
+
"mcp_reconnect_terminal",
|
|
538
|
+
"mcp_reconnect_terminal_unsupported",
|
|
539
|
+
"mcp_reauth_failed",
|
|
540
|
+
"mcp_adopted_set_failed",
|
|
541
|
+
"mcp_push_failed",
|
|
542
|
+
"harness_mcp_registration_failed",
|
|
543
|
+
"codex_auth_divergence_detected",
|
|
544
|
+
"cursor_auth_divergence_detected",
|
|
545
|
+
/**
|
|
546
|
+
* A Codex remote-compact cycle failed with a 401 "Missing bearer" error —
|
|
547
|
+
* the app-server lost its in-memory token during refresh-token rotation.
|
|
548
|
+
* Emitted once per compact attempt (not per retry) so fleet dashboards can
|
|
549
|
+
* surface the storm rate without log amplification.
|
|
550
|
+
*/
|
|
551
|
+
"codex_compact_auth_failure",
|
|
552
|
+
"event_loop_stall",
|
|
553
|
+
"machine_sleep_artifact",
|
|
554
|
+
/**
|
|
555
|
+
* Per-process memory from the Electron main process (`app.getAppMetrics()`).
|
|
556
|
+
* The only source of true per-process RSS for the renderer/GPU/utility — JS
|
|
557
|
+
* heap (browser_metrics_sample) is capped ~4GB and cannot reveal a 50GB
|
|
558
|
+
* process. Forwarded to D1 by the daemon so runaway RAM is localizable
|
|
559
|
+
* fleet-wide to the offending Electron process.
|
|
560
|
+
*/
|
|
561
|
+
"electron_app_metrics",
|
|
562
|
+
/** Electron main cleared a wedged Squirrel.Mac staged install on launch. */
|
|
563
|
+
"squirrel_install_stuck_recovered",
|
|
564
|
+
/**
|
|
565
|
+
* An ALO control-channel entry exhausted its maxDeliver retry budget
|
|
566
|
+
* without receiving an ack. Payload: { streamId, attempts, channel: 'control' }.
|
|
567
|
+
* Emitted via the `onDeadLetter` callback in control-channel-wiring.ts.
|
|
568
|
+
* Complements the `alo_resend_exhausted` ERROR log event emitted by the
|
|
569
|
+
* shell itself; this telemetry path routes it to D1 for fleet-wide
|
|
570
|
+
* observability so silent resend exhaustion is detectable in aggregate.
|
|
571
|
+
*/
|
|
572
|
+
"alo_resend_exhausted",
|
|
573
|
+
/**
|
|
574
|
+
* An ALO control-channel shell reaped itself as an orphan — no truncating
|
|
575
|
+
* ack landed for `orphanThresholdMs` (5 min) while its retry buffer was
|
|
576
|
+
* non-empty, so the WHOLE buffer of unacked control messages was discarded.
|
|
577
|
+
* This is the bulk-loss sibling of `alo_resend_exhausted` (one entry): a
|
|
578
|
+
* reap can drop dozens of messages at once. Payload:
|
|
579
|
+
* { streamId, discardedCount, msSinceLastAck, attempts, channel: 'control' }.
|
|
580
|
+
* Emitted via the `onOrphanReaped` callback in control-channel-wiring.ts;
|
|
581
|
+
* the shell also emits a matching ERROR log. Routed to D1 so silent
|
|
582
|
+
* reconnect-time loss is detectable fleet-wide.
|
|
583
|
+
*/
|
|
584
|
+
"alo_shell_orphan_reaped",
|
|
585
|
+
/**
|
|
586
|
+
* A `task_index_snapshot` envelope serialized past the control-channel
|
|
587
|
+
* high-water even after byte-bounded pagination — i.e. a single slim entry
|
|
588
|
+
* alone exceeds the cap (a page is guaranteed >=1 entry for forward
|
|
589
|
+
* progress). The control channel may drop it whole (`channel_send_dropped`).
|
|
590
|
+
* Payload: { bytes, taskCount, limitBytes }. Surfaces the pathological
|
|
591
|
+
* oversized-record case the byte budget cannot otherwise bound.
|
|
592
|
+
*/
|
|
593
|
+
"task_index_snapshot_oversized"
|
|
594
|
+
];
|
|
595
|
+
var TELEMETERED_EVENTS = new Set(TELEMETERED_EVENT_NAMES);
|
|
596
|
+
var sink = null;
|
|
597
|
+
function setTelemetrySink(fn) {
|
|
598
|
+
sink = fn;
|
|
599
|
+
}
|
|
600
|
+
function telemeter(event, payload) {
|
|
601
|
+
sink?.(event, payload);
|
|
602
|
+
}
|
|
603
|
+
|
|
526
604
|
// src/shared/auth/anthropic-credentials.ts
|
|
527
605
|
import { execFile as execFileCb2 } from "child_process";
|
|
528
606
|
import { promisify as promisify2 } from "util";
|
|
@@ -677,6 +755,17 @@ function classifyHttpStatus(status) {
|
|
|
677
755
|
if (status >= 500 && status < 600) return "http_5xx";
|
|
678
756
|
return "http_other";
|
|
679
757
|
}
|
|
758
|
+
function classifyClaudeAiIntegrationsFailure(input) {
|
|
759
|
+
const accountIssue = input.status === 403 && input.errorBody?.includes("user:mcp_servers") ? {
|
|
760
|
+
kind: "missing_user_mcp_servers_scope",
|
|
761
|
+
message: "Re-authenticate with Claude to enable claude.ai connectors."
|
|
762
|
+
} : null;
|
|
763
|
+
return {
|
|
764
|
+
errorClass: classifyHttpStatus(input.status),
|
|
765
|
+
shouldBackoffAuth: input.status === 401 || input.status === 403,
|
|
766
|
+
accountIssue
|
|
767
|
+
};
|
|
768
|
+
}
|
|
680
769
|
function classifyException(err) {
|
|
681
770
|
if (err instanceof Error) {
|
|
682
771
|
if (err.name === "AbortError") return "timeout";
|
|
@@ -693,16 +782,16 @@ async function readErrorBody(response) {
|
|
|
693
782
|
return null;
|
|
694
783
|
}
|
|
695
784
|
}
|
|
696
|
-
async function
|
|
785
|
+
async function fetchClaudeAiIntegrationsWithStatus(log) {
|
|
697
786
|
const url = CLAUDEAI_INTEGRATIONS_URL;
|
|
698
787
|
if (Date.now() < authBackoffUntil) {
|
|
699
|
-
return [];
|
|
788
|
+
return { servers: [] };
|
|
700
789
|
}
|
|
701
790
|
try {
|
|
702
791
|
const token = await readKeychainOAuthToken(log);
|
|
703
792
|
if (!token) {
|
|
704
793
|
log({ event: "claudeai_integrations_skipped", reason: "no_oauth_token" });
|
|
705
|
-
return [];
|
|
794
|
+
return { servers: [] };
|
|
706
795
|
}
|
|
707
796
|
const controller = new AbortController();
|
|
708
797
|
const timeout = setTimeout(() => controller.abort(), 5e3);
|
|
@@ -717,14 +806,22 @@ async function fetchClaudeAiIntegrations(log) {
|
|
|
717
806
|
});
|
|
718
807
|
if (!response.ok) {
|
|
719
808
|
const errorBody = await readErrorBody(response);
|
|
809
|
+
const decision = classifyClaudeAiIntegrationsFailure({
|
|
810
|
+
status: response.status,
|
|
811
|
+
errorBody
|
|
812
|
+
});
|
|
720
813
|
log({
|
|
721
814
|
event: "claudeai_integrations_fetch_failed",
|
|
722
815
|
url,
|
|
723
816
|
status: response.status,
|
|
724
|
-
errorClass:
|
|
817
|
+
errorClass: decision.errorClass,
|
|
725
818
|
errorBody
|
|
726
819
|
});
|
|
727
|
-
|
|
820
|
+
telemeter("claudeai_integrations_fetch_failed", {
|
|
821
|
+
status: response.status,
|
|
822
|
+
errorClass: decision.errorClass
|
|
823
|
+
});
|
|
824
|
+
if (decision.shouldBackoffAuth) {
|
|
728
825
|
authBackoffUntil = Date.now() + AUTH_BACKOFF_MS;
|
|
729
826
|
log({
|
|
730
827
|
event: "claudeai_integrations_auth_backoff",
|
|
@@ -732,39 +829,49 @@ async function fetchClaudeAiIntegrations(log) {
|
|
|
732
829
|
backoffMs: AUTH_BACKOFF_MS
|
|
733
830
|
});
|
|
734
831
|
}
|
|
735
|
-
return [];
|
|
832
|
+
return decision.accountIssue ? { servers: [], accountIssue: decision.accountIssue } : { servers: [] };
|
|
736
833
|
}
|
|
737
834
|
authBackoffUntil = 0;
|
|
738
835
|
const body = await response.json();
|
|
739
836
|
const servers = parseClaudeAiServers(body, log);
|
|
740
|
-
return
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
837
|
+
return {
|
|
838
|
+
servers: servers.map((s) => ({
|
|
839
|
+
name: s.name,
|
|
840
|
+
type: "http",
|
|
841
|
+
runtimeId: CLAUDE_CODE_RUNTIME_ID,
|
|
842
|
+
url: s.url,
|
|
843
|
+
enabled: true,
|
|
844
|
+
source: "claudeai",
|
|
845
|
+
authStatus: "unknown",
|
|
846
|
+
/** Gateway id — drives the `mcp-proxy.anthropic.com/v1/mcp/{id}` route. */
|
|
847
|
+
...s.id ? { id: s.id } : {}
|
|
848
|
+
}))
|
|
849
|
+
};
|
|
751
850
|
} finally {
|
|
752
851
|
clearTimeout(timeout);
|
|
753
852
|
}
|
|
754
853
|
} catch (err) {
|
|
854
|
+
const errorClass = classifyException(err);
|
|
755
855
|
log({
|
|
756
856
|
event: "claudeai_integrations_fetch_failed",
|
|
757
857
|
url,
|
|
758
858
|
status: null,
|
|
759
|
-
errorClass
|
|
859
|
+
errorClass,
|
|
760
860
|
errorBody: null,
|
|
761
861
|
error: err instanceof Error ? err.message : String(err)
|
|
762
862
|
});
|
|
763
|
-
|
|
863
|
+
telemeter("claudeai_integrations_fetch_failed", {
|
|
864
|
+
status: null,
|
|
865
|
+
errorClass
|
|
866
|
+
});
|
|
867
|
+
return { servers: [] };
|
|
764
868
|
}
|
|
765
869
|
}
|
|
766
870
|
|
|
767
|
-
// src/shared/capabilities/mcp-
|
|
871
|
+
// src/shared/capabilities/mcp-config-readers.ts
|
|
872
|
+
import { readFile as readFile3, stat as stat2 } from "fs/promises";
|
|
873
|
+
import { basename } from "path";
|
|
874
|
+
import { parse as parseToml } from "toml";
|
|
768
875
|
var MCPStdioEntrySchema = external_exports.object({
|
|
769
876
|
type: external_exports.literal("stdio").optional(),
|
|
770
877
|
command: external_exports.string(),
|
|
@@ -811,54 +918,6 @@ var CodexMCPHttpEntrySchema = external_exports.object({
|
|
|
811
918
|
bearer_token_env_var: external_exports.string().optional(),
|
|
812
919
|
enabled: external_exports.boolean().optional()
|
|
813
920
|
}).passthrough();
|
|
814
|
-
function shouldFetchClaudeAiIntegrations(preferredAuth) {
|
|
815
|
-
if (preferredAuth == null) return true;
|
|
816
|
-
return preferredAuth === "claude-ai";
|
|
817
|
-
}
|
|
818
|
-
function canonicalMcpServerKey(server) {
|
|
819
|
-
if (!server.url) return server.name.toLowerCase();
|
|
820
|
-
try {
|
|
821
|
-
const parsed = new URL(server.url);
|
|
822
|
-
parsed.hostname = parsed.hostname.toLowerCase();
|
|
823
|
-
parsed.protocol = parsed.protocol.toLowerCase();
|
|
824
|
-
const normalized = parsed.toString();
|
|
825
|
-
return normalized.endsWith("/") ? normalized.slice(0, -1) : normalized;
|
|
826
|
-
} catch {
|
|
827
|
-
return server.name.toLowerCase();
|
|
828
|
-
}
|
|
829
|
-
}
|
|
830
|
-
function dedupeServerCandidates(candidates) {
|
|
831
|
-
const deduped = /* @__PURE__ */ new Map();
|
|
832
|
-
const allSources = /* @__PURE__ */ new Map();
|
|
833
|
-
const firstId = /* @__PURE__ */ new Map();
|
|
834
|
-
for (const candidate of candidates) {
|
|
835
|
-
const key = canonicalMcpServerKey(candidate.server);
|
|
836
|
-
const existing = deduped.get(key);
|
|
837
|
-
if (!existing || candidate.priority >= existing.priority) {
|
|
838
|
-
deduped.set(key, candidate);
|
|
839
|
-
}
|
|
840
|
-
const src = candidate.server.source;
|
|
841
|
-
const srcs = allSources.get(key);
|
|
842
|
-
if (srcs === void 0) {
|
|
843
|
-
allSources.set(key, [src]);
|
|
844
|
-
} else if (!srcs.includes(src)) {
|
|
845
|
-
srcs.push(src);
|
|
846
|
-
}
|
|
847
|
-
if (!firstId.has(key) && candidate.server.id) {
|
|
848
|
-
firstId.set(key, candidate.server.id);
|
|
849
|
-
}
|
|
850
|
-
}
|
|
851
|
-
return [...deduped.values()].map((candidate) => {
|
|
852
|
-
const key = canonicalMcpServerKey(candidate.server);
|
|
853
|
-
const sources = allSources.get(key) ?? [candidate.server.source];
|
|
854
|
-
const id = firstId.get(key) ?? candidate.server.id;
|
|
855
|
-
return {
|
|
856
|
-
...candidate.server,
|
|
857
|
-
sources,
|
|
858
|
-
...id !== void 0 ? { id } : {}
|
|
859
|
-
};
|
|
860
|
-
});
|
|
861
|
-
}
|
|
862
921
|
var SECRET_PATTERNS = /^(sk-|ghp_|gho_|glpat-|xoxb-|xoxp-|Bearer\s|token\s)/i;
|
|
863
922
|
var SECRET_FLAGS = /* @__PURE__ */ new Set(["--api-key", "--token", "--secret", "--password", "--key", "-k"]);
|
|
864
923
|
function redactArgs(args) {
|
|
@@ -1166,15 +1225,80 @@ async function readCursorMCPConfig(filePath, source, log, metadata, now = Date.n
|
|
|
1166
1225
|
now
|
|
1167
1226
|
);
|
|
1168
1227
|
}
|
|
1228
|
+
|
|
1229
|
+
// src/shared/capabilities/mcp-servers.ts
|
|
1230
|
+
function shouldFetchClaudeAiIntegrations(preferredAuth) {
|
|
1231
|
+
if (preferredAuth == null) return true;
|
|
1232
|
+
return preferredAuth === "claude-ai";
|
|
1233
|
+
}
|
|
1234
|
+
function claudeAiAccountIssueServer() {
|
|
1235
|
+
return {
|
|
1236
|
+
name: "claude.ai connectors",
|
|
1237
|
+
type: "http",
|
|
1238
|
+
runtimeId: CLAUDE_CODE_RUNTIME_ID,
|
|
1239
|
+
enabled: false,
|
|
1240
|
+
source: "claudeai",
|
|
1241
|
+
sourceLabel: "Claude.ai",
|
|
1242
|
+
authStatus: "unauthenticated"
|
|
1243
|
+
};
|
|
1244
|
+
}
|
|
1245
|
+
function parseTomlRecord2(raw) {
|
|
1246
|
+
const parsed = parseToml2(raw);
|
|
1247
|
+
return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed) ? parsed : {};
|
|
1248
|
+
}
|
|
1249
|
+
function canonicalMcpServerKey(server) {
|
|
1250
|
+
if (!server.url) return server.name.toLowerCase();
|
|
1251
|
+
try {
|
|
1252
|
+
const parsed = new URL(server.url);
|
|
1253
|
+
parsed.hostname = parsed.hostname.toLowerCase();
|
|
1254
|
+
parsed.protocol = parsed.protocol.toLowerCase();
|
|
1255
|
+
const normalized = parsed.toString();
|
|
1256
|
+
return normalized.endsWith("/") ? normalized.slice(0, -1) : normalized;
|
|
1257
|
+
} catch {
|
|
1258
|
+
return server.name.toLowerCase();
|
|
1259
|
+
}
|
|
1260
|
+
}
|
|
1261
|
+
function dedupeServerCandidates(candidates) {
|
|
1262
|
+
const deduped = /* @__PURE__ */ new Map();
|
|
1263
|
+
const allSources = /* @__PURE__ */ new Map();
|
|
1264
|
+
const firstId = /* @__PURE__ */ new Map();
|
|
1265
|
+
for (const candidate of candidates) {
|
|
1266
|
+
const key = canonicalMcpServerKey(candidate.server);
|
|
1267
|
+
const existing = deduped.get(key);
|
|
1268
|
+
if (!existing || candidate.priority >= existing.priority) {
|
|
1269
|
+
deduped.set(key, candidate);
|
|
1270
|
+
}
|
|
1271
|
+
const src = candidate.server.source;
|
|
1272
|
+
const srcs = allSources.get(key);
|
|
1273
|
+
if (srcs === void 0) {
|
|
1274
|
+
allSources.set(key, [src]);
|
|
1275
|
+
} else if (!srcs.includes(src)) {
|
|
1276
|
+
srcs.push(src);
|
|
1277
|
+
}
|
|
1278
|
+
if (!firstId.has(key) && candidate.server.id) {
|
|
1279
|
+
firstId.set(key, candidate.server.id);
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1282
|
+
return [...deduped.values()].map((candidate) => {
|
|
1283
|
+
const key = canonicalMcpServerKey(candidate.server);
|
|
1284
|
+
const sources = allSources.get(key) ?? [candidate.server.source];
|
|
1285
|
+
const id = firstId.get(key) ?? candidate.server.id;
|
|
1286
|
+
return {
|
|
1287
|
+
...candidate.server,
|
|
1288
|
+
sources,
|
|
1289
|
+
...id !== void 0 ? { id } : {}
|
|
1290
|
+
};
|
|
1291
|
+
});
|
|
1292
|
+
}
|
|
1169
1293
|
async function readPluginMCPServers(log) {
|
|
1170
1294
|
const servers = [];
|
|
1171
1295
|
try {
|
|
1172
1296
|
const settingsPath = join3(homedir2(), ".claude", "settings.json");
|
|
1173
|
-
const settingsRaw = await
|
|
1297
|
+
const settingsRaw = await readFile4(settingsPath, "utf-8");
|
|
1174
1298
|
const settings = JSON.parse(settingsRaw);
|
|
1175
1299
|
if (!settings.enabledPlugins) return [];
|
|
1176
1300
|
const installedPath = join3(homedir2(), ".claude", "plugins", "installed_plugins.json");
|
|
1177
|
-
const installedRaw = await
|
|
1301
|
+
const installedRaw = await readFile4(installedPath, "utf-8");
|
|
1178
1302
|
const installed = JSON.parse(installedRaw);
|
|
1179
1303
|
if (!installed.plugins) return [];
|
|
1180
1304
|
for (const [pluginId, enabled] of Object.entries(settings.enabledPlugins)) {
|
|
@@ -1229,8 +1353,8 @@ var CodexPluginMcpServersFileSchema = external_exports.object({
|
|
|
1229
1353
|
});
|
|
1230
1354
|
async function readCodexTomlConfig(configPath) {
|
|
1231
1355
|
try {
|
|
1232
|
-
const raw = await
|
|
1233
|
-
const parsed =
|
|
1356
|
+
const raw = await readFile4(configPath, "utf-8");
|
|
1357
|
+
const parsed = parseTomlRecord2(raw);
|
|
1234
1358
|
const result = CodexConfigTomlSchema.safeParse(parsed);
|
|
1235
1359
|
return result.success ? result.data : null;
|
|
1236
1360
|
} catch {
|
|
@@ -1244,7 +1368,7 @@ async function readMarketplaceJson(marketplaceSourceDir) {
|
|
|
1244
1368
|
];
|
|
1245
1369
|
for (const candidate of candidates) {
|
|
1246
1370
|
try {
|
|
1247
|
-
const raw = await
|
|
1371
|
+
const raw = await readFile4(candidate, "utf-8");
|
|
1248
1372
|
const parsed = JSON.parse(raw);
|
|
1249
1373
|
const result = MarketplaceJsonSchema.safeParse(parsed);
|
|
1250
1374
|
if (result.success) return result.data;
|
|
@@ -1256,7 +1380,7 @@ async function readMarketplaceJson(marketplaceSourceDir) {
|
|
|
1256
1380
|
async function readCodexPluginManifestMcps(pluginRoot, pluginId, marketplaceName, log) {
|
|
1257
1381
|
const manifestPath = join3(pluginRoot, ".codex-plugin", "plugin.json");
|
|
1258
1382
|
try {
|
|
1259
|
-
const raw = await
|
|
1383
|
+
const raw = await readFile4(manifestPath, "utf-8");
|
|
1260
1384
|
const parsed = JSON.parse(raw);
|
|
1261
1385
|
const manifestResult = CodexPluginManifestSchema.safeParse(parsed);
|
|
1262
1386
|
if (!manifestResult.success) {
|
|
@@ -1272,7 +1396,7 @@ async function readCodexPluginManifestMcps(pluginRoot, pluginId, marketplaceName
|
|
|
1272
1396
|
if (!manifest.mcpServers) return [];
|
|
1273
1397
|
const mcpFilePath = resolve(pluginRoot, manifest.mcpServers);
|
|
1274
1398
|
try {
|
|
1275
|
-
const mcpRaw = await
|
|
1399
|
+
const mcpRaw = await readFile4(mcpFilePath, "utf-8");
|
|
1276
1400
|
const mcpParsed = JSON.parse(mcpRaw);
|
|
1277
1401
|
const mcpResult = CodexPluginMcpServersFileSchema.safeParse(mcpParsed);
|
|
1278
1402
|
if (!mcpResult.success || !mcpResult.data.mcpServers) return [];
|
|
@@ -1317,7 +1441,7 @@ async function detectCodexPluginMcps(codexHome, configToml, log) {
|
|
|
1317
1441
|
}
|
|
1318
1442
|
await Promise.all(
|
|
1319
1443
|
marketplaceJson.plugins.map(async (plugin) => {
|
|
1320
|
-
if (
|
|
1444
|
+
if (plugin.source?.source !== "local") return;
|
|
1321
1445
|
const pluginId = `${plugin.name}@${marketplaceName}`;
|
|
1322
1446
|
const pluginEnabledEntry = pluginEnabledMap[pluginId];
|
|
1323
1447
|
if (pluginEnabledEntry?.enabled === false) return;
|
|
@@ -1343,12 +1467,15 @@ function pushCandidates(target, servers, priority) {
|
|
|
1343
1467
|
target.push({ server, priority });
|
|
1344
1468
|
}
|
|
1345
1469
|
}
|
|
1470
|
+
function isCcExpiryActive(expiresAt) {
|
|
1471
|
+
return expiresAt == null || expiresAt > Date.now();
|
|
1472
|
+
}
|
|
1346
1473
|
async function resolveClaudeCodeAuthStatuses(servers) {
|
|
1347
1474
|
for (const server of servers.values()) {
|
|
1348
1475
|
if (server.authStatus !== "unknown") continue;
|
|
1349
1476
|
if (server.type === "stdio") continue;
|
|
1350
1477
|
const ccCreds = await readClaudeCodeCredentials(server.name, server.url ?? "");
|
|
1351
|
-
if (ccCreds?.accessToken && ccCreds.expiresAt
|
|
1478
|
+
if (ccCreds?.accessToken && isCcExpiryActive(ccCreds.expiresAt)) {
|
|
1352
1479
|
server.authStatus = "authenticated";
|
|
1353
1480
|
}
|
|
1354
1481
|
}
|
|
@@ -1470,7 +1597,7 @@ async function detectMCPServersInner(environments, tokenStore, log, preferredAut
|
|
|
1470
1597
|
const userClaudeJsonPath = join3(homedir2(), ".claude.json");
|
|
1471
1598
|
const codexHome = join3(homedir2(), ".codex");
|
|
1472
1599
|
const fetchClaudeAi = shouldFetchClaudeAiIntegrations(preferredAuth);
|
|
1473
|
-
const claudeAiPromise = fetchClaudeAi ?
|
|
1600
|
+
const claudeAiPromise = fetchClaudeAi ? fetchClaudeAiIntegrationsWithStatus(log) : Promise.resolve({ servers: [] });
|
|
1474
1601
|
if (!fetchClaudeAi) {
|
|
1475
1602
|
log({ event: "claudeai_integrations_skipped_by_method", method: preferredAuth ?? null });
|
|
1476
1603
|
}
|
|
@@ -1484,7 +1611,7 @@ async function detectMCPServersInner(environments, tokenStore, log, preferredAut
|
|
|
1484
1611
|
userCursorServers,
|
|
1485
1612
|
pluginServers,
|
|
1486
1613
|
codexPluginServers,
|
|
1487
|
-
|
|
1614
|
+
claudeAiResult,
|
|
1488
1615
|
claudeJsonLocalServers
|
|
1489
1616
|
] = await Promise.all([
|
|
1490
1617
|
readMCPConfig(userSettingsPath, "user", log, {
|
|
@@ -1528,6 +1655,7 @@ async function detectMCPServersInner(environments, tokenStore, log, preferredAut
|
|
|
1528
1655
|
}
|
|
1529
1656
|
)
|
|
1530
1657
|
]);
|
|
1658
|
+
const claudeAiServers = claudeAiResult.accountIssue ? [...claudeAiResult.servers, claudeAiAccountIssueServer()] : claudeAiResult.servers;
|
|
1531
1659
|
pushCandidates(allCandidates, claudeAiServers, 10);
|
|
1532
1660
|
pushCandidates(allCandidates, pluginServers, 20);
|
|
1533
1661
|
pushCandidates(allCandidates, codexPluginServers, 25);
|
|
@@ -1570,15 +1698,14 @@ export {
|
|
|
1570
1698
|
resolveStdioEnv,
|
|
1571
1699
|
resolveEnabledMcpServers,
|
|
1572
1700
|
MCPTokenStore,
|
|
1701
|
+
setTelemetrySink,
|
|
1702
|
+
telemeter,
|
|
1573
1703
|
readKeychainOAuthToken,
|
|
1574
1704
|
CLAUDE_CODE_RUNTIME_ID,
|
|
1575
1705
|
CODEX_RUNTIME_ID,
|
|
1576
1706
|
CURSOR_RUNTIME_ID,
|
|
1577
1707
|
getRuntimeDescriptor,
|
|
1578
1708
|
getRuntimeDisplayName,
|
|
1579
|
-
shouldFetchClaudeAiIntegrations,
|
|
1580
|
-
canonicalMcpServerKey,
|
|
1581
|
-
dedupeServerCandidates,
|
|
1582
1709
|
redactArgs,
|
|
1583
1710
|
redactEnv,
|
|
1584
1711
|
resetMCPConfigCaches,
|
|
@@ -1586,7 +1713,13 @@ export {
|
|
|
1586
1713
|
readClaudeJsonLocalMcpServers,
|
|
1587
1714
|
readCodexMCPConfig,
|
|
1588
1715
|
readCursorMCPConfig,
|
|
1716
|
+
shouldFetchClaudeAiIntegrations,
|
|
1717
|
+
canonicalMcpServerKey,
|
|
1718
|
+
dedupeServerCandidates,
|
|
1589
1719
|
detectCodexPluginMcps,
|
|
1720
|
+
isCcExpiryActive,
|
|
1721
|
+
resolveClaudeCodeAuthStatuses,
|
|
1722
|
+
resolveAuthStatuses,
|
|
1590
1723
|
detectMCPServers
|
|
1591
1724
|
};
|
|
1592
|
-
//# sourceMappingURL=chunk-
|
|
1725
|
+
//# sourceMappingURL=chunk-B7WZUKYX.js.map
|