@drisp/cli 0.5.24 → 0.5.26

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.
@@ -475,58 +475,10 @@ function writeGatewayTrace(message) {
475
475
  process.stderr.write(line);
476
476
  }
477
477
 
478
- // src/infra/db/openVersionedDb.ts
478
+ // src/gateway/transport/uds.ts
479
479
  import fs4 from "fs";
480
+ import net from "net";
480
481
  import path3 from "path";
481
- import Database from "better-sqlite3";
482
- function migrateVersionedSchema(db, schema) {
483
- db.exec(
484
- "CREATE TABLE IF NOT EXISTS schema_version (version INTEGER NOT NULL)"
485
- );
486
- const existing = db.prepare("SELECT version FROM schema_version").get();
487
- if (existing && existing.version > schema.version) {
488
- throw schema.onNewerVersion?.(existing.version, schema.version) ?? new Error(
489
- `Database has newer schema version ${existing.version} (expected <= ${schema.version}).`
490
- );
491
- }
492
- schema.migrate(db, existing?.version);
493
- if (!existing) {
494
- db.prepare("INSERT INTO schema_version (version) VALUES (?)").run(
495
- schema.version
496
- );
497
- }
498
- }
499
- function openVersionedDb(dbPath, options) {
500
- if (options.ensureDir && dbPath !== ":memory:") {
501
- fs4.mkdirSync(path3.dirname(dbPath), {
502
- recursive: true,
503
- ...options.dirMode !== void 0 ? { mode: options.dirMode } : {}
504
- });
505
- }
506
- const db = new Database(dbPath);
507
- db.exec("PRAGMA journal_mode = WAL");
508
- if (options.foreignKeys) {
509
- db.exec("PRAGMA foreign_keys = ON");
510
- }
511
- if (options.version === void 0) {
512
- options.migrate(db, void 0);
513
- } else {
514
- migrateVersionedSchema(db, {
515
- version: options.version,
516
- migrate: options.migrate,
517
- ...options.onNewerVersion ? { onNewerVersion: options.onNewerVersion } : {}
518
- });
519
- }
520
- return db;
521
- }
522
-
523
- // src/gateway/transport/types.ts
524
- var TransportUnreachableError = class extends Error {
525
- constructor(message) {
526
- super(message);
527
- this.name = "TransportUnreachableError";
528
- }
529
- };
530
482
 
531
483
  // src/gateway/transport/trace.ts
