@learnrudi/cli 1.9.8 → 1.9.9

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/index.cjs CHANGED
@@ -70,9 +70,9 @@ function ensureDirectories() {
70
70
  }
71
71
  }
72
72
  function parsePackageId(id) {
73
- const match = id.match(/^(stack|prompt|runtime|binary|agent):(.+)$/);
73
+ const match = id.match(/^(stack|prompt|runtime|binary|agent|npm):(.+)$/);
74
74
  if (!match) {
75
- throw new Error(`Invalid package ID: ${id} (expected format: kind:name, where kind is one of: ${PACKAGE_KINDS.join(", ")})`);
75
+ throw new Error(`Invalid package ID: ${id} (expected format: kind:name, where kind is one of: ${PACKAGE_KINDS.join(", ")}, npm)`);
76
76
  }
77
77
  return [match[1], match[2]];
78
78
  }
@@ -92,14 +92,21 @@ function getPackagePath(id) {
92
92
  return import_path.default.join(PATHS.binaries, name);
93
93
  case "agent":
94
94
  return import_path.default.join(PATHS.agents, name);
95
+ case "npm":
96
+ const sanitized = name.replace(/\//g, "__").replace(/^@/, "");
97
+ return import_path.default.join(PATHS.binaries, "npm", sanitized);
95
98
  default:
96
99
  throw new Error(`Unknown package kind: ${kind}`);
97
100
  }
98
101
  }