532
484
  function traceGatewayFrame(transport, peer, direction, frame) {
@@ -549,12 +501,55 @@ function redactFrame(value) {
549
501
  return out;
550
502
  }
551
503
 
552
- // src/gateway/transport/uds.ts
553
- import fs5 from "fs";
554
- import net from "net";
555
- import path4 from "path";
504
+ // src/gateway/transport/framedConnection.ts
505
+ function createFramedConnection(peer, channel) {
506
+ const frameHandlers = /* @__PURE__ */ new Set();
507
+ const closeHandlers = /* @__PURE__ */ new Set();
508
+ const errorHandlers = /* @__PURE__ */ new Set();
509
+ channel.onMessage((text) => {
510
+ let parsed;
511
+ try {
512
+ parsed = JSON.parse(text);
513
+ } catch {
514
+ channel.close();
515
+ return;
516
+ }
517
+ traceGatewayFrame(channel.traceTag, peer, "in", parsed);
518
+ for (const handler of frameHandlers) handler(parsed);
519
+ });
520
+ channel.onError((err) => {
521
+ for (const handler of errorHandlers) handler(err);
522
+ });
523
+ channel.onClose(() => {
524
+ for (const handler of closeHandlers) handler();
525
+ });
526
+ return {
527
+ kind: channel.kind,
528
+ peer,
529
+ send: (frame) => {
530
+ if (!channel.isOpen()) return;
531
+ traceGatewayFrame(channel.traceTag, peer, "out", frame);
532
+ channel.writeFrame(frame);
533
+ },
534
+ close: () => channel.close(),
535
+ onFrame: (cb) => {
536
+ frameHandlers.add(cb);
537
+ return () => frameHandlers.delete(cb);
538
+ },
539
+ onClose: (cb) => {
540
+ closeHandlers.add(cb);
541
+ return () => closeHandlers.delete(cb);
542
+ },
543
+ onError: (cb) => {
544
+ errorHandlers.add(cb);
545
+ return () => errorHandlers.delete(cb);
546
+ }
547
+ };
548
+ }
556
549
 
557
550
  // src/gateway/transport/framing.ts
551
+ import { Buffer as Buffer2 } from "buffer";
552
+ import { StringDecoder } from "string_decoder";
558
553
  var DEFAULT_MAX_LINE_BYTES = 1024 * 1024;
559
554
  var LineReaderOverflowError = class extends Error {
560
555
  constructor(limit) {
@@ -564,14 +559,18 @@ var LineReaderOverflowError = class extends Error {
564
559
  };
565
560
  var LineReader = class {
566
561
  buffer = "";
562
+ // Streams UTF-8 across chunk boundaries: a multi-byte sequence split by a
563
+ // stream `data` event is buffered here until complete, never truncated to
564
+ // U+FFFD the way a per-chunk `Buffer.toString('utf-8')` would.
565
+ decoder = new StringDecoder("utf8");
567
566
  maxBytes;
568
567
  constructor(maxBytes = DEFAULT_MAX_LINE_BYTES) {
569
568
  this.maxBytes = maxBytes;
570
569
  }
571
570
  push(chunk) {
572
- const incoming = typeof chunk === "string" ? chunk : chunk.toString("utf-8");
573
- if (this.buffer.length + incoming.length > this.maxBytes) {
574
- this.buffer = "";
571
+ const incoming = typeof chunk === "string" ? chunk : this.decoder.write(chunk);
572
+ if (Buffer2.byteLength(this.buffer) + Buffer2.byteLength(incoming) > this.maxBytes) {
573
+ this.reset();
575
574
  throw new LineReaderOverflowError(this.maxBytes);
576
575
  }
577
576
  this.buffer += incoming;
@@ -586,21 +585,29 @@ var LineReader = class {
586
585
  }
587
586
  return lines;
588
587
  }
589
- flush() {
590
- const remainder = this.buffer.trim();
588
+ reset() {
591
589
  this.buffer = "";
592
- return remainder.length > 0 ? [remainder] : [];
590
+ this.decoder = new StringDecoder("utf8");
593
591
  }
594
592
  };
595
593
  function encodeLine(value) {
596
594
  return JSON.stringify(value) + "\n";
597
595
  }
598
596
 
597
+ // src/gateway/transport/types.ts
598
+ var TransportUnreachableError = class extends Error {
599
+ constructor(message) {
600
+ super(message);
601
+ this.name = "TransportUnreachableError";
602
+ }
603
+ };
604
+
599
605
  // src/gateway/transport/uds.ts
600
606
  function createUdsServerTransport(opts) {
601
607
  return {
602
608
  kind: "uds",
603
- listen: (onConnection) => listenUds(opts, onConnection)
609
+ listen: (onConnection) => listenUds(opts, onConnection),
610
+ describe: () => ({ kind: "uds", socketPath: opts.socketPath })
604
611
  };
605
612
  }
606
613
  function createUdsClientTransport(opts) {
@@ -612,7 +619,7 @@ function createUdsClientTransport(opts) {
612
619
  async function listenUds(opts, onConnection) {
613
620
  const logError = opts.logError ?? ((m) => process.stderr.write(m + "\n"));
614
621
  await unlinkIfStale(opts.socketPath);
615
- fs5.mkdirSync(path4.dirname(opts.socketPath), { recursive: true, mode: 448 });
622
+ fs4.mkdirSync(path3.dirname(opts.socketPath), { recursive: true, mode: 448 });
616
623
  const activeSockets = /* @__PURE__ */ new Set();
617
624
  const server = net.createServer({ pauseOnConnect: false }, (socket) => {
618
625
  activeSockets.add(socket);
@@ -626,7 +633,7 @@ async function listenUds(opts, onConnection) {
626
633
  server.off("error", onError);
627
634
  try {
628
635
  if (process.platform !== "win32") {
629
- fs5.chmodSync(opts.socketPath, 384);
636
+ fs4.chmodSync(opts.socketPath, 384);
630
637
  }
631
638
  } catch (err) {
632
639
  logError(
@@ -644,7 +651,7 @@ async function listenUds(opts, onConnection) {
644
651
  activeSockets.clear();
645
652
  server.close(() => {
646
653
  try {
647
- fs5.unlinkSync(opts.socketPath);
654
+ fs4.unlinkSync(opts.socketPath);
648
655
  } catch {
649
656
  }
650
657
  resolve();
@@ -683,7 +690,7 @@ async function connectUds(opts) {
683
690
  return createSocketConnection(socket, "uds");
684
691
  }
685
692
  async function unlinkIfStale(socketPath) {
686
- if (!fs5.existsSync(socketPath)) return;
693
+ if (!fs4.existsSync(socketPath)) return;
687
694
  const alive = await new Promise((resolve) => {
688
695
  const probe = net.connect(socketPath);
689
696
  const timer = setTimeout(() => {
@@ -702,68 +709,326 @@ async function unlinkIfStale(socketPath) {
702
709
  });
703
710
  if (!alive) {
704
711
  try {
705
- fs5.unlinkSync(socketPath);
712
+ fs4.unlinkSync(socketPath);
706
713
  } catch {
707
714
  }
708
715
  }
709
716
  }
710
717
  function createSocketConnection(socket, peer, logError) {
718
+ return createFramedConnection(peer, udsRawChannel(socket, logError));
719
+ }
720
+ function udsRawChannel(socket, logError) {
711
721
  const reader = new LineReader();
712
- const frameHandlers = /* @__PURE__ */ new Set();
713
- const closeHandlers = /* @__PURE__ */ new Set();
714
- const errorHandlers = /* @__PURE__ */ new Set();
715
- socket.on("data", (chunk) => {
716
- let lines;
717
- try {
718
- lines = reader.push(chunk);
719
- } catch (err) {
720
- if (err instanceof LineReaderOverflowError) {
721
- logError?.(`gateway: control connection overflow \u2014 closing`);
722
- socket.destroy();
723
- return;
724
- }
725
- throw err;
726
- }
727
- for (const line of lines) {
728
- let parsed;
729
- try {
730
- parsed = JSON.parse(line);
731
- } catch {
732
- socket.destroy();
733
- return;
734
- }
735
- traceGatewayFrame("uds", peer, "in", parsed);
736
- for (const handler of frameHandlers) handler(parsed);
737
- }
738
- });
739
- socket.on("error", (err) => {
740
- for (const handler of errorHandlers) handler(err);
741
- });
742
- socket.on("close", () => {
743
- for (const handler of closeHandlers) handler();
744
- });
745
722
  return {
746
723
  kind: "uds",
747
- peer,
748
- send: (frame) => {
749
- if (!socket.writable) return;
750
- traceGatewayFrame("uds", peer, "out", frame);
751
- socket.write(encodeLine(frame));
752
- },
724
+ traceTag: "uds",
725
+ isOpen: () => socket.writable,
726
+ writeFrame: (frame) => socket.write(encodeLine(frame)),
753
727
  close: () => socket.destroy(),
754
- onFrame: (cb) => {
755
- frameHandlers.add(cb);
756
- return () => frameHandlers.delete(cb);
728
+ onMessage: (cb) => {
729
+ socket.on("data", (chunk) => {
730
+ let lines;
731
+ try {
732
+ lines = reader.push(chunk);
733
+ } catch (err) {
734
+ if (err instanceof LineReaderOverflowError) {
735
+ logError?.(`gateway: control connection overflow \u2014 closing`);
736
+ } else {
737
+ const detail = err instanceof Error ? err.message : String(err);
738
+ logError?.(
739
+ `gateway: control connection error \u2014 closing: ${detail}`
740
+ );
741
+ }
742
+ socket.destroy();
743
+ return;
744
+ }
745
+ for (const line of lines) cb(line);
746
+ });
757
747
  },
758
748
  onClose: (cb) => {
759
- closeHandlers.add(cb);
760
- return () => closeHandlers.delete(cb);
749
+ socket.on("close", cb);
761
750
  },
762
751
  onError: (cb) => {
763
- errorHandlers.add(cb);
764
- return () => errorHandlers.delete(cb);
752
+ socket.on("error", cb);
753
+ }
754
+ };
755
+ }
756
+
757
+ // src/gateway/transport/ws.ts
758
+ import { WebSocketServer, WebSocket } from "ws";
759
+ import { createServer as createHttpsServer } from "https";
760
+ import { readFileSync } from "fs";
761
+
762
+ // src/gateway/transport/wsChannel.ts
763
+ function createWsConnection(ws, peer, traceTag) {
764
+ return createFramedConnection(peer, wsRawChannel(ws, traceTag));
765
+ }
766
+ function wsRawChannel(ws, traceTag) {
767
+ return {
768
+ kind: "ws",
769
+ traceTag,
770
+ isOpen: () => ws.readyState === ws.OPEN,
771
+ writeFrame: (frame) => ws.send(JSON.stringify(frame)),
772
+ close: () => ws.close(),
773
+ onMessage: (cb) => {
774
+ ws.on("message", (data) => cb(data.toString()));
775
+ },
776
+ onClose: (cb) => {
777
+ ws.on("close", cb);
778
+ },
779
+ onError: (cb) => {
780
+ ws.on("error", cb);
781
+ }
782
+ };
783
+ }
784
+
785
+ // src/gateway/transport/ws.ts
786
+ function createWsServerTransport(opts) {
787
+ if (!opts.allowNonLoopback && !isLoopbackHost(opts.host)) {
788
+ throw new Error(`gateway: refusing non-loopback bind without --insecure`);
789
+ }
790
+ let endpoint = null;
791
+ const scheme = opts.tls ? "wss" : "ws";
792
+ const rateLimit = createConnectRateLimiter(opts.rateLimitPerMin ?? 10);
793
+ const readEndpoint = () => {
794
+ if (!endpoint) {
795
+ throw new Error("gateway: WS transport has not started listening");
765
796
  }
797
+ return endpoint;
766
798
  };
799
+ return {
800
+ kind: "ws",
801
+ endpoint: readEndpoint,
802
+ describe: () => {
803
+ const ep = readEndpoint();
804
+ return {
805
+ kind: "ws",
806
+ host: ep.host,
807
+ port: ep.port,
808
+ url: ep.url,
809
+ tls: Boolean(opts.tls)
810
+ };
811
+ },
812
+ listen: (onConnection) => new Promise((resolve, reject) => {
813
+ const verifyClient = (info) => rateLimit.allow(info.req.socket.remoteAddress ?? "unknown");
814
+ const { wss, httpsServer } = createWss({
815
+ host: opts.host,
816
+ port: opts.port,
817
+ tls: opts.tls,
818
+ verifyClient
819
+ });
820
+ const onError = (err) => reject(err);
821
+ wss.once("error", onError);
822
+ if (httpsServer) httpsServer.once("error", onError);
823
+ const onListening = () => {
824
+ wss.off("error", onError);
825
+ if (httpsServer) httpsServer.off("error", onError);
826
+ const addr = httpsServer ? httpsServer.address() : wss.address();
827
+ if (typeof addr === "string" || addr === null) {
828
+ wss.close();
829
+ httpsServer?.close();
830
+ reject(
831
+ new Error("gateway: WS listener did not expose TCP address")
832
+ );
833
+ return;
834
+ }
835
+ endpoint = {
836
+ host: opts.host,
837
+ port: addr.port,
838
+ url: `${scheme}://${opts.host}:${addr.port}`
839
+ };
840
+ resolve({
841
+ close: () => new Promise((closeResolve) => {
842
+ for (const client2 of wss.clients) client2.terminate();
843
+ wss.close(() => {
844
+ if (httpsServer) httpsServer.close(() => closeResolve());
845
+ else closeResolve();
846
+ });
847
+ })
848
+ });
849
+ };
850
+ if (httpsServer) httpsServer.once("listening", onListening);
851
+ else wss.once("listening", onListening);
852
+ const pingIntervalMs = opts.pingIntervalMs ?? 15e3;
853
+ const pongTimeoutMs = opts.pongTimeoutMs ?? 3e4;
854
+ wss.on("connection", (ws) => {
855
+ attachHeartbeat(ws, pingIntervalMs, pongTimeoutMs);
856
+ onConnection(createWsConnection(ws, `${scheme}:${opts.host}`, "ws"));
857
+ });
858
+ })
859
+ };
860
+ }
861
+ function loadTlsOptions(tls) {
862
+ return {
863
+ cert: readFileSync(tls.certPath),
864
+ key: readFileSync(tls.keyPath)
865
+ };
866
+ }
867
+ function createWss(input) {
868
+ if (input.tls) {
869
+ const httpsServer = createHttpsServer(loadTlsOptions(input.tls));
870
+ httpsServer.listen({ host: input.host, port: input.port });
871
+ return {
872
+ wss: new WebSocketServer({
873
+ server: httpsServer,
874
+ verifyClient: input.verifyClient
875
+ }),
876
+ httpsServer
877
+ };
878
+ }
879
+ return {
880
+ wss: new WebSocketServer({
881
+ host: input.host,
882
+ port: input.port,
883
+ verifyClient: input.verifyClient
884
+ }),
885
+ httpsServer: null
886
+ };
887
+ }
888
+ function createConnectRateLimiter(maxPerMin) {
889
+ if (maxPerMin <= 0) return { allow: () => true };
890
+ const buckets = /* @__PURE__ */ new Map();
891
+ let pruneCountdown = 256;
892
+ const prune = (cutoff) => {
893
+ for (const [ip, arr] of buckets) {
894
+ const fresh = arr.filter((t) => t > cutoff);
895
+ if (fresh.length === 0) buckets.delete(ip);
896
+ else if (fresh.length !== arr.length) buckets.set(ip, fresh);
897
+ }
898
+ };
899
+ return {
900
+ allow(ip) {
901
+ const now = Date.now();
902
+ const cutoff = now - 6e4;
903
+ pruneCountdown -= 1;
904
+ if (pruneCountdown <= 0) {
905
+ prune(cutoff);
906
+ pruneCountdown = 256;
907
+ }
908
+ const recent = (buckets.get(ip) ?? []).filter((t) => t > cutoff);
909
+ if (recent.length >= maxPerMin) {
910
+ buckets.set(ip, recent);
911
+ return false;
912
+ }
913
+ recent.push(now);
914
+ buckets.set(ip, recent);
915
+ return true;
916
+ }
917
+ };
918
+ }
919
+ function attachHeartbeat(ws, pingIntervalMs, pongTimeoutMs) {
920
+ if (pingIntervalMs <= 0) return;
921
+ let pongTimer = null;
922
+ const clearPongTimer = () => {
923
+ if (pongTimer) {
924
+ clearTimeout(pongTimer);
925
+ pongTimer = null;
926
+ }
927
+ };
928
+ ws.on("pong", clearPongTimer);
929
+ const interval = setInterval(() => {
930
+ if (ws.readyState !== ws.OPEN) return;
931
+ try {
932
+ ws.ping();
933
+ } catch {
934
+ return;
935
+ }
936
+ if (!pongTimer) {
937
+ pongTimer = setTimeout(() => ws.terminate(), pongTimeoutMs);
938
+ }
939
+ }, pingIntervalMs);
940
+ const stop = () => {
941
+ clearInterval(interval);
942
+ clearPongTimer();
943
+ };
944
+ ws.on("close", stop);
945
+ ws.on("error", stop);
946
+ }
947
+ function createWsClientTransport(opts) {
948
+ return {
949
+ kind: "ws",
950
+ connect: () => connectWs(opts)
951
+ };
952
+ }
953
+ function wsClientOptionsForEndpoint(input) {
954
+ return {
955
+ url: input.url,
956
+ ...input.timeoutMs !== void 0 ? { timeoutMs: input.timeoutMs } : {},
957
+ ...input.tlsCaPath !== void 0 ? { tlsCaPath: input.tlsCaPath } : {}
958
+ };
959
+ }
960
+ async function connectWs(opts) {
961
+ const timeoutMs = opts.timeoutMs ?? 5e3;
962
+ const wsOpts = opts.tlsCaPath ? { ca: readFileSync(opts.tlsCaPath) } : {};
963
+ const ws = new WebSocket(opts.url, wsOpts);
964
+ await new Promise((resolve, reject) => {
965
+ const timer = setTimeout(() => {
966
+ ws.close();
967
+ reject(
968
+ new TransportUnreachableError(`connect timed out after ${timeoutMs}ms`)
969
+ );
970
+ }, timeoutMs);
971
+ ws.once("open", () => {
972
+ clearTimeout(timer);
973
+ resolve();
974
+ });
975
+ ws.once("error", (err) => {
976
+ clearTimeout(timer);
977
+ reject(
978
+ new TransportUnreachableError(
979
+ `gateway not reachable at ${opts.url}: ${err.message}`
980
+ )
981
+ );
982
+ });
983
+ });
984
+ return createWsConnection(ws, opts.url, "ws-client");
985
+ }
986
+
987
+ // src/infra/db/openVersionedDb.ts
988
+ import fs5 from "fs";
989
+ import path4 from "path";
990
+ import Database from "better-sqlite3";
991
+ function migrateVersionedSchema(db, schema) {
992
+ db.exec(
993
+ "CREATE TABLE IF NOT EXISTS schema_version (version INTEGER NOT NULL)"
994
+ );
995
+ const existing = db.prepare("SELECT version FROM schema_version").get();
996
+ if (existing && existing.version > schema.version) {
997
+ throw schema.onNewerVersion?.(existing.version, schema.version) ?? new Error(
998
+ `Database has newer schema version ${existing.version} (expected <= ${schema.version}).`
999
+ );
1000
+ }
1001
+ db.transaction(() => {
1002
+ schema.migrate(db, existing?.version);
1003
+ if (!existing) {
1004
+ db.prepare("INSERT INTO schema_version (version) VALUES (?)").run(
1005
+ schema.version
1006
+ );
1007
+ }
1008
+ })();
1009
+ }
1010
+ function openVersionedDb(dbPath, options) {
1011
+ if (options.ensureDir && dbPath !== ":memory:") {
1012
+ fs5.mkdirSync(path4.dirname(dbPath), {
1013
+ recursive: true,
1014
+ ...options.dirMode !== void 0 ? { mode: options.dirMode } : {}
1015
+ });
1016
+ }
1017
+ const db = new Database(dbPath);
1018
+ db.exec("PRAGMA journal_mode = WAL");
1019
+ if (options.foreignKeys) {
1020
+ db.exec("PRAGMA foreign_keys = ON");
1021
+ }
1022
+ if (options.version === void 0) {
1023
+ options.migrate(db, void 0);
1024
+ } else {
1025
+ migrateVersionedSchema(db, {
1026
+ version: options.version,
1027
+ migrate: options.migrate,
1028
+ ...options.onNewerVersion ? { onNewerVersion: options.onNewerVersion } : {}
1029
+ });
1030
+ }
1031
+ return db;
767
1032
  }
768
1033
 
769
1034
  // src/shared/gateway-protocol/channelRequestId.ts
@@ -791,12 +1056,14 @@ export {
791
1056
  removeDashboardClientConfig,
792
1057
  openVersionedDb,
793
1058
  TransportUnreachableError,
794
- traceGatewayFrame,
795
1059
  createUdsServerTransport,
796
1060
  createUdsClientTransport,
797
1061
  resolveGatewayPaths,
798
1062
  resolveListenSpec,
799
1063
  isLoopbackHost,
1064
+ createWsServerTransport,
1065
+ createWsClientTransport,
1066
+ wsClientOptionsForEndpoint,
800
1067
  CHANNEL_REQUEST_ID_REGEX,
801
1068
  generateChannelRequestId,
802
1069
  isValidChannelRequestId,
@@ -818,4 +1085,4 @@ export {
818
1085
  trackSetupCompleted,
819
1086
  refreshDashboardAccessToken
820
1087
  };
821
- //# sourceMappingURL=chunk-YU2WMPRC.js.map
1088
+ //# sourceMappingURL=chunk-3U37HT4T.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  isLoopbackHost
3
- } from "./chunk-YU2WMPRC.js";
3
+ } from "./chunk-3U37HT4T.js";
4
4
 
5
5
  // src/gateway/auth.ts
6
6
  import crypto from "crypto";
@@ -73,4 +73,4 @@ export {
73
73
  timingSafeTokenEqual,
74
74
  requireTokenForBind
75
75
  };
76
- //# sourceMappingURL=chunk-7GEQJQMR.js.map
76
+ //# sourceMappingURL=chunk-4NX4WFPB.js.map
@@ -952,18 +952,9 @@ function readConfigFile(configPath, baseDir) {
952
952
  );
953
953
  }
954
954
  const plugins = (raw.plugins ?? []).map((p) => {
955
- if (isMarketplaceRef(p)) {
956
- try {
957
- return resolveMarketplacePlugin(p);
958
- } catch (error) {
959
- console.error(
960
- `Warning: skipping plugin "${p}": ${error.message}`
961
- );
962
- return null;
963
- }
964
- }
955
+ if (isMarketplaceRef(p)) return p;
965
956
  return path4.isAbsolute(p) ? p : path4.resolve(baseDir, p);
966
- }).filter((p) => p !== null);
957
+ });
967
958
  const additionalDirectories = (raw.additionalDirectories ?? []).map(
968
959
  (dir) => path4.isAbsolute(dir) ? dir : path4.resolve(baseDir, dir)
969
960
  );
@@ -980,7 +971,12 @@ function readConfigFile(configPath, baseDir) {
980
971
  telemetry: raw.telemetry,
981
972
  telemetryDiagnostics: raw.telemetryDiagnostics,
982
973
  deviceId: raw.deviceId,
983
- channels: raw.channels
974
+ channels: raw.channels,
975
+ // Personal capabilities are stored opaque. In particular skill `path`
976
+ // is NOT relative-resolved against baseDir (R1) — Issue 3 resolves it
977
+ // to an absolute path at install time.
978
+ mcpServers: raw.mcpServers,
979
+ skills: raw.skills
984
980
  };
985
981
  }
986
982
  function readExistingConfig(configPath) {
@@ -2210,6 +2206,7 @@ export {
2210
2206
  gatherMarketplaceWorkflowSources,
2211
2207
  resolveWorkflowInstall,
2212
2208
  pullMarketplaceRepo,
2209
+ resolveMarketplacePlugin,
2213
2210
  projectConfigPath,
2214
2211
  readConfig,
2215
2212
  resolveActiveWorkflow,
@@ -2229,4 +2226,4 @@ export {
2229
2226
  compileWorkflowPlan,
2230
2227
  collectMcpServersWithOptions
2231
2228
  };
2232
- //# sourceMappingURL=chunk-7UUPLAP4.js.map
2229
+ //# sourceMappingURL=chunk-73V7GXV6.js.map
@@ -147,4 +147,4 @@ export {
147
147
  createPermissionRequestDenyResult,
148
148
  createStopBlockResult
149
149
  };
150
- //# sourceMappingURL=chunk-BTKQ67RE.js.map
150
+ //# sourceMappingURL=chunk-QYB6N2OT.js.map