99
102
  function getLockfilePath(id) {
100
103
  const [kind, name] = parsePackageId(id);
101
- const lockDir = kind === "binary" ? "binaries" : kind + "s";
102
- return import_path.default.join(PATHS.locks, lockDir, `${name}.lock.yaml`);
104
+ let lockName = name;
105
+ if (kind === "npm") {
106
+ lockName = name.replace(/\//g, "__").replace(/^@/, "");
107
+ }
108
+ const lockDir = kind === "binary" ? "binaries" : kind === "npm" ? "npms" : kind + "s";
109
+ return import_path.default.join(PATHS.locks, lockDir, `${lockName}.lock.yaml`);
103
110
  }
104
111
  function isPackageInstalled(id) {
105
112
  const packagePath = getPackagePath(id);
@@ -190,27 +197,6 @@ var init_src = __esm({
190
197
  });
191
198
 
192
199
  // node_modules/.pnpm/@learnrudi+registry-client@1.0.1/node_modules/@learnrudi/registry-client/src/index.js
193
- var src_exports = {};
194
- __export(src_exports, {
195
- CACHE_TTL: () => CACHE_TTL,
196
- DEFAULT_REGISTRY_URL: () => DEFAULT_REGISTRY_URL,
197
- PACKAGE_KINDS: () => PACKAGE_KINDS2,
198
- RUNTIMES_DOWNLOAD_BASE: () => RUNTIMES_DOWNLOAD_BASE,
199
- RUNTIMES_RELEASE_VERSION: () => RUNTIMES_RELEASE_VERSION,
200
- checkCache: () => checkCache,
201
- clearCache: () => clearCache,
202
- computeHash: () => computeHash,
203
- downloadPackage: () => downloadPackage,
204
- downloadRuntime: () => downloadRuntime,
205
- downloadTool: () => downloadTool,
206
- fetchIndex: () => fetchIndex,
207
- getManifest: () => getManifest,
208
- getPackage: () => getPackage,
209
- getPackageKinds: () => getPackageKinds,
210
- listPackages: () => listPackages,
211
- searchPackages: () => searchPackages,
212
- verifyHash: () => verifyHash
213
- });
214
200
  function getLocalRegistryPaths() {
215
201
  if (process.env.USE_LOCAL_REGISTRY !== "true") {
216
202
  return [];
@@ -316,19 +302,6 @@ function clearCache() {
316
302
  import_fs2.default.unlinkSync(PATHS.registryCache);
317
303
  }
318
304
  }
319
- function checkCache() {
320
- const cachePath = PATHS.registryCache;
321
- if (!import_fs2.default.existsSync(cachePath)) {
322
- return { fresh: false, age: null };
323
- }
324
- try {
325
- const stat = import_fs2.default.statSync(cachePath);
326
- const age = Date.now() - stat.mtimeMs;
327
- return { fresh: age <= CACHE_TTL, age };
328
- } catch {
329
- return { fresh: false, age: null };
330
- }
331
- }
332
305
  function getKindSection(kind) {
333
306
  return KIND_PLURALS[kind] || `${kind}s`;
334
307
  }
@@ -420,9 +393,6 @@ async function listPackages(kind) {
420
393
  if (!section) return [];
421
394
  return [...section.official || [], ...section.community || []];
422
395
  }
423
- function getPackageKinds() {
424
- return PACKAGE_KINDS2;
425
- }
426
396
  async function downloadPackage(pkg, destPath, options = {}) {
427
397
  const { onProgress } = options;
428
398
  const registryPath = pkg.path;
@@ -833,33 +803,11 @@ function guessArchiveType(filename) {
833
803
  if (filename.endsWith(".zip")) return "zip";
834
804
  return "tar.gz";
835
805
  }
836
- async function verifyHash(filePath, expectedHash) {
837
- return new Promise((resolve, reject) => {
838
- const hash = import_crypto.default.createHash("sha256");
839
- const stream = import_fs2.default.createReadStream(filePath);
840
- stream.on("data", (data) => hash.update(data));
841
- stream.on("end", () => {
842
- const actualHash = hash.digest("hex");
843
- resolve(actualHash === expectedHash);
844
- });
845
- stream.on("error", reject);
846
- });
847
- }
848
- async function computeHash(filePath) {
849
- return new Promise((resolve, reject) => {
850
- const hash = import_crypto.default.createHash("sha256");
851
- const stream = import_fs2.default.createReadStream(filePath);
852
- stream.on("data", (data) => hash.update(data));
853
- stream.on("end", () => resolve(hash.digest("hex")));
854
- stream.on("error", reject);
855
- });
856
- }
857
- var import_fs2, import_path2, import_crypto, DEFAULT_REGISTRY_URL, RUNTIMES_DOWNLOAD_BASE, CACHE_TTL, PACKAGE_KINDS2, KIND_PLURALS, GITHUB_RAW_BASE, RUNTIMES_RELEASE_VERSION;
806
+ var import_fs2, import_path2, DEFAULT_REGISTRY_URL, RUNTIMES_DOWNLOAD_BASE, CACHE_TTL, PACKAGE_KINDS2, KIND_PLURALS, GITHUB_RAW_BASE, RUNTIMES_RELEASE_VERSION;
858
807
  var init_src2 = __esm({
859
808
  "node_modules/.pnpm/@learnrudi+registry-client@1.0.1/node_modules/@learnrudi/registry-client/src/index.js"() {
860
809
  import_fs2 = __toESM(require("fs"), 1);
861
810
  import_path2 = __toESM(require("path"), 1);
862
- import_crypto = __toESM(require("crypto"), 1);
863
811
  init_src();
864
812
  DEFAULT_REGISTRY_URL = "https://raw.githubusercontent.com/learn-rudi/registry/main/index.json";
865
813
  RUNTIMES_DOWNLOAD_BASE = "https://github.com/learn-rudi/registry/releases/download";
@@ -873,8 +821,11 @@ var init_src2 = __esm({
873
821
  }
874
822
  });
875
823
 
876
- // node_modules/.pnpm/@learnrudi+core@1.0.2/node_modules/@learnrudi/core/src/resolver.js
824
+ // packages/core/src/resolver.js
877
825
  async function resolvePackage(id) {
826
+ if (id.startsWith("npm:")) {
827
+ return resolveDynamicNpm(id);
828
+ }
878
829
  const normalizedId = id.includes(":") ? id : `stack:${id}`;
879
830
  const pkg = await getPackage(normalizedId);
880
831
  if (!pkg) {
@@ -912,6 +863,51 @@ async function resolvePackage(id) {
912
863
  installType: mergedPkg.installType
913
864
  };
914
865
  }
866
+ async function resolveDynamicNpm(id) {
867
+ const spec = id.replace("npm:", "");
868
+ let name, version;
869
+ if (spec.startsWith("@")) {
870
+ const parts = spec.split("@");
871
+ if (parts.length >= 3) {
872
+ name = `@${parts[1]}`;
873
+ version = parts[2];
874
+ } else {
875
+ name = `@${parts[1]}`;
876
+ version = "latest";
877
+ }
878
+ } else {
879
+ const lastAt = spec.lastIndexOf("@");
880
+ if (lastAt > 0) {
881
+ name = spec.substring(0, lastAt);
882
+ version = spec.substring(lastAt + 1);
883
+ } else {
884
+ name = spec;
885
+ version = "latest";
886
+ }
887
+ }
888
+ const sanitizedName = name.replace(/\//g, "__").replace(/^@/, "");
889
+ const installDir = `npm/${sanitizedName}`;
890
+ const fullId = id;
891
+ const installed = isPackageInstalled(fullId);
892
+ return {
893
+ id: fullId,
894
+ kind: "binary",
895
+ name,
896
+ version,
897
+ description: `Dynamic npm package: ${name}`,
898
+ installType: "npm",
899
+ npmPackage: name,
900
+ installDir,
901
+ installed,
902
+ dependencies: [],
903
+ source: {
904
+ type: "npm",
905
+ spec
906
+ },
907
+ // bins will be discovered after install by installer
908
+ bins: null
909
+ };
910
+ }
915
911
  async function resolveDependencies(pkg) {
916
912
  const dependencies = [];
917
913
  const runtimes = pkg.requires?.runtimes || (pkg.runtime ? [pkg.runtime] : []);
@@ -1028,7 +1024,7 @@ function compareVersions(a, b) {
1028
1024
  return 0;
1029
1025
  }
1030
1026
  var init_resolver = __esm({
1031
- "node_modules/.pnpm/@learnrudi+core@1.0.2/node_modules/@learnrudi/core/src/resolver.js"() {
1027
+ "packages/core/src/resolver.js"() {
1032
1028
  init_src2();
1033
1029
  init_src();
1034
1030
  }
@@ -1111,17 +1107,17 @@ var require_visit = __commonJS({
1111
1107
  visit.BREAK = BREAK;
1112
1108
  visit.SKIP = SKIP;
1113
1109
  visit.REMOVE = REMOVE;
1114
- function visit_(key, node, visitor, path30) {
1115
- const ctrl = callVisitor(key, node, visitor, path30);
1110
+ function visit_(key, node, visitor, path35) {
1111
+ const ctrl = callVisitor(key, node, visitor, path35);
1116
1112
  if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
1117
- replaceNode(key, path30, ctrl);
1118
- return visit_(key, ctrl, visitor, path30);
1113
+ replaceNode(key, path35, ctrl);
1114
+ return visit_(key, ctrl, visitor, path35);
1119
1115
  }
1120
1116
  if (typeof ctrl !== "symbol") {
1121
1117
  if (identity.isCollection(node)) {
1122
- path30 = Object.freeze(path30.concat(node));
1118
+ path35 = Object.freeze(path35.concat(node));
1123
1119
  for (let i = 0; i < node.items.length; ++i) {
1124
- const ci = visit_(i, node.items[i], visitor, path30);
1120
+ const ci = visit_(i, node.items[i], visitor, path35);
1125
1121
  if (typeof ci === "number")
1126
1122
  i = ci - 1;
1127
1123
  else if (ci === BREAK)
@@ -1132,13 +1128,13 @@ var require_visit = __commonJS({
1132
1128
  }
1133
1129
  }
1134
1130
  } else if (identity.isPair(node)) {
1135
- path30 = Object.freeze(path30.concat(node));
1136
- const ck = visit_("key", node.key, visitor, path30);
1131
+ path35 = Object.freeze(path35.concat(node));
1132
+ const ck = visit_("key", node.key, visitor, path35);
1137
1133
  if (ck === BREAK)
1138
1134
  return BREAK;
1139
1135
  else if (ck === REMOVE)
1140
1136
  node.key = null;
1141
- const cv = visit_("value", node.value, visitor, path30);
1137
+ const cv = visit_("value", node.value, visitor, path35);
1142
1138
  if (cv === BREAK)
1143
1139
  return BREAK;
1144
1140
  else if (cv === REMOVE)
@@ -1159,17 +1155,17 @@ var require_visit = __commonJS({
1159
1155
  visitAsync.BREAK = BREAK;
1160
1156
  visitAsync.SKIP = SKIP;
1161
1157
  visitAsync.REMOVE = REMOVE;
1162
- async function visitAsync_(key, node, visitor, path30) {
1163
- const ctrl = await callVisitor(key, node, visitor, path30);
1158
+ async function visitAsync_(key, node, visitor, path35) {
1159
+ const ctrl = await callVisitor(key, node, visitor, path35);
1164
1160
  if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
1165
- replaceNode(key, path30, ctrl);
1166
- return visitAsync_(key, ctrl, visitor, path30);
1161
+ replaceNode(key, path35, ctrl);
1162
+ return visitAsync_(key, ctrl, visitor, path35);
1167
1163
  }
1168
1164
  if (typeof ctrl !== "symbol") {
1169
1165
  if (identity.isCollection(node)) {
1170
- path30 = Object.freeze(path30.concat(node));
1166
+ path35 = Object.freeze(path35.concat(node));
1171
1167
  for (let i = 0; i < node.items.length; ++i) {
1172
- const ci = await visitAsync_(i, node.items[i], visitor, path30);
1168
+ const ci = await visitAsync_(i, node.items[i], visitor, path35);
1173
1169
  if (typeof ci === "number")
1174
1170
  i = ci - 1;
1175
1171
  else if (ci === BREAK)
@@ -1180,13 +1176,13 @@ var require_visit = __commonJS({
1180
1176
  }
1181
1177
  }
1182
1178
  } else if (identity.isPair(node)) {
1183
- path30 = Object.freeze(path30.concat(node));
1184
- const ck = await visitAsync_("key", node.key, visitor, path30);
1179
+ path35 = Object.freeze(path35.concat(node));
1180
+ const ck = await visitAsync_("key", node.key, visitor, path35);
1185
1181
  if (ck === BREAK)
1186
1182
  return BREAK;
1187
1183
  else if (ck === REMOVE)
1188
1184
  node.key = null;
1189
- const cv = await visitAsync_("value", node.value, visitor, path30);
1185
+ const cv = await visitAsync_("value", node.value, visitor, path35);
1190
1186
  if (cv === BREAK)
1191
1187
  return BREAK;
1192
1188
  else if (cv === REMOVE)
@@ -1213,23 +1209,23 @@ var require_visit = __commonJS({
1213
1209
  }
1214
1210
  return visitor;
1215
1211
  }
1216
- function callVisitor(key, node, visitor, path30) {
1212
+ function callVisitor(key, node, visitor, path35) {
1217
1213
  if (typeof visitor === "function")
1218
- return visitor(key, node, path30);
1214
+ return visitor(key, node, path35);
1219
1215
  if (identity.isMap(node))
1220
- return visitor.Map?.(key, node, path30);
1216
+ return visitor.Map?.(key, node, path35);
1221
1217
  if (identity.isSeq(node))
1222
- return visitor.Seq?.(key, node, path30);
1218
+ return visitor.Seq?.(key, node, path35);
1223
1219
  if (identity.isPair(node))
1224
- return visitor.Pair?.(key, node, path30);
1220
+ return visitor.Pair?.(key, node, path35);
1225
1221
  if (identity.isScalar(node))
1226
- return visitor.Scalar?.(key, node, path30);
1222
+ return visitor.Scalar?.(key, node, path35);
1227
1223
  if (identity.isAlias(node))
1228
- return visitor.Alias?.(key, node, path30);
1224
+ return visitor.Alias?.(key, node, path35);
1229
1225
  return void 0;
1230
1226
  }
1231
- function replaceNode(key, path30, node) {
1232
- const parent = path30[path30.length - 1];
1227
+ function replaceNode(key, path35, node) {
1228
+ const parent = path35[path35.length - 1];
1233
1229
  if (identity.isCollection(parent)) {
1234
1230
  parent.items[key] = node;
1235
1231
  } else if (identity.isPair(parent)) {
@@ -1837,10 +1833,10 @@ var require_Collection = __commonJS({
1837
1833
  var createNode = require_createNode();
1838
1834
  var identity = require_identity();
1839
1835
  var Node = require_Node();
1840
- function collectionFromPath(schema, path30, value) {
1836
+ function collectionFromPath(schema, path35, value) {
1841
1837
  let v = value;
1842
- for (let i = path30.length - 1; i >= 0; --i) {
1843
- const k = path30[i];
1838
+ for (let i = path35.length - 1; i >= 0; --i) {
1839
+ const k = path35[i];
1844
1840
  if (typeof k === "number" && Number.isInteger(k) && k >= 0) {
1845
1841
  const a = [];
1846
1842
  a[k] = v;
@@ -1859,7 +1855,7 @@ var require_Collection = __commonJS({
1859
1855
  sourceObjects: /* @__PURE__ */ new Map()
1860
1856
  });
1861
1857
  }
1862
- var isEmptyPath = (path30) => path30 == null || typeof path30 === "object" && !!path30[Symbol.iterator]().next().done;
1858
+ var isEmptyPath = (path35) => path35 == null || typeof path35 === "object" && !!path35[Symbol.iterator]().next().done;
1863
1859
  var Collection = class extends Node.NodeBase {
1864
1860
  constructor(type, schema) {
1865
1861
  super(type);
@@ -1889,11 +1885,11 @@ var require_Collection = __commonJS({
1889
1885
  * be a Pair instance or a `{ key, value }` object, which may not have a key
1890
1886
  * that already exists in the map.
1891
1887
  */
1892
- addIn(path30, value) {
1893
- if (isEmptyPath(path30))
1888
+ addIn(path35, value) {
1889
+ if (isEmptyPath(path35))
1894
1890
  this.add(value);
1895
1891
  else {
1896
- const [key, ...rest] = path30;
1892
+ const [key, ...rest] = path35;
1897
1893
  const node = this.get(key, true);
1898
1894
  if (identity.isCollection(node))
1899
1895
  node.addIn(rest, value);
@@ -1907,8 +1903,8 @@ var require_Collection = __commonJS({
1907
1903
  * Removes a value from the collection.
1908
1904
  * @returns `true` if the item was found and removed.
1909
1905
  */
1910
- deleteIn(path30) {
1911
- const [key, ...rest] = path30;
1906
+ deleteIn(path35) {
1907
+ const [key, ...rest] = path35;
1912
1908
  if (rest.length === 0)
1913
1909
  return this.delete(key);
1914
1910
  const node = this.get(key, true);
@@ -1922,8 +1918,8 @@ var require_Collection = __commonJS({
1922
1918
  * scalar values from their surrounding node; to disable set `keepScalar` to
1923
1919
  * `true` (collections are always returned intact).
1924
1920
  */
1925
- getIn(path30, keepScalar) {
1926
- const [key, ...rest] = path30;
1921
+ getIn(path35, keepScalar) {
1922
+ const [key, ...rest] = path35;
1927
1923
  const node = this.get(key, true);
1928
1924
  if (rest.length === 0)
1929
1925
  return !keepScalar && identity.isScalar(node) ? node.value : node;
@@ -1941,8 +1937,8 @@ var require_Collection = __commonJS({
1941
1937
  /**
1942
1938
  * Checks if the collection includes a value with the key `key`.
1943
1939
  */
1944
- hasIn(path30) {
1945
- const [key, ...rest] = path30;
1940
+ hasIn(path35) {
1941
+ const [key, ...rest] = path35;
1946
1942
  if (rest.length === 0)
1947
1943
  return this.has(key);
1948
1944
  const node = this.get(key, true);
@@ -1952,8 +1948,8 @@ var require_Collection = __commonJS({
1952
1948
  * Sets a value in this collection. For `!!set`, `value` needs to be a
1953
1949
  * boolean to add/remove the item from the set.
1954
1950
  */
1955
- setIn(path30, value) {
1956
- const [key, ...rest] = path30;
1951
+ setIn(path35, value) {
1952
+ const [key, ...rest] = path35;
1957
1953
  if (rest.length === 0) {
1958
1954
  this.set(key, value);
1959
1955
  } else {
@@ -4457,9 +4453,9 @@ var require_Document = __commonJS({
4457
4453
  this.contents.add(value);
4458
4454
  }
4459
4455
  /** Adds a value to the document. */
4460
- addIn(path30, value) {
4456
+ addIn(path35, value) {
4461
4457
  if (assertCollection(this.contents))
4462
- this.contents.addIn(path30, value);
4458
+ this.contents.addIn(path35, value);
4463
4459
  }
4464
4460
  /**
4465
4461
  * Create a new `Alias` node, ensuring that the target `node` has the required anchor.
@@ -4534,14 +4530,14 @@ var require_Document = __commonJS({
4534
4530
  * Removes a value from the document.
4535
4531
  * @returns `true` if the item was found and removed.
4536
4532
  */
4537
- deleteIn(path30) {
4538
- if (Collection.isEmptyPath(path30)) {
4533
+ deleteIn(path35) {
4534
+ if (Collection.isEmptyPath(path35)) {
4539
4535
  if (this.contents == null)
4540
4536
  return false;
4541
4537
  this.contents = null;
4542
4538
  return true;
4543
4539
  }
4544
- return assertCollection(this.contents) ? this.contents.deleteIn(path30) : false;
4540
+ return assertCollection(this.contents) ? this.contents.deleteIn(path35) : false;
4545
4541
  }
4546
4542
  /**
4547
4543
  * Returns item at `key`, or `undefined` if not found. By default unwraps
@@ -4556,10 +4552,10 @@ var require_Document = __commonJS({
4556
4552
  * scalar values from their surrounding node; to disable set `keepScalar` to
4557
4553
  * `true` (collections are always returned intact).
4558
4554
  */
4559
- getIn(path30, keepScalar) {
4560
- if (Collection.isEmptyPath(path30))
4555
+ getIn(path35, keepScalar) {
4556
+ if (Collection.isEmptyPath(path35))
4561
4557
  return !keepScalar && identity.isScalar(this.contents) ? this.contents.value : this.contents;
4562
- return identity.isCollection(this.contents) ? this.contents.getIn(path30, keepScalar) : void 0;
4558
+ return identity.isCollection(this.contents) ? this.contents.getIn(path35, keepScalar) : void 0;
4563
4559
  }
4564
4560
  /**
4565
4561
  * Checks if the document includes a value with the key `key`.
@@ -4570,10 +4566,10 @@ var require_Document = __commonJS({
4570
4566
  /**
4571
4567
  * Checks if the document includes a value at `path`.
4572
4568
  */
4573
- hasIn(path30) {
4574
- if (Collection.isEmptyPath(path30))
4569
+ hasIn(path35) {
4570
+ if (Collection.isEmptyPath(path35))
4575
4571
  return this.contents !== void 0;
4576
- return identity.isCollection(this.contents) ? this.contents.hasIn(path30) : false;
4572
+ return identity.isCollection(this.contents) ? this.contents.hasIn(path35) : false;
4577
4573
  }
4578
4574
  /**
4579
4575
  * Sets a value in this document. For `!!set`, `value` needs to be a
@@ -4590,13 +4586,13 @@ var require_Document = __commonJS({
4590
4586
  * Sets a value in this document. For `!!set`, `value` needs to be a
4591
4587
  * boolean to add/remove the item from the set.
4592
4588
  */
4593
- setIn(path30, value) {
4594
- if (Collection.isEmptyPath(path30)) {
4589
+ setIn(path35, value) {
4590
+ if (Collection.isEmptyPath(path35)) {
4595
4591
  this.contents = value;
4596
4592
  } else if (this.contents == null) {
4597
- this.contents = Collection.collectionFromPath(this.schema, Array.from(path30), value);
4593
+ this.contents = Collection.collectionFromPath(this.schema, Array.from(path35), value);
4598
4594
  } else if (assertCollection(this.contents)) {
4599
- this.contents.setIn(path30, value);
4595
+ this.contents.setIn(path35, value);
4600
4596
  }
4601
4597
  }
4602
4598
  /**
@@ -6548,9 +6544,9 @@ var require_cst_visit = __commonJS({
6548
6544
  visit.BREAK = BREAK;
6549
6545
  visit.SKIP = SKIP;
6550
6546
  visit.REMOVE = REMOVE;
6551
- visit.itemAtPath = (cst, path30) => {
6547
+ visit.itemAtPath = (cst, path35) => {
6552
6548
  let item = cst;
6553
- for (const [field, index] of path30) {
6549
+ for (const [field, index] of path35) {
6554
6550
  const tok = item?.[field];
6555
6551
  if (tok && "items" in tok) {
6556
6552
  item = tok.items[index];
@@ -6559,23 +6555,23 @@ var require_cst_visit = __commonJS({
6559
6555
  }
6560
6556
  return item;
6561
6557
  };
6562
- visit.parentCollection = (cst, path30) => {
6563
- const parent = visit.itemAtPath(cst, path30.slice(0, -1));
6564
- const field = path30[path30.length - 1][0];
6558
+ visit.parentCollection = (cst, path35) => {
6559
+ const parent = visit.itemAtPath(cst, path35.slice(0, -1));
6560
+ const field = path35[path35.length - 1][0];
6565
6561
  const coll = parent?.[field];
6566
6562
  if (coll && "items" in coll)
6567
6563
  return coll;
6568
6564
  throw new Error("Parent collection not found");
6569
6565
  };
6570
- function _visit(path30, item, visitor) {
6571
- let ctrl = visitor(item, path30);
6566
+ function _visit(path35, item, visitor) {
6567
+ let ctrl = visitor(item, path35);
6572
6568
  if (typeof ctrl === "symbol")
6573
6569
  return ctrl;
6574
6570
  for (const field of ["key", "value"]) {
6575
6571
  const token = item[field];
6576
6572
  if (token && "items" in token) {
6577
6573
  for (let i = 0; i < token.items.length; ++i) {
6578
- const ci = _visit(Object.freeze(path30.concat([[field, i]])), token.items[i], visitor);
6574
+ const ci = _visit(Object.freeze(path35.concat([[field, i]])), token.items[i], visitor);
6579
6575
  if (typeof ci === "number")
6580
6576
  i = ci - 1;
6581
6577
  else if (ci === BREAK)
@@ -6586,10 +6582,10 @@ var require_cst_visit = __commonJS({
6586
6582
  }
6587
6583
  }
6588
6584
  if (typeof ctrl === "function" && field === "key")
6589
- ctrl = ctrl(item, path30);
6585
+ ctrl = ctrl(item, path35);
6590
6586
  }
6591
6587
  }
6592
- return typeof ctrl === "function" ? ctrl(item, path30) : ctrl;
6588
+ return typeof ctrl === "function" ? ctrl(item, path35) : ctrl;
6593
6589
  }
6594
6590
  exports2.visit = visit;
6595
6591
  }
@@ -7874,14 +7870,14 @@ var require_parser = __commonJS({
7874
7870
  case "scalar":
7875
7871
  case "single-quoted-scalar":
7876
7872
  case "double-quoted-scalar": {
7877
- const fs32 = this.flowScalar(this.type);
7873
+ const fs35 = this.flowScalar(this.type);
7878
7874
  if (atNextItem || it.value) {
7879
- map.items.push({ start, key: fs32, sep: [] });
7875
+ map.items.push({ start, key: fs35, sep: [] });
7880
7876
  this.onKeyLine = true;
7881
7877
  } else if (it.sep) {
7882
- this.stack.push(fs32);
7878
+ this.stack.push(fs35);
7883
7879
  } else {
7884
- Object.assign(it, { key: fs32, sep: [] });
7880
+ Object.assign(it, { key: fs35, sep: [] });
7885
7881
  this.onKeyLine = true;
7886
7882
  }
7887
7883
  return;
@@ -8009,13 +8005,13 @@ var require_parser = __commonJS({
8009
8005
  case "scalar":
8010
8006
  case "single-quoted-scalar":
8011
8007
  case "double-quoted-scalar": {
8012
- const fs32 = this.flowScalar(this.type);
8008
+ const fs35 = this.flowScalar(this.type);
8013
8009
  if (!it || it.value)
8014
- fc.items.push({ start: [], key: fs32, sep: [] });
8010
+ fc.items.push({ start: [], key: fs35, sep: [] });
8015
8011
  else if (it.sep)
8016
- this.stack.push(fs32);
8012
+ this.stack.push(fs35);
8017
8013
  else
8018
- Object.assign(it, { key: fs32, sep: [] });
8014
+ Object.assign(it, { key: fs35, sep: [] });
8019
8015
  return;
8020
8016
  }
8021
8017
  case "flow-map-end":
@@ -8323,15 +8319,13 @@ var require_dist = __commonJS({
8323
8319
  }
8324
8320
  });
8325
8321
 
8326
- // node_modules/.pnpm/@learnrudi+core@1.0.2/node_modules/@learnrudi/core/src/lockfile.js
8322
+ // packages/core/src/lockfile.js
8327
8323
  async function writeLockfile(resolved) {
8328
- const [kind, name] = parsePackageId(resolved.id);
8329
- const lockKind = kind === "binary" ? "binaries" : kind + "s";
8330
- const lockDir = import_path3.default.join(PATHS.locks, lockKind);
8324
+ const lockPath = getLockfilePath(resolved.id);
8325
+ const lockDir = import_path3.default.dirname(lockPath);
8331
8326
  if (!import_fs3.default.existsSync(lockDir)) {
8332
8327
  import_fs3.default.mkdirSync(lockDir, { recursive: true });
8333
8328
  }
8334
- const lockPath = import_path3.default.join(lockDir, `${name}.lock.yaml`);
8335
8329
  const lockfile = {
8336
8330
  id: resolved.id,
8337
8331
  version: resolved.version,
@@ -8443,7 +8437,7 @@ async function cleanOrphanedLockfiles() {
8443
8437
  }
8444
8438
  var import_fs3, import_path3, import_yaml;
8445
8439
  var init_lockfile = __esm({
8446
- "node_modules/.pnpm/@learnrudi+core@1.0.2/node_modules/@learnrudi/core/src/lockfile.js"() {
8440
+ "packages/core/src/lockfile.js"() {
8447
8441
  import_fs3 = __toESM(require("fs"), 1);
8448
8442
  import_path3 = __toESM(require("path"), 1);
8449
8443
  import_yaml = __toESM(require_dist(), 1);
@@ -8451,28 +8445,91 @@ var init_lockfile = __esm({
8451
8445
  }
8452
8446
  });
8453
8447
 
8454
- // node_modules/.pnpm/@learnrudi+core@1.0.2/node_modules/@learnrudi/core/src/shims.js
8448
+ // packages/core/src/shims.js
8455
8449
  var shims_exports = {};
8456
8450
  __export(shims_exports, {
8457
8451
  createShimsForTool: () => createShimsForTool,
8452
+ getAllShimOwners: () => getAllShimOwners,
8453
+ getShimOwner: () => getShimOwner,
8458
8454
  listShims: () => listShims,
8459
8455
  removeShims: () => removeShims,
8460
8456
  validateShim: () => validateShim
8461
8457
  });
8458
+ function getShimRegistryPath() {
8459
+ return import_path4.default.join(PATHS.home, "shim-registry.json");
8460
+ }
8461
+ function loadShimRegistry() {
8462
+ const registryPath = getShimRegistryPath();
8463
+ try {
8464
+ if (import_fs4.default.existsSync(registryPath)) {
8465
+ return JSON.parse(import_fs4.default.readFileSync(registryPath, "utf-8"));
8466
+ }
8467
+ } catch {
8468
+ }
8469
+ return {};
8470
+ }
8471
+ function saveShimRegistry(registry) {
8472
+ const registryPath = getShimRegistryPath();
8473
+ const dir = import_path4.default.dirname(registryPath);
8474
+ if (!import_fs4.default.existsSync(dir)) {
8475
+ import_fs4.default.mkdirSync(dir, { recursive: true });
8476
+ }
8477
+ import_fs4.default.writeFileSync(registryPath, JSON.stringify(registry, null, 2));
8478
+ }
8479
+ function registerShim(bin, owner, type, target) {
8480
+ const registry = loadShimRegistry();
8481
+ const existing = registry[bin];
8482
+ let collision = false;
8483
+ let previousOwner = void 0;
8484
+ if (existing && existing.owner !== owner) {
8485
+ collision = true;
8486
+ previousOwner = existing.owner;
8487
+ }
8488
+ registry[bin] = {
8489
+ owner,
8490
+ type,
8491
+ target,
8492
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
8493
+ };
8494
+ saveShimRegistry(registry);
8495
+ return { collision, previousOwner };
8496
+ }
8497
+ function unregisterShim(bin) {
8498
+ const registry = loadShimRegistry();
8499
+ delete registry[bin];
8500
+ saveShimRegistry(registry);
8501
+ }
8502
+ function getShimOwner(bin) {
8503
+ const registry = loadShimRegistry();
8504
+ return registry[bin] || null;
8505
+ }
8506
+ function getAllShimOwners() {
8507
+ return loadShimRegistry();
8508
+ }
8462
8509
  async function createShimsForTool(manifest) {
8463
8510
  const bins = manifest.bins || [manifest.name || manifest.id.split(":")[1]];
8511
+ const created = [];
8512
+ const collisions = [];
8464
8513
  for (const bin of bins) {
8465
8514
  const target = resolveBinTarget(manifest, bin);
8466
8515
  if (!import_fs4.default.existsSync(target)) {
8467
8516
  console.warn(`[Shims] Warning: Binary target does not exist: ${target}`);
8468
8517
  continue;
8469
8518
  }
8519
+ const shimType = manifest.installType === "binary" ? "symlink" : "wrapper";
8470
8520
  if (manifest.installType === "binary") {
8471
8521
  createSymlinkShim(bin, target, PATHS.bins);
8472
8522
  } else {
8473
8523
  createWrapperShim(bin, target, PATHS.bins);
8474
8524
  }
8525
+ const { collision, previousOwner } = registerShim(bin, manifest.id, shimType, target);
8526
+ if (collision) {
8527
+ collisions.push({ bin, previousOwner });
8528
+ console.warn(`[Shims] Warning: '${bin}' was owned by ${previousOwner}, now owned by ${manifest.id}`);
8529
+ }
8530
+ created.push(bin);
8475
8531
  }
8532
+ return { created, collisions };
8476
8533
  }
8477
8534
  function resolveBinTarget(manifest, bin) {
8478
8535
  switch (manifest.installType) {
@@ -8513,14 +8570,21 @@ function createSymlinkShim(name, targetAbs, binsDir) {
8513
8570
  console.log(`[Shims] Created symlink shim: ${name} \u2192 ${targetAbs}`);
8514
8571
  }
8515
8572
  function removeShims(bins) {
8573
+ const removed = [];
8574
+ const notFound = [];
8516
8575
  for (const bin of bins) {
8517
8576
  const shimPath = import_path4.default.join(PATHS.bins, bin);
8518
8577
  try {
8519
8578
  import_fs4.default.unlinkSync(shimPath);
8579
+ unregisterShim(bin);
8580
+ removed.push(bin);
8520
8581
  console.log(`[Shims] Removed shim: ${bin}`);
8521
8582
  } catch (err) {
8583
+ notFound.push(bin);
8584
+ unregisterShim(bin);
8522
8585
  }
8523
8586
  }
8587
+ return { removed, notFound };
8524
8588
  }
8525
8589
  function listShims() {
8526
8590
  if (!import_fs4.default.existsSync(PATHS.bins)) {
@@ -8569,16 +8633,53 @@ function validateShim(bin) {
8569
8633
  }
8570
8634
  var import_fs4, import_path4;
8571
8635
  var init_shims = __esm({
8572
- "node_modules/.pnpm/@learnrudi+core@1.0.2/node_modules/@learnrudi/core/src/shims.js"() {
8636
+ "packages/core/src/shims.js"() {
8573
8637
  import_fs4 = __toESM(require("fs"), 1);
8574
8638
  import_path4 = __toESM(require("path"), 1);
8575
8639
  init_src();
8576
8640
  }
8577
8641
  });
8578
8642
 
8579
- // node_modules/.pnpm/@learnrudi+core@1.0.2/node_modules/@learnrudi/core/src/installer.js
8643
+ // packages/core/src/installer.js
8644
+ function discoverNpmBins(installPath, packageName) {
8645
+ try {
8646
+ const pkgJsonPath = import_path5.default.join(installPath, "node_modules", packageName, "package.json");
8647
+ if (!import_fs5.default.existsSync(pkgJsonPath)) {
8648
+ console.warn(`[Installer] Warning: Could not find package.json at ${pkgJsonPath}`);
8649
+ return [];
8650
+ }
8651
+ const pkgJson = JSON.parse(import_fs5.default.readFileSync(pkgJsonPath, "utf8"));
8652
+ const bins = [];
8653
+ if (typeof pkgJson.bin === "string") {
8654
+ const binName = packageName.split("/").pop();
8655
+ bins.push(binName);
8656
+ } else if (typeof pkgJson.bin === "object" && pkgJson.bin !== null) {
8657
+ bins.push(...Object.keys(pkgJson.bin));
8658
+ } else {
8659
+ console.warn(`[Installer] Warning: Package '${packageName}' has no 'bin' field`);
8660
+ }
8661
+ return bins;
8662
+ } catch (error) {
8663
+ console.warn(`[Installer] Error discovering bins: ${error.message}`);
8664
+ return [];
8665
+ }
8666
+ }
8667
+ function hasInstallScripts(installPath, packageName) {
8668
+ try {
8669
+ const pkgJsonPath = import_path5.default.join(installPath, "node_modules", packageName, "package.json");
8670
+ if (!import_fs5.default.existsSync(pkgJsonPath)) {
8671
+ return false;
8672
+ }
8673
+ const pkgJson = JSON.parse(import_fs5.default.readFileSync(pkgJsonPath, "utf8"));
8674
+ const scripts = pkgJson.scripts || {};
8675
+ const installScriptKeys = ["preinstall", "install", "postinstall", "prepare"];
8676
+ return installScriptKeys.some((key) => scripts[key]);
8677
+ } catch (error) {
8678
+ return false;
8679
+ }
8680
+ }
8580
8681
  async function installPackage(id, options = {}) {
8581
- const { force = false, onProgress } = options;
8682
+ const { force = false, allowScripts = false, onProgress } = options;
8582
8683
  ensureDirectories();
8583
8684
  onProgress?.({ phase: "resolving", package: id });
8584
8685
  const resolved = await resolvePackage(id);
@@ -8598,7 +8699,7 @@ async function installPackage(id, options = {}) {
8598
8699
  for (const pkg of toInstall) {
8599
8700
  onProgress?.({ phase: "installing", package: pkg.id, total: toInstall.length, current: results.length + 1 });
8600
8701
  try {
8601
- const result = await installSinglePackage(pkg, { force, onProgress });
8702
+ const result = await installSinglePackage(pkg, { force, allowScripts, onProgress });
8602
8703
  results.push(result);
8603
8704
  } catch (error) {
8604
8705
  return {
@@ -8618,7 +8719,7 @@ async function installPackage(id, options = {}) {
8618
8719
  };
8619
8720
  }
8620
8721
  async function installSinglePackage(pkg, options = {}) {
8621
- const { force = false, onProgress } = options;
8722
+ const { force = false, allowScripts = false, onProgress } = options;
8622
8723
  const installPath = getPackagePath(pkg.id);
8623
8724
  if (import_fs5.default.existsSync(installPath) && !force) {
8624
8725
  return { success: true, id: pkg.id, path: installPath, skipped: true };
@@ -8638,7 +8739,23 @@ async function installSinglePackage(pkg, options = {}) {
8638
8739
  if (!import_fs5.default.existsSync(import_path5.default.join(installPath, "package.json"))) {
8639
8740
  execSync10(`"${npmCmd}" init -y`, { cwd: installPath, stdio: "pipe" });
8640
8741
  }
8641
- execSync10(`"${npmCmd}" install ${pkg.npmPackage}`, { cwd: installPath, stdio: "pipe" });
8742
+ const shouldIgnoreScripts = pkg.source?.type === "npm" && !allowScripts;
8743
+ const installFlags = shouldIgnoreScripts ? "--ignore-scripts --no-audit --no-fund" : "--no-audit --no-fund";
8744
+ execSync10(`"${npmCmd}" install ${pkg.npmPackage} ${installFlags}`, { cwd: installPath, stdio: "pipe" });
8745
+ let bins = pkg.bins;
8746
+ if (!bins || bins.length === 0) {
8747
+ bins = discoverNpmBins(installPath, pkg.npmPackage);
8748
+ console.log(`[Installer] Discovered binaries: ${bins.join(", ") || "(none)"}`);
8749
+ }
8750
+ let installedVersion = pkg.version || "latest";
8751
+ try {
8752
+ const pkgJsonPath = import_path5.default.join(installPath, "node_modules", pkg.npmPackage, "package.json");
8753
+ if (import_fs5.default.existsSync(pkgJsonPath)) {
8754
+ const pkgJson = JSON.parse(import_fs5.default.readFileSync(pkgJsonPath, "utf8"));
8755
+ installedVersion = pkgJson.version;
8756
+ }
8757
+ } catch (err) {
8758
+ }
8642
8759
  if (pkg.postInstall) {
8643
8760
  onProgress?.({ phase: "postInstall", package: pkg.id, message: pkg.postInstall });
8644
8761
  const postInstallCmd = pkg.postInstall.replace(
@@ -8647,27 +8764,43 @@ async function installSinglePackage(pkg, options = {}) {
8647
8764
  );
8648
8765
  execSync10(postInstallCmd, { cwd: installPath, stdio: "pipe" });
8649
8766
  }
8767
+ const scriptsDetected = hasInstallScripts(installPath, pkg.npmPackage);
8768
+ const scriptsPolicy = installFlags.includes("--ignore-scripts") ? "ignore" : "allow";
8769
+ if (scriptsDetected && scriptsPolicy === "ignore") {
8770
+ console.warn(`
8771
+ \u26A0\uFE0F This package defines install scripts that were skipped for security.`);
8772
+ console.warn(` If the CLI fails to run, reinstall with:`);
8773
+ console.warn(` rudi install ${pkg.id} --allow-scripts
8774
+ `);
8775
+ }
8650
8776
  const manifest2 = {
8651
8777
  id: pkg.id,
8652
8778
  kind: pkg.kind,
8653
8779
  name: pkgName,
8654
- version: pkg.version || "latest",
8780
+ version: installedVersion,
8655
8781
  npmPackage: pkg.npmPackage,
8782
+ bins,
8783
+ hasInstallScripts: scriptsDetected,
8784
+ scriptsPolicy,
8656
8785
  postInstall: pkg.postInstall,
8657
8786
  installedAt: (/* @__PURE__ */ new Date()).toISOString(),
8658
- source: "npm"
8787
+ source: pkg.source || { type: "npm" }
8659
8788
  };
8660
8789
  import_fs5.default.writeFileSync(
8661
8790
  import_path5.default.join(installPath, "manifest.json"),
8662
8791
  JSON.stringify(manifest2, null, 2)
8663
8792
  );
8664
- await createShimsForTool({
8665
- id: pkg.id,
8666
- installType: "npm",
8667
- installDir: installPath,
8668
- bins: pkg.bins || [pkgName],
8669
- name: pkgName
8670
- });
8793
+ if (bins && bins.length > 0) {
8794
+ await createShimsForTool({
8795
+ id: pkg.id,
8796
+ installType: "npm",
8797
+ installDir: installPath,
8798
+ bins,
8799
+ name: pkgName
8800
+ });
8801
+ } else {
8802
+ console.warn(`[Installer] Warning: No binaries found for ${pkg.npmPackage}`);
8803
+ }
8671
8804
  return { success: true, id: pkg.id, path: installPath };
8672
8805
  } catch (error) {
8673
8806
  throw new Error(`Failed to install ${pkg.npmPackage}: ${error.message}`);
@@ -8815,17 +8948,33 @@ async function uninstallPackage(id) {
8815
8948
  return { success: false, error: `Package not installed: ${id}` };
8816
8949
  }
8817
8950
  try {
8951
+ let bins = [];
8952
+ if (kind !== "prompt") {
8953
+ const manifestPath = import_path5.default.join(installPath, "manifest.json");
8954
+ if (import_fs5.default.existsSync(manifestPath)) {
8955
+ try {
8956
+ const manifest = JSON.parse(import_fs5.default.readFileSync(manifestPath, "utf-8"));
8957
+ bins = manifest.bins || manifest.binaries || [];
8958
+ } catch {
8959
+ bins = [name];
8960
+ }
8961
+ }
8962
+ }
8963
+ if (bins.length > 0) {
8964
+ removeShims(bins);
8965
+ }
8818
8966
  if (kind === "prompt") {
8819
8967
  import_fs5.default.unlinkSync(installPath);
8820
8968
  } else {
8821
8969
  import_fs5.default.rmSync(installPath, { recursive: true });
8822
8970
  }
8823
- const lockDir = kind === "binary" ? "binaries" : kind + "s";
8824
- const lockPath = import_path5.default.join(PATHS.locks, lockDir, `${name}.lock.yaml`);
8971
+ const lockDir = kind === "binary" ? "binaries" : kind === "npm" ? "npms" : kind + "s";
8972
+ const lockName = name.replace(/\//g, "__").replace(/^@/, "");
8973
+ const lockPath = import_path5.default.join(PATHS.locks, lockDir, `${lockName}.lock.yaml`);
8825
8974
  if (import_fs5.default.existsSync(lockPath)) {
8826
8975
  import_fs5.default.unlinkSync(lockPath);
8827
8976
  }
8828
- return { success: true };
8977
+ return { success: true, removedShims: bins };
8829
8978
  } catch (error) {
8830
8979
  return { success: false, error: error.message };
8831
8980
  }
@@ -9109,7 +9258,7 @@ async function installPythonRequirements(pythonPath, onProgress) {
9109
9258
  }
9110
9259
  var import_fs5, import_path5;
9111
9260
  var init_installer = __esm({
9112
- "node_modules/.pnpm/@learnrudi+core@1.0.2/node_modules/@learnrudi/core/src/installer.js"() {
9261
+ "packages/core/src/installer.js"() {
9113
9262
  import_fs5 = __toESM(require("fs"), 1);
9114
9263
  import_path5 = __toESM(require("path"), 1);
9115
9264
  init_src();
@@ -9120,7 +9269,7 @@ var init_installer = __esm({
9120
9269
  }
9121
9270
  });
9122
9271
 
9123
- // node_modules/.pnpm/@learnrudi+core@1.0.2/node_modules/@learnrudi/core/src/deps.js
9272
+ // packages/core/src/deps.js
9124
9273
  function checkRuntime(runtime) {
9125
9274
  const name = runtime.replace(/^runtime:/, "");
9126
9275
  const rudiPath = import_path6.default.join(PATHS.runtimes, name);
@@ -9323,7 +9472,7 @@ async function getAllDepsFromRegistry() {
9323
9472
  }
9324
9473
  var import_fs6, import_path6, import_child_process;
9325
9474
  var init_deps = __esm({
9326
- "node_modules/.pnpm/@learnrudi+core@1.0.2/node_modules/@learnrudi/core/src/deps.js"() {
9475
+ "packages/core/src/deps.js"() {
9327
9476
  import_fs6 = __toESM(require("fs"), 1);
9328
9477
  import_path6 = __toESM(require("path"), 1);
9329
9478
  import_child_process = require("child_process");
@@ -9332,7 +9481,7 @@ var init_deps = __esm({
9332
9481
  }
9333
9482
  });
9334
9483
 
9335
- // node_modules/.pnpm/@learnrudi+core@1.0.2/node_modules/@learnrudi/core/src/rudi-config.js
9484
+ // packages/core/src/rudi-config.js
9336
9485
  function createRudiConfig() {
9337
9486
  const now = (/* @__PURE__ */ new Date()).toISOString();
9338
9487
  return {
@@ -9555,7 +9704,7 @@ function updateSecretStatus(secretName, configured, provider) {
9555
9704
  }
9556
9705
  var fs7, path7, RUDI_JSON_PATH, RUDI_JSON_TMP, RUDI_JSON_LOCK, CONFIG_MODE, LOCK_TIMEOUT_MS;
9557
9706
  var init_rudi_config = __esm({
9558
- "node_modules/.pnpm/@learnrudi+core@1.0.2/node_modules/@learnrudi/core/src/rudi-config.js"() {
9707
+ "packages/core/src/rudi-config.js"() {
9559
9708
  fs7 = __toESM(require("fs"), 1);
9560
9709
  path7 = __toESM(require("path"), 1);
9561
9710
  init_src();
@@ -9567,7 +9716,7 @@ var init_rudi_config = __esm({
9567
9716
  }
9568
9717
  });
9569
9718
 
9570
- // node_modules/.pnpm/@learnrudi+core@1.0.2/node_modules/@learnrudi/core/src/tool-index.js
9719
+ // packages/core/src/tool-index.js
9571
9720
  function loadSecrets() {
9572
9721
  try {
9573
9722
  const content = fs8.readFileSync(SECRETS_PATH, "utf-8");
@@ -9825,7 +9974,7 @@ async function indexAllStacks(options = {}) {
9825
9974
  }
9826
9975
  var import_child_process2, fs8, path8, readline, TOOL_INDEX_PATH, TOOL_INDEX_TMP, SECRETS_PATH, REQUEST_TIMEOUT_MS, PROTOCOL_VERSION;
9827
9976
  var init_tool_index = __esm({
9828
- "node_modules/.pnpm/@learnrudi+core@1.0.2/node_modules/@learnrudi/core/src/tool-index.js"() {
9977
+ "packages/core/src/tool-index.js"() {
9829
9978
  import_child_process2 = require("child_process");
9830
9979
  fs8 = __toESM(require("fs"), 1);
9831
9980
  path8 = __toESM(require("path"), 1);
@@ -9840,7 +9989,7 @@ var init_tool_index = __esm({
9840
9989
  }
9841
9990
  });
9842
9991
 
9843
- // node_modules/.pnpm/@learnrudi+core@1.0.2/node_modules/@learnrudi/core/src/system-registry.js
9992
+ // packages/core/src/system-registry.js
9844
9993
  async function registerSystemBinary(name, options = {}) {
9845
9994
  const {
9846
9995
  searchPaths = getDefaultSearchPaths(),
@@ -9974,7 +10123,7 @@ function getSystemBinaryInfo(name) {
9974
10123
  }
9975
10124
  var import_fs7, import_path7, import_child_process3;
9976
10125
  var init_system_registry = __esm({
9977
- "node_modules/.pnpm/@learnrudi+core@1.0.2/node_modules/@learnrudi/core/src/system-registry.js"() {
10126
+ "packages/core/src/system-registry.js"() {
9978
10127
  import_fs7 = __toESM(require("fs"), 1);
9979
10128
  import_path7 = __toESM(require("path"), 1);
9980
10129
  import_child_process3 = require("child_process");
@@ -9983,9 +10132,9 @@ var init_system_registry = __esm({
9983
10132
  }
9984
10133
  });
9985
10134
 
9986
- // node_modules/.pnpm/@learnrudi+core@1.0.2/node_modules/@learnrudi/core/src/index.js
9987
- var src_exports2 = {};
9988
- __export(src_exports2, {
10135
+ // packages/core/src/index.js
10136
+ var src_exports = {};
10137
+ __export(src_exports, {
9989
10138
  CONFIG_MODE: () => CONFIG_MODE,
9990
10139
  PATHS: () => PATHS,
9991
10140
  RUDI_JSON_PATH: () => RUDI_JSON_PATH,
@@ -10012,6 +10161,7 @@ __export(src_exports2, {
10012
10161
  formatDependencyResults: () => formatDependencyResults,
10013
10162
  getAllDepsFromRegistry: () => getAllDepsFromRegistry,
10014
10163
  getAllLockfiles: () => getAllLockfiles,
10164
+ getAllShimOwners: () => getAllShimOwners,
10015
10165
  getAvailableDeps: () => getAvailableDeps,
10016
10166
  getDefaultNpxBin: () => getDefaultNpxBin,
10017
10167
  getDefaultRuntimeBin: () => getDefaultRuntimeBin,
@@ -10021,6 +10171,7 @@ __export(src_exports2, {
10021
10171
  getLockfilePath: () => getLockfilePath,
10022
10172
  getPackage: () => getPackage,
10023
10173
  getPackagePath: () => getPackagePath,
10174
+ getShimOwner: () => getShimOwner,
10024
10175
  getSystemBinaryInfo: () => getSystemBinaryInfo,
10025
10176
  hasLockfile: () => hasLockfile,
10026
10177
  indexAllStacks: () => indexAllStacks,
@@ -10058,7 +10209,7 @@ __export(src_exports2, {
10058
10209
  writeToolIndex: () => writeToolIndex
10059
10210
  });
10060
10211
  var init_src3 = __esm({
10061
- "node_modules/.pnpm/@learnrudi+core@1.0.2/node_modules/@learnrudi/core/src/index.js"() {
10212
+ "packages/core/src/index.js"() {
10062
10213
  init_src();
10063
10214
  init_src2();
10064
10215
  init_resolver();
@@ -10072,6 +10223,13 @@ var init_src3 = __esm({
10072
10223
  }
10073
10224
  });
10074
10225
 
10226
+ // node_modules/.pnpm/@learnrudi+core@1.0.2/node_modules/@learnrudi/core/src/shims.js
10227
+ var init_shims2 = __esm({
10228
+ "node_modules/.pnpm/@learnrudi+core@1.0.2/node_modules/@learnrudi/core/src/shims.js"() {
10229
+ init_src();
10230
+ }
10231
+ });
10232
+
10075
10233
  // node_modules/.pnpm/ajv@8.17.1/node_modules/ajv/dist/compile/codegen/code.js
10076
10234
  var require_code = __commonJS({
10077
10235
  "node_modules/.pnpm/ajv@8.17.1/node_modules/ajv/dist/compile/codegen/code.js"(exports2) {
@@ -13265,8 +13423,8 @@ var require_utils = __commonJS({
13265
13423
  }
13266
13424
  return ind;
13267
13425
  }
13268
- function removeDotSegments(path30) {
13269
- let input = path30;
13426
+ function removeDotSegments(path35) {
13427
+ let input = path35;
13270
13428
  const output = [];
13271
13429
  let nextSlash = -1;
13272
13430
  let len = 0;
@@ -13465,8 +13623,8 @@ var require_schemes = __commonJS({
13465
13623
  wsComponent.secure = void 0;
13466
13624
  }
13467
13625
  if (wsComponent.resourceName) {
13468
- const [path30, query] = wsComponent.resourceName.split("?");
13469
- wsComponent.path = path30 && path30 !== "/" ? path30 : void 0;
13626
+ const [path35, query] = wsComponent.resourceName.split("?");
13627
+ wsComponent.path = path35 && path35 !== "/" ? path35 : void 0;
13470
13628
  wsComponent.query = query;
13471
13629
  wsComponent.resourceName = void 0;
13472
13630
  }
@@ -16819,12 +16977,12 @@ var require_dist2 = __commonJS({
16819
16977
  throw new Error(`Unknown format "${name}"`);
16820
16978
  return f;
16821
16979
  };
16822
- function addFormats2(ajv2, list, fs32, exportName) {
16980
+ function addFormats2(ajv2, list, fs35, exportName) {
16823
16981
  var _a;
16824
16982
  var _b;
16825
16983
  (_a = (_b = ajv2.opts.code).formats) !== null && _a !== void 0 ? _a : _b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
16826
16984
  for (const f of list)
16827
- ajv2.addFormat(f, fs32[f]);
16985
+ ajv2.addFormat(f, fs35[f]);
16828
16986
  }
16829
16987
  module2.exports = exports2 = formatsPlugin;
16830
16988
  Object.defineProperty(exports2, "__esModule", { value: true });
@@ -16832,65 +16990,749 @@ var require_dist2 = __commonJS({
16832
16990
  }
16833
16991
  });
16834
16992
 
16835
- // node_modules/.pnpm/@learnrudi+utils@1.0.0/node_modules/@learnrudi/utils/src/args.js
16836
- function parseArgs(argv) {
16837
- const flags = {};
16838
- const args = [];
16839
- let command = null;
16840
- for (let i = 0; i < argv.length; i++) {
16841
- const arg = argv[i];
16842
- if (arg.startsWith("--")) {
16843
- const eqIndex = arg.indexOf("=");
16844
- if (eqIndex !== -1) {
16845
- const key = arg.slice(2, eqIndex);
16846
- const value = arg.slice(eqIndex + 1);
16847
- flags[key] = value;
16848
- } else {
16849
- const key = arg.slice(2);
16850
- const nextArg = argv[i + 1];
16851
- if (nextArg && !nextArg.startsWith("-")) {
16852
- flags[key] = nextArg;
16853
- i++;
16854
- } else {
16855
- flags[key] = true;
16856
- }
16857
- }
16858
- } else if (arg.startsWith("-") && arg.length > 1) {
16859
- const chars = arg.slice(1);
16860
- for (const char of chars) {
16861
- flags[char] = true;
16993
+ // packages/registry-client/src/index.js
16994
+ var src_exports2 = {};
16995
+ __export(src_exports2, {
16996
+ CACHE_TTL: () => CACHE_TTL2,
16997
+ DEFAULT_REGISTRY_URL: () => DEFAULT_REGISTRY_URL2,
16998
+ PACKAGE_KINDS: () => PACKAGE_KINDS4,
16999
+ RUNTIMES_DOWNLOAD_BASE: () => RUNTIMES_DOWNLOAD_BASE2,
17000
+ RUNTIMES_RELEASE_VERSION: () => RUNTIMES_RELEASE_VERSION2,
17001
+ checkCache: () => checkCache,
17002
+ clearCache: () => clearCache2,
17003
+ computeHash: () => computeHash,
17004
+ downloadPackage: () => downloadPackage2,
17005
+ downloadRuntime: () => downloadRuntime2,
17006
+ downloadTool: () => downloadTool2,
17007
+ fetchIndex: () => fetchIndex2,
17008
+ getManifest: () => getManifest2,
17009
+ getPackage: () => getPackage2,
17010
+ getPackageKinds: () => getPackageKinds,
17011
+ listPackages: () => listPackages2,
17012
+ searchPackages: () => searchPackages2,
17013
+ verifyHash: () => verifyHash
17014
+ });
17015
+ function getLocalRegistryPaths2() {
17016
+ if (process.env.USE_LOCAL_REGISTRY !== "true") {
17017
+ return [];
17018
+ }
17019
+ return [
17020
+ import_path18.default.join(process.cwd(), "registry", "index.json"),
17021
+ import_path18.default.join(process.cwd(), "..", "registry", "index.json"),
17022
+ "/Users/hoff/dev/RUDI/registry/index.json"
17023
+ ];
17024
+ }
17025
+ async function fetchIndex2(options = {}) {
17026
+ const { url = DEFAULT_REGISTRY_URL2, force = false } = options;
17027
+ const localResult = getLocalIndex2();
17028
+ if (localResult) {
17029
+ const { index: localIndex, mtime: localMtime } = localResult;
17030
+ const cacheMtime = getCacheMtime2();
17031
+ if (force || !cacheMtime || localMtime > cacheMtime) {
17032
+ cacheIndex2(localIndex);
17033
+ return localIndex;
17034
+ }
17035
+ }
17036
+ if (!force) {
17037
+ const cached = getCachedIndex2();
17038
+ if (cached) {
17039
+ return cached;
17040
+ }
17041
+ }
17042
+ if (localResult) {
17043
+ return localResult.index;
17044
+ }
17045
+ try {
17046
+ const response = await fetch(url, {
17047
+ headers: {
17048
+ "Accept": "application/json",
17049
+ "User-Agent": "rudi-cli/2.0"
16862
17050
  }
16863
- } else if (!command) {
16864
- command = arg;
16865
- } else {
16866
- args.push(arg);
17051
+ });
17052
+ if (!response.ok) {
17053
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
17054
+ }
17055
+ const index = await response.json();
17056
+ cacheIndex2(index);
17057
+ return index;
17058
+ } catch (error) {
17059
+ const fallback = getLocalIndex2();
17060
+ if (fallback) {
17061
+ return fallback.index;
16867
17062
  }
17063
+ throw new Error(`Failed to fetch registry: ${error.message}`);
16868
17064
  }
16869
- return { command, args, flags };
16870
17065
  }
16871
- function formatBytes(bytes) {
16872
- if (bytes === 0) return "0 B";
16873
- const k = 1024;
16874
- const sizes = ["B", "KB", "MB", "GB"];
16875
- const i = Math.floor(Math.log(bytes) / Math.log(k));
16876
- return `${(bytes / Math.pow(k, i)).toFixed(1)} ${sizes[i]}`;
17066
+ function getCachedIndex2() {
17067
+ const cachePath = PATHS.registryCache;
17068
+ if (!import_fs19.default.existsSync(cachePath)) {
17069
+ return null;
17070
+ }
17071
+ try {
17072
+ const stat = import_fs19.default.statSync(cachePath);
17073
+ const age = Date.now() - stat.mtimeMs;
17074
+ if (age > CACHE_TTL2) {
17075
+ return null;
17076
+ }
17077
+ return JSON.parse(import_fs19.default.readFileSync(cachePath, "utf-8"));
17078
+ } catch {
17079
+ return null;
17080
+ }
16877
17081
  }
16878
- function formatDuration(ms) {
16879
- if (ms < 1e3) return `${ms}ms`;
16880
- if (ms < 6e4) return `${(ms / 1e3).toFixed(1)}s`;
16881
- const mins = Math.floor(ms / 6e4);
16882
- const secs = Math.floor(ms % 6e4 / 1e3);
16883
- return `${mins}m ${secs}s`;
17082
+ function cacheIndex2(index) {
17083
+ const cachePath = PATHS.registryCache;
17084
+ const cacheDir = import_path18.default.dirname(cachePath);
17085
+ if (!import_fs19.default.existsSync(cacheDir)) {
17086
+ import_fs19.default.mkdirSync(cacheDir, { recursive: true });
17087
+ }
17088
+ import_fs19.default.writeFileSync(cachePath, JSON.stringify(index, null, 2));
16884
17089
  }
16885
-
16886
- // node_modules/.pnpm/@learnrudi+utils@1.0.0/node_modules/@learnrudi/utils/src/help.js
16887
- function printVersion(version) {
16888
- console.log(`rudi v${version}`);
17090
+ function getCacheMtime2() {
17091
+ const cachePath = PATHS.registryCache;
17092
+ if (!import_fs19.default.existsSync(cachePath)) {
17093
+ return null;
17094
+ }
17095
+ try {
17096
+ return import_fs19.default.statSync(cachePath).mtimeMs;
17097
+ } catch {
17098
+ return null;
17099
+ }
16889
17100
  }
16890
- function printHelp(topic) {
16891
- if (topic) {
16892
- printCommandHelp(topic);
16893
- return;
17101
+ function getLocalIndex2() {
17102
+ for (const localPath of getLocalRegistryPaths2()) {
17103
+ if (import_fs19.default.existsSync(localPath)) {
17104
+ try {
17105
+ const index = JSON.parse(import_fs19.default.readFileSync(localPath, "utf-8"));
17106
+ const mtime = import_fs19.default.statSync(localPath).mtimeMs;
17107
+ return { index, mtime };
17108
+ } catch {
17109
+ continue;
17110
+ }
17111
+ }
17112
+ }
17113
+ return null;
17114
+ }
17115
+ function clearCache2() {
17116
+ if (import_fs19.default.existsSync(PATHS.registryCache)) {
17117
+ import_fs19.default.unlinkSync(PATHS.registryCache);
17118
+ }
17119
+ }
17120
+ function checkCache() {
17121
+ const cachePath = PATHS.registryCache;
17122
+ if (!import_fs19.default.existsSync(cachePath)) {
17123
+ return { fresh: false, age: null };
17124
+ }
17125
+ try {
17126
+ const stat = import_fs19.default.statSync(cachePath);
17127
+ const age = Date.now() - stat.mtimeMs;
17128
+ return { fresh: age <= CACHE_TTL2, age };
17129
+ } catch {
17130
+ return { fresh: false, age: null };
17131
+ }
17132
+ }
17133
+ function getKindSection2(kind) {
17134
+ return KIND_PLURALS2[kind] || `${kind}s`;
17135
+ }
17136
+ async function searchPackages2(query, options = {}) {
17137
+ const { kind } = options;
17138
+ const index = await fetchIndex2();
17139
+ const results = [];
17140
+ const queryLower = query.toLowerCase();
17141
+ const kinds = kind ? [kind] : PACKAGE_KINDS4;
17142
+ for (const k of kinds) {
17143
+ const section = index.packages?.[getKindSection2(k)];
17144
+ if (!section) continue;
17145
+ const packages = [...section.official || [], ...section.community || []];
17146
+ for (const pkg of packages) {
17147
+ if (matchesQuery2(pkg, queryLower)) {
17148
+ results.push({ ...pkg, kind: k });
17149
+ }
17150
+ }
17151
+ }
17152
+ return results;
17153
+ }
17154
+ function matchesQuery2(pkg, query) {
17155
+ const searchable = [
17156
+ pkg.id || "",
17157
+ pkg.name || "",
17158
+ pkg.description || "",
17159
+ ...pkg.tags || []
17160
+ ].join(" ").toLowerCase();
17161
+ return searchable.includes(query);
17162
+ }
17163
+ async function getPackage2(id) {
17164
+ const index = await fetchIndex2();
17165
+ const [kind, name] = id.includes(":") ? id.split(":") : [null, id];
17166
+ const kinds = kind ? [kind] : PACKAGE_KINDS4;
17167
+ for (const k of kinds) {
17168
+ const section = index.packages?.[getKindSection2(k)];
17169
+ if (!section) continue;
17170
+ const packages = [...section.official || [], ...section.community || []];
17171
+ for (const pkg of packages) {
17172
+ const kindPrefixPattern = new RegExp(`^(${PACKAGE_KINDS4.join("|")}):`);
17173
+ const pkgShortId = pkg.id?.replace(kindPrefixPattern, "") || "";
17174
+ if (pkgShortId === name || pkg.id === id) {
17175
+ return { ...pkg, kind: k };
17176
+ }
17177
+ }
17178
+ }
17179
+ return null;
17180
+ }
17181
+ async function getManifest2(pkg) {
17182
+ if (!pkg || !pkg.path) {
17183
+ return null;
17184
+ }
17185
+ const manifestPath = pkg.path;
17186
+ if (process.env.USE_LOCAL_REGISTRY === "true") {
17187
+ const localPaths = [
17188
+ import_path18.default.join(process.cwd(), "registry", manifestPath),
17189
+ import_path18.default.join(process.cwd(), "..", "registry", manifestPath),
17190
+ `/Users/hoff/dev/RUDI/registry/${manifestPath}`
17191
+ ];
17192
+ for (const localPath of localPaths) {
17193
+ if (import_fs19.default.existsSync(localPath)) {
17194
+ try {
17195
+ const content = import_fs19.default.readFileSync(localPath, "utf-8");
17196
+ return JSON.parse(content);
17197
+ } catch (err) {
17198
+ }
17199
+ }
17200
+ }
17201
+ }
17202
+ try {
17203
+ const url = `${GITHUB_RAW_BASE2}/${manifestPath}`;
17204
+ const response = await fetch(url, {
17205
+ headers: {
17206
+ "Accept": "application/json",
17207
+ "User-Agent": "rudi-cli/2.0"
17208
+ }
17209
+ });
17210
+ if (!response.ok) {
17211
+ return null;
17212
+ }
17213
+ return await response.json();
17214
+ } catch (err) {
17215
+ return null;
17216
+ }
17217
+ }
17218
+ async function listPackages2(kind) {
17219
+ const index = await fetchIndex2();
17220
+ const section = index.packages?.[getKindSection2(kind)];
17221
+ if (!section) return [];
17222
+ return [...section.official || [], ...section.community || []];
17223
+ }
17224
+ function getPackageKinds() {
17225
+ return PACKAGE_KINDS4;
17226
+ }
17227
+ async function downloadPackage2(pkg, destPath, options = {}) {
17228
+ const { onProgress } = options;
17229
+ const registryPath = pkg.path;
17230
+ if (!import_fs19.default.existsSync(destPath)) {
17231
+ import_fs19.default.mkdirSync(destPath, { recursive: true });
17232
+ }
17233
+ onProgress?.({ phase: "downloading", package: pkg.name || pkg.id });
17234
+ if (pkg.kind === "stack" || registryPath.includes("/stacks/")) {
17235
+ await downloadStackFromGitHub2(registryPath, destPath, onProgress);
17236
+ return { success: true, path: destPath };
17237
+ }
17238
+ if (registryPath.endsWith(".md")) {
17239
+ const url = `${GITHUB_RAW_BASE2}/${registryPath}`;
17240
+ const response = await fetch(url, {
17241
+ headers: { "User-Agent": "rudi-cli/2.0" }
17242
+ });
17243
+ if (!response.ok) {
17244
+ throw new Error(`Failed to download ${registryPath}: HTTP ${response.status}`);
17245
+ }
17246
+ const content = await response.text();
17247
+ const destDir = import_path18.default.dirname(destPath);
17248
+ if (!import_fs19.default.existsSync(destDir)) {
17249
+ import_fs19.default.mkdirSync(destDir, { recursive: true });
17250
+ }
17251
+ import_fs19.default.writeFileSync(destPath, content);
17252
+ return { success: true, path: destPath };
17253
+ }
17254
+ throw new Error(`Unsupported package type: ${registryPath}`);
17255
+ }
17256
+ async function downloadStackFromGitHub2(registryPath, destPath, onProgress) {
17257
+ const baseUrl = `${GITHUB_RAW_BASE2}/${registryPath}`;
17258
+ const apiUrl = `https://api.github.com/repos/learn-rudi/registry/contents/${registryPath}`;
17259
+ const listResponse = await fetch(apiUrl, {
17260
+ headers: {
17261
+ "User-Agent": "rudi-cli/2.0",
17262
+ "Accept": "application/vnd.github.v3+json"
17263
+ }
17264
+ });
17265
+ if (!listResponse.ok) {
17266
+ throw new Error(`Stack not found: ${registryPath}`);
17267
+ }
17268
+ const contents = await listResponse.json();
17269
+ if (!Array.isArray(contents)) {
17270
+ throw new Error(`Invalid stack directory: ${registryPath}`);
17271
+ }
17272
+ const existingItems = /* @__PURE__ */ new Map();
17273
+ for (const item of contents) {
17274
+ existingItems.set(item.name, item);
17275
+ }
17276
+ const manifestItem = existingItems.get("manifest.json");
17277
+ if (!manifestItem) {
17278
+ throw new Error(`Stack missing manifest.json: ${registryPath}`);
17279
+ }
17280
+ const manifestResponse = await fetch(manifestItem.download_url, {
17281
+ headers: { "User-Agent": "rudi-cli/2.0" }
17282
+ });
17283
+ const manifest = await manifestResponse.json();
17284
+ import_fs19.default.writeFileSync(import_path18.default.join(destPath, "manifest.json"), JSON.stringify(manifest, null, 2));
17285
+ onProgress?.({ phase: "downloading", file: "manifest.json" });
17286
+ const pkgJsonItem = existingItems.get("package.json");
17287
+ if (pkgJsonItem) {
17288
+ const pkgJsonResponse = await fetch(pkgJsonItem.download_url, {
17289
+ headers: { "User-Agent": "rudi-cli/2.0" }
17290
+ });
17291
+ if (pkgJsonResponse.ok) {
17292
+ const pkgJson = await pkgJsonResponse.text();
17293
+ import_fs19.default.writeFileSync(import_path18.default.join(destPath, "package.json"), pkgJson);
17294
+ onProgress?.({ phase: "downloading", file: "package.json" });
17295
+ }
17296
+ }
17297
+ const envExampleItem = existingItems.get(".env.example");
17298
+ if (envExampleItem) {
17299
+ const envResponse = await fetch(envExampleItem.download_url, {
17300
+ headers: { "User-Agent": "rudi-cli/2.0" }
17301
+ });
17302
+ if (envResponse.ok) {
17303
+ const envContent = await envResponse.text();
17304
+ import_fs19.default.writeFileSync(import_path18.default.join(destPath, ".env.example"), envContent);
17305
+ }
17306
+ }
17307
+ const tsconfigItem = existingItems.get("tsconfig.json");
17308
+ if (tsconfigItem) {
17309
+ const tsconfigResponse = await fetch(tsconfigItem.download_url, {
17310
+ headers: { "User-Agent": "rudi-cli/2.0" }
17311
+ });
17312
+ if (tsconfigResponse.ok) {
17313
+ const tsconfig = await tsconfigResponse.text();
17314
+ import_fs19.default.writeFileSync(import_path18.default.join(destPath, "tsconfig.json"), tsconfig);
17315
+ }
17316
+ }
17317
+ const requirementsItem = existingItems.get("requirements.txt");
17318
+ if (requirementsItem) {
17319
+ const reqResponse = await fetch(requirementsItem.download_url, {
17320
+ headers: { "User-Agent": "rudi-cli/2.0" }
17321
+ });
17322
+ if (reqResponse.ok) {
17323
+ const requirements = await reqResponse.text();
17324
+ import_fs19.default.writeFileSync(import_path18.default.join(destPath, "requirements.txt"), requirements);
17325
+ }
17326
+ }
17327
+ const sourceDirs = ["src", "dist", "node", "python", "lib"];
17328
+ for (const dirName of sourceDirs) {
17329
+ const dirItem = existingItems.get(dirName);
17330
+ if (dirItem && dirItem.type === "dir") {
17331
+ onProgress?.({ phase: "downloading", directory: dirName });
17332
+ await downloadDirectoryFromGitHub2(
17333
+ `${baseUrl}/${dirName}`,
17334
+ import_path18.default.join(destPath, dirName),
17335
+ onProgress
17336
+ );
17337
+ }
17338
+ }
17339
+ }
17340
+ async function downloadDirectoryFromGitHub2(dirUrl, destDir, onProgress) {
17341
+ const apiUrl = dirUrl.replace("https://raw.githubusercontent.com/", "https://api.github.com/repos/").replace("/main/", "/contents/");
17342
+ try {
17343
+ const response = await fetch(apiUrl, {
17344
+ headers: {
17345
+ "User-Agent": "rudi-cli/2.0",
17346
+ "Accept": "application/vnd.github.v3+json"
17347
+ }
17348
+ });
17349
+ if (!response.ok) {
17350
+ return;
17351
+ }
17352
+ const contents = await response.json();
17353
+ if (!Array.isArray(contents)) {
17354
+ return;
17355
+ }
17356
+ if (!import_fs19.default.existsSync(destDir)) {
17357
+ import_fs19.default.mkdirSync(destDir, { recursive: true });
17358
+ }
17359
+ for (const item of contents) {
17360
+ if (item.type === "file") {
17361
+ const fileResponse = await fetch(item.download_url, {
17362
+ headers: { "User-Agent": "rudi-cli/2.0" }
17363
+ });
17364
+ if (fileResponse.ok) {
17365
+ const content = await fileResponse.text();
17366
+ import_fs19.default.writeFileSync(import_path18.default.join(destDir, item.name), content);
17367
+ onProgress?.({ phase: "downloading", file: item.name });
17368
+ }
17369
+ } else if (item.type === "dir") {
17370
+ await downloadDirectoryFromGitHub2(
17371
+ item.url.replace("https://api.github.com/repos/", "https://raw.githubusercontent.com/").replace("/contents/", "/main/"),
17372
+ import_path18.default.join(destDir, item.name),
17373
+ onProgress
17374
+ );
17375
+ }
17376
+ }
17377
+ } catch (error) {
17378
+ console.error(`Warning: Could not download ${dirUrl}: ${error.message}`);
17379
+ }
17380
+ }
17381
+ async function downloadRuntime2(runtime, version, destPath, options = {}) {
17382
+ const { onProgress } = options;
17383
+ const platformArch = getPlatformArch();
17384
+ const shortVersion = version.replace(/\.x$/, "").replace(/\.0$/, "");
17385
+ const filename = `${runtime}-${shortVersion}-${platformArch}.tar.gz`;
17386
+ const url = `${RUNTIMES_DOWNLOAD_BASE2}/${RUNTIMES_RELEASE_VERSION2}/${filename}`;
17387
+ onProgress?.({ phase: "downloading", runtime, version, url });
17388
+ const tempDir = import_path18.default.join(PATHS.cache, "downloads");
17389
+ if (!import_fs19.default.existsSync(tempDir)) {
17390
+ import_fs19.default.mkdirSync(tempDir, { recursive: true });
17391
+ }
17392
+ const tempFile = import_path18.default.join(tempDir, filename);
17393
+ try {
17394
+ const response = await fetch(url, {
17395
+ headers: {
17396
+ "User-Agent": "rudi-cli/2.0",
17397
+ "Accept": "application/octet-stream"
17398
+ }
17399
+ });
17400
+ if (!response.ok) {
17401
+ throw new Error(`Failed to download ${runtime}: HTTP ${response.status}`);
17402
+ }
17403
+ const buffer = await response.arrayBuffer();
17404
+ import_fs19.default.writeFileSync(tempFile, Buffer.from(buffer));
17405
+ onProgress?.({ phase: "extracting", runtime, version });
17406
+ if (import_fs19.default.existsSync(destPath)) {
17407
+ import_fs19.default.rmSync(destPath, { recursive: true });
17408
+ }
17409
+ import_fs19.default.mkdirSync(destPath, { recursive: true });
17410
+ const { execSync: execSync10 } = await import("child_process");
17411
+ execSync10(`tar -xzf "${tempFile}" -C "${destPath}" --strip-components=1`, {
17412
+ stdio: "pipe"
17413
+ });
17414
+ import_fs19.default.unlinkSync(tempFile);
17415
+ import_fs19.default.writeFileSync(
17416
+ import_path18.default.join(destPath, "runtime.json"),
17417
+ JSON.stringify({
17418
+ runtime,
17419
+ version,
17420
+ platformArch,
17421
+ downloadedAt: (/* @__PURE__ */ new Date()).toISOString(),
17422
+ source: url
17423
+ }, null, 2)
17424
+ );
17425
+ onProgress?.({ phase: "complete", runtime, version, path: destPath });
17426
+ return { success: true, path: destPath };
17427
+ } catch (error) {
17428
+ if (import_fs19.default.existsSync(tempFile)) {
17429
+ import_fs19.default.unlinkSync(tempFile);
17430
+ }
17431
+ throw new Error(`Failed to install ${runtime} ${version}: ${error.message}`);
17432
+ }
17433
+ }
17434
+ async function downloadTool2(toolName, destPath, options = {}) {
17435
+ const { onProgress } = options;
17436
+ const platformArch = getPlatformArch();
17437
+ const toolManifest = await loadToolManifest2(toolName);
17438
+ if (!toolManifest) {
17439
+ throw new Error(`Binary manifest not found for: ${toolName}`);
17440
+ }
17441
+ const tempDir = import_path18.default.join(PATHS.cache, "downloads");
17442
+ if (!import_fs19.default.existsSync(tempDir)) {
17443
+ import_fs19.default.mkdirSync(tempDir, { recursive: true });
17444
+ }
17445
+ if (import_fs19.default.existsSync(destPath)) {
17446
+ import_fs19.default.rmSync(destPath, { recursive: true });
17447
+ }
17448
+ import_fs19.default.mkdirSync(destPath, { recursive: true });
17449
+ const { execSync: execSync10 } = await import("child_process");
17450
+ const downloads = toolManifest.downloads?.[platformArch];
17451
+ if (downloads && Array.isArray(downloads)) {
17452
+ const downloadedUrls = /* @__PURE__ */ new Set();
17453
+ for (const download of downloads) {
17454
+ const { url, type, binary } = download;
17455
+ if (downloadedUrls.has(url)) {
17456
+ await extractBinaryFromPath2(destPath, binary, destPath);
17457
+ continue;
17458
+ }
17459
+ onProgress?.({ phase: "downloading", tool: toolName, binary: import_path18.default.basename(binary), url });
17460
+ const urlFilename = import_path18.default.basename(new URL(url).pathname);
17461
+ const tempFile = import_path18.default.join(tempDir, urlFilename);
17462
+ try {
17463
+ const response = await fetch(url, {
17464
+ headers: {
17465
+ "User-Agent": "rudi-cli/2.0",
17466
+ "Accept": "application/octet-stream"
17467
+ }
17468
+ });
17469
+ if (!response.ok) {
17470
+ throw new Error(`Failed to download ${binary}: HTTP ${response.status}`);
17471
+ }
17472
+ const buffer = await response.arrayBuffer();
17473
+ import_fs19.default.writeFileSync(tempFile, Buffer.from(buffer));
17474
+ downloadedUrls.add(url);
17475
+ onProgress?.({ phase: "extracting", tool: toolName, binary: import_path18.default.basename(binary) });
17476
+ const archiveType = type || guessArchiveType2(urlFilename);
17477
+ if (archiveType === "zip") {
17478
+ execSync10(`unzip -o "${tempFile}" -d "${destPath}"`, { stdio: "pipe" });
17479
+ } else if (archiveType === "tar.xz") {
17480
+ execSync10(`tar -xJf "${tempFile}" -C "${destPath}"`, { stdio: "pipe" });
17481
+ } else if (archiveType === "tar.gz" || archiveType === "tgz") {
17482
+ execSync10(`tar -xzf "${tempFile}" -C "${destPath}"`, { stdio: "pipe" });
17483
+ } else {
17484
+ throw new Error(`Unsupported archive type: ${archiveType}`);
17485
+ }
17486
+ await extractBinaryFromPath2(destPath, binary, destPath);
17487
+ import_fs19.default.unlinkSync(tempFile);
17488
+ } catch (error) {
17489
+ if (import_fs19.default.existsSync(tempFile)) {
17490
+ import_fs19.default.unlinkSync(tempFile);
17491
+ }
17492
+ throw error;
17493
+ }
17494
+ }
17495
+ const binaries = toolManifest.binaries || [toolName];
17496
+ for (const bin of binaries) {
17497
+ const binPath = import_path18.default.join(destPath, bin);
17498
+ if (import_fs19.default.existsSync(binPath)) {
17499
+ import_fs19.default.chmodSync(binPath, 493);
17500
+ }
17501
+ }
17502
+ } else {
17503
+ const upstreamUrl = toolManifest.upstream?.[platformArch];
17504
+ if (!upstreamUrl) {
17505
+ throw new Error(`No upstream URL for ${toolName} on ${platformArch}`);
17506
+ }
17507
+ const extractConfig = toolManifest.extract?.[platformArch] || toolManifest.extract?.default;
17508
+ if (!extractConfig) {
17509
+ throw new Error(`No extract config for ${toolName} on ${platformArch}`);
17510
+ }
17511
+ onProgress?.({ phase: "downloading", tool: toolName, url: upstreamUrl });
17512
+ const urlFilename = import_path18.default.basename(new URL(upstreamUrl).pathname);
17513
+ const tempFile = import_path18.default.join(tempDir, urlFilename);
17514
+ try {
17515
+ const response = await fetch(upstreamUrl, {
17516
+ headers: {
17517
+ "User-Agent": "rudi-cli/2.0",
17518
+ "Accept": "application/octet-stream"
17519
+ }
17520
+ });
17521
+ if (!response.ok) {
17522
+ throw new Error(`Failed to download ${toolName}: HTTP ${response.status}`);
17523
+ }
17524
+ const buffer = await response.arrayBuffer();
17525
+ import_fs19.default.writeFileSync(tempFile, Buffer.from(buffer));
17526
+ onProgress?.({ phase: "extracting", tool: toolName });
17527
+ const archiveType = extractConfig.type || guessArchiveType2(urlFilename);
17528
+ const stripComponents = extractConfig.strip || 0;
17529
+ const stripFlag = stripComponents > 0 ? ` --strip-components=${stripComponents}` : "";
17530
+ if (archiveType === "zip") {
17531
+ execSync10(`unzip -o "${tempFile}" -d "${destPath}"`, { stdio: "pipe" });
17532
+ } else if (archiveType === "tar.xz") {
17533
+ execSync10(`tar -xJf "${tempFile}" -C "${destPath}"${stripFlag}`, { stdio: "pipe" });
17534
+ } else if (archiveType === "tar.gz" || archiveType === "tgz") {
17535
+ execSync10(`tar -xzf "${tempFile}" -C "${destPath}"${stripFlag}`, { stdio: "pipe" });
17536
+ } else {
17537
+ throw new Error(`Unsupported archive type: ${archiveType}`);
17538
+ }
17539
+ await extractBinaryFromPath2(destPath, extractConfig.binary || toolName, destPath);
17540
+ const binaries = [toolName, ...toolManifest.additionalBinaries || []];
17541
+ for (const bin of binaries) {
17542
+ const binPath = import_path18.default.join(destPath, bin);
17543
+ if (import_fs19.default.existsSync(binPath)) {
17544
+ import_fs19.default.chmodSync(binPath, 493);
17545
+ }
17546
+ }
17547
+ import_fs19.default.unlinkSync(tempFile);
17548
+ } catch (error) {
17549
+ if (import_fs19.default.existsSync(tempFile)) {
17550
+ import_fs19.default.unlinkSync(tempFile);
17551
+ }
17552
+ throw new Error(`Failed to install ${toolName}: ${error.message}`);
17553
+ }
17554
+ }
17555
+ import_fs19.default.writeFileSync(
17556
+ import_path18.default.join(destPath, "manifest.json"),
17557
+ JSON.stringify({
17558
+ id: `binary:${toolName}`,
17559
+ kind: "binary",
17560
+ name: toolManifest.name || toolName,
17561
+ version: toolManifest.version,
17562
+ binaries: toolManifest.bins || toolManifest.binaries || [toolName],
17563
+ platformArch,
17564
+ installedAt: (/* @__PURE__ */ new Date()).toISOString()
17565
+ }, null, 2)
17566
+ );
17567
+ onProgress?.({ phase: "complete", tool: toolName, path: destPath });
17568
+ return { success: true, path: destPath };
17569
+ }
17570
+ async function extractBinaryFromPath2(extractedPath, binaryPattern, destPath) {
17571
+ const directPath = import_path18.default.join(destPath, import_path18.default.basename(binaryPattern));
17572
+ if (!binaryPattern.includes("/") && !binaryPattern.includes("*")) {
17573
+ if (import_fs19.default.existsSync(directPath)) {
17574
+ return;
17575
+ }
17576
+ }
17577
+ if (binaryPattern.includes("*") || binaryPattern.includes("/")) {
17578
+ const parts = binaryPattern.split("/");
17579
+ let currentPath = extractedPath;
17580
+ for (let i = 0; i < parts.length; i++) {
17581
+ const part = parts[i];
17582
+ if (part.includes("*")) {
17583
+ if (!import_fs19.default.existsSync(currentPath)) break;
17584
+ const entries = import_fs19.default.readdirSync(currentPath);
17585
+ const pattern = new RegExp("^" + part.replace(/\*/g, ".*") + "$");
17586
+ const match = entries.find((e) => pattern.test(e));
17587
+ if (match) {
17588
+ currentPath = import_path18.default.join(currentPath, match);
17589
+ } else {
17590
+ break;
17591
+ }
17592
+ } else {
17593
+ currentPath = import_path18.default.join(currentPath, part);
17594
+ }
17595
+ }
17596
+ if (import_fs19.default.existsSync(currentPath) && currentPath !== destPath) {
17597
+ const finalPath = import_path18.default.join(destPath, import_path18.default.basename(currentPath));
17598
+ if (currentPath !== finalPath && !import_fs19.default.existsSync(finalPath)) {
17599
+ import_fs19.default.renameSync(currentPath, finalPath);
17600
+ }
17601
+ }
17602
+ }
17603
+ }
17604
+ async function loadToolManifest2(toolName) {
17605
+ for (const basePath of getLocalRegistryPaths2()) {
17606
+ const registryDir = import_path18.default.dirname(basePath);
17607
+ const manifestPath = import_path18.default.join(registryDir, "catalog", "binaries", `${toolName}.json`);
17608
+ if (import_fs19.default.existsSync(manifestPath)) {
17609
+ try {
17610
+ return JSON.parse(import_fs19.default.readFileSync(manifestPath, "utf-8"));
17611
+ } catch {
17612
+ continue;
17613
+ }
17614
+ }
17615
+ }
17616
+ try {
17617
+ const url = `https://raw.githubusercontent.com/learn-rudi/registry/main/catalog/binaries/${toolName}.json`;
17618
+ const response = await fetch(url, {
17619
+ headers: {
17620
+ "User-Agent": "rudi-cli/2.0",
17621
+ "Accept": "application/json"
17622
+ }
17623
+ });
17624
+ if (response.ok) {
17625
+ return await response.json();
17626
+ }
17627
+ } catch {
17628
+ }
17629
+ return null;
17630
+ }
17631
+ function guessArchiveType2(filename) {
17632
+ if (filename.endsWith(".tar.gz") || filename.endsWith(".tgz")) return "tar.gz";
17633
+ if (filename.endsWith(".tar.xz")) return "tar.xz";
17634
+ if (filename.endsWith(".zip")) return "zip";
17635
+ return "tar.gz";
17636
+ }
17637
+ async function verifyHash(filePath, expectedHash) {
17638
+ return new Promise((resolve, reject) => {
17639
+ const hash = import_crypto2.default.createHash("sha256");
17640
+ const stream = import_fs19.default.createReadStream(filePath);
17641
+ stream.on("data", (data) => hash.update(data));
17642
+ stream.on("end", () => {
17643
+ const actualHash = hash.digest("hex");
17644
+ resolve(actualHash === expectedHash);
17645
+ });
17646
+ stream.on("error", reject);
17647
+ });
17648
+ }
17649
+ async function computeHash(filePath) {
17650
+ return new Promise((resolve, reject) => {
17651
+ const hash = import_crypto2.default.createHash("sha256");
17652
+ const stream = import_fs19.default.createReadStream(filePath);
17653
+ stream.on("data", (data) => hash.update(data));
17654
+ stream.on("end", () => resolve(hash.digest("hex")));
17655
+ stream.on("error", reject);
17656
+ });
17657
+ }
17658
+ var import_fs19, import_path18, import_crypto2, DEFAULT_REGISTRY_URL2, RUNTIMES_DOWNLOAD_BASE2, CACHE_TTL2, PACKAGE_KINDS4, KIND_PLURALS2, GITHUB_RAW_BASE2, RUNTIMES_RELEASE_VERSION2;
17659
+ var init_src4 = __esm({
17660
+ "packages/registry-client/src/index.js"() {
17661
+ import_fs19 = __toESM(require("fs"), 1);
17662
+ import_path18 = __toESM(require("path"), 1);
17663
+ import_crypto2 = __toESM(require("crypto"), 1);
17664
+ init_src();
17665
+ DEFAULT_REGISTRY_URL2 = "https://raw.githubusercontent.com/learn-rudi/registry/main/index.json";
17666
+ RUNTIMES_DOWNLOAD_BASE2 = "https://github.com/learn-rudi/registry/releases/download";
17667
+ CACHE_TTL2 = 24 * 60 * 60 * 1e3;
17668
+ PACKAGE_KINDS4 = ["stack", "prompt", "runtime", "binary", "agent"];
17669
+ KIND_PLURALS2 = {
17670
+ binary: "binaries"
17671
+ };
17672
+ GITHUB_RAW_BASE2 = "https://raw.githubusercontent.com/learn-rudi/registry/main";
17673
+ RUNTIMES_RELEASE_VERSION2 = "v1.0.0";
17674
+ }
17675
+ });
17676
+
17677
+ // packages/utils/src/args.js
17678
+ function parseArgs(argv) {
17679
+ const flags = {};
17680
+ const args = [];
17681
+ let command = null;
17682
+ for (let i = 0; i < argv.length; i++) {
17683
+ const arg = argv[i];
17684
+ if (arg.startsWith("--")) {
17685
+ const eqIndex = arg.indexOf("=");
17686
+ if (eqIndex !== -1) {
17687
+ const key = arg.slice(2, eqIndex);
17688
+ const value = arg.slice(eqIndex + 1);
17689
+ flags[key] = value;
17690
+ } else {
17691
+ const key = arg.slice(2);
17692
+ const nextArg = argv[i + 1];
17693
+ if (nextArg && !nextArg.startsWith("-")) {
17694
+ flags[key] = nextArg;
17695
+ i++;
17696
+ } else {
17697
+ flags[key] = true;
17698
+ }
17699
+ }
17700
+ } else if (arg.startsWith("-") && arg.length > 1) {
17701
+ const chars = arg.slice(1);
17702
+ for (const char of chars) {
17703
+ flags[char] = true;
17704
+ }
17705
+ } else if (!command) {
17706
+ command = arg;
17707
+ } else {
17708
+ args.push(arg);
17709
+ }
17710
+ }
17711
+ return { command, args, flags };
17712
+ }
17713
+ function formatBytes(bytes) {
17714
+ if (bytes === 0) return "0 B";
17715
+ const k = 1024;
17716
+ const sizes = ["B", "KB", "MB", "GB"];
17717
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
17718
+ return `${(bytes / Math.pow(k, i)).toFixed(1)} ${sizes[i]}`;
17719
+ }
17720
+ function formatDuration(ms) {
17721
+ if (ms < 1e3) return `${ms}ms`;
17722
+ if (ms < 6e4) return `${(ms / 1e3).toFixed(1)}s`;
17723
+ const mins = Math.floor(ms / 6e4);
17724
+ const secs = Math.floor(ms % 6e4 / 1e3);
17725
+ return `${mins}m ${secs}s`;
17726
+ }
17727
+
17728
+ // packages/utils/src/help.js
17729
+ function printVersion(version) {
17730
+ console.log(`rudi v${version}`);
17731
+ }
17732
+ function printHelp(topic) {
17733
+ if (topic) {
17734
+ printCommandHelp(topic);
17735
+ return;
16894
17736
  }
16895
17737
  console.log(`
16896
17738
  rudi - RUDI CLI
@@ -17337,7 +18179,7 @@ var path13 = __toESM(require("path"), 1);
17337
18179
  var import_child_process4 = require("child_process");
17338
18180
  init_src3();
17339
18181
 
17340
- // node_modules/.pnpm/@learnrudi+secrets@1.0.1/node_modules/@learnrudi/secrets/src/index.js
18182
+ // packages/secrets/src/index.js
17341
18183
  var fs10 = __toESM(require("fs"), 1);
17342
18184
  var path10 = __toESM(require("path"), 1);
17343
18185
  init_src();
@@ -17418,7 +18260,7 @@ function getStorageInfo() {
17418
18260
  };
17419
18261
  }
17420
18262
 
17421
- // node_modules/.pnpm/@learnrudi+mcp@1.0.0/node_modules/@learnrudi/mcp/src/agents.js
18263
+ // packages/mcp/src/agents.js
17422
18264
  var import_fs8 = __toESM(require("fs"), 1);
17423
18265
  var import_path8 = __toESM(require("path"), 1);
17424
18266
  var import_os2 = __toESM(require("os"), 1);
@@ -17593,7 +18435,7 @@ function getMcpServerSummary() {
17593
18435
  return summary;
17594
18436
  }
17595
18437
 
17596
- // node_modules/.pnpm/@learnrudi+mcp@1.0.0/node_modules/@learnrudi/mcp/src/registry.js
18438
+ // packages/mcp/src/registry.js
17597
18439
  var fs12 = __toESM(require("fs/promises"), 1);
17598
18440
  var path12 = __toESM(require("path"), 1);
17599
18441
  var os3 = __toESM(require("os"), 1);
@@ -17982,6 +18824,7 @@ async function cmdInstall(args, flags) {
17982
18824
  process.exit(1);
17983
18825
  }
17984
18826
  const force = flags.force || false;
18827
+ const allowScripts = flags["allow-scripts"] || flags.allowScripts || false;
17985
18828
  console.log(`Resolving ${pkgId}...`);
17986
18829
  try {
17987
18830
  const resolved = await resolvePackage(pkgId);
@@ -18043,6 +18886,7 @@ Or use --force to install anyway.`);
18043
18886
  Installing...`);
18044
18887
  const result = await installPackage(pkgId, {
18045
18888
  force,
18889
+ allowScripts,
18046
18890
  onProgress: (progress) => {
18047
18891
  if (progress.phase === "installing") {
18048
18892
  console.log(` Installing ${progress.package}...`);
@@ -18179,23 +19023,66 @@ Next steps:`);
18179
19023
  // src/commands/run.js
18180
19024
  init_src3();
18181
19025
 
18182
- // node_modules/.pnpm/@learnrudi+runner@1.0.1/node_modules/@learnrudi/runner/src/spawn.js
19026
+ // packages/runner/src/spawn.js
18183
19027
  var import_child_process5 = require("child_process");
18184
19028
  var import_path10 = __toESM(require("path"), 1);
18185
19029
  var import_fs10 = __toESM(require("fs"), 1);
18186
- init_src3();
18187
19030
 
18188
- // node_modules/.pnpm/@learnrudi+runner@1.0.1/node_modules/@learnrudi/runner/src/secrets.js
19031
+ // node_modules/.pnpm/@learnrudi+core@1.0.2/node_modules/@learnrudi/core/src/index.js
19032
+ init_src();
19033
+ init_src2();
19034
+
19035
+ // node_modules/.pnpm/@learnrudi+core@1.0.2/node_modules/@learnrudi/core/src/resolver.js
19036
+ init_src2();
19037
+ init_src();
19038
+
19039
+ // node_modules/.pnpm/@learnrudi+core@1.0.2/node_modules/@learnrudi/core/src/installer.js
19040
+ init_src();
19041
+ init_src2();
19042
+
19043
+ // node_modules/.pnpm/@learnrudi+core@1.0.2/node_modules/@learnrudi/core/src/lockfile.js
19044
+ var import_yaml2 = __toESM(require_dist(), 1);
19045
+ init_src();
19046
+
19047
+ // node_modules/.pnpm/@learnrudi+core@1.0.2/node_modules/@learnrudi/core/src/installer.js
19048
+ init_shims2();
19049
+
19050
+ // node_modules/.pnpm/@learnrudi+core@1.0.2/node_modules/@learnrudi/core/src/deps.js
19051
+ init_src();
19052
+ init_src2();
19053
+
19054
+ // node_modules/.pnpm/@learnrudi+core@1.0.2/node_modules/@learnrudi/core/src/rudi-config.js
19055
+ var path14 = __toESM(require("path"), 1);
19056
+ init_src();
19057
+ var RUDI_JSON_PATH2 = path14.join(RUDI_HOME, "rudi.json");
19058
+ var RUDI_JSON_TMP2 = path14.join(RUDI_HOME, "rudi.json.tmp");
19059
+ var RUDI_JSON_LOCK2 = path14.join(RUDI_HOME, "rudi.json.lock");
19060
+
19061
+ // node_modules/.pnpm/@learnrudi+core@1.0.2/node_modules/@learnrudi/core/src/tool-index.js
19062
+ var path15 = __toESM(require("path"), 1);
19063
+ init_src();
19064
+ var TOOL_INDEX_PATH2 = path15.join(RUDI_HOME, "cache", "tool-index.json");
19065
+ var TOOL_INDEX_TMP2 = path15.join(RUDI_HOME, "cache", "tool-index.json.tmp");
19066
+ var SECRETS_PATH2 = path15.join(RUDI_HOME, "secrets.json");
19067
+
19068
+ // node_modules/.pnpm/@learnrudi+core@1.0.2/node_modules/@learnrudi/core/src/index.js
19069
+ init_shims2();
19070
+
19071
+ // node_modules/.pnpm/@learnrudi+core@1.0.2/node_modules/@learnrudi/core/src/system-registry.js
19072
+ init_src();
19073
+ init_shims2();
19074
+
19075
+ // packages/runner/src/secrets.js
18189
19076
  var import_fs9 = __toESM(require("fs"), 1);
18190
19077
  var import_path9 = __toESM(require("path"), 1);
18191
19078
  var import_os3 = __toESM(require("os"), 1);
18192
- var SECRETS_PATH2 = import_path9.default.join(import_os3.default.homedir(), ".rudi", "secrets.json");
19079
+ var SECRETS_PATH3 = import_path9.default.join(import_os3.default.homedir(), ".rudi", "secrets.json");
18193
19080
  function loadSecrets3() {
18194
- if (!import_fs9.default.existsSync(SECRETS_PATH2)) {
19081
+ if (!import_fs9.default.existsSync(SECRETS_PATH3)) {
18195
19082
  return {};
18196
19083
  }
18197
19084
  try {
18198
- const content = import_fs9.default.readFileSync(SECRETS_PATH2, "utf-8");
19085
+ const content = import_fs9.default.readFileSync(SECRETS_PATH3, "utf-8");
18199
19086
  return JSON.parse(content);
18200
19087
  } catch {
18201
19088
  return {};
@@ -18246,17 +19133,17 @@ function redactSecrets(text, secrets) {
18246
19133
  return result;
18247
19134
  }
18248
19135
 
18249
- // node_modules/.pnpm/@learnrudi+runner@1.0.1/node_modules/@learnrudi/runner/src/spawn.js
19136
+ // packages/runner/src/spawn.js
18250
19137
  async function runStack(id, options = {}) {
18251
19138
  const { inputs = {}, cwd, env = {}, onStdout, onStderr, onExit, signal } = options;
18252
19139
  const startTime = Date.now();
18253
19140
  const packagePath = getPackagePath(id);
18254
19141
  const manifestPath = import_path10.default.join(packagePath, "manifest.json");
18255
- const { default: fs32 } = await import("fs");
18256
- if (!fs32.existsSync(manifestPath)) {
19142
+ const { default: fs35 } = await import("fs");
19143
+ if (!fs35.existsSync(manifestPath)) {
18257
19144
  throw new Error(`Stack manifest not found: ${id}`);
18258
19145
  }
18259
- const manifest = JSON.parse(fs32.readFileSync(manifestPath, "utf-8"));
19146
+ const manifest = JSON.parse(fs35.readFileSync(manifestPath, "utf-8"));
18260
19147
  const { command, args } = resolveCommandFromManifest(manifest, packagePath);
18261
19148
  const secrets = await getSecrets(manifest.requires?.secrets || []);
18262
19149
  const runEnv = {
@@ -18362,8 +19249,8 @@ function resolveRelativePath(value, basePath) {
18362
19249
  return value;
18363
19250
  }
18364
19251
 
18365
- // node_modules/.pnpm/@learnrudi+manifest@1.0.0/node_modules/@learnrudi/manifest/src/stack.js
18366
- var import_yaml2 = __toESM(require_dist(), 1);
19252
+ // packages/manifest/src/stack.js
19253
+ var import_yaml3 = __toESM(require_dist(), 1);
18367
19254
  var import_fs11 = __toESM(require("fs"), 1);
18368
19255
  var import_path11 = __toESM(require("path"), 1);
18369
19256
  function parseStackManifest(filePath) {
@@ -18371,7 +19258,7 @@ function parseStackManifest(filePath) {
18371
19258
  return parseStackYaml(content, filePath);
18372
19259
  }
18373
19260
  function parseStackYaml(content, source = "stack.yaml") {
18374
- const raw = (0, import_yaml2.parse)(content);
19261
+ const raw = (0, import_yaml3.parse)(content);
18375
19262
  if (!raw || typeof raw !== "object") {
18376
19263
  throw new Error(`Invalid stack manifest in ${source}: expected object`);
18377
19264
  }
@@ -18493,13 +19380,13 @@ function findStackManifest(dir) {
18493
19380
  return null;
18494
19381
  }
18495
19382
 
18496
- // node_modules/.pnpm/@learnrudi+manifest@1.0.0/node_modules/@learnrudi/manifest/src/prompt.js
18497
- var import_yaml3 = __toESM(require_dist(), 1);
18498
-
18499
- // node_modules/.pnpm/@learnrudi+manifest@1.0.0/node_modules/@learnrudi/manifest/src/runtime.js
19383
+ // packages/manifest/src/prompt.js
18500
19384
  var import_yaml4 = __toESM(require_dist(), 1);
18501
19385
 
18502
- // node_modules/.pnpm/@learnrudi+manifest@1.0.0/node_modules/@learnrudi/manifest/src/validate.js
19386
+ // packages/manifest/src/runtime.js
19387
+ var import_yaml5 = __toESM(require_dist(), 1);
19388
+
19389
+ // packages/manifest/src/validate.js
18503
19390
  var import_ajv = __toESM(require_ajv(), 1);
18504
19391
  var import_ajv_formats = __toESM(require_dist2(), 1);
18505
19392
  var ajv = new import_ajv.default({ allErrors: true, strict: false });
@@ -19235,13 +20122,13 @@ function promptSecret(prompt) {
19235
20122
  var import_fs14 = require("fs");
19236
20123
  var import_path14 = require("path");
19237
20124
 
19238
- // node_modules/.pnpm/@learnrudi+db@1.0.2/node_modules/@learnrudi/db/src/index.js
20125
+ // packages/db/src/index.js
19239
20126
  var import_better_sqlite3 = __toESM(require("better-sqlite3"), 1);
19240
20127
  var import_path13 = __toESM(require("path"), 1);
19241
20128
  var import_fs13 = __toESM(require("fs"), 1);
19242
20129
  init_src();
19243
20130
 
19244
- // node_modules/.pnpm/@learnrudi+db@1.0.2/node_modules/@learnrudi/db/src/schema.js
20131
+ // packages/db/src/schema.js
19245
20132
  var SCHEMA_VERSION = 5;
19246
20133
  var SCHEMA_SQL = `
19247
20134
  -- Schema version tracking
@@ -19801,7 +20688,7 @@ function seedModelPricing(db2) {
19801
20688
  console.log(` Seeded ${pricingData.length} model pricing entries`);
19802
20689
  }
19803
20690
 
19804
- // node_modules/.pnpm/@learnrudi+db@1.0.2/node_modules/@learnrudi/db/src/search.js
20691
+ // packages/db/src/search.js
19805
20692
  function search(query, options = {}) {
19806
20693
  const { limit = 20, provider, sessionId, offset = 0 } = options;
19807
20694
  const db2 = getDb();
@@ -19888,7 +20775,7 @@ function searchFallback(query, options = {}) {
19888
20775
  return db2.prepare(sql).all(...params);
19889
20776
  }
19890
20777
 
19891
- // node_modules/.pnpm/@learnrudi+db@1.0.2/node_modules/@learnrudi/db/src/stats.js
20778
+ // packages/db/src/stats.js
19892
20779
  function getStats() {
19893
20780
  const db2 = getDb();
19894
20781
  const totals = db2.prepare(`
@@ -19995,7 +20882,7 @@ function getToolsUsage(db2) {
19995
20882
  return Object.entries(toolCounts).sort((a, b) => b[1] - a[1]).slice(0, 20).map(([name, count]) => ({ name, count }));
19996
20883
  }
19997
20884
 
19998
- // node_modules/.pnpm/@learnrudi+db@1.0.2/node_modules/@learnrudi/db/src/logs.js
20885
+ // packages/db/src/logs.js
19999
20886
  function queryLogs(options = {}) {
20000
20887
  const db2 = getDb();
20001
20888
  const {
@@ -20139,11 +21026,11 @@ function getBeforeCrashLogs() {
20139
21026
  return getRecentLogs(3e4);
20140
21027
  }
20141
21028
 
20142
- // node_modules/.pnpm/@learnrudi+db@1.0.2/node_modules/@learnrudi/db/src/import.js
21029
+ // packages/db/src/import.js
20143
21030
  init_src();
20144
21031
  var RUDI_HOME2 = PATHS.home;
20145
21032
 
20146
- // node_modules/.pnpm/@learnrudi+db@1.0.2/node_modules/@learnrudi/db/src/index.js
21033
+ // packages/db/src/index.js
20147
21034
  var DB_PATH = PATHS.dbFile;
20148
21035
  var db = null;
20149
21036
  function getDb(options = {}) {
@@ -20569,7 +21456,7 @@ function dbTables(flags) {
20569
21456
  var import_fs15 = require("fs");
20570
21457
  var import_path15 = require("path");
20571
21458
  var import_os4 = require("os");
20572
- var import_crypto2 = require("crypto");
21459
+ var import_crypto = require("crypto");
20573
21460
  var PROVIDERS = {
20574
21461
  claude: {
20575
21462
  name: "Claude Code",
@@ -20728,7 +21615,7 @@ async function importSessions(args, flags) {
20728
21615
  try {
20729
21616
  const nowIso = (/* @__PURE__ */ new Date()).toISOString();
20730
21617
  insertStmt.run(
20731
- (0, import_crypto2.randomUUID)(),
21618
+ (0, import_crypto.randomUUID)(),
20732
21619
  providerKey,
20733
21620
  sessionId,
20734
21621
  nowIso,
@@ -21147,13 +22034,115 @@ async function cmdHome(args, flags) {
21147
22034
  }
21148
22035
 
21149
22036
  // src/commands/init.js
21150
- var import_fs18 = __toESM(require("fs"), 1);
21151
- var import_path17 = __toESM(require("path"), 1);
22037
+ var import_fs20 = __toESM(require("fs"), 1);
22038
+ var import_path19 = __toESM(require("path"), 1);
21152
22039
  var import_promises = require("stream/promises");
21153
- var import_fs19 = require("fs");
22040
+ var import_fs21 = require("fs");
21154
22041
  var import_child_process6 = require("child_process");
21155
- init_src();
21156
- init_src2();
22042
+
22043
+ // packages/env/src/index.js
22044
+ var import_path17 = __toESM(require("path"), 1);
22045
+ var import_os5 = __toESM(require("os"), 1);
22046
+ var import_fs18 = __toESM(require("fs"), 1);
22047
+ var RUDI_HOME3 = import_path17.default.join(import_os5.default.homedir(), ".rudi");
22048
+ var PATHS2 = {
22049
+ // Root
22050
+ home: RUDI_HOME3,
22051
+ // Installed packages - shared with Studio for unified discovery
22052
+ packages: import_path17.default.join(RUDI_HOME3, "packages"),
22053
+ stacks: import_path17.default.join(RUDI_HOME3, "stacks"),
22054
+ // Shared with Studio
22055
+ prompts: import_path17.default.join(RUDI_HOME3, "prompts"),
22056
+ // Shared with Studio
22057
+ // Runtimes (interpreters: node, python, deno, bun)
22058
+ runtimes: import_path17.default.join(RUDI_HOME3, "runtimes"),
22059
+ // Binaries (utility CLIs: ffmpeg, imagemagick, ripgrep, etc.)
22060
+ binaries: import_path17.default.join(RUDI_HOME3, "binaries"),
22061
+ // Agents (AI CLI tools: claude, codex, gemini, copilot, ollama)
22062
+ agents: import_path17.default.join(RUDI_HOME3, "agents"),
22063
+ // Runtime binaries (content-addressed)
22064
+ store: import_path17.default.join(RUDI_HOME3, "store"),
22065
+ // Shims (symlinks to store/)
22066
+ bins: import_path17.default.join(RUDI_HOME3, "bins"),
22067
+ // Lockfiles
22068
+ locks: import_path17.default.join(RUDI_HOME3, "locks"),
22069
+ // Secrets (OS Keychain preferred, encrypted file fallback)
22070
+ vault: import_path17.default.join(RUDI_HOME3, "vault"),
22071
+ // Database (shared with Studio)
22072
+ db: RUDI_HOME3,
22073
+ dbFile: import_path17.default.join(RUDI_HOME3, "rudi.db"),
22074
+ // Cache
22075
+ cache: import_path17.default.join(RUDI_HOME3, "cache"),
22076
+ registryCache: import_path17.default.join(RUDI_HOME3, "cache", "registry.json"),
22077
+ // Config
22078
+ config: import_path17.default.join(RUDI_HOME3, "config.json"),
22079
+ // Logs
22080
+ logs: import_path17.default.join(RUDI_HOME3, "logs")
22081
+ };
22082
+ function getPlatformArch2() {
22083
+ const platform = import_os5.default.platform();
22084
+ const arch = import_os5.default.arch();
22085
+ const normalizedArch = arch === "x64" ? "x64" : arch === "arm64" ? "arm64" : arch;
22086
+ return `${platform}-${normalizedArch}`;
22087
+ }
22088
+ function ensureDirectories2() {
22089
+ const dirs = [
22090
+ PATHS2.stacks,
22091
+ // MCP servers (google-ai, notion-workspace, etc.)
22092
+ PATHS2.prompts,
22093
+ // Reusable prompts
22094
+ PATHS2.runtimes,
22095
+ // Language runtimes (node, python, bun, deno)
22096
+ PATHS2.binaries,
22097
+ // Utility binaries (ffmpeg, git, jq, etc.)
22098
+ PATHS2.agents,
22099
+ // AI CLI agents (claude, codex, gemini, copilot)
22100
+ PATHS2.bins,
22101
+ // Shims directory (Studio only)
22102
+ PATHS2.locks,
22103
+ // Lock files
22104
+ PATHS2.db,
22105
+ // Database directory
22106
+ PATHS2.cache
22107
+ // Registry cache
22108
+ ];
22109
+ for (const dir of dirs) {
22110
+ if (!import_fs18.default.existsSync(dir)) {
22111
+ import_fs18.default.mkdirSync(dir, { recursive: true });
22112
+ }
22113
+ }
22114
+ }
22115
+ var PACKAGE_KINDS3 = ["stack", "prompt", "runtime", "binary", "agent"];
22116
+ function parsePackageId2(id) {
22117
+ const match = id.match(/^(stack|prompt|runtime|binary|agent|npm):(.+)$/);
22118
+ if (!match) {
22119
+ throw new Error(`Invalid package ID: ${id} (expected format: kind:name, where kind is one of: ${PACKAGE_KINDS3.join(", ")}, npm)`);
22120
+ }
22121
+ return [match[1], match[2]];
22122
+ }
22123
+ function getPackagePath2(id) {
22124
+ const [kind, name] = parsePackageId2(id);
22125
+ switch (kind) {
22126
+ case "stack":
22127
+ return import_path17.default.join(PATHS2.stacks, name);
22128
+ case "prompt":
22129
+ return import_path17.default.join(PATHS2.prompts, `${name}.md`);
22130
+ case "runtime":
22131
+ return import_path17.default.join(PATHS2.runtimes, name);
22132
+ case "binary":
22133
+ return import_path17.default.join(PATHS2.binaries, name);
22134
+ case "agent":
22135
+ return import_path17.default.join(PATHS2.agents, name);
22136
+ case "npm":
22137
+ const sanitized = name.replace(/\//g, "__").replace(/^@/, "");
22138
+ return import_path17.default.join(PATHS2.binaries, "npm", sanitized);
22139
+ default:
22140
+ throw new Error(`Unknown package kind: ${kind}`);
22141
+ }
22142
+ }
22143
+
22144
+ // src/commands/init.js
22145
+ init_src4();
21157
22146
  var RELEASES_BASE = "https://github.com/learn-rudi/registry/releases/download/v1.0.0";
21158
22147
  var BUNDLED_RUNTIMES = ["node", "python"];
21159
22148
  var ESSENTIAL_BINARIES = ["sqlite", "ripgrep"];
@@ -21165,25 +22154,25 @@ async function cmdInit(args, flags) {
21165
22154
  console.log("\u2550".repeat(60));
21166
22155
  console.log("RUDI Initialization");
21167
22156
  console.log("\u2550".repeat(60));
21168
- console.log(`Home: ${PATHS.home}`);
22157
+ console.log(`Home: ${PATHS2.home}`);
21169
22158
  console.log();
21170
22159
  }
21171
22160
  const actions = { created: [], skipped: [], failed: [] };
21172
22161
  if (!quiet) console.log("1. Checking directory structure...");
21173
- ensureDirectories();
22162
+ ensureDirectories2();
21174
22163
  const dirs = [
21175
- PATHS.stacks,
21176
- PATHS.prompts,
21177
- PATHS.runtimes,
21178
- PATHS.binaries,
21179
- PATHS.agents,
21180
- PATHS.cache,
21181
- import_path17.default.join(PATHS.home, "shims")
22164
+ PATHS2.stacks,
22165
+ PATHS2.prompts,
22166
+ PATHS2.runtimes,
22167
+ PATHS2.binaries,
22168
+ PATHS2.agents,
22169
+ PATHS2.cache,
22170
+ import_path19.default.join(PATHS2.home, "shims")
21182
22171
  ];
21183
22172
  for (const dir of dirs) {
21184
- const dirName = import_path17.default.basename(dir);
21185
- if (!import_fs18.default.existsSync(dir)) {
21186
- import_fs18.default.mkdirSync(dir, { recursive: true });
22173
+ const dirName = import_path19.default.basename(dir);
22174
+ if (!import_fs20.default.existsSync(dir)) {
22175
+ import_fs20.default.mkdirSync(dir, { recursive: true });
21187
22176
  actions.created.push(`dir:${dirName}`);
21188
22177
  if (!quiet) console.log(` + ${dirName}/ (created)`);
21189
22178
  } else {
@@ -21193,8 +22182,8 @@ async function cmdInit(args, flags) {
21193
22182
  }
21194
22183
  if (!skipDownloads) {
21195
22184
  if (!quiet) console.log("\n2. Checking runtimes...");
21196
- const index = await fetchIndex();
21197
- const platform = getPlatformArch();
22185
+ const index = await fetchIndex2();
22186
+ const platform = getPlatformArch2();
21198
22187
  for (const runtimeName of BUNDLED_RUNTIMES) {
21199
22188
  const runtime = index.packages?.runtimes?.official?.find(
21200
22189
  (r) => r.id === `runtime:${runtimeName}` || r.id === runtimeName
@@ -21204,14 +22193,14 @@ async function cmdInit(args, flags) {
21204
22193
  if (!quiet) console.log(` \u26A0 ${runtimeName}: not found in registry`);
21205
22194
  continue;
21206
22195
  }
21207
- const destPath = import_path17.default.join(PATHS.runtimes, runtimeName);
21208
- if (import_fs18.default.existsSync(destPath) && !force) {
22196
+ const destPath = import_path19.default.join(PATHS2.runtimes, runtimeName);
22197
+ if (import_fs20.default.existsSync(destPath) && !force) {
21209
22198
  actions.skipped.push(`runtime:${runtimeName}`);
21210
22199
  if (!quiet) console.log(` \u2713 ${runtimeName}: already installed`);
21211
22200
  continue;
21212
22201
  }
21213
22202
  try {
21214
- await downloadRuntime2(runtime, runtimeName, destPath, platform);
22203
+ await downloadRuntime3(runtime, runtimeName, destPath, platform);
21215
22204
  actions.created.push(`runtime:${runtimeName}`);
21216
22205
  if (!quiet) console.log(` + ${runtimeName}: installed`);
21217
22206
  } catch (error) {
@@ -21229,8 +22218,8 @@ async function cmdInit(args, flags) {
21229
22218
  if (!quiet) console.log(` \u26A0 ${binaryName}: not found in registry`);
21230
22219
  continue;
21231
22220
  }
21232
- const destPath = import_path17.default.join(PATHS.binaries, binaryName);
21233
- if (import_fs18.default.existsSync(destPath) && !force) {
22221
+ const destPath = import_path19.default.join(PATHS2.binaries, binaryName);
22222
+ if (import_fs20.default.existsSync(destPath) && !force) {
21234
22223
  actions.skipped.push(`binary:${binaryName}`);
21235
22224
  if (!quiet) console.log(` \u2713 ${binaryName}: already installed`);
21236
22225
  continue;
@@ -21248,14 +22237,14 @@ async function cmdInit(args, flags) {
21248
22237
  if (!quiet) console.log("\n2-3. Skipping downloads (--skip-downloads)");
21249
22238
  }
21250
22239
  if (!quiet) console.log("\n4. Updating shims...");
21251
- const shimsDir = import_path17.default.join(PATHS.home, "shims");
22240
+ const shimsDir = import_path19.default.join(PATHS2.home, "shims");
21252
22241
  const shimCount = await createShims(shimsDir, quiet);
21253
22242
  if (shimCount > 0) {
21254
22243
  actions.created.push(`shims:${shimCount}`);
21255
22244
  }
21256
22245
  if (!quiet) console.log("\n5. Checking database...");
21257
- const dbPath = import_path17.default.join(PATHS.home, "rudi.db");
21258
- const dbExists = import_fs18.default.existsSync(dbPath);
22246
+ const dbPath = import_path19.default.join(PATHS2.home, "rudi.db");
22247
+ const dbExists = import_fs20.default.existsSync(dbPath);
21259
22248
  try {
21260
22249
  const result = initSchema();
21261
22250
  if (dbExists) {
@@ -21270,14 +22259,14 @@ async function cmdInit(args, flags) {
21270
22259
  if (!quiet) console.log(` \u2717 Database error: ${error.message}`);
21271
22260
  }
21272
22261
  if (!quiet) console.log("\n6. Checking settings...");
21273
- const settingsPath = import_path17.default.join(PATHS.home, "settings.json");
21274
- if (!import_fs18.default.existsSync(settingsPath)) {
22262
+ const settingsPath = import_path19.default.join(PATHS2.home, "settings.json");
22263
+ if (!import_fs20.default.existsSync(settingsPath)) {
21275
22264
  const settings = {
21276
22265
  version: "1.0.0",
21277
22266
  initialized: (/* @__PURE__ */ new Date()).toISOString(),
21278
22267
  theme: "system"
21279
22268
  };
21280
- import_fs18.default.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
22269
+ import_fs20.default.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
21281
22270
  actions.created.push("settings");
21282
22271
  if (!quiet) console.log(" + settings.json created");
21283
22272
  } else {
@@ -21293,7 +22282,7 @@ async function cmdInit(args, flags) {
21293
22282
  }
21294
22283
  console.log("\u2550".repeat(60));
21295
22284
  if (actions.created.includes("settings")) {
21296
- const shimsPath = import_path17.default.join(PATHS.home, "shims");
22285
+ const shimsPath = import_path19.default.join(PATHS2.home, "shims");
21297
22286
  console.log("\nAdd to your shell profile (~/.zshrc or ~/.bashrc):");
21298
22287
  console.log(` export PATH="${shimsPath}:$PATH"`);
21299
22288
  console.log("\nThen run:");
@@ -21303,7 +22292,7 @@ async function cmdInit(args, flags) {
21303
22292
  }
21304
22293
  return actions;
21305
22294
  }
21306
- async function downloadRuntime2(runtime, name, destPath, platform) {
22295
+ async function downloadRuntime3(runtime, name, destPath, platform) {
21307
22296
  let url;
21308
22297
  if (runtime.upstream?.[platform]) {
21309
22298
  url = runtime.upstream[platform];
@@ -21326,15 +22315,15 @@ async function downloadBinary(binary, name, destPath, platform) {
21326
22315
  await downloadAndExtract(url, destPath, name, binary.extract);
21327
22316
  }
21328
22317
  async function downloadAndExtract(url, destPath, name, extractConfig) {
21329
- const tempFile = import_path17.default.join(PATHS.cache, `${name}-download.tar.gz`);
22318
+ const tempFile = import_path19.default.join(PATHS2.cache, `${name}-download.tar.gz`);
21330
22319
  const response = await fetch(url);
21331
22320
  if (!response.ok) {
21332
22321
  throw new Error(`HTTP ${response.status}`);
21333
22322
  }
21334
- if (!import_fs18.default.existsSync(destPath)) {
21335
- import_fs18.default.mkdirSync(destPath, { recursive: true });
22323
+ if (!import_fs20.default.existsSync(destPath)) {
22324
+ import_fs20.default.mkdirSync(destPath, { recursive: true });
21336
22325
  }
21337
- const fileStream = (0, import_fs19.createWriteStream)(tempFile);
22326
+ const fileStream = (0, import_fs21.createWriteStream)(tempFile);
21338
22327
  await (0, import_promises.pipeline)(response.body, fileStream);
21339
22328
  try {
21340
22329
  (0, import_child_process6.execSync)(`tar -xzf "${tempFile}" -C "${destPath}" --strip-components=1`, {
@@ -21343,7 +22332,7 @@ async function downloadAndExtract(url, destPath, name, extractConfig) {
21343
22332
  } catch {
21344
22333
  (0, import_child_process6.execSync)(`tar -xzf "${tempFile}" -C "${destPath}"`, { stdio: "pipe" });
21345
22334
  }
21346
- import_fs18.default.unlinkSync(tempFile);
22335
+ import_fs20.default.unlinkSync(tempFile);
21347
22336
  }
21348
22337
  async function createShims(shimsDir, quiet = false) {
21349
22338
  const shims = [];
@@ -21362,17 +22351,17 @@ async function createShims(shimsDir, quiet = false) {
21362
22351
  ripgrep: "binaries/ripgrep/rg"
21363
22352
  };
21364
22353
  for (const [shimName, targetPath] of Object.entries(runtimeShims)) {
21365
- const fullTarget = import_path17.default.join(PATHS.home, targetPath);
21366
- const shimPath = import_path17.default.join(shimsDir, shimName);
21367
- if (import_fs18.default.existsSync(fullTarget)) {
22354
+ const fullTarget = import_path19.default.join(PATHS2.home, targetPath);
22355
+ const shimPath = import_path19.default.join(shimsDir, shimName);
22356
+ if (import_fs20.default.existsSync(fullTarget)) {
21368
22357
  createShim(shimPath, fullTarget);
21369
22358
  shims.push(shimName);
21370
22359
  }
21371
22360
  }
21372
22361
  for (const [shimName, targetPath] of Object.entries(binaryShims)) {
21373
- const fullTarget = import_path17.default.join(PATHS.home, targetPath);
21374
- const shimPath = import_path17.default.join(shimsDir, shimName);
21375
- if (import_fs18.default.existsSync(fullTarget)) {
22362
+ const fullTarget = import_path19.default.join(PATHS2.home, targetPath);
22363
+ const shimPath = import_path19.default.join(shimsDir, shimName);
22364
+ if (import_fs20.default.existsSync(fullTarget)) {
21376
22365
  createShim(shimPath, fullTarget);
21377
22366
  shims.push(shimName);
21378
22367
  }
@@ -21387,18 +22376,17 @@ async function createShims(shimsDir, quiet = false) {
21387
22376
  return shims.length;
21388
22377
  }
21389
22378
  function createShim(shimPath, targetPath) {
21390
- if (import_fs18.default.existsSync(shimPath)) {
21391
- import_fs18.default.unlinkSync(shimPath);
22379
+ if (import_fs20.default.existsSync(shimPath)) {
22380
+ import_fs20.default.unlinkSync(shimPath);
21392
22381
  }
21393
- import_fs18.default.symlinkSync(targetPath, shimPath);
22382
+ import_fs20.default.symlinkSync(targetPath, shimPath);
21394
22383
  }
21395
22384
 
21396
22385
  // src/commands/update.js
21397
- var import_fs20 = __toESM(require("fs"), 1);
21398
- var import_path18 = __toESM(require("path"), 1);
22386
+ var import_fs22 = __toESM(require("fs"), 1);
22387
+ var import_path20 = __toESM(require("path"), 1);
21399
22388
  var import_child_process7 = require("child_process");
21400
- init_src();
21401
- init_src2();
22389
+ init_src4();
21402
22390
  async function cmdUpdate(args, flags) {
21403
22391
  const pkgId = args[0];
21404
22392
  if (!pkgId) {
@@ -21419,12 +22407,12 @@ async function cmdUpdate(args, flags) {
21419
22407
  }
21420
22408
  }
21421
22409
  async function updatePackage2(pkgId, flags) {
21422
- const [kind, name] = parsePackageId(pkgId);
21423
- const installPath = getPackagePath(pkgId);
21424
- if (!import_fs20.default.existsSync(installPath)) {
22410
+ const [kind, name] = parsePackageId2(pkgId);
22411
+ const installPath = getPackagePath2(pkgId);
22412
+ if (!import_fs22.default.existsSync(installPath)) {
21425
22413
  return { success: false, error: "Package not installed" };
21426
22414
  }
21427
- const pkg = await getPackage(pkgId);
22415
+ const pkg = await getPackage2(pkgId);
21428
22416
  if (!pkg) {
21429
22417
  return { success: false, error: "Package not found in registry" };
21430
22418
  }
@@ -21444,7 +22432,7 @@ async function updatePackage2(pkgId, flags) {
21444
22432
  }
21445
22433
  if (pkg.pipPackage) {
21446
22434
  try {
21447
- const venvPip = import_path18.default.join(installPath, "venv", "bin", "pip");
22435
+ const venvPip = import_path20.default.join(installPath, "venv", "bin", "pip");
21448
22436
  (0, import_child_process7.execSync)(`"${venvPip}" install --upgrade ${pkg.pipPackage}`, {
21449
22437
  stdio: flags.verbose ? "inherit" : "pipe"
21450
22438
  });
@@ -21460,9 +22448,9 @@ async function updatePackage2(pkgId, flags) {
21460
22448
  }
21461
22449
  if (kind === "runtime" && !pkg.npmPackage && !pkg.pipPackage) {
21462
22450
  try {
21463
- const { downloadRuntime: downloadRuntime3 } = await Promise.resolve().then(() => (init_src2(), src_exports));
21464
- import_fs20.default.rmSync(installPath, { recursive: true, force: true });
21465
- await downloadRuntime3(name, pkg.version || "latest", installPath, {
22451
+ const { downloadRuntime: downloadRuntime4 } = await Promise.resolve().then(() => (init_src4(), src_exports2));
22452
+ import_fs22.default.rmSync(installPath, { recursive: true, force: true });
22453
+ await downloadRuntime4(name, pkg.version || "latest", installPath, {
21466
22454
  onProgress: (p) => {
21467
22455
  if (flags.verbose) console.log(` ${p.phase}...`);
21468
22456
  }
@@ -21480,9 +22468,9 @@ async function updateAll2(flags) {
21480
22468
  let updated = 0;
21481
22469
  let failed = 0;
21482
22470
  for (const kind of kinds) {
21483
- const dir = kind === "runtime" ? PATHS.runtimes : kind === "stack" ? PATHS.stacks : PATHS.prompts;
21484
- if (!import_fs20.default.existsSync(dir)) continue;
21485
- const entries = import_fs20.default.readdirSync(dir, { withFileTypes: true });
22471
+ const dir = kind === "runtime" ? PATHS2.runtimes : kind === "stack" ? PATHS2.stacks : PATHS2.prompts;
22472
+ if (!import_fs22.default.existsSync(dir)) continue;
22473
+ const entries = import_fs22.default.readdirSync(dir, { withFileTypes: true });
21486
22474
  for (const entry of entries) {
21487
22475
  if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
21488
22476
  const pkgId = `${kind}:${entry.name}`;
@@ -21501,14 +22489,14 @@ Updated ${updated} package(s)${failed > 0 ? `, ${failed} failed` : ""}`);
21501
22489
  }
21502
22490
  function getInstalledVersion(installPath, npmPackage) {
21503
22491
  try {
21504
- const pkgJsonPath = import_path18.default.join(installPath, "node_modules", npmPackage.replace("@", "").split("/")[0], "package.json");
21505
- if (import_fs20.default.existsSync(pkgJsonPath)) {
21506
- const pkgJson = JSON.parse(import_fs20.default.readFileSync(pkgJsonPath, "utf-8"));
22492
+ const pkgJsonPath = import_path20.default.join(installPath, "node_modules", npmPackage.replace("@", "").split("/")[0], "package.json");
22493
+ if (import_fs22.default.existsSync(pkgJsonPath)) {
22494
+ const pkgJson = JSON.parse(import_fs22.default.readFileSync(pkgJsonPath, "utf-8"));
21507
22495
  return pkgJson.version;
21508
22496
  }
21509
- const rootPkgPath = import_path18.default.join(installPath, "package.json");
21510
- if (import_fs20.default.existsSync(rootPkgPath)) {
21511
- const rootPkg = JSON.parse(import_fs20.default.readFileSync(rootPkgPath, "utf-8"));
22497
+ const rootPkgPath = import_path20.default.join(installPath, "package.json");
22498
+ if (import_fs22.default.existsSync(rootPkgPath)) {
22499
+ const rootPkg = JSON.parse(import_fs22.default.readFileSync(rootPkgPath, "utf-8"));
21512
22500
  const dep = rootPkg.dependencies?.[npmPackage];
21513
22501
  if (dep) return dep.replace(/[\^~]/, "");
21514
22502
  }
@@ -21517,20 +22505,20 @@ function getInstalledVersion(installPath, npmPackage) {
21517
22505
  return null;
21518
22506
  }
21519
22507
  function updateRuntimeMetadata(installPath, updates) {
21520
- const metaPath = import_path18.default.join(installPath, "runtime.json");
22508
+ const metaPath = import_path20.default.join(installPath, "runtime.json");
21521
22509
  try {
21522
22510
  let meta = {};
21523
- if (import_fs20.default.existsSync(metaPath)) {
21524
- meta = JSON.parse(import_fs20.default.readFileSync(metaPath, "utf-8"));
22511
+ if (import_fs22.default.existsSync(metaPath)) {
22512
+ meta = JSON.parse(import_fs22.default.readFileSync(metaPath, "utf-8"));
21525
22513
  }
21526
22514
  meta = { ...meta, ...updates };
21527
- import_fs20.default.writeFileSync(metaPath, JSON.stringify(meta, null, 2));
22515
+ import_fs22.default.writeFileSync(metaPath, JSON.stringify(meta, null, 2));
21528
22516
  } catch {
21529
22517
  }
21530
22518
  }
21531
22519
 
21532
22520
  // src/commands/logs.js
21533
- var import_fs21 = __toESM(require("fs"), 1);
22521
+ var import_fs23 = __toESM(require("fs"), 1);
21534
22522
  function parseTimeAgo(str) {
21535
22523
  const match = str.match(/^(\d+)([smhd])$/);
21536
22524
  if (!match) return null;
@@ -21630,7 +22618,7 @@ function exportLogs(logs, filepath, format) {
21630
22618
  });
21631
22619
  content = JSON.stringify(formatted, null, 2);
21632
22620
  }
21633
- import_fs21.default.writeFileSync(filepath, content, "utf-8");
22621
+ import_fs23.default.writeFileSync(filepath, content, "utf-8");
21634
22622
  return filepath;
21635
22623
  }
21636
22624
  function printStats(stats) {
@@ -21756,11 +22744,10 @@ async function handleLogsCommand(args, flags) {
21756
22744
  }
21757
22745
 
21758
22746
  // src/commands/which.js
21759
- var fs24 = __toESM(require("fs/promises"), 1);
21760
- var path22 = __toESM(require("path"), 1);
22747
+ var fs26 = __toESM(require("fs/promises"), 1);
22748
+ var path26 = __toESM(require("path"), 1);
21761
22749
  var import_child_process8 = require("child_process");
21762
22750
  init_src3();
21763
- init_src();
21764
22751
  async function cmdWhich(args, flags) {
21765
22752
  const stackId = args[0];
21766
22753
  if (!stackId) {
@@ -21827,7 +22814,7 @@ Installed stacks:`);
21827
22814
  if (runtimeInfo.entry) {
21828
22815
  console.log("");
21829
22816
  console.log("Run MCP server directly:");
21830
- const entryPath = path22.join(stackPath, runtimeInfo.entry);
22817
+ const entryPath = path26.join(stackPath, runtimeInfo.entry);
21831
22818
  if (runtimeInfo.runtime === "node") {
21832
22819
  console.log(` echo '{"jsonrpc":"2.0","method":"tools/list","id":1}' | node ${entryPath}`);
21833
22820
  } else if (runtimeInfo.runtime === "python") {
@@ -21846,27 +22833,27 @@ Installed stacks:`);
21846
22833
  async function detectRuntime(stackPath) {
21847
22834
  const runtimes = ["node", "python"];
21848
22835
  for (const runtime of runtimes) {
21849
- const runtimePath = path22.join(stackPath, runtime);
22836
+ const runtimePath = path26.join(stackPath, runtime);
21850
22837
  try {
21851
- await fs24.access(runtimePath);
22838
+ await fs26.access(runtimePath);
21852
22839
  if (runtime === "node") {
21853
- const distEntry = path22.join(runtimePath, "dist", "index.js");
21854
- const srcEntry = path22.join(runtimePath, "src", "index.ts");
22840
+ const distEntry = path26.join(runtimePath, "dist", "index.js");
22841
+ const srcEntry = path26.join(runtimePath, "src", "index.ts");
21855
22842
  try {
21856
- await fs24.access(distEntry);
22843
+ await fs26.access(distEntry);
21857
22844
  return { runtime: "node", entry: `${runtime}/dist/index.js` };
21858
22845
  } catch {
21859
22846
  try {
21860
- await fs24.access(srcEntry);
22847
+ await fs26.access(srcEntry);
21861
22848
  return { runtime: "node", entry: `${runtime}/src/index.ts` };
21862
22849
  } catch {
21863
22850
  return { runtime: "node", entry: null };
21864
22851
  }
21865
22852
  }
21866
22853
  } else if (runtime === "python") {
21867
- const entry = path22.join(runtimePath, "src", "index.py");
22854
+ const entry = path26.join(runtimePath, "src", "index.py");
21868
22855
  try {
21869
- await fs24.access(entry);
22856
+ await fs26.access(entry);
21870
22857
  return { runtime: "python", entry: `${runtime}/src/index.py` };
21871
22858
  } catch {
21872
22859
  return { runtime: "python", entry: null };
@@ -21882,21 +22869,21 @@ async function checkAuth(stackPath, runtime) {
21882
22869
  const authFiles = [];
21883
22870
  let configured = false;
21884
22871
  if (runtime === "node" || runtime === "python") {
21885
- const runtimePath = path22.join(stackPath, runtime);
21886
- const tokenPath = path22.join(runtimePath, "token.json");
22872
+ const runtimePath = path26.join(stackPath, runtime);
22873
+ const tokenPath = path26.join(runtimePath, "token.json");
21887
22874
  try {
21888
- await fs24.access(tokenPath);
22875
+ await fs26.access(tokenPath);
21889
22876
  authFiles.push(`${runtime}/token.json`);
21890
22877
  configured = true;
21891
22878
  } catch {
21892
- const accountsPath = path22.join(runtimePath, "accounts");
22879
+ const accountsPath = path26.join(runtimePath, "accounts");
21893
22880
  try {
21894
- const accounts = await fs24.readdir(accountsPath);
22881
+ const accounts = await fs26.readdir(accountsPath);
21895
22882
  for (const account of accounts) {
21896
22883
  if (account.startsWith(".")) continue;
21897
- const accountTokenPath = path22.join(accountsPath, account, "token.json");
22884
+ const accountTokenPath = path26.join(accountsPath, account, "token.json");
21898
22885
  try {
21899
- await fs24.access(accountTokenPath);
22886
+ await fs26.access(accountTokenPath);
21900
22887
  authFiles.push(`${runtime}/accounts/${account}/token.json`);
21901
22888
  configured = true;
21902
22889
  } catch {
@@ -21906,9 +22893,9 @@ async function checkAuth(stackPath, runtime) {
21906
22893
  }
21907
22894
  }
21908
22895
  }
21909
- const envPath = path22.join(stackPath, ".env");
22896
+ const envPath = path26.join(stackPath, ".env");
21910
22897
  try {
21911
- const envContent = await fs24.readFile(envPath, "utf-8");
22898
+ const envContent = await fs26.readFile(envPath, "utf-8");
21912
22899
  const hasValues = envContent.split("\n").some((line) => {
21913
22900
  const trimmed = line.trim();
21914
22901
  if (!trimmed || trimmed.startsWith("#")) return false;
@@ -21952,11 +22939,10 @@ function checkIfRunning(stackName) {
21952
22939
  }
21953
22940
 
21954
22941
  // src/commands/auth.js
21955
- var fs25 = __toESM(require("fs/promises"), 1);
21956
- var path23 = __toESM(require("path"), 1);
22942
+ var fs27 = __toESM(require("fs/promises"), 1);
22943
+ var path27 = __toESM(require("path"), 1);
21957
22944
  var import_child_process9 = require("child_process");
21958
22945
  init_src3();
21959
- init_src();
21960
22946
  var net = __toESM(require("net"), 1);
21961
22947
  async function findAvailablePort(basePort = 3456) {
21962
22948
  for (let port = basePort; port < basePort + 10; port++) {
@@ -21986,26 +22972,26 @@ function isPortAvailable(port) {
21986
22972
  async function detectRuntime2(stackPath) {
21987
22973
  const runtimes = ["node", "python"];
21988
22974
  for (const runtime of runtimes) {
21989
- const runtimePath = path23.join(stackPath, runtime);
22975
+ const runtimePath = path27.join(stackPath, runtime);
21990
22976
  try {
21991
- await fs25.access(runtimePath);
22977
+ await fs27.access(runtimePath);
21992
22978
  if (runtime === "node") {
21993
- const authTs = path23.join(runtimePath, "src", "auth.ts");
21994
- const authJs = path23.join(runtimePath, "dist", "auth.js");
22979
+ const authTs = path27.join(runtimePath, "src", "auth.ts");
22980
+ const authJs = path27.join(runtimePath, "dist", "auth.js");
21995
22981
  try {
21996
- await fs25.access(authTs);
22982
+ await fs27.access(authTs);
21997
22983
  return { runtime: "node", authScript: authTs, useTsx: true };
21998
22984
  } catch {
21999
22985
  try {
22000
- await fs25.access(authJs);
22986
+ await fs27.access(authJs);
22001
22987
  return { runtime: "node", authScript: authJs, useTsx: false };
22002
22988
  } catch {
22003
22989
  }
22004
22990
  }
22005
22991
  } else if (runtime === "python") {
22006
- const authPy = path23.join(runtimePath, "src", "auth.py");
22992
+ const authPy = path27.join(runtimePath, "src", "auth.py");
22007
22993
  try {
22008
- await fs25.access(authPy);
22994
+ await fs27.access(authPy);
22009
22995
  return { runtime: "python", authScript: authPy, useTsx: false };
22010
22996
  } catch {
22011
22997
  }
@@ -22055,14 +23041,14 @@ Installed stacks:`);
22055
23041
  console.log(`Using port: ${port}`);
22056
23042
  console.log("");
22057
23043
  let cmd;
22058
- const cwd = path23.dirname(authInfo.authScript);
23044
+ const cwd = path27.dirname(authInfo.authScript);
22059
23045
  if (authInfo.runtime === "node") {
22060
- const distAuth = path23.join(cwd, "..", "dist", "auth.js");
23046
+ const distAuth = path27.join(cwd, "..", "dist", "auth.js");
22061
23047
  let useBuiltInPort = false;
22062
23048
  let tempAuthScript = null;
22063
23049
  try {
22064
- await fs25.access(distAuth);
22065
- const distContent = await fs25.readFile(distAuth, "utf-8");
23050
+ await fs27.access(distAuth);
23051
+ const distContent = await fs27.readFile(distAuth, "utf-8");
22066
23052
  if (distContent.includes("findAvailablePort")) {
22067
23053
  console.log("Using compiled authentication script...");
22068
23054
  cmd = `node ${distAuth}${accountEmail ? ` ${accountEmail}` : ""}`;
@@ -22071,11 +23057,11 @@ Installed stacks:`);
22071
23057
  } catch {
22072
23058
  }
22073
23059
  if (!useBuiltInPort) {
22074
- const authContent = await fs25.readFile(authInfo.authScript, "utf-8");
23060
+ const authContent = await fs27.readFile(authInfo.authScript, "utf-8");
22075
23061
  const tempExt = authInfo.useTsx ? ".ts" : ".mjs";
22076
- tempAuthScript = path23.join(cwd, "..", `auth-temp${tempExt}`);
23062
+ tempAuthScript = path27.join(cwd, "..", `auth-temp${tempExt}`);
22077
23063
  const modifiedContent = authContent.replace(/localhost:3456/g, `localhost:${port}`).replace(/server\.listen\(3456/g, `server.listen(${port}`);
22078
- await fs25.writeFile(tempAuthScript, modifiedContent);
23064
+ await fs27.writeFile(tempAuthScript, modifiedContent);
22079
23065
  if (authInfo.useTsx) {
22080
23066
  cmd = `npx tsx ${tempAuthScript}${accountEmail ? ` ${accountEmail}` : ""}`;
22081
23067
  } else {
@@ -22090,12 +23076,12 @@ Installed stacks:`);
22090
23076
  stdio: "inherit"
22091
23077
  });
22092
23078
  if (tempAuthScript) {
22093
- await fs25.unlink(tempAuthScript);
23079
+ await fs27.unlink(tempAuthScript);
22094
23080
  }
22095
23081
  } catch (error) {
22096
23082
  if (tempAuthScript) {
22097
23083
  try {
22098
- await fs25.unlink(tempAuthScript);
23084
+ await fs27.unlink(tempAuthScript);
22099
23085
  } catch {
22100
23086
  }
22101
23087
  }
@@ -22127,21 +23113,20 @@ Installed stacks:`);
22127
23113
  }
22128
23114
 
22129
23115
  // src/commands/mcp.js
22130
- var fs26 = __toESM(require("fs"), 1);
22131
- var path24 = __toESM(require("path"), 1);
23116
+ var fs28 = __toESM(require("fs"), 1);
23117
+ var path28 = __toESM(require("path"), 1);
22132
23118
  var import_child_process10 = require("child_process");
22133
- init_src();
22134
23119
  function getBundledRuntime(runtime) {
22135
23120
  const platform = process.platform;
22136
23121
  if (runtime === "node") {
22137
- const nodePath = platform === "win32" ? path24.join(PATHS.runtimes, "node", "node.exe") : path24.join(PATHS.runtimes, "node", "bin", "node");
22138
- if (fs26.existsSync(nodePath)) {
23122
+ const nodePath = platform === "win32" ? path28.join(PATHS2.runtimes, "node", "node.exe") : path28.join(PATHS2.runtimes, "node", "bin", "node");
23123
+ if (fs28.existsSync(nodePath)) {
22139
23124
  return nodePath;
22140
23125
  }
22141
23126
  }
22142
23127
  if (runtime === "python") {
22143
- const pythonPath = platform === "win32" ? path24.join(PATHS.runtimes, "python", "python.exe") : path24.join(PATHS.runtimes, "python", "bin", "python3");
22144
- if (fs26.existsSync(pythonPath)) {
23128
+ const pythonPath = platform === "win32" ? path28.join(PATHS2.runtimes, "python", "python.exe") : path28.join(PATHS2.runtimes, "python", "bin", "python3");
23129
+ if (fs28.existsSync(pythonPath)) {
22145
23130
  return pythonPath;
22146
23131
  }
22147
23132
  }
@@ -22149,18 +23134,18 @@ function getBundledRuntime(runtime) {
22149
23134
  }
22150
23135
  function getBundledNpx() {
22151
23136
  const platform = process.platform;
22152
- const npxPath = platform === "win32" ? path24.join(PATHS.runtimes, "node", "npx.cmd") : path24.join(PATHS.runtimes, "node", "bin", "npx");
22153
- if (fs26.existsSync(npxPath)) {
23137
+ const npxPath = platform === "win32" ? path28.join(PATHS2.runtimes, "node", "npx.cmd") : path28.join(PATHS2.runtimes, "node", "bin", "npx");
23138
+ if (fs28.existsSync(npxPath)) {
22154
23139
  return npxPath;
22155
23140
  }
22156
23141
  return null;
22157
23142
  }
22158
23143
  function loadManifest2(stackPath) {
22159
- const manifestPath = path24.join(stackPath, "manifest.json");
22160
- if (!fs26.existsSync(manifestPath)) {
23144
+ const manifestPath = path28.join(stackPath, "manifest.json");
23145
+ if (!fs28.existsSync(manifestPath)) {
22161
23146
  return null;
22162
23147
  }
22163
- return JSON.parse(fs26.readFileSync(manifestPath, "utf-8"));
23148
+ return JSON.parse(fs28.readFileSync(manifestPath, "utf-8"));
22164
23149
  }
22165
23150
  function getRequiredSecrets(manifest) {
22166
23151
  const secrets = manifest?.requires?.secrets || manifest?.secrets || [];
@@ -22193,8 +23178,8 @@ async function cmdMcp(args, flags) {
22193
23178
  console.error("Example: rudi mcp slack");
22194
23179
  process.exit(1);
22195
23180
  }
22196
- const stackPath = path24.join(PATHS.stacks, stackName);
22197
- if (!fs26.existsSync(stackPath)) {
23181
+ const stackPath = path28.join(PATHS2.stacks, stackName);
23182
+ if (!fs28.existsSync(stackPath)) {
22198
23183
  console.error(`Stack not found: ${stackName}`);
22199
23184
  console.error(`Expected at: ${stackPath}`);
22200
23185
  console.error("");
@@ -22243,22 +23228,22 @@ async function cmdMcp(args, flags) {
22243
23228
  }
22244
23229
  return part;
22245
23230
  }
22246
- if (part.startsWith("./") || part.startsWith("../") || !path24.isAbsolute(part)) {
22247
- const resolved = path24.join(stackPath, part);
22248
- if (fs26.existsSync(resolved)) {
23231
+ if (part.startsWith("./") || part.startsWith("../") || !path28.isAbsolute(part)) {
23232
+ const resolved = path28.join(stackPath, part);
23233
+ if (fs28.existsSync(resolved)) {
22249
23234
  return resolved;
22250
23235
  }
22251
23236
  }
22252
23237
  return part;
22253
23238
  });
22254
23239
  const [cmd, ...cmdArgs] = resolvedCommand;
22255
- const bundledNodeBin = path24.join(PATHS.runtimes, "node", "bin");
22256
- const bundledPythonBin = path24.join(PATHS.runtimes, "python", "bin");
22257
- if (fs26.existsSync(bundledNodeBin) || fs26.existsSync(bundledPythonBin)) {
23240
+ const bundledNodeBin = path28.join(PATHS2.runtimes, "node", "bin");
23241
+ const bundledPythonBin = path28.join(PATHS2.runtimes, "python", "bin");
23242
+ if (fs28.existsSync(bundledNodeBin) || fs28.existsSync(bundledPythonBin)) {
22258
23243
  const runtimePaths = [];
22259
- if (fs26.existsSync(bundledNodeBin)) runtimePaths.push(bundledNodeBin);
22260
- if (fs26.existsSync(bundledPythonBin)) runtimePaths.push(bundledPythonBin);
22261
- env.PATH = runtimePaths.join(path24.delimiter) + path24.delimiter + (env.PATH || "");
23244
+ if (fs28.existsSync(bundledNodeBin)) runtimePaths.push(bundledNodeBin);
23245
+ if (fs28.existsSync(bundledPythonBin)) runtimePaths.push(bundledPythonBin);
23246
+ env.PATH = runtimePaths.join(path28.delimiter) + path28.delimiter + (env.PATH || "");
22262
23247
  }
22263
23248
  if (flags.debug) {
22264
23249
  console.error(`[rudi mcp] Stack: ${stackName}`);
@@ -22288,14 +23273,13 @@ async function cmdMcp(args, flags) {
22288
23273
  }
22289
23274
 
22290
23275
  // src/commands/integrate.js
22291
- var fs27 = __toESM(require("fs"), 1);
22292
- var path25 = __toESM(require("path"), 1);
22293
- var import_os5 = __toESM(require("os"), 1);
22294
- init_src();
22295
- var HOME2 = import_os5.default.homedir();
22296
- var ROUTER_SHIM_PATH = path25.join(PATHS.home, "shims", "rudi-router");
23276
+ var fs29 = __toESM(require("fs"), 1);
23277
+ var path29 = __toESM(require("path"), 1);
23278
+ var import_os6 = __toESM(require("os"), 1);
23279
+ var HOME2 = import_os6.default.homedir();
23280
+ var ROUTER_SHIM_PATH = path29.join(PATHS2.home, "shims", "rudi-router");
22297
23281
  function checkRouterShim() {
22298
- if (!fs27.existsSync(ROUTER_SHIM_PATH)) {
23282
+ if (!fs29.existsSync(ROUTER_SHIM_PATH)) {
22299
23283
  throw new Error(
22300
23284
  `Router shim not found at ${ROUTER_SHIM_PATH}
22301
23285
  Run: npm install -g @learnrudi/cli@latest`
@@ -22304,27 +23288,27 @@ Run: npm install -g @learnrudi/cli@latest`
22304
23288
  return ROUTER_SHIM_PATH;
22305
23289
  }
22306
23290
  function backupConfig(configPath) {
22307
- if (!fs27.existsSync(configPath)) return null;
23291
+ if (!fs29.existsSync(configPath)) return null;
22308
23292
  const backupPath = configPath + ".backup." + Date.now();
22309
- fs27.copyFileSync(configPath, backupPath);
23293
+ fs29.copyFileSync(configPath, backupPath);
22310
23294
  return backupPath;
22311
23295
  }
22312
23296
  function readJsonConfig(configPath) {
22313
- if (!fs27.existsSync(configPath)) {
23297
+ if (!fs29.existsSync(configPath)) {
22314
23298
  return {};
22315
23299
  }
22316
23300
  try {
22317
- return JSON.parse(fs27.readFileSync(configPath, "utf-8"));
23301
+ return JSON.parse(fs29.readFileSync(configPath, "utf-8"));
22318
23302
  } catch {
22319
23303
  return {};
22320
23304
  }
22321
23305
  }
22322
23306
  function writeJsonConfig(configPath, config) {
22323
- const dir = path25.dirname(configPath);
22324
- if (!fs27.existsSync(dir)) {
22325
- fs27.mkdirSync(dir, { recursive: true });
23307
+ const dir = path29.dirname(configPath);
23308
+ if (!fs29.existsSync(dir)) {
23309
+ fs29.mkdirSync(dir, { recursive: true });
22326
23310
  }
22327
- fs27.writeFileSync(configPath, JSON.stringify(config, null, 2));
23311
+ fs29.writeFileSync(configPath, JSON.stringify(config, null, 2));
22328
23312
  }
22329
23313
  function buildRouterEntry(agentId) {
22330
23314
  const base = {
@@ -22343,11 +23327,11 @@ async function integrateAgent(agentId, flags) {
22343
23327
  return { success: false, error: "Unknown agent" };
22344
23328
  }
22345
23329
  const configPath = findAgentConfig(agentConfig);
22346
- const targetPath = configPath || path25.join(HOME2, agentConfig.paths[process.platform]?.[0] || agentConfig.paths.darwin[0]);
23330
+ const targetPath = configPath || path29.join(HOME2, agentConfig.paths[process.platform]?.[0] || agentConfig.paths.darwin[0]);
22347
23331
  console.log(`
22348
23332
  ${agentConfig.name}:`);
22349
23333
  console.log(` Config: ${targetPath}`);
22350
- if (fs27.existsSync(targetPath)) {
23334
+ if (fs29.existsSync(targetPath)) {
22351
23335
  const backup = backupConfig(targetPath);
22352
23336
  if (backup && flags.verbose) {
22353
23337
  console.log(` Backup: ${backup}`);
@@ -22358,7 +23342,7 @@ ${agentConfig.name}:`);
22358
23342
  if (!config[key]) {
22359
23343
  config[key] = {};
22360
23344
  }
22361
- const rudiMcpShimPath = path25.join(PATHS.home, "shims", "rudi-mcp");
23345
+ const rudiMcpShimPath = path29.join(PATHS2.home, "shims", "rudi-mcp");
22362
23346
  const removedEntries = [];
22363
23347
  for (const [serverName, serverConfig] of Object.entries(config[key])) {
22364
23348
  if (serverConfig.command === rudiMcpShimPath) {
@@ -22490,52 +23474,51 @@ Wiring up RUDI router...`);
22490
23474
  }
22491
23475
 
22492
23476
  // src/commands/migrate.js
22493
- var fs28 = __toESM(require("fs"), 1);
22494
- var path26 = __toESM(require("path"), 1);
22495
- var import_os6 = __toESM(require("os"), 1);
22496
- init_src();
22497
- var HOME3 = import_os6.default.homedir();
22498
- var OLD_PROMPT_STACK = path26.join(HOME3, ".prompt-stack");
22499
- var SHIM_PATH = path26.join(PATHS.home, "shims", "rudi-mcp");
23477
+ var fs30 = __toESM(require("fs"), 1);
23478
+ var path30 = __toESM(require("path"), 1);
23479
+ var import_os7 = __toESM(require("os"), 1);
23480
+ var HOME3 = import_os7.default.homedir();
23481
+ var OLD_PROMPT_STACK = path30.join(HOME3, ".prompt-stack");
23482
+ var SHIM_PATH = path30.join(PATHS2.home, "shims", "rudi-mcp");
22500
23483
  function getOldStacks() {
22501
- const stacksDir = path26.join(OLD_PROMPT_STACK, "stacks");
22502
- if (!fs28.existsSync(stacksDir)) return [];
22503
- return fs28.readdirSync(stacksDir, { withFileTypes: true }).filter((d) => d.isDirectory() && !d.name.startsWith(".")).filter((d) => {
22504
- const hasManifest = fs28.existsSync(path26.join(stacksDir, d.name, "manifest.json"));
22505
- const hasPackage = fs28.existsSync(path26.join(stacksDir, d.name, "package.json"));
23484
+ const stacksDir = path30.join(OLD_PROMPT_STACK, "stacks");
23485
+ if (!fs30.existsSync(stacksDir)) return [];
23486
+ return fs30.readdirSync(stacksDir, { withFileTypes: true }).filter((d) => d.isDirectory() && !d.name.startsWith(".")).filter((d) => {
23487
+ const hasManifest = fs30.existsSync(path30.join(stacksDir, d.name, "manifest.json"));
23488
+ const hasPackage = fs30.existsSync(path30.join(stacksDir, d.name, "package.json"));
22506
23489
  return hasManifest || hasPackage;
22507
23490
  }).map((d) => d.name);
22508
23491
  }
22509
23492
  function copyStack(stackName) {
22510
- const oldPath = path26.join(OLD_PROMPT_STACK, "stacks", stackName);
22511
- const newPath = path26.join(PATHS.stacks, stackName);
22512
- if (!fs28.existsSync(oldPath)) {
23493
+ const oldPath = path30.join(OLD_PROMPT_STACK, "stacks", stackName);
23494
+ const newPath = path30.join(PATHS2.stacks, stackName);
23495
+ if (!fs30.existsSync(oldPath)) {
22513
23496
  return { success: false, error: "Source not found" };
22514
23497
  }
22515
- if (fs28.existsSync(newPath)) {
23498
+ if (fs30.existsSync(newPath)) {
22516
23499
  return { success: true, skipped: true, reason: "Already exists" };
22517
23500
  }
22518
- if (!fs28.existsSync(PATHS.stacks)) {
22519
- fs28.mkdirSync(PATHS.stacks, { recursive: true });
23501
+ if (!fs30.existsSync(PATHS2.stacks)) {
23502
+ fs30.mkdirSync(PATHS2.stacks, { recursive: true });
22520
23503
  }
22521
23504
  copyRecursive(oldPath, newPath);
22522
23505
  return { success: true, copied: true };
22523
23506
  }
22524
23507
  function copyRecursive(src, dest) {
22525
- const stat = fs28.statSync(src);
23508
+ const stat = fs30.statSync(src);
22526
23509
  if (stat.isDirectory()) {
22527
- fs28.mkdirSync(dest, { recursive: true });
22528
- for (const child of fs28.readdirSync(src)) {
22529
- copyRecursive(path26.join(src, child), path26.join(dest, child));
23510
+ fs30.mkdirSync(dest, { recursive: true });
23511
+ for (const child of fs30.readdirSync(src)) {
23512
+ copyRecursive(path30.join(src, child), path30.join(dest, child));
22530
23513
  }
22531
23514
  } else {
22532
- fs28.copyFileSync(src, dest);
23515
+ fs30.copyFileSync(src, dest);
22533
23516
  }
22534
23517
  }
22535
23518
  function ensureShim() {
22536
- const shimsDir = path26.dirname(SHIM_PATH);
22537
- if (!fs28.existsSync(shimsDir)) {
22538
- fs28.mkdirSync(shimsDir, { recursive: true });
23519
+ const shimsDir = path30.dirname(SHIM_PATH);
23520
+ if (!fs30.existsSync(shimsDir)) {
23521
+ fs30.mkdirSync(shimsDir, { recursive: true });
22539
23522
  }
22540
23523
  const shimContent = `#!/usr/bin/env bash
22541
23524
  set -euo pipefail
@@ -22545,7 +23528,7 @@ else
22545
23528
  exec npx --yes @learnrudi/cli mcp "$1"
22546
23529
  fi
22547
23530
  `;
22548
- fs28.writeFileSync(SHIM_PATH, shimContent, { mode: 493 });
23531
+ fs30.writeFileSync(SHIM_PATH, shimContent, { mode: 493 });
22549
23532
  }
22550
23533
  function buildNewEntry(stackName, agentId) {
22551
23534
  const base = {
@@ -22569,7 +23552,7 @@ function migrateAgentConfig(agentConfig, installedStacks, flags) {
22569
23552
  if (!configPath) return { skipped: true, reason: "Config not found" };
22570
23553
  let config;
22571
23554
  try {
22572
- config = JSON.parse(fs28.readFileSync(configPath, "utf-8"));
23555
+ config = JSON.parse(fs30.readFileSync(configPath, "utf-8"));
22573
23556
  } catch {
22574
23557
  return { skipped: true, reason: "Could not parse config" };
22575
23558
  }
@@ -22596,9 +23579,9 @@ function migrateAgentConfig(agentConfig, installedStacks, flags) {
22596
23579
  }
22597
23580
  if (updated > 0 || removed > 0) {
22598
23581
  const backupPath = configPath + ".backup." + Date.now();
22599
- fs28.copyFileSync(configPath, backupPath);
23582
+ fs30.copyFileSync(configPath, backupPath);
22600
23583
  config[key] = mcpServers;
22601
- fs28.writeFileSync(configPath, JSON.stringify(config, null, 2));
23584
+ fs30.writeFileSync(configPath, JSON.stringify(config, null, 2));
22602
23585
  }
22603
23586
  return { updated, removed, changes };
22604
23587
  }
@@ -22647,15 +23630,15 @@ async function migrateStatus() {
22647
23630
  console.log(`Old .prompt-stack stacks: ${oldStacks.length}`);
22648
23631
  if (oldStacks.length > 0) {
22649
23632
  for (const name of oldStacks) {
22650
- const existsInRudi = fs28.existsSync(path26.join(PATHS.stacks, name));
23633
+ const existsInRudi = fs30.existsSync(path30.join(PATHS2.stacks, name));
22651
23634
  const status = existsInRudi ? "\u2713 (already in .rudi)" : "\u25CB (needs migration)";
22652
23635
  console.log(` ${status} ${name}`);
22653
23636
  }
22654
23637
  }
22655
- const newStacksDir = PATHS.stacks;
23638
+ const newStacksDir = PATHS2.stacks;
22656
23639
  let newStacks = [];
22657
- if (fs28.existsSync(newStacksDir)) {
22658
- newStacks = fs28.readdirSync(newStacksDir, { withFileTypes: true }).filter((d) => d.isDirectory() && !d.name.startsWith(".")).map((d) => d.name);
23640
+ if (fs30.existsSync(newStacksDir)) {
23641
+ newStacks = fs30.readdirSync(newStacksDir, { withFileTypes: true }).filter((d) => d.isDirectory() && !d.name.startsWith(".")).map((d) => d.name);
22659
23642
  }
22660
23643
  console.log(`
22661
23644
  New .rudi stacks: ${newStacks.length}`);
@@ -22670,7 +23653,7 @@ New .rudi stacks: ${newStacks.length}`);
22670
23653
  if (!configPath) continue;
22671
23654
  let config;
22672
23655
  try {
22673
- config = JSON.parse(fs28.readFileSync(configPath, "utf-8"));
23656
+ config = JSON.parse(fs30.readFileSync(configPath, "utf-8"));
22674
23657
  } catch {
22675
23658
  continue;
22676
23659
  }
@@ -22706,7 +23689,7 @@ async function migrateStacks(flags) {
22706
23689
  `);
22707
23690
  for (const name of oldStacks) {
22708
23691
  if (flags.dryRun) {
22709
- const exists = fs28.existsSync(path26.join(PATHS.stacks, name));
23692
+ const exists = fs30.existsSync(path30.join(PATHS2.stacks, name));
22710
23693
  console.log(` [dry-run] ${name}: ${exists ? "would skip (exists)" : "would copy"}`);
22711
23694
  } else {
22712
23695
  const result = copyStack(name);
@@ -22721,7 +23704,7 @@ async function migrateStacks(flags) {
22721
23704
  }
22722
23705
  if (!flags.dryRun) {
22723
23706
  console.log(`
22724
- Stacks migrated to: ${PATHS.stacks}`);
23707
+ Stacks migrated to: ${PATHS2.stacks}`);
22725
23708
  }
22726
23709
  }
22727
23710
  async function migrateConfigs(flags) {
@@ -22732,8 +23715,8 @@ async function migrateConfigs(flags) {
22732
23715
  `);
22733
23716
  }
22734
23717
  let installedStacks = [];
22735
- if (fs28.existsSync(PATHS.stacks)) {
22736
- installedStacks = fs28.readdirSync(PATHS.stacks, { withFileTypes: true }).filter((d) => d.isDirectory() && !d.name.startsWith(".")).map((d) => d.name);
23718
+ if (fs30.existsSync(PATHS2.stacks)) {
23719
+ installedStacks = fs30.readdirSync(PATHS2.stacks, { withFileTypes: true }).filter((d) => d.isDirectory() && !d.name.startsWith(".")).map((d) => d.name);
22737
23720
  }
22738
23721
  for (const agentConfig of AGENT_CONFIGS) {
22739
23722
  const configPath = findAgentConfig(agentConfig);
@@ -22901,9 +23884,9 @@ After configuring secrets, run: rudi index`);
22901
23884
  // src/commands/status.js
22902
23885
  init_src3();
22903
23886
  var import_child_process11 = require("child_process");
22904
- var import_fs22 = __toESM(require("fs"), 1);
22905
- var import_path19 = __toESM(require("path"), 1);
22906
- var import_os7 = __toESM(require("os"), 1);
23887
+ var import_fs24 = __toESM(require("fs"), 1);
23888
+ var import_path21 = __toESM(require("path"), 1);
23889
+ var import_os8 = __toESM(require("os"), 1);
22907
23890
  var AGENTS = [
22908
23891
  {
22909
23892
  id: "claude",
@@ -22948,8 +23931,8 @@ var BINARIES = [
22948
23931
  { id: "jq", name: "jq", command: "jq", versionFlag: "--version" }
22949
23932
  ];
22950
23933
  function fileExists(filePath) {
22951
- const resolved = filePath.replace("~", import_os7.default.homedir());
22952
- return import_fs22.default.existsSync(resolved);
23934
+ const resolved = filePath.replace("~", import_os8.default.homedir());
23935
+ return import_fs24.default.existsSync(resolved);
22953
23936
  }
22954
23937
  function checkKeychain(service) {
22955
23938
  if (process.platform !== "darwin") return false;
@@ -22977,13 +23960,13 @@ function getVersion2(command, versionFlag) {
22977
23960
  }
22978
23961
  function findBinary(command, kind = "binary") {
22979
23962
  const rudiPaths = [
22980
- import_path19.default.join(PATHS.agents, command, "node_modules", ".bin", command),
22981
- import_path19.default.join(PATHS.runtimes, command, "bin", command),
22982
- import_path19.default.join(PATHS.binaries, command, command),
22983
- import_path19.default.join(PATHS.binaries, command)
23963
+ import_path21.default.join(PATHS.agents, command, "node_modules", ".bin", command),
23964
+ import_path21.default.join(PATHS.runtimes, command, "bin", command),
23965
+ import_path21.default.join(PATHS.binaries, command, command),
23966
+ import_path21.default.join(PATHS.binaries, command)
22984
23967
  ];
22985
23968
  for (const p of rudiPaths) {
22986
- if (import_fs22.default.existsSync(p)) {
23969
+ if (import_fs24.default.existsSync(p)) {
22987
23970
  return { found: true, path: p, source: "rudi" };
22988
23971
  }
22989
23972
  }
@@ -23001,8 +23984,8 @@ function findBinary(command, kind = "binary") {
23001
23984
  return { found: false, path: null, source: null };
23002
23985
  }
23003
23986
  function getAgentStatus(agent) {
23004
- const rudiPath = import_path19.default.join(PATHS.agents, agent.id, "node_modules", ".bin", agent.id);
23005
- const rudiInstalled = import_fs22.default.existsSync(rudiPath);
23987
+ const rudiPath = import_path21.default.join(PATHS.agents, agent.id, "node_modules", ".bin", agent.id);
23988
+ const rudiInstalled = import_fs24.default.existsSync(rudiPath);
23006
23989
  let globalPath = null;
23007
23990
  let globalInstalled = false;
23008
23991
  if (!rudiInstalled) {
@@ -23084,12 +24067,12 @@ async function getFullStatus() {
23084
24067
  } catch {
23085
24068
  }
23086
24069
  const directories = {
23087
- home: { path: PATHS.home, exists: import_fs22.default.existsSync(PATHS.home) },
23088
- stacks: { path: PATHS.stacks, exists: import_fs22.default.existsSync(PATHS.stacks) },
23089
- agents: { path: PATHS.agents, exists: import_fs22.default.existsSync(PATHS.agents) },
23090
- runtimes: { path: PATHS.runtimes, exists: import_fs22.default.existsSync(PATHS.runtimes) },
23091
- binaries: { path: PATHS.binaries, exists: import_fs22.default.existsSync(PATHS.binaries) },
23092
- db: { path: PATHS.db, exists: import_fs22.default.existsSync(PATHS.db) }
24070
+ home: { path: PATHS.home, exists: import_fs24.default.existsSync(PATHS.home) },
24071
+ stacks: { path: PATHS.stacks, exists: import_fs24.default.existsSync(PATHS.stacks) },
24072
+ agents: { path: PATHS.agents, exists: import_fs24.default.existsSync(PATHS.agents) },
24073
+ runtimes: { path: PATHS.runtimes, exists: import_fs24.default.existsSync(PATHS.runtimes) },
24074
+ binaries: { path: PATHS.binaries, exists: import_fs24.default.existsSync(PATHS.binaries) },
24075
+ db: { path: PATHS.db, exists: import_fs24.default.existsSync(PATHS.db) }
23093
24076
  };
23094
24077
  const summary = {
23095
24078
  agentsInstalled: agents.filter((a) => a.installed).length,
@@ -23197,9 +24180,9 @@ async function cmdStatus(args, flags) {
23197
24180
  // src/commands/check.js
23198
24181
  init_src3();
23199
24182
  var import_child_process12 = require("child_process");
23200
- var import_fs23 = __toESM(require("fs"), 1);
23201
- var import_path20 = __toESM(require("path"), 1);
23202
- var import_os8 = __toESM(require("os"), 1);
24183
+ var import_fs25 = __toESM(require("fs"), 1);
24184
+ var import_path22 = __toESM(require("path"), 1);
24185
+ var import_os9 = __toESM(require("os"), 1);
23203
24186
  var AGENT_CREDENTIALS = {
23204
24187
  claude: { type: "keychain", service: "Claude Code-credentials" },
23205
24188
  codex: { type: "file", path: "~/.codex/auth.json" },
@@ -23207,8 +24190,8 @@ var AGENT_CREDENTIALS = {
23207
24190
  copilot: { type: "file", path: "~/.config/github-copilot/hosts.json" }
23208
24191
  };
23209
24192
  function fileExists2(filePath) {
23210
- const resolved = filePath.replace("~", import_os8.default.homedir());
23211
- return import_fs23.default.existsSync(resolved);
24193
+ const resolved = filePath.replace("~", import_os9.default.homedir());
24194
+ return import_fs25.default.existsSync(resolved);
23212
24195
  }
23213
24196
  function checkKeychain2(service) {
23214
24197
  if (process.platform !== "darwin") return false;
@@ -23234,15 +24217,15 @@ function getVersion3(binaryPath, versionFlag = "--version") {
23234
24217
  }
23235
24218
  }
23236
24219
  function detectKindFromFilesystem(name) {
23237
- const agentPath = import_path20.default.join(PATHS.agents, name, "node_modules", ".bin", name);
23238
- if (import_fs23.default.existsSync(agentPath)) return "agent";
23239
- const runtimePath = import_path20.default.join(PATHS.runtimes, name, "bin", name);
23240
- if (import_fs23.default.existsSync(runtimePath)) return "runtime";
23241
- const binaryPath = import_path20.default.join(PATHS.binaries, name, name);
23242
- const binaryPath2 = import_path20.default.join(PATHS.binaries, name);
23243
- if (import_fs23.default.existsSync(binaryPath) || import_fs23.default.existsSync(binaryPath2)) return "binary";
23244
- const stackPath = import_path20.default.join(PATHS.stacks, name);
23245
- if (import_fs23.default.existsSync(stackPath)) return "stack";
24220
+ const agentPath = import_path22.default.join(PATHS.agents, name, "node_modules", ".bin", name);
24221
+ if (import_fs25.default.existsSync(agentPath)) return "agent";
24222
+ const runtimePath = import_path22.default.join(PATHS.runtimes, name, "bin", name);
24223
+ if (import_fs25.default.existsSync(runtimePath)) return "runtime";
24224
+ const binaryPath = import_path22.default.join(PATHS.binaries, name, name);
24225
+ const binaryPath2 = import_path22.default.join(PATHS.binaries, name);
24226
+ if (import_fs25.default.existsSync(binaryPath) || import_fs25.default.existsSync(binaryPath2)) return "binary";
24227
+ const stackPath = import_path22.default.join(PATHS.stacks, name);
24228
+ if (import_fs25.default.existsSync(stackPath)) return "stack";
23246
24229
  try {
23247
24230
  const globalPath = (0, import_child_process12.execSync)(`which ${name} 2>/dev/null`, { encoding: "utf-8" }).trim();
23248
24231
  if (globalPath) {
@@ -23288,8 +24271,8 @@ async function cmdCheck(args, flags) {
23288
24271
  };
23289
24272
  switch (kind) {
23290
24273
  case "agent": {
23291
- const rudiPath = import_path20.default.join(PATHS.agents, name, "node_modules", ".bin", name);
23292
- const rudiInstalled = import_fs23.default.existsSync(rudiPath);
24274
+ const rudiPath = import_path22.default.join(PATHS.agents, name, "node_modules", ".bin", name);
24275
+ const rudiInstalled = import_fs25.default.existsSync(rudiPath);
23293
24276
  let globalPath = null;
23294
24277
  let globalInstalled = false;
23295
24278
  if (!rudiInstalled) {
@@ -23320,8 +24303,8 @@ async function cmdCheck(args, flags) {
23320
24303
  break;
23321
24304
  }
23322
24305
  case "runtime": {
23323
- const rudiPath = import_path20.default.join(PATHS.runtimes, name, "bin", name);
23324
- if (import_fs23.default.existsSync(rudiPath)) {
24306
+ const rudiPath = import_path22.default.join(PATHS.runtimes, name, "bin", name);
24307
+ if (import_fs25.default.existsSync(rudiPath)) {
23325
24308
  result.installed = true;
23326
24309
  result.path = rudiPath;
23327
24310
  result.version = getVersion3(rudiPath);
@@ -23340,8 +24323,8 @@ async function cmdCheck(args, flags) {
23340
24323
  break;
23341
24324
  }
23342
24325
  case "binary": {
23343
- const rudiPath = import_path20.default.join(PATHS.binaries, name, name);
23344
- if (import_fs23.default.existsSync(rudiPath)) {
24326
+ const rudiPath = import_path22.default.join(PATHS.binaries, name, name);
24327
+ if (import_fs25.default.existsSync(rudiPath)) {
23345
24328
  result.installed = true;
23346
24329
  result.path = rudiPath;
23347
24330
  } else {
@@ -23395,27 +24378,27 @@ async function cmdCheck(args, flags) {
23395
24378
 
23396
24379
  // src/commands/shims.js
23397
24380
  init_src3();
23398
- var import_fs24 = __toESM(require("fs"), 1);
23399
- var import_path21 = __toESM(require("path"), 1);
24381
+ var import_fs26 = __toESM(require("fs"), 1);
24382
+ var import_path23 = __toESM(require("path"), 1);
23400
24383
  function listShims2() {
23401
24384
  const binsDir = PATHS.bins;
23402
- if (!import_fs24.default.existsSync(binsDir)) {
24385
+ if (!import_fs26.default.existsSync(binsDir)) {
23403
24386
  return [];
23404
24387
  }
23405
- const entries = import_fs24.default.readdirSync(binsDir);
24388
+ const entries = import_fs26.default.readdirSync(binsDir);
23406
24389
  return entries.filter((entry) => {
23407
- const fullPath = import_path21.default.join(binsDir, entry);
23408
- const stat = import_fs24.default.lstatSync(fullPath);
24390
+ const fullPath = import_path23.default.join(binsDir, entry);
24391
+ const stat = import_fs26.default.lstatSync(fullPath);
23409
24392
  return stat.isFile() || stat.isSymbolicLink();
23410
24393
  });
23411
24394
  }
23412
24395
  function getShimType(shimPath) {
23413
- const stat = import_fs24.default.lstatSync(shimPath);
24396
+ const stat = import_fs26.default.lstatSync(shimPath);
23414
24397
  if (stat.isSymbolicLink()) {
23415
24398
  return "symlink";
23416
24399
  }
23417
24400
  try {
23418
- const content = import_fs24.default.readFileSync(shimPath, "utf8");
24401
+ const content = import_fs26.default.readFileSync(shimPath, "utf8");
23419
24402
  if (content.includes("#!/usr/bin/env bash")) {
23420
24403
  return "wrapper";
23421
24404
  }
@@ -23426,14 +24409,14 @@ function getShimType(shimPath) {
23426
24409
  function getShimTarget(name, shimPath, type) {
23427
24410
  if (type === "symlink") {
23428
24411
  try {
23429
- return import_fs24.default.readlinkSync(shimPath);
24412
+ return import_fs26.default.readlinkSync(shimPath);
23430
24413
  } catch (err) {
23431
24414
  return null;
23432
24415
  }
23433
24416
  }
23434
24417
  if (type === "wrapper") {
23435
24418
  try {
23436
- const content = import_fs24.default.readFileSync(shimPath, "utf8");
24419
+ const content = import_fs26.default.readFileSync(shimPath, "utf8");
23437
24420
  const match = content.match(/exec "([^"]+)"/);
23438
24421
  return match ? match[1] : null;
23439
24422
  } catch (err) {
@@ -23455,18 +24438,18 @@ function getPackageFromShim(shimName, target) {
23455
24438
  return `${kindMap[kind]}:${pkgName}`;
23456
24439
  }
23457
24440
  const manifestDirs = [
23458
- import_path21.default.join(PATHS.binaries),
23459
- import_path21.default.join(PATHS.runtimes),
23460
- import_path21.default.join(PATHS.agents)
24441
+ import_path23.default.join(PATHS.binaries),
24442
+ import_path23.default.join(PATHS.runtimes),
24443
+ import_path23.default.join(PATHS.agents)
23461
24444
  ];
23462
24445
  for (const dir of manifestDirs) {
23463
- if (!import_fs24.default.existsSync(dir)) continue;
23464
- const packages = import_fs24.default.readdirSync(dir);
24446
+ if (!import_fs26.default.existsSync(dir)) continue;
24447
+ const packages = import_fs26.default.readdirSync(dir);
23465
24448
  for (const pkg of packages) {
23466
- const manifestPath = import_path21.default.join(dir, pkg, "manifest.json");
23467
- if (import_fs24.default.existsSync(manifestPath)) {
24449
+ const manifestPath = import_path23.default.join(dir, pkg, "manifest.json");
24450
+ if (import_fs26.default.existsSync(manifestPath)) {
23468
24451
  try {
23469
- const manifest = JSON.parse(import_fs24.default.readFileSync(manifestPath, "utf8"));
24452
+ const manifest = JSON.parse(import_fs26.default.readFileSync(manifestPath, "utf8"));
23470
24453
  const bins = manifest.bins || manifest.binaries || [manifest.name || pkg];
23471
24454
  if (bins.includes(shimName)) {
23472
24455
  const kind = dir.includes("binaries") ? "binary" : dir.includes("runtimes") ? "runtime" : "agent";
@@ -23514,7 +24497,7 @@ async function cmdShims(args, flags) {
23514
24497
  const results = [];
23515
24498
  let hasIssues = false;
23516
24499
  for (const name of shimNames) {
23517
- const shimPath = import_path21.default.join(PATHS.bins, name);
24500
+ const shimPath = import_path23.default.join(PATHS.bins, name);
23518
24501
  const validation = validateShim(name);
23519
24502
  const type = getShimType(shimPath);
23520
24503
  const target = getShimTarget(name, shimPath, type);
@@ -23567,30 +24550,151 @@ ${valid} valid, ${broken} broken`);
23567
24550
  }
23568
24551
  if (subcommand === "fix") {
23569
24552
  console.log("\n\x1B[33mAttempting to fix broken shims...\x1B[0m\n");
23570
- const { installPackage: installPackage2 } = await Promise.resolve().then(() => (init_src3(), src_exports2));
23571
- const brokenPackages = /* @__PURE__ */ new Set();
23572
- results.forEach((r) => {
23573
- if (!r.valid && r.package) {
23574
- brokenPackages.add(r.package);
24553
+ const brokenWithPkg = results.filter((r) => !r.valid && r.package);
24554
+ const orphaned = results.filter((r) => !r.valid && !r.package);
24555
+ if (orphaned.length > 0) {
24556
+ console.log(`Removing ${orphaned.length} orphaned shims...`);
24557
+ for (const shim of orphaned) {
24558
+ const shimPath = import_path23.default.join(PATHS.bins, shim.name);
24559
+ try {
24560
+ import_fs26.default.unlinkSync(shimPath);
24561
+ console.log(` \x1B[32m\u2713\x1B[0m Removed ${shim.name}`);
24562
+ } catch (err) {
24563
+ console.log(` \x1B[31m\u2717\x1B[0m Failed to remove ${shim.name}: ${err.message}`);
24564
+ }
23575
24565
  }
23576
- });
23577
- if (brokenPackages.size === 0) {
24566
+ console.log("");
24567
+ }
24568
+ const brokenPackages = new Set(brokenWithPkg.map((r) => r.package));
24569
+ if (brokenPackages.size === 0 && orphaned.length === 0) {
23578
24570
  console.log("No broken shims to fix.");
23579
24571
  process.exit(0);
23580
24572
  }
23581
- for (const pkg of brokenPackages) {
23582
- console.log(`Reinstalling ${pkg}...`);
23583
- try {
23584
- await installPackage2(pkg, { force: true });
23585
- console.log(`\x1B[32m\u2713\x1B[0m Fixed ${pkg}`);
23586
- } catch (err) {
23587
- console.log(`\x1B[31m\u2717\x1B[0m Failed to fix ${pkg}: ${err.message}`);
24573
+ if (brokenPackages.size > 0) {
24574
+ const { installPackage: installPackage2 } = await Promise.resolve().then(() => (init_src3(), src_exports));
24575
+ for (const pkg of brokenPackages) {
24576
+ console.log(`Reinstalling ${pkg}...`);
24577
+ try {
24578
+ await installPackage2(pkg, { force: true });
24579
+ console.log(`\x1B[32m\u2713\x1B[0m Fixed ${pkg}`);
24580
+ } catch (err) {
24581
+ console.log(`\x1B[31m\u2717\x1B[0m Failed to fix ${pkg}: ${err.message}`);
24582
+ }
23588
24583
  }
23589
24584
  }
24585
+ console.log("\n\x1B[32m\u2713\x1B[0m Fix complete");
23590
24586
  }
23591
24587
  process.exit(hasIssues ? 1 : 0);
23592
24588
  }
23593
24589
 
24590
+ // src/commands/info.js
24591
+ var import_fs27 = __toESM(require("fs"), 1);
24592
+ var import_path24 = __toESM(require("path"), 1);
24593
+ init_src3();
24594
+ async function cmdInfo(args, flags) {
24595
+ const pkgId = args[0];
24596
+ if (!pkgId) {
24597
+ console.error("Usage: rudi info <package>");
24598
+ console.error("Example: rudi info npm:typescript");
24599
+ console.error(" rudi info binary:supabase");
24600
+ process.exit(1);
24601
+ }
24602
+ try {
24603
+ const [kind, name] = parsePackageId2(pkgId);
24604
+ const installPath = getPackagePath2(pkgId);
24605
+ if (!import_fs27.default.existsSync(installPath)) {
24606
+ console.error(`Package not installed: ${pkgId}`);
24607
+ process.exit(1);
24608
+ }
24609
+ const manifestPath = import_path24.default.join(installPath, "manifest.json");
24610
+ let manifest = null;
24611
+ if (import_fs27.default.existsSync(manifestPath)) {
24612
+ try {
24613
+ manifest = JSON.parse(import_fs27.default.readFileSync(manifestPath, "utf-8"));
24614
+ } catch {
24615
+ console.warn("Warning: Could not parse manifest.json");
24616
+ }
24617
+ }
24618
+ console.log(`
24619
+ Package: ${pkgId}`);
24620
+ console.log("\u2500".repeat(50));
24621
+ console.log(` Name: ${manifest?.name || name}`);
24622
+ console.log(` Kind: ${kind}`);
24623
+ console.log(` Version: ${manifest?.version || "unknown"}`);
24624
+ console.log(` Install Dir: ${installPath}`);
24625
+ const installType = manifest?.installType || (manifest?.npmPackage ? "npm" : manifest?.pipPackage ? "pip" : kind);
24626
+ console.log(` Install Type: ${installType}`);
24627
+ if (manifest?.source) {
24628
+ if (typeof manifest.source === "string") {
24629
+ console.log(` Source: ${manifest.source}`);
24630
+ } else {
24631
+ console.log(` Source: ${manifest.source.type || "unknown"}`);
24632
+ if (manifest.source.spec) {
24633
+ console.log(` Spec: ${manifest.source.spec}`);
24634
+ }
24635
+ }
24636
+ }
24637
+ if (manifest?.npmPackage) {
24638
+ console.log(` npm Package: ${manifest.npmPackage}`);
24639
+ }
24640
+ if (manifest?.pipPackage) {
24641
+ console.log(` pip Package: ${manifest.pipPackage}`);
24642
+ }
24643
+ if (manifest?.hasInstallScripts !== void 0) {
24644
+ console.log(` Has Install Scripts: ${manifest.hasInstallScripts ? "yes" : "no"}`);
24645
+ }
24646
+ if (manifest?.scriptsPolicy) {
24647
+ console.log(` Scripts Policy: ${manifest.scriptsPolicy}`);
24648
+ }
24649
+ if (manifest?.installedAt) {
24650
+ console.log(` Installed: ${new Date(manifest.installedAt).toLocaleString()}`);
24651
+ }
24652
+ const bins = manifest?.bins || manifest?.binaries || [];
24653
+ if (bins.length > 0) {
24654
+ console.log(`
24655
+ Binaries (${bins.length}):`);
24656
+ console.log("\u2500".repeat(50));
24657
+ for (const bin of bins) {
24658
+ const shimPath = import_path24.default.join(PATHS2.bins, bin);
24659
+ const validation = validateShim(bin);
24660
+ const ownership = getShimOwner(bin);
24661
+ let shimStatus = "\u2717 no shim";
24662
+ if (import_fs27.default.existsSync(shimPath)) {
24663
+ if (validation.valid) {
24664
+ shimStatus = `\u2713 ${validation.target}`;
24665
+ } else {
24666
+ shimStatus = `\u26A0 broken: ${validation.error}`;
24667
+ }
24668
+ }
24669
+ console.log(` ${bin}:`);
24670
+ console.log(` Shim: ${shimStatus}`);
24671
+ if (ownership) {
24672
+ const ownerMatch = ownership.owner === pkgId;
24673
+ const ownerStatus = ownerMatch ? "(this package)" : `(owned by ${ownership.owner})`;
24674
+ console.log(` Type: ${ownership.type} ${ownerStatus}`);
24675
+ }
24676
+ }
24677
+ } else {
24678
+ console.log(`
24679
+ Binaries: none`);
24680
+ }
24681
+ const lockName = name.replace(/\//g, "__").replace(/^@/, "");
24682
+ const lockDir = kind === "binary" ? "binaries" : kind === "npm" ? "npms" : kind + "s";
24683
+ const lockPath = import_path24.default.join(PATHS2.locks, lockDir, `${lockName}.lock.yaml`);
24684
+ if (import_fs27.default.existsSync(lockPath)) {
24685
+ console.log(`
24686
+ Lockfile: ${lockPath}`);
24687
+ }
24688
+ console.log("");
24689
+ } catch (error) {
24690
+ console.error(`Error: ${error.message}`);
24691
+ if (flags.verbose) {
24692
+ console.error(error.stack);
24693
+ }
24694
+ process.exit(1);
24695
+ }
24696
+ }
24697
+
23594
24698
  // src/index.js
23595
24699
  var VERSION = "2.0.0";
23596
24700
  async function main() {
@@ -23686,6 +24790,10 @@ async function main() {
23686
24790
  case "shims":
23687
24791
  await cmdShims(args, flags);
23688
24792
  break;
24793
+ case "pkg":
24794
+ case "package":
24795
+ await cmdInfo(args, flags);
24796
+ break;
23689
24797
  // Shortcuts for listing specific package types
23690
24798
  case "stacks":
23691
24799
  await cmdList(["stacks"], flags);