@nuucognition/flint-cli 0.5.5 → 0.5.6-dev.0

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.js CHANGED
@@ -1,5 +1,7 @@
1
1
  import {
2
2
  LiveSessionManager,
3
+ OBSIDIAN_REPO_URL,
4
+ OBSIDIAN_WINDOWS_REPO_URL,
3
5
  STANDARD_DIRECTORIES,
4
6
  TranscriptWatcher,
5
7
  addCodebaseReference,
@@ -121,7 +123,7 @@ import {
121
123
  updateSession,
122
124
  updateShards,
123
125
  updateSourceRepository
124
- } from "./chunk-XWUP7WHQ.js";
126
+ } from "./chunk-WMXC6KO6.js";
125
127
  import {
126
128
  cleanRegistryFile,
127
129
  findFlintByName,
@@ -132,7 +134,7 @@ import {
132
134
  registerFlintByPath,
133
135
  unregisterFlint,
134
136
  upsertFlintEntry
135
- } from "./chunk-C66KJDI7.js";
137
+ } from "./chunk-X6OG5PEE.js";
136
138
  import "./chunk-V7YA5RXL.js";
137
139
  import {
138
140
  generateSourceMeshExportMetadata,
@@ -148,7 +150,7 @@ import {
148
150
  resolveDocument,
149
151
  scanExportEligible,
150
152
  scanExports
151
- } from "./chunk-VAJMJ47E.js";
153
+ } from "./chunk-6MPRSFXI.js";
152
154
  import {
153
155
  addExportToConfig,
154
156
  addLatticeDeclaration,
@@ -170,6 +172,7 @@ import {
170
172
  hasFlintJson,
171
173
  hasFlintToml,
172
174
  isLocalShard,
175
+ parse,
173
176
  readFlintJson,
174
177
  readFlintToml,
175
178
  readLatticesState,
@@ -184,14 +187,227 @@ import {
184
187
  writeFlintJson,
185
188
  writeFlintToml
186
189
  } from "./chunk-CBGQBE6C.js";
190
+ import {
191
+ __commonJS,
192
+ __toESM
193
+ } from "./chunk-JSBRDJBE.js";
194
+
195
+ // ../../node_modules/.pnpm/balanced-match@1.0.2/node_modules/balanced-match/index.js
196
+ var require_balanced_match = __commonJS({
197
+ "../../node_modules/.pnpm/balanced-match@1.0.2/node_modules/balanced-match/index.js"(exports, module) {
198
+ "use strict";
199
+ module.exports = balanced;
200
+ function balanced(a, b, str) {
201
+ if (a instanceof RegExp) a = maybeMatch(a, str);
202
+ if (b instanceof RegExp) b = maybeMatch(b, str);
203
+ var r = range(a, b, str);
204
+ return r && {
205
+ start: r[0],
206
+ end: r[1],
207
+ pre: str.slice(0, r[0]),
208
+ body: str.slice(r[0] + a.length, r[1]),
209
+ post: str.slice(r[1] + b.length)
210
+ };
211
+ }
212
+ function maybeMatch(reg, str) {
213
+ var m = str.match(reg);
214
+ return m ? m[0] : null;
215
+ }
216
+ balanced.range = range;
217
+ function range(a, b, str) {
218
+ var begs, beg, left, right, result;
219
+ var ai = str.indexOf(a);
220
+ var bi = str.indexOf(b, ai + 1);
221
+ var i = ai;
222
+ if (ai >= 0 && bi > 0) {
223
+ if (a === b) {
224
+ return [ai, bi];
225
+ }
226
+ begs = [];
227
+ left = str.length;
228
+ while (i >= 0 && !result) {
229
+ if (i == ai) {
230
+ begs.push(i);
231
+ ai = str.indexOf(a, i + 1);
232
+ } else if (begs.length == 1) {
233
+ result = [begs.pop(), bi];
234
+ } else {
235
+ beg = begs.pop();
236
+ if (beg < left) {
237
+ left = beg;
238
+ right = bi;
239
+ }
240
+ bi = str.indexOf(b, i + 1);
241
+ }
242
+ i = ai < bi && ai >= 0 ? ai : bi;
243
+ }
244
+ if (begs.length) {
245
+ result = [left, right];
246
+ }
247
+ }
248
+ return result;
249
+ }
250
+ }
251
+ });
252
+
253
+ // ../../node_modules/.pnpm/brace-expansion@2.0.2/node_modules/brace-expansion/index.js
254
+ var require_brace_expansion = __commonJS({
255
+ "../../node_modules/.pnpm/brace-expansion@2.0.2/node_modules/brace-expansion/index.js"(exports, module) {
256
+ "use strict";
257
+ var balanced = require_balanced_match();
258
+ module.exports = expandTop;
259
+ var escSlash = "\0SLASH" + Math.random() + "\0";
260
+ var escOpen = "\0OPEN" + Math.random() + "\0";
261
+ var escClose = "\0CLOSE" + Math.random() + "\0";
262
+ var escComma = "\0COMMA" + Math.random() + "\0";
263
+ var escPeriod = "\0PERIOD" + Math.random() + "\0";
264
+ function numeric(str) {
265
+ return parseInt(str, 10) == str ? parseInt(str, 10) : str.charCodeAt(0);
266
+ }
267
+ function escapeBraces(str) {
268
+ return str.split("\\\\").join(escSlash).split("\\{").join(escOpen).split("\\}").join(escClose).split("\\,").join(escComma).split("\\.").join(escPeriod);
269
+ }
270
+ function unescapeBraces(str) {
271
+ return str.split(escSlash).join("\\").split(escOpen).join("{").split(escClose).join("}").split(escComma).join(",").split(escPeriod).join(".");
272
+ }
273
+ function parseCommaParts(str) {
274
+ if (!str)
275
+ return [""];
276
+ var parts = [];
277
+ var m = balanced("{", "}", str);
278
+ if (!m)
279
+ return str.split(",");
280
+ var pre = m.pre;
281
+ var body = m.body;
282
+ var post = m.post;
283
+ var p = pre.split(",");
284
+ p[p.length - 1] += "{" + body + "}";
285
+ var postParts = parseCommaParts(post);
286
+ if (post.length) {
287
+ p[p.length - 1] += postParts.shift();
288
+ p.push.apply(p, postParts);
289
+ }
290
+ parts.push.apply(parts, p);
291
+ return parts;
292
+ }
293
+ function expandTop(str) {
294
+ if (!str)
295
+ return [];
296
+ if (str.substr(0, 2) === "{}") {
297
+ str = "\\{\\}" + str.substr(2);
298
+ }
299
+ return expand2(escapeBraces(str), true).map(unescapeBraces);
300
+ }
301
+ function embrace(str) {
302
+ return "{" + str + "}";
303
+ }
304
+ function isPadded(el) {
305
+ return /^-?0\d/.test(el);
306
+ }
307
+ function lte(i, y) {
308
+ return i <= y;
309
+ }
310
+ function gte(i, y) {
311
+ return i >= y;
312
+ }
313
+ function expand2(str, isTop) {
314
+ var expansions = [];
315
+ var m = balanced("{", "}", str);
316
+ if (!m) return [str];
317
+ var pre = m.pre;
318
+ var post = m.post.length ? expand2(m.post, false) : [""];
319
+ if (/\$$/.test(m.pre)) {
320
+ for (var k = 0; k < post.length; k++) {
321
+ var expansion = pre + "{" + m.body + "}" + post[k];
322
+ expansions.push(expansion);
323
+ }
324
+ } else {
325
+ var isNumericSequence = /^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(m.body);
326
+ var isAlphaSequence = /^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(m.body);
327
+ var isSequence = isNumericSequence || isAlphaSequence;
328
+ var isOptions = m.body.indexOf(",") >= 0;
329
+ if (!isSequence && !isOptions) {
330
+ if (m.post.match(/,(?!,).*\}/)) {
331
+ str = m.pre + "{" + m.body + escClose + m.post;
332
+ return expand2(str);
333
+ }
334
+ return [str];
335
+ }
336
+ var n;
337
+ if (isSequence) {
338
+ n = m.body.split(/\.\./);
339
+ } else {
340
+ n = parseCommaParts(m.body);
341
+ if (n.length === 1) {
342
+ n = expand2(n[0], false).map(embrace);
343
+ if (n.length === 1) {
344
+ return post.map(function(p) {
345
+ return m.pre + n[0] + p;
346
+ });
347
+ }
348
+ }
349
+ }
350
+ var N;
351
+ if (isSequence) {
352
+ var x = numeric(n[0]);
353
+ var y = numeric(n[1]);
354
+ var width = Math.max(n[0].length, n[1].length);
355
+ var incr = n.length == 3 ? Math.abs(numeric(n[2])) : 1;
356
+ var test = lte;
357
+ var reverse = y < x;
358
+ if (reverse) {
359
+ incr *= -1;
360
+ test = gte;
361
+ }
362
+ var pad3 = n.some(isPadded);
363
+ N = [];
364
+ for (var i = x; test(i, y); i += incr) {
365
+ var c;
366
+ if (isAlphaSequence) {
367
+ c = String.fromCharCode(i);
368
+ if (c === "\\")
369
+ c = "";
370
+ } else {
371
+ c = String(i);
372
+ if (pad3) {
373
+ var need = width - c.length;
374
+ if (need > 0) {
375
+ var z = new Array(need + 1).join("0");
376
+ if (i < 0)
377
+ c = "-" + z + c.slice(1);
378
+ else
379
+ c = z + c;
380
+ }
381
+ }
382
+ }
383
+ N.push(c);
384
+ }
385
+ } else {
386
+ N = [];
387
+ for (var j = 0; j < n.length; j++) {
388
+ N.push.apply(N, expand2(n[j], false));
389
+ }
390
+ }
391
+ for (var j = 0; j < N.length; j++) {
392
+ for (var k = 0; k < post.length; k++) {
393
+ var expansion = pre + N[j] + post[k];
394
+ if (!isTop || isSequence || expansion)
395
+ expansions.push(expansion);
396
+ }
397
+ }
398
+ }
399
+ return expansions;
400
+ }
401
+ }
402
+ });
187
403
 
188
404
  // src/index.ts
189
- import { Command as Command37 } from "commander";
405
+ import { Command as Command38 } from "commander";
190
406
  import { readFileSync as readFileSync11, existsSync as existsSync15, cpSync, mkdirSync as mkdirSync5, readdirSync as readdirSync8 } from "fs";
191
407
  import { fileURLToPath as fileURLToPath4 } from "url";
192
- import { dirname as dirname4, join as join19 } from "path";
408
+ import { dirname as dirname4, join as join20 } from "path";
193
409
  import { homedir as homedir11 } from "os";
194
- import pc42 from "picocolors";
410
+ import pc43 from "picocolors";
195
411
 
196
412
  // ../../../main/packages/cli-core/dist/index.js
197
413
  import { homedir } from "os";
@@ -275,7 +491,7 @@ function skipVoid(str, ptr, banNewLines, banComments) {
275
491
  ptr++;
276
492
  return banComments || c !== "#" ? ptr : skipVoid(str, skipComment(str, ptr), banNewLines);
277
493
  }
278
- function skipUntil(str, ptr, sep, end, banNewLines = false) {
494
+ function skipUntil(str, ptr, sep2, end, banNewLines = false) {
279
495
  if (!end) {
280
496
  ptr = indexOfNewline(str, ptr);
281
497
  return ptr < 0 ? str.length : ptr;
@@ -284,7 +500,7 @@ function skipUntil(str, ptr, sep, end, banNewLines = false) {
284
500
  let c = str[i];
285
501
  if (c === "#") {
286
502
  i = indexOfNewline(str, i);
287
- } else if (c === sep) {
503
+ } else if (c === sep2) {
288
504
  return i + 1;
289
505
  } else if (c === end || banNewLines && (c === "\n" || c === "\r" && str[i + 1] === "\n")) {
290
506
  return i;
@@ -325,18 +541,18 @@ var TomlDate = class _TomlDate extends Date {
325
541
  let hasTime = true;
326
542
  let offset = "Z";
327
543
  if (typeof date === "string") {
328
- let match = date.match(DATE_TIME_RE);
329
- if (match) {
330
- if (!match[1]) {
544
+ let match2 = date.match(DATE_TIME_RE);
545
+ if (match2) {
546
+ if (!match2[1]) {
331
547
  hasDate = false;
332
548
  date = `0000-01-01T${date}`;
333
549
  }
334
- hasTime = !!match[2];
550
+ hasTime = !!match2[2];
335
551
  hasTime && date[10] === " " && (date = date.replace(" ", "T"));
336
- if (match[2] && +match[2] > 23) {
552
+ if (match2[2] && +match2[2] > 23) {
337
553
  date = "";
338
554
  } else {
339
- offset = match[3] || null;
555
+ offset = match2[3] || null;
340
556
  date = date.toUpperCase();
341
557
  if (!offset && hasTime)
342
558
  date += "Z";
@@ -820,7 +1036,7 @@ function peekTable(key, table, meta, type) {
820
1036
  }
821
1037
  return [k, t, state.c];
822
1038
  }
823
- function parse(toml, { maxDepth = 1e3, integersAsBigInt } = {}) {
1039
+ function parse2(toml, { maxDepth = 1e3, integersAsBigInt } = {}) {
824
1040
  let res = {};
825
1041
  let meta = {};
826
1042
  let tbl = res;
@@ -1189,8 +1405,8 @@ async function defaultBrowserId() {
1189
1405
  throw new Error("macOS only");
1190
1406
  }
1191
1407
  const { stdout } = await execFileAsync("defaults", ["read", "com.apple.LaunchServices/com.apple.launchservices.secure", "LSHandlers"]);
1192
- const match = /LSHandlerRoleAll = "(?!-)(?<id>[^"]+?)";\s+?LSHandlerURLScheme = (?:http|https);/.exec(stdout);
1193
- const browserId = match?.groups.id ?? "com.apple.Safari";
1408
+ const match2 = /LSHandlerRoleAll = "(?!-)(?<id>[^"]+?)";\s+?LSHandlerURLScheme = (?:http|https);/.exec(stdout);
1409
+ const browserId = match2?.groups.id ?? "com.apple.Safari";
1194
1410
  if (browserId === "com.apple.safari") {
1195
1411
  return "com.apple.Safari";
1196
1412
  }
@@ -1254,11 +1470,11 @@ async function defaultBrowser(_execFileAsync = execFileAsync3) {
1254
1470
  "/v",
1255
1471
  "ProgId"
1256
1472
  ]);
1257
- const match = /ProgId\s*REG_SZ\s*(?<id>\S+)/.exec(stdout);
1258
- if (!match) {
1473
+ const match2 = /ProgId\s*REG_SZ\s*(?<id>\S+)/.exec(stdout);
1474
+ if (!match2) {
1259
1475
  throw new UnknownBrowserError(`Cannot find Windows browser in stdout: ${JSON.stringify(stdout)}`);
1260
1476
  }
1261
- const { id } = match.groups;
1477
+ const { id } = match2.groups;
1262
1478
  const browser = windowsBrowserProgIds[id];
1263
1479
  if (!browser) {
1264
1480
  throw new UnknownBrowserError(`Unknown browser ID: ${id}`);
@@ -1566,10 +1782,10 @@ function normalizeRuntimeMode(input) {
1566
1782
  function authEnvForMode(mode) {
1567
1783
  return mode === "dev" ? "dev" : "prod";
1568
1784
  }
1569
- async function readConfigFile(path8) {
1785
+ async function readConfigFile(path10) {
1570
1786
  try {
1571
- const content = await fsReadFile(path8, "utf-8");
1572
- return parse(content);
1787
+ const content = await fsReadFile(path10, "utf-8");
1788
+ return parse2(content);
1573
1789
  } catch (error22) {
1574
1790
  if (error22.code === "ENOENT") {
1575
1791
  return null;
@@ -1577,10 +1793,10 @@ async function readConfigFile(path8) {
1577
1793
  throw error22;
1578
1794
  }
1579
1795
  }
1580
- function readConfigFileSync(path8) {
1796
+ function readConfigFileSync(path10) {
1581
1797
  try {
1582
- const content = fsReadFileSync(path8, "utf-8");
1583
- return parse(content);
1798
+ const content = fsReadFileSync(path10, "utf-8");
1799
+ return parse2(content);
1584
1800
  } catch (error22) {
1585
1801
  if (error22.code === "ENOENT") {
1586
1802
  return null;
@@ -1588,25 +1804,25 @@ function readConfigFileSync(path8) {
1588
1804
  throw error22;
1589
1805
  }
1590
1806
  }
1591
- async function writeConfigFile(path8, data) {
1592
- await mkdir(dirname(path8), { recursive: true });
1593
- await fsWriteFile(path8, `${stringify(data)}
1807
+ async function writeConfigFile(path10, data) {
1808
+ await mkdir(dirname(path10), { recursive: true });
1809
+ await fsWriteFile(path10, `${stringify(data)}
1594
1810
  `, "utf-8");
1595
1811
  }
1596
- async function setConfigField(path8, key, value) {
1597
- const existing = await readConfigFile(path8) ?? {};
1812
+ async function setConfigField(path10, key, value) {
1813
+ const existing = await readConfigFile(path10) ?? {};
1598
1814
  existing[key] = value;
1599
- await writeConfigFile(path8, existing);
1815
+ await writeConfigFile(path10, existing);
1600
1816
  }
1601
- async function setFeatureOverride(path8, featureId, enabled) {
1602
- const existing = await readConfigFile(path8) ?? {};
1817
+ async function setFeatureOverride(path10, featureId, enabled) {
1818
+ const existing = await readConfigFile(path10) ?? {};
1603
1819
  const features = existing.features && typeof existing.features === "object" && !Array.isArray(existing.features) ? { ...existing.features } : {};
1604
1820
  features[featureId] = enabled;
1605
1821
  existing.features = features;
1606
- await writeConfigFile(path8, existing);
1822
+ await writeConfigFile(path10, existing);
1607
1823
  }
1608
- async function removeFeatureOverride(path8, featureId) {
1609
- const existing = await readConfigFile(path8);
1824
+ async function removeFeatureOverride(path10, featureId) {
1825
+ const existing = await readConfigFile(path10);
1610
1826
  if (!existing) return;
1611
1827
  const features = existing.features;
1612
1828
  if (!features || typeof features !== "object" || Array.isArray(features)) {
@@ -1619,7 +1835,7 @@ async function removeFeatureOverride(path8, featureId) {
1619
1835
  } else {
1620
1836
  existing.features = next;
1621
1837
  }
1622
- await writeConfigFile(path8, existing);
1838
+ await writeConfigFile(path10, existing);
1623
1839
  }
1624
1840
  var CONFIG_FILENAME = "config.toml";
1625
1841
  function getConfigDir(cliname) {
@@ -1628,10 +1844,10 @@ function getConfigDir(cliname) {
1628
1844
  function getConfigPath(cliname) {
1629
1845
  return join(getConfigDir(cliname), CONFIG_FILENAME);
1630
1846
  }
1631
- function mergeDefaults(config, defaults) {
1632
- if (!defaults) return config;
1847
+ function mergeDefaults(config, defaults2) {
1848
+ if (!defaults2) return config;
1633
1849
  return {
1634
- ...defaults,
1850
+ ...defaults2,
1635
1851
  ...config
1636
1852
  };
1637
1853
  }
@@ -1828,9 +2044,9 @@ async function loadAuth(env = "prod") {
1828
2044
  function loadAuthSync(env = "prod") {
1829
2045
  try {
1830
2046
  ensureNuuDirSync();
1831
- const path8 = authPath(env);
1832
- if (!existsSync(path8)) return null;
1833
- return normalizeCredentials(JSON.parse(readFileSync(path8, "utf-8")));
2047
+ const path10 = authPath(env);
2048
+ if (!existsSync(path10)) return null;
2049
+ return normalizeCredentials(JSON.parse(readFileSync(path10, "utf-8")));
1834
2050
  } catch {
1835
2051
  return null;
1836
2052
  }
@@ -2319,6 +2535,7 @@ var FEATURES = createFeatureRegistry([
2319
2535
  { id: "code", tier: "prod", type: "command", description: "Launch AI coding agents", requiresAuth: false },
2320
2536
  { id: "orb", tier: "prod", type: "command", description: "Orbh meta-harness agent management", requiresAuth: false },
2321
2537
  { id: "server", tier: "prod", type: "command", description: "Flint runtime server", requiresAuth: false },
2538
+ { id: "steel", tier: "prod", type: "command", description: "Manage Steel UI state", requiresAuth: false },
2322
2539
  { id: "runtime", tier: "dev", type: "command", description: "Flint runtime management", requiresAuth: false },
2323
2540
  { id: "obsidian.push", tier: "dev", type: "function", description: "Push obsidian config changes to remote", requiresAuth: false },
2324
2541
  { id: "agent.start", tier: "dev", type: "function", description: "Start AI agent session", requiresAuth: false }
@@ -2395,25 +2612,25 @@ function createProgressDisplay(label, total) {
2395
2612
  import { homedir as homedir3 } from "os";
2396
2613
  import { access } from "fs/promises";
2397
2614
  import { createInterface } from "readline";
2398
- function abbreviatePath(path8) {
2615
+ function abbreviatePath(path10) {
2399
2616
  const home = homedir3();
2400
- if (path8.startsWith(home)) {
2401
- return path8.replace(home, "~");
2617
+ if (path10.startsWith(home)) {
2618
+ return path10.replace(home, "~");
2402
2619
  }
2403
- return path8;
2620
+ return path10;
2404
2621
  }
2405
- function expandPath(path8) {
2406
- if (path8.startsWith("~/")) {
2407
- return path8.replace("~", homedir3());
2622
+ function expandPath(path10) {
2623
+ if (path10.startsWith("~/")) {
2624
+ return path10.replace("~", homedir3());
2408
2625
  }
2409
- return path8;
2626
+ return path10;
2410
2627
  }
2411
2628
  function padEnd(str, length) {
2412
2629
  return str.padEnd(length);
2413
2630
  }
2414
- async function checkPathExists(path8) {
2631
+ async function checkPathExists(path10) {
2415
2632
  try {
2416
- await access(path8);
2633
+ await access(path10);
2417
2634
  return true;
2418
2635
  } catch {
2419
2636
  return false;
@@ -2664,12 +2881,12 @@ function resolvePath(flint, fullPath) {
2664
2881
  }
2665
2882
  function printFlint(flint, opts) {
2666
2883
  const { nameColWidth, showStatus, fullPath, indent = " " } = opts;
2667
- const path8 = resolvePath(flint, fullPath);
2884
+ const path10 = resolvePath(flint, fullPath);
2668
2885
  const isBroken = showStatus && !flint.valid;
2669
2886
  const tags = formatTags(flint.tags);
2670
2887
  const nameCell = tags ? `${pc7.bold(flint.name)} ${tags}` : pc7.bold(flint.name);
2671
2888
  const status = showStatus ? statusBadge(flint) + " " : "";
2672
- const pathColor = isBroken ? pc7.red(path8) : pc7.dim(path8);
2889
+ const pathColor = isBroken ? pc7.red(path10) : pc7.dim(path10);
2673
2890
  console.log(`${indent}${pad(nameCell, nameColWidth)}${status}${pathColor}`);
2674
2891
  if (flint.description) {
2675
2892
  console.log(`${indent} ${pc7.dim(truncate(flint.description, 65))}`);
@@ -2677,10 +2894,10 @@ function printFlint(flint, opts) {
2677
2894
  }
2678
2895
  function printGroupRow(flint, opts) {
2679
2896
  const { nameColWidth, showStatus, fullPath } = opts;
2680
- const path8 = resolvePath(flint, fullPath);
2897
+ const path10 = resolvePath(flint, fullPath);
2681
2898
  const isBroken = showStatus && !flint.valid;
2682
2899
  const status = showStatus ? statusBadge(flint) + " " : "";
2683
- const pathColor = isBroken ? pc7.red(path8) : pc7.dim(path8);
2900
+ const pathColor = isBroken ? pc7.red(path10) : pc7.dim(path10);
2684
2901
  console.log(` ${pad(flint.name, nameColWidth)}${status}${pathColor}`);
2685
2902
  }
2686
2903
  function measureNameCol(flints) {
@@ -3208,9 +3425,9 @@ Uninstalled ${pc8.bold(result.name)}`));
3208
3425
  if (!existsSync3(gitDir)) continue;
3209
3426
  try {
3210
3427
  const url = execSync6("git remote get-url origin", { cwd: shardPath, encoding: "utf-8" }).trim();
3211
- const match = url.match(/(?:github\.com[/:])([\w.-]+\/[\w.-]+?)(?:\.git)?$/);
3212
- if (match) {
3213
- gitRemotes.set(shard.name, match[1]);
3428
+ const match2 = url.match(/(?:github\.com[/:])([\w.-]+\/[\w.-]+?)(?:\.git)?$/);
3429
+ if (match2) {
3430
+ gitRemotes.set(shard.name, match2[1]);
3214
3431
  }
3215
3432
  } catch {
3216
3433
  }
@@ -3421,8 +3638,8 @@ Cloned ${pc8.bold(result.name)} for development`));
3421
3638
  try {
3422
3639
  const flintPath = await resolveFlint(options.path);
3423
3640
  const installed = await getInstalledShardsWithVersions(flintPath);
3424
- const match = resolveInstalledShardInfo(installed, name);
3425
- if (!match) {
3641
+ const match2 = resolveInstalledShardInfo(installed, name);
3642
+ if (!match2) {
3426
3643
  console.error(pc8.red(`
3427
3644
  Shard "${name}" not found.`));
3428
3645
  console.log(pc8.dim(` Run ${pc8.cyan("flint shard list")} to see installed shards.`));
@@ -3430,11 +3647,11 @@ Shard "${name}" not found.`));
3430
3647
  return;
3431
3648
  }
3432
3649
  const declarations = await getShardDeclarations(flintPath);
3433
- const decl = declarations[match.name];
3650
+ const decl = declarations[match2.name];
3434
3651
  const source = decl?.source || "";
3435
3652
  console.log(pc8.dim(`
3436
- Transitioning ${match.folderName} to dev mode...`));
3437
- const result = await editShard(flintPath, match.folderName, source);
3653
+ Transitioning ${match2.folderName} to dev mode...`));
3654
+ const result = await editShard(flintPath, match2.folderName, source);
3438
3655
  await updateGitignore(flintPath);
3439
3656
  console.log(pc8.green(`
3440
3657
  ${pc8.bold(result.name)} is now in dev mode`));
@@ -3451,8 +3668,8 @@ ${pc8.bold(result.name)} is now in dev mode`));
3451
3668
  try {
3452
3669
  const flintPath = await resolveFlint(options.path);
3453
3670
  const installed = await getInstalledShardsWithVersions(flintPath);
3454
- const match = resolveInstalledShardInfo(installed, name);
3455
- if (!match) {
3671
+ const match2 = resolveInstalledShardInfo(installed, name);
3672
+ if (!match2) {
3456
3673
  console.error(pc8.red(`
3457
3674
  Shard "${name}" not found.`));
3458
3675
  console.log(pc8.dim(` Run ${pc8.cyan("flint shard list")} to see installed shards.`));
@@ -3460,8 +3677,8 @@ Shard "${name}" not found.`));
3460
3677
  return;
3461
3678
  }
3462
3679
  console.log(pc8.dim(`
3463
- Freezing ${match.folderName}...`));
3464
- const result = await freezeShard(flintPath, match.folderName);
3680
+ Freezing ${match2.folderName}...`));
3681
+ const result = await freezeShard(flintPath, match2.folderName);
3465
3682
  await updateGitignore(flintPath);
3466
3683
  console.log(pc8.green(`
3467
3684
  ${pc8.bold(result.name)} is now a normal shard`));
@@ -3478,17 +3695,17 @@ ${pc8.bold(result.name)} is now a normal shard`));
3478
3695
  try {
3479
3696
  const flintPath = await resolveFlint(options.path);
3480
3697
  const installed = await getInstalledShardsWithVersions(flintPath);
3481
- const match = resolveInstalledShardInfo(installed, name);
3482
- if (!match) {
3698
+ const match2 = resolveInstalledShardInfo(installed, name);
3699
+ if (!match2) {
3483
3700
  console.error(pc8.red(`
3484
3701
  Shard "${name}" not found.`));
3485
3702
  console.log(pc8.dim(` Run ${pc8.cyan("flint shard list")} to see installed shards.`));
3486
3703
  console.log();
3487
3704
  return;
3488
3705
  }
3489
- const result = await addShardGitRemote(flintPath, match.folderName, url);
3706
+ const result = await addShardGitRemote(flintPath, match2.folderName, url);
3490
3707
  console.log(pc8.green(`
3491
- Remote added to ${pc8.bold(match.folderName)}`));
3708
+ Remote added to ${pc8.bold(match2.folderName)}`));
3492
3709
  console.log(pc8.dim(` Remote: origin \u2192 ${url}`));
3493
3710
  console.log(pc8.dim(` Source: ${result.ownerRepo}`));
3494
3711
  console.log();
@@ -3614,15 +3831,15 @@ Shard not found: "${identifier}"`));
3614
3831
  const installed = await getInstalledShardsWithVersions(flintPath);
3615
3832
  const targets = [];
3616
3833
  if (name) {
3617
- const match = resolveInstalledShardInfo(installed, name);
3618
- if (!match) {
3834
+ const match2 = resolveInstalledShardInfo(installed, name);
3835
+ if (!match2) {
3619
3836
  console.error(pc8.red(`
3620
3837
  Shard "${name}" not found.`));
3621
3838
  console.log(pc8.dim(` Run ${pc8.cyan("flint shard list")} to see installed shards.`));
3622
3839
  console.log();
3623
3840
  return;
3624
3841
  }
3625
- targets.push(match);
3842
+ targets.push(match2);
3626
3843
  } else {
3627
3844
  for (const s of installed) {
3628
3845
  targets.push({ folderName: s.folderName });
@@ -3749,8 +3966,8 @@ Reinstalling ${shorthand}...
3749
3966
  const { execSync: execSync6 } = await import("child_process");
3750
3967
  const flintPath = await resolveFlint(options.path);
3751
3968
  const installed = await getInstalledShardsWithVersions(flintPath);
3752
- const match = resolveInstalledShardInfo(installed, name);
3753
- if (!match) {
3969
+ const match2 = resolveInstalledShardInfo(installed, name);
3970
+ if (!match2) {
3754
3971
  console.error(pc8.red(`
3755
3972
  Shard "${name}" not found.`));
3756
3973
  console.log(pc8.dim(` Run ${pc8.cyan("flint shard list")} to see installed shards.`));
@@ -3758,28 +3975,28 @@ Shard "${name}" not found.`));
3758
3975
  return;
3759
3976
  }
3760
3977
  const declarations = await getShardDeclarations(flintPath);
3761
- const declaration = declarations[match.name];
3978
+ const declaration = declarations[match2.name];
3762
3979
  const gitInitMode = declaration ? resolveShardMode(declaration) : void 0;
3763
3980
  if (gitInitMode === "custom") {
3764
3981
  console.error(pc8.red(`
3765
- "${match.folderName}" is a custom shard. Custom shards cannot have git remotes.`));
3982
+ "${match2.folderName}" is a custom shard. Custom shards cannot have git remotes.`));
3766
3983
  console.log();
3767
3984
  return;
3768
3985
  }
3769
3986
  if (gitInitMode !== "dev") {
3770
3987
  console.error(pc8.red(`
3771
- "${match.folderName}" is not a dev shard.`));
3988
+ "${match2.folderName}" is not a dev shard.`));
3772
3989
  console.log();
3773
3990
  return;
3774
3991
  }
3775
- const shardPath = join5(flintPath, "Shards", match.folderName);
3992
+ const shardPath = join5(flintPath, "Shards", match2.folderName);
3776
3993
  const gitDir = join5(shardPath, ".git");
3777
3994
  const hasGit = existsSync3(gitDir);
3778
3995
  if (hasGit) {
3779
3996
  try {
3780
3997
  const existing = execSync6("git remote get-url origin", { cwd: shardPath, stdio: "pipe" }).toString().trim();
3781
3998
  console.error(pc8.red(`
3782
- "${match.folderName}" already has a remote: ${existing}`));
3999
+ "${match2.folderName}" already has a remote: ${existing}`));
3783
4000
  console.log(pc8.dim(` Use ${pc8.cyan("flint shard push")} instead.`));
3784
4001
  console.log();
3785
4002
  return;
@@ -3787,7 +4004,7 @@ Shard "${name}" not found.`));
3787
4004
  }
3788
4005
  }
3789
4006
  console.log(pc8.bold(`
3790
- Initializing ${match.folderName}...
4007
+ Initializing ${match2.folderName}...
3791
4008
  `));
3792
4009
  if (!hasGit) {
3793
4010
  execSync6("git init", { cwd: shardPath, stdio: "pipe" });
@@ -3798,7 +4015,7 @@ Initializing ${match.folderName}...
3798
4015
  execSync6('git commit -m "initial commit"', { cwd: shardPath, stdio: "pipe" });
3799
4016
  execSync6("git push -u origin main", { cwd: shardPath, stdio: "inherit" });
3800
4017
  console.log(pc8.green(`
3801
- ${pc8.bold(match.folderName)} pushed to ${pc8.dim(url)}`));
4018
+ ${pc8.bold(match2.folderName)} pushed to ${pc8.dim(url)}`));
3802
4019
  console.log();
3803
4020
  } catch (err) {
3804
4021
  handleError(err);
@@ -3810,8 +4027,8 @@ Initializing ${match.folderName}...
3810
4027
  const { execSync: execSync6 } = await import("child_process");
3811
4028
  const flintPath = await resolveFlint(options.path);
3812
4029
  const installed = await getInstalledShardsWithVersions(flintPath);
3813
- const match = resolveInstalledShardInfo(installed, name);
3814
- if (!match) {
4030
+ const match2 = resolveInstalledShardInfo(installed, name);
4031
+ if (!match2) {
3815
4032
  console.error(pc8.red(`
3816
4033
  Shard "${name}" not found.`));
3817
4034
  console.log(pc8.dim(` Run ${pc8.cyan("flint shard list")} to see installed shards.`));
@@ -3819,26 +4036,26 @@ Shard "${name}" not found.`));
3819
4036
  return;
3820
4037
  }
3821
4038
  const declarations = await getShardDeclarations(flintPath);
3822
- const declaration = declarations[match.name];
4039
+ const declaration = declarations[match2.name];
3823
4040
  const shardMode = declaration ? resolveShardMode(declaration) : void 0;
3824
4041
  if (shardMode === "custom") {
3825
4042
  console.error(pc8.red(`
3826
- "${match.folderName}" is a custom shard. Custom shards are workspace-specific and cannot be pushed.`));
4043
+ "${match2.folderName}" is a custom shard. Custom shards are workspace-specific and cannot be pushed.`));
3827
4044
  console.log();
3828
4045
  return;
3829
4046
  }
3830
4047
  if (shardMode !== "dev") {
3831
4048
  console.error(pc8.red(`
3832
- "${match.folderName}" is not a dev shard. Only dev shards can be pushed.`));
4049
+ "${match2.folderName}" is not a dev shard. Only dev shards can be pushed.`));
3833
4050
  console.log();
3834
4051
  return;
3835
4052
  }
3836
- const shardPath = join5(flintPath, "Shards", match.folderName);
4053
+ const shardPath = join5(flintPath, "Shards", match2.folderName);
3837
4054
  const gitDir = join5(shardPath, ".git");
3838
4055
  if (!existsSync3(gitDir)) {
3839
4056
  console.error(pc8.red(`
3840
- "${match.folderName}" has no git repo. Initialize one first:`));
3841
- console.log(pc8.dim(` cd "Shards/${match.folderName}" && git init && git remote add origin <url>`));
4057
+ "${match2.folderName}" has no git repo. Initialize one first:`));
4058
+ console.log(pc8.dim(` cd "Shards/${match2.folderName}" && git init && git remote add origin <url>`));
3842
4059
  console.log();
3843
4060
  return;
3844
4061
  }
@@ -3848,7 +4065,7 @@ Shard "${name}" not found.`));
3848
4065
  const unpushed = execSync6("git log @{u}..HEAD --oneline", { cwd: shardPath, encoding: "utf-8" }).trim();
3849
4066
  if (unpushed) {
3850
4067
  console.log(pc8.bold(`
3851
- Pushing ${match.folderName}...
4068
+ Pushing ${match2.folderName}...
3852
4069
  `));
3853
4070
  execSync6("git push", { cwd: shardPath, stdio: "inherit" });
3854
4071
  console.log(pc8.green(`
@@ -3859,7 +4076,7 @@ Pushing ${match.folderName}...
3859
4076
  } catch {
3860
4077
  }
3861
4078
  console.log(pc8.dim(`
3862
- No changes to push in "${match.folderName}".`));
4079
+ No changes to push in "${match2.folderName}".`));
3863
4080
  console.log();
3864
4081
  return;
3865
4082
  }
@@ -3872,9 +4089,9 @@ Invalid bump level "${level}". Use: patch, minor, or major.`));
3872
4089
  console.log();
3873
4090
  return;
3874
4091
  }
3875
- const { readFile: readFile9, writeFile: writeFile7 } = await import("fs/promises");
4092
+ const { readFile: readFile10, writeFile: writeFile7 } = await import("fs/promises");
3876
4093
  const yamlPath = join5(shardPath, "shard.yaml");
3877
- const yamlContent = await readFile9(yamlPath, "utf-8");
4094
+ const yamlContent = await readFile10(yamlPath, "utf-8");
3878
4095
  const versionMatch = yamlContent.match(/^version:\s*"?(\d+)\.(\d+)\.(\d+)"?/m);
3879
4096
  if (!versionMatch) {
3880
4097
  console.error(pc8.red(`
@@ -3889,10 +4106,10 @@ Could not parse version from shard.yaml.`));
3889
4106
  const updatedYaml = yamlContent.replace(/^version:\s*.+$/m, `version: "${bumpedVersion}"`);
3890
4107
  await writeFile7(yamlPath, updatedYaml, "utf-8");
3891
4108
  }
3892
- const baseMessage = options.message || `update ${match.folderName.replace(/^\(Dev\)\s*/, "")} shard`;
4109
+ const baseMessage = options.message || `update ${match2.folderName.replace(/^\(Dev\)\s*/, "")} shard`;
3893
4110
  const message = bumpedVersion ? `v${bumpedVersion} ${baseMessage}` : baseMessage;
3894
4111
  console.log(pc8.bold(`
3895
- Pushing ${match.folderName}...
4112
+ Pushing ${match2.folderName}...
3896
4113
  `));
3897
4114
  execSync6("git add -A", { cwd: shardPath, stdio: "pipe" });
3898
4115
  execSync6(`git commit -m "${message.replace(/"/g, '\\"')}"`, { cwd: shardPath, stdio: "pipe" });
@@ -3903,7 +4120,7 @@ Pushing ${match.folderName}...
3903
4120
  execSync6(`git push -u origin ${branch}`, { cwd: shardPath, stdio: "inherit" });
3904
4121
  }
3905
4122
  console.log(pc8.green(`
3906
- ${pc8.bold(match.folderName)} pushed.`));
4123
+ ${pc8.bold(match2.folderName)} pushed.`));
3907
4124
  console.log(pc8.dim(` ${message}`));
3908
4125
  console.log();
3909
4126
  } catch (err) {
@@ -3924,15 +4141,15 @@ Pushing ${match.folderName}...
3924
4141
  try {
3925
4142
  const flintPath = await resolveFlint(options.path);
3926
4143
  const installed = await getInstalledShardsWithVersions(flintPath);
3927
- const match = resolveInstalledShardInfo(installed, name);
3928
- if (!match) {
4144
+ const match2 = resolveInstalledShardInfo(installed, name);
4145
+ if (!match2) {
3929
4146
  console.error(pc8.red(`
3930
4147
  Shard "${name}" not found.`));
3931
4148
  console.log(pc8.dim(` Run ${pc8.cyan("flint shard list")} to see installed shards.`));
3932
4149
  console.log();
3933
4150
  process.exit(1);
3934
4151
  }
3935
- const shardPath = join5(flintPath, "Shards", match.folderName);
4152
+ const shardPath = join5(flintPath, "Shards", match2.folderName);
3936
4153
  const detail2 = await getShardInfo(flintPath, name);
3937
4154
  if (!detail2) {
3938
4155
  console.error(pc8.red(`
@@ -3940,7 +4157,7 @@ Cannot read shard info for "${name}".`));
3940
4157
  process.exit(1);
3941
4158
  }
3942
4159
  const declarations = await getShardDeclarations(flintPath);
3943
- const declaration = declarations[match.name];
4160
+ const declaration = declarations[match2.name];
3944
4161
  let repo = "";
3945
4162
  if (declaration?.source) {
3946
4163
  const parsed = parseShardSource(declaration.source);
@@ -4969,11 +5186,12 @@ var REQUIRED_DIRS = [
4969
5186
  "Exports",
4970
5187
  "Workspace",
4971
5188
  "Workspace/Bench",
4972
- ".flint"
5189
+ ".flint",
5190
+ ".steel"
4973
5191
  ];
4974
- async function exists(path8) {
5192
+ async function exists(path10) {
4975
5193
  try {
4976
- await access2(path8);
5194
+ await access2(path10);
4977
5195
  return true;
4978
5196
  } catch {
4979
5197
  return false;
@@ -5198,9 +5416,9 @@ import pc12 from "picocolors";
5198
5416
  import { readFile as readFile4, stat } from "fs/promises";
5199
5417
  import { join as join7, basename as basename2 } from "path";
5200
5418
  import { createInterface as createInterface2 } from "readline";
5201
- async function exists2(path8) {
5419
+ async function exists2(path10) {
5202
5420
  try {
5203
- await stat(path8);
5421
+ await stat(path10);
5204
5422
  return true;
5205
5423
  } catch {
5206
5424
  return false;
@@ -5494,17 +5712,17 @@ import { resolve as resolve2 } from "path";
5494
5712
  import { platform as platform3 } from "os";
5495
5713
  import pc13 from "picocolors";
5496
5714
  var execAsync2 = promisify7(exec2);
5497
- async function openInObsidian(path8) {
5715
+ async function openInObsidian(path10) {
5498
5716
  const os2 = platform3();
5499
5717
  if (os2 === "darwin") {
5500
- await execAsync2(`open -a "Obsidian" "${path8}"`);
5718
+ await execAsync2(`open -a "Obsidian" "${path10}"`);
5501
5719
  } else if (os2 === "win32") {
5502
- await execAsync2(`start "" "Obsidian" "${path8}"`);
5720
+ await execAsync2(`start "" "Obsidian" "${path10}"`);
5503
5721
  } else {
5504
5722
  try {
5505
- await execAsync2(`obsidian "${path8}"`);
5723
+ await execAsync2(`obsidian "${path10}"`);
5506
5724
  } catch {
5507
- await execAsync2(`xdg-open "${path8}"`);
5725
+ await execAsync2(`xdg-open "${path10}"`);
5508
5726
  }
5509
5727
  }
5510
5728
  }
@@ -6445,7 +6663,10 @@ import pc18 from "picocolors";
6445
6663
  import { execSync as execSync2, spawnSync as spawnSync2 } from "child_process";
6446
6664
  import { join as join8 } from "path";
6447
6665
  import { stat as stat2, rm as rm2 } from "fs/promises";
6448
- var OBSIDIAN_REPO_URL = "https://github.com/NUU-Cognition/flint-dot-obsidian.git";
6666
+ import { platform as platform4 } from "os";
6667
+ function getExpectedRepoUrl() {
6668
+ return platform4() === "win32" ? OBSIDIAN_WINDOWS_REPO_URL : OBSIDIAN_REPO_URL;
6669
+ }
6449
6670
  var obsidianCommand = new Command15("obsidian").description("Manage .obsidian configuration").option("-p, --path <dir>", "Path to flint (default: auto-detect)");
6450
6671
  obsidianCommand.command("update").description("Force pull latest .obsidian from remote (discards local changes)").action(async () => {
6451
6672
  const options = obsidianCommand.opts();
@@ -6462,11 +6683,20 @@ obsidianCommand.command("update").description("Force pull latest .obsidian from
6462
6683
  console.log(pc18.dim("Run `flint init` to create a new flint with .obsidian."));
6463
6684
  process.exit(1);
6464
6685
  }
6465
- console.log(pc18.dim("Fetching latest from remote..."));
6466
6686
  try {
6467
- execSync2("git fetch origin", { cwd: obsidianDir, stdio: "pipe" });
6468
- execSync2("git reset --hard origin/main", { cwd: obsidianDir, stdio: "pipe" });
6469
- console.log(pc18.green("Updated .obsidian to latest from remote."));
6687
+ const expectedUrl = getExpectedRepoUrl();
6688
+ const currentUrl = execSync2("git remote get-url origin", { cwd: obsidianDir, encoding: "utf-8" }).trim();
6689
+ if (currentUrl !== expectedUrl) {
6690
+ console.log(pc18.dim("Detected wrong platform repo. Re-cloning with correct one..."));
6691
+ await rm2(obsidianDir, { recursive: true, force: true });
6692
+ await cloneObsidian(flintPath);
6693
+ console.log(pc18.green("Re-cloned .obsidian with correct platform repo."));
6694
+ } else {
6695
+ console.log(pc18.dim("Fetching latest from remote..."));
6696
+ execSync2("git fetch origin", { cwd: obsidianDir, stdio: "pipe" });
6697
+ execSync2("git reset --hard origin/main", { cwd: obsidianDir, stdio: "pipe" });
6698
+ console.log(pc18.green("Updated .obsidian to latest from remote."));
6699
+ }
6470
6700
  } catch (err) {
6471
6701
  const message = err instanceof Error ? err.message : String(err);
6472
6702
  console.error(pc18.red(`Error updating .obsidian: ${message}`));
@@ -6519,25 +6749,25 @@ obsidianCommand.command("reset").description("Delete and re-clone .obsidian from
6519
6749
  process.exit(1);
6520
6750
  }
6521
6751
  const obsidianDir = join8(flintPath, ".obsidian");
6522
- let exists5 = false;
6752
+ let exists6 = false;
6523
6753
  try {
6524
6754
  await stat2(obsidianDir);
6525
- exists5 = true;
6755
+ exists6 = true;
6526
6756
  } catch {
6527
6757
  }
6528
- if (exists5 && !cmdOptions.force) {
6758
+ if (exists6 && !cmdOptions.force) {
6529
6759
  console.log(pc18.yellow("Warning: This will delete your current .obsidian folder and re-clone from the template repo."));
6530
6760
  console.log(pc18.yellow("Any local changes will be lost."));
6531
6761
  console.log(pc18.dim("\nUse --force to skip this confirmation."));
6532
6762
  process.exit(1);
6533
6763
  }
6534
6764
  try {
6535
- if (exists5) {
6765
+ if (exists6) {
6536
6766
  console.log(pc18.dim("Removing existing .obsidian..."));
6537
6767
  await rm2(obsidianDir, { recursive: true, force: true });
6538
6768
  }
6539
6769
  console.log(pc18.dim("Cloning .obsidian from template repo..."));
6540
- execSync2(`git clone ${OBSIDIAN_REPO_URL} "${obsidianDir}"`, { stdio: "pipe" });
6770
+ await cloneObsidian(flintPath);
6541
6771
  console.log(pc18.green("Reset .obsidian to fresh state from template repo."));
6542
6772
  } catch (err) {
6543
6773
  const message = err instanceof Error ? err.message : String(err);
@@ -7009,7 +7239,7 @@ repoCommand.command("add").description("Add a plate from a git repo").argument("
7009
7239
  getPlateDeclaration,
7010
7240
  nameFormats,
7011
7241
  updateGitignore: updateGitignore2
7012
- } = await import("./dist-RGQKIZQW.js");
7242
+ } = await import("./dist-EAYA2DAP.js");
7013
7243
  const { proper, slug } = nameFormats(name);
7014
7244
  const existing = await getPlateDeclaration(flintPath, slug);
7015
7245
  if (existing) {
@@ -7021,7 +7251,7 @@ repoCommand.command("add").description("Add a plate from a git repo").argument("
7021
7251
  Cloning ${url}...`));
7022
7252
  await clonePlateFromRepo(flintPath, slug, url, platePath);
7023
7253
  await addPlateDeclaration(flintPath, slug, platePath, { title: proper });
7024
- const { setPlateRepo } = await import("./dist-RGQKIZQW.js");
7254
+ const { setPlateRepo } = await import("./dist-EAYA2DAP.js");
7025
7255
  await setPlateRepo(flintPath, slug, url);
7026
7256
  await updateGitignore2(flintPath);
7027
7257
  console.log(pc22.green(`
@@ -7039,9 +7269,9 @@ Added plate: ${pc22.bold(proper)}`));
7039
7269
  repoCommand.command("remove").description("Remove a repo-sourced plate").argument("<name>", "Plate declaration name or slug").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (name, options) => {
7040
7270
  try {
7041
7271
  const flintPath = await resolveFlintPath2(options.path);
7042
- const { removePlateDeclaration, updateGitignore: updateGitignore2 } = await import("./dist-RGQKIZQW.js");
7043
- const { rm: rm5, stat: stat11 } = await import("fs/promises");
7044
- const { join: join20 } = await import("path");
7272
+ const { removePlateDeclaration, updateGitignore: updateGitignore2 } = await import("./dist-EAYA2DAP.js");
7273
+ const { rm: rm6, stat: stat11 } = await import("fs/promises");
7274
+ const { join: join21 } = await import("path");
7045
7275
  const plate = await getPlate(flintPath, name);
7046
7276
  if (!plate) {
7047
7277
  console.error(pc22.red(`Error: Plate "${name}" not found.`));
@@ -7049,7 +7279,7 @@ repoCommand.command("remove").description("Remove a repo-sourced plate").argumen
7049
7279
  }
7050
7280
  try {
7051
7281
  await stat11(plate.path);
7052
- await rm5(plate.path, { recursive: true, force: true });
7282
+ await rm6(plate.path, { recursive: true, force: true });
7053
7283
  } catch {
7054
7284
  }
7055
7285
  await removePlateDeclaration(flintPath, plate.declarationName);
@@ -7073,11 +7303,11 @@ plateCommand.command("install").description("Install a Plate from a git repo URL
7073
7303
  readPlateManifest,
7074
7304
  setPlateRepo,
7075
7305
  updateGitignore: updateGitignore2
7076
- } = await import("./dist-RGQKIZQW.js");
7077
- const { join: join20 } = await import("path");
7078
- const { mkdtemp: mkdtemp2, rm: rm5, rename: rename2 } = await import("fs/promises");
7306
+ } = await import("./dist-EAYA2DAP.js");
7307
+ const { join: join21 } = await import("path");
7308
+ const { mkdtemp: mkdtemp2, rm: rm6, rename: rename3 } = await import("fs/promises");
7079
7309
  const { tmpdir: tmpdir2 } = await import("os");
7080
- const tmpDir = await mkdtemp2(join20(tmpdir2(), "flint-plate-"));
7310
+ const tmpDir = await mkdtemp2(join21(tmpdir2(), "flint-plate-"));
7081
7311
  console.log(pc22.dim(`
7082
7312
  Cloning ${url}...`));
7083
7313
  try {
@@ -7085,7 +7315,7 @@ Cloning ${url}...`));
7085
7315
  } catch {
7086
7316
  const { execSync: execSync6 } = await import("child_process");
7087
7317
  execSync6(`git clone --depth 1 "${url}" "${tmpDir}"`, { timeout: 6e4, stdio: "ignore" });
7088
- await rm5(join20(tmpDir, ".git"), { recursive: true, force: true }).catch(() => {
7318
+ await rm6(join21(tmpDir, ".git"), { recursive: true, force: true }).catch(() => {
7089
7319
  });
7090
7320
  }
7091
7321
  const manifest = await readPlateManifest(tmpDir);
@@ -7093,15 +7323,15 @@ Cloning ${url}...`));
7093
7323
  const title = manifest.title;
7094
7324
  const existing = await getPlate(flintPath, slug);
7095
7325
  if (existing) {
7096
- await rm5(tmpDir, { recursive: true, force: true });
7326
+ await rm6(tmpDir, { recursive: true, force: true });
7097
7327
  console.error(pc22.red(`Error: Plate "${slug}" already exists.`));
7098
7328
  process.exit(1);
7099
7329
  }
7100
7330
  const { mkdir: mkdir9 } = await import("fs/promises");
7101
7331
  const platePath = `Plates/${title}`;
7102
- const absolutePlatePath = join20(flintPath, platePath);
7103
- await mkdir9(join20(flintPath, "Plates"), { recursive: true });
7104
- await rename2(tmpDir, absolutePlatePath);
7332
+ const absolutePlatePath = join21(flintPath, platePath);
7333
+ await mkdir9(join21(flintPath, "Plates"), { recursive: true });
7334
+ await rename3(tmpDir, absolutePlatePath);
7105
7335
  await addPlateDeclaration(flintPath, slug, platePath, { title });
7106
7336
  await setPlateRepo(flintPath, slug, url);
7107
7337
  await updateGitignore2(flintPath);
@@ -7122,7 +7352,7 @@ Installed plate: ${pc22.bold(title)}`));
7122
7352
  plateCommand.command("push").description("Initialize a plate as a git repo, set remote, and push").argument("<name>", "Plate name").argument("<url>", "Git remote URL").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (name, url, options) => {
7123
7353
  try {
7124
7354
  const flintPath = await resolveFlintPath2(options.path);
7125
- const { setPlateRepo } = await import("./dist-RGQKIZQW.js");
7355
+ const { setPlateRepo } = await import("./dist-EAYA2DAP.js");
7126
7356
  console.log(pc22.dim(`
7127
7357
  Pushing plate "${name}"...`));
7128
7358
  const result = await initPlateRepo(flintPath, name, url);
@@ -7148,7 +7378,7 @@ Pushing plate "${name}"...`));
7148
7378
  plateCommand.command("sync").description("Sync plates that have a repo configured").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (options) => {
7149
7379
  try {
7150
7380
  const flintPath = await resolveFlintPath2(options.path);
7151
- const { getPlateDeclarations, syncPlateRepos } = await import("./dist-RGQKIZQW.js");
7381
+ const { getPlateDeclarations, syncPlateRepos } = await import("./dist-EAYA2DAP.js");
7152
7382
  const declarations = await getPlateDeclarations(flintPath);
7153
7383
  const hasRepos = Object.values(declarations).some((d) => d.repo);
7154
7384
  if (!hasRepos) {
@@ -7424,9 +7654,9 @@ repoCommand2.addCommand(
7424
7654
  }
7425
7655
  })
7426
7656
  );
7427
- async function fileExists(path8) {
7657
+ async function fileExists(path10) {
7428
7658
  try {
7429
- await stat3(path8);
7659
+ await stat3(path10);
7430
7660
  return true;
7431
7661
  } catch {
7432
7662
  return false;
@@ -7445,12 +7675,12 @@ function parseExportRef(ref) {
7445
7675
  }
7446
7676
  async function findFlintByName2(name) {
7447
7677
  const flints = await getFlintRegistry();
7448
- let match = flints.find((f) => f.name === name);
7449
- if (match) return match;
7450
- match = flints.find((f) => getSimplifiedName(f.name) === name);
7451
- if (match) return match;
7452
- match = flints.find((f) => getSimplifiedName(basename3(f.path)) === name);
7453
- if (match) return match;
7678
+ let match2 = flints.find((f) => f.name === name);
7679
+ if (match2) return match2;
7680
+ match2 = flints.find((f) => getSimplifiedName(f.name) === name);
7681
+ if (match2) return match2;
7682
+ match2 = flints.find((f) => getSimplifiedName(basename3(f.path)) === name);
7683
+ if (match2) return match2;
7454
7684
  return null;
7455
7685
  }
7456
7686
  async function getRegisteredFlintsWithExports() {
@@ -7712,9 +7942,9 @@ function readPinsToml(latticeRoot) {
7712
7942
  if (!recordsMatch) return [];
7713
7943
  const recordsStr = recordsMatch[1];
7714
7944
  const entryPattern = /\{\s*id\s*=\s*"([^"]+)"\s*,\s*title\s*=\s*"([^"]+)"\s*\}/g;
7715
- let match;
7716
- while ((match = entryPattern.exec(recordsStr)) !== null) {
7717
- records.push({ id: match[1], title: match[2] });
7945
+ let match2;
7946
+ while ((match2 = entryPattern.exec(recordsStr)) !== null) {
7947
+ records.push({ id: match2[1], title: match2[2] });
7718
7948
  }
7719
7949
  return records;
7720
7950
  }
@@ -8045,7 +8275,7 @@ var latticeCommand = new Command21("lattice").description("Manage lattice connec
8045
8275
  // src/commands/server.ts
8046
8276
  import { Command as Command22 } from "commander";
8047
8277
  import { createRequire } from "module";
8048
- import path6 from "path";
8278
+ import path8 from "path";
8049
8279
  import { spawn as spawn6 } from "child_process";
8050
8280
  import { stat as stat6 } from "fs/promises";
8051
8281
  import pc25 from "picocolors";
@@ -8054,8 +8284,8 @@ import pc25 from "picocolors";
8054
8284
  import Fastify from "fastify";
8055
8285
  import fastifyCors from "@fastify/cors";
8056
8286
  import fastifyStatic from "@fastify/static";
8057
- import { stat as stat4 } from "fs/promises";
8058
- import path5 from "path";
8287
+ import { stat as stat5 } from "fs/promises";
8288
+ import path7 from "path";
8059
8289
  import { fileURLToPath as fileURLToPath2 } from "url";
8060
8290
  import { join as join43 } from "path";
8061
8291
 
@@ -10358,12 +10588,12 @@ function readGeminiSessionId(transcriptPath) {
10358
10588
  function parseGeminiSessionList(output) {
10359
10589
  const mapping = /* @__PURE__ */ new Map();
10360
10590
  for (const line of output.split("\n")) {
10361
- const match = line.match(/^\s*(\d+)\.\s+.*\[(.+?)\]\s*$/);
10362
- if (!match) {
10591
+ const match2 = line.match(/^\s*(\d+)\.\s+.*\[(.+?)\]\s*$/);
10592
+ if (!match2) {
10363
10593
  continue;
10364
10594
  }
10365
- const index = match[1];
10366
- const sessionId = match[2];
10595
+ const index = match2[1];
10596
+ const sessionId = match2[2];
10367
10597
  if (index && sessionId) {
10368
10598
  mapping.set(sessionId, index);
10369
10599
  }
@@ -10766,209 +10996,2241 @@ function killHarnessProcess(options) {
10766
10996
  }
10767
10997
 
10768
10998
  // ../../packages/flint-server/dist/index.js
10769
- import {
10770
- createRuntime,
10771
- computeRuntimeId
10772
- } from "@nuucognition/flint-runtime";
10773
- import { existsSync as existsSync10, watch as watch3 } from "fs";
10774
- import { stat as stat5 } from "fs/promises";
10775
- import path3 from "path";
10776
- import { mkdir as mkdir5, readFile as readFile6, writeFile as writeFile3 } from "fs/promises";
10777
- import { homedir as homedir6 } from "os";
10778
- import { join as join11, resolve as resolve7 } from "path";
10779
- import { existsSync as existsSync23 } from "fs";
10780
- import { stat as stat22, readFile as readFile22 } from "fs/promises";
10781
- import path22 from "path";
10782
- import { existsSync as existsSync33 } from "fs";
10999
+ import { randomUUID as randomUUID3, createHash as createHash2 } from "crypto";
11000
+ import { EventEmitter } from "events";
11001
+ import { readFile as readFile6, stat as stat4 } from "fs/promises";
10783
11002
  import { spawn as spawn5 } from "child_process";
10784
- import { readFile as readFile32 } from "fs/promises";
10785
- import path32 from "path";
10786
- import { readdir as readdir2 } from "fs/promises";
10787
11003
  import path4 from "path";
10788
- import { readdir as readdir22 } from "fs/promises";
10789
- import { join as join23 } from "path";
10790
- import { randomUUID as randomUUID3 } from "crypto";
10791
- import { writeFile as writeFile22, mkdir as mkdir22, readdir as readdir3, readFile as readFile42, stat as stat32 } from "fs/promises";
10792
- import { join as join33 } from "path";
10793
- function sendApiError(reply, status, error3, message, extra = {}) {
10794
- return reply.code(status).send({ error: error3, message, ...extra });
10795
- }
10796
- var CONTENT_TYPES = {
10797
- ".css": "text/css; charset=utf-8",
10798
- ".html": "text/html; charset=utf-8",
10799
- ".js": "application/javascript; charset=utf-8",
10800
- ".json": "application/json; charset=utf-8",
10801
- ".map": "application/json; charset=utf-8",
10802
- ".mjs": "application/javascript; charset=utf-8",
10803
- ".png": "image/png",
10804
- ".svg": "image/svg+xml",
10805
- ".tsx": "text/plain; charset=utf-8",
10806
- ".txt": "text/plain; charset=utf-8",
10807
- ".woff": "font/woff",
10808
- ".woff2": "font/woff2"
10809
- };
10810
- function contentTypeFor(filePath) {
10811
- return CONTENT_TYPES[path3.extname(filePath).toLowerCase()] ?? "application/octet-stream";
10812
- }
10813
- function isImmutableAsset(filePath) {
10814
- return /\.[a-f0-9]{8,}\./i.test(path3.basename(filePath));
10815
- }
10816
- async function resolveFlintPath4(inputPath) {
10817
- const resolved = path3.resolve(inputPath);
10818
- const flintToml = path3.join(resolved, "flint.toml");
10819
- const flintState = path3.join(resolved, ".flint");
10820
- const hasConfig = await exists3(flintToml);
10821
- const hasState = await exists3(flintState);
10822
- if (!hasConfig && !hasState) {
10823
- throw new Error(`Not a Flint workspace: ${resolved}`);
10824
- }
10825
- return resolved;
10826
- }
10827
- async function exists3(targetPath) {
10828
- try {
10829
- await stat5(targetPath);
10830
- return true;
10831
- } catch {
10832
- return false;
11004
+ import chokidar from "chokidar";
11005
+ import { glob } from "glob";
11006
+
11007
+ // ../../node_modules/.pnpm/minimatch@9.0.9/node_modules/minimatch/dist/esm/index.js
11008
+ var import_brace_expansion = __toESM(require_brace_expansion(), 1);
11009
+
11010
+ // ../../node_modules/.pnpm/minimatch@9.0.9/node_modules/minimatch/dist/esm/assert-valid-pattern.js
11011
+ var MAX_PATTERN_LENGTH = 1024 * 64;
11012
+ var assertValidPattern = (pattern) => {
11013
+ if (typeof pattern !== "string") {
11014
+ throw new TypeError("invalid pattern");
10833
11015
  }
10834
- }
10835
- function toError(error3, fallbackMessage) {
10836
- if (error3 instanceof Error) {
10837
- return error3;
11016
+ if (pattern.length > MAX_PATTERN_LENGTH) {
11017
+ throw new TypeError("pattern is too long");
10838
11018
  }
10839
- return new Error(typeof error3 === "string" ? error3 : fallbackMessage);
10840
- }
10841
- function isUnsupportedRecursiveWatchError(error3) {
10842
- const code = typeof error3 === "object" && error3 !== null && "code" in error3 ? String(error3.code ?? "") : "";
10843
- return code === "ERR_FEATURE_UNAVAILABLE_ON_PLATFORM" || code === "ENOSYS" || code === "ENOTSUP";
10844
- }
10845
- function createResilientWatcher({
10846
- label,
10847
- targetPath,
10848
- recursive = false,
10849
- retryMs = 1e3,
10850
- onChange
10851
- }) {
10852
- let watcher = null;
10853
- let retryTimer = null;
10854
- let closed = false;
10855
- const scheduleRestart = () => {
10856
- if (closed || retryTimer) {
10857
- return;
10858
- }
10859
- retryTimer = setTimeout(() => {
10860
- retryTimer = null;
10861
- start();
10862
- }, retryMs);
10863
- retryTimer.unref?.();
10864
- };
10865
- const handleWatchError = (error3) => {
10866
- const resolved = toError(error3, `${label} watcher failed`);
10867
- const unsupported = recursive && isUnsupportedRecursiveWatchError(error3);
10868
- watcher?.close();
10869
- watcher = null;
10870
- if (unsupported) {
10871
- console.warn(`[flint-server] ${label} watcher disabled: recursive fs.watch is not supported on this platform.`);
10872
- return;
11019
+ };
11020
+
11021
+ // ../../node_modules/.pnpm/minimatch@9.0.9/node_modules/minimatch/dist/esm/brace-expressions.js
11022
+ var posixClasses = {
11023
+ "[:alnum:]": ["\\p{L}\\p{Nl}\\p{Nd}", true],
11024
+ "[:alpha:]": ["\\p{L}\\p{Nl}", true],
11025
+ "[:ascii:]": ["\\x00-\\x7f", false],
11026
+ "[:blank:]": ["\\p{Zs}\\t", true],
11027
+ "[:cntrl:]": ["\\p{Cc}", true],
11028
+ "[:digit:]": ["\\p{Nd}", true],
11029
+ "[:graph:]": ["\\p{Z}\\p{C}", true, true],
11030
+ "[:lower:]": ["\\p{Ll}", true],
11031
+ "[:print:]": ["\\p{C}", true],
11032
+ "[:punct:]": ["\\p{P}", true],
11033
+ "[:space:]": ["\\p{Z}\\t\\r\\n\\v\\f", true],
11034
+ "[:upper:]": ["\\p{Lu}", true],
11035
+ "[:word:]": ["\\p{L}\\p{Nl}\\p{Nd}\\p{Pc}", true],
11036
+ "[:xdigit:]": ["A-Fa-f0-9", false]
11037
+ };
11038
+ var braceEscape = (s) => s.replace(/[[\]\\-]/g, "\\$&");
11039
+ var regexpEscape = (s) => s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
11040
+ var rangesToString = (ranges) => ranges.join("");
11041
+ var parseClass = (glob2, position) => {
11042
+ const pos = position;
11043
+ if (glob2.charAt(pos) !== "[") {
11044
+ throw new Error("not in a brace expression");
11045
+ }
11046
+ const ranges = [];
11047
+ const negs = [];
11048
+ let i = pos + 1;
11049
+ let sawStart = false;
11050
+ let uflag = false;
11051
+ let escaping = false;
11052
+ let negate = false;
11053
+ let endPos = pos;
11054
+ let rangeStart = "";
11055
+ WHILE: while (i < glob2.length) {
11056
+ const c = glob2.charAt(i);
11057
+ if ((c === "!" || c === "^") && i === pos + 1) {
11058
+ negate = true;
11059
+ i++;
11060
+ continue;
10873
11061
  }
10874
- console.warn(`[flint-server] ${label} watcher error: ${resolved.message}. Retrying.`);
10875
- scheduleRestart();
10876
- };
10877
- const start = () => {
10878
- if (closed) {
10879
- return;
11062
+ if (c === "]" && sawStart && !escaping) {
11063
+ endPos = i + 1;
11064
+ break;
10880
11065
  }
10881
- if (!existsSync10(targetPath)) {
10882
- scheduleRestart();
10883
- return;
11066
+ sawStart = true;
11067
+ if (c === "\\") {
11068
+ if (!escaping) {
11069
+ escaping = true;
11070
+ i++;
11071
+ continue;
11072
+ }
10884
11073
  }
10885
- try {
10886
- watcher = watch3(targetPath, { recursive }, (_eventType, filename) => {
10887
- onChange(filename);
10888
- });
10889
- watcher.on("error", handleWatchError);
10890
- } catch (error3) {
10891
- handleWatchError(error3);
11074
+ if (c === "[" && !escaping) {
11075
+ for (const [cls, [unip, u, neg]] of Object.entries(posixClasses)) {
11076
+ if (glob2.startsWith(cls, i)) {
11077
+ if (rangeStart) {
11078
+ return ["$.", false, glob2.length - pos, true];
11079
+ }
11080
+ i += cls.length;
11081
+ if (neg)
11082
+ negs.push(unip);
11083
+ else
11084
+ ranges.push(unip);
11085
+ uflag = uflag || u;
11086
+ continue WHILE;
11087
+ }
11088
+ }
10892
11089
  }
10893
- };
10894
- start();
10895
- return {
10896
- close() {
10897
- closed = true;
10898
- if (retryTimer) {
10899
- clearTimeout(retryTimer);
10900
- retryTimer = null;
11090
+ escaping = false;
11091
+ if (rangeStart) {
11092
+ if (c > rangeStart) {
11093
+ ranges.push(braceEscape(rangeStart) + "-" + braceEscape(c));
11094
+ } else if (c === rangeStart) {
11095
+ ranges.push(braceEscape(c));
10901
11096
  }
10902
- watcher?.close();
10903
- watcher = null;
11097
+ rangeStart = "";
11098
+ i++;
11099
+ continue;
10904
11100
  }
10905
- };
10906
- }
10907
- var RuntimeManager = class {
10908
- runtimes = /* @__PURE__ */ new Map();
10909
- async startRuntime(flintPath) {
10910
- const resolved = await resolveFlintPath4(flintPath);
10911
- const runtimeId = computeRuntimeId(resolved);
10912
- const existing = this.runtimes.get(runtimeId);
10913
- if (existing) {
10914
- return existing.getStatus();
11101
+ if (glob2.startsWith("-]", i + 1)) {
11102
+ ranges.push(braceEscape(c + "-"));
11103
+ i += 2;
11104
+ continue;
10915
11105
  }
10916
- const runtime2 = createRuntime({ flintPath: resolved });
10917
- await runtime2.start();
10918
- this.runtimes.set(runtimeId, runtime2);
10919
- return runtime2.getStatus();
10920
- }
10921
- listRuntimes() {
10922
- return Array.from(this.runtimes.values()).map((runtime2) => runtime2.getStatus());
11106
+ if (glob2.startsWith("-", i + 1)) {
11107
+ rangeStart = c;
11108
+ i += 2;
11109
+ continue;
11110
+ }
11111
+ ranges.push(braceEscape(c));
11112
+ i++;
10923
11113
  }
10924
- getRuntime(id) {
10925
- return this.runtimes.get(id);
11114
+ if (endPos < i) {
11115
+ return ["", false, 0, false];
10926
11116
  }
10927
- async stopRuntime(id) {
10928
- const runtime2 = this.runtimes.get(id);
10929
- if (!runtime2) {
10930
- return false;
10931
- }
10932
- await runtime2.stop();
10933
- this.runtimes.delete(id);
10934
- return true;
11117
+ if (!ranges.length && !negs.length) {
11118
+ return ["$.", false, glob2.length - pos, true];
10935
11119
  }
10936
- async stopAll() {
10937
- const entries = Array.from(this.runtimes.entries());
10938
- await Promise.all(entries.map(async ([id, runtime2]) => {
10939
- await runtime2.stop();
10940
- this.runtimes.delete(id);
10941
- }));
11120
+ if (negs.length === 0 && ranges.length === 1 && /^\\?.$/.test(ranges[0]) && !negate) {
11121
+ const r = ranges[0].length === 2 ? ranges[0].slice(-1) : ranges[0];
11122
+ return [regexpEscape(r), false, endPos - pos, false];
10942
11123
  }
11124
+ const sranges = "[" + (negate ? "^" : "") + rangesToString(ranges) + "]";
11125
+ const snegs = "[" + (negate ? "" : "^") + rangesToString(negs) + "]";
11126
+ const comb = ranges.length && negs.length ? "(" + sranges + "|" + snegs + ")" : ranges.length ? sranges : snegs;
11127
+ return [comb, uflag, endPos - pos, true];
10943
11128
  };
10944
- var REGISTRY_PATH = join11(homedir6(), ".nuucognition", "servers.json");
10945
- function getRegistryDir() {
10946
- return join11(homedir6(), ".nuucognition");
10947
- }
10948
- async function readServerRegistry() {
10949
- try {
10950
- const content = await readFile6(REGISTRY_PATH, "utf-8");
10951
- const data = JSON.parse(content);
10952
- return data.servers ?? [];
10953
- } catch (error3) {
10954
- if (error3.code === "ENOENT") {
10955
- return [];
11129
+
11130
+ // ../../node_modules/.pnpm/minimatch@9.0.9/node_modules/minimatch/dist/esm/unescape.js
11131
+ var unescape = (s, { windowsPathsNoEscape = false } = {}) => {
11132
+ return windowsPathsNoEscape ? s.replace(/\[([^\/\\])\]/g, "$1") : s.replace(/((?!\\).|^)\[([^\/\\])\]/g, "$1$2").replace(/\\([^\/])/g, "$1");
11133
+ };
11134
+
11135
+ // ../../node_modules/.pnpm/minimatch@9.0.9/node_modules/minimatch/dist/esm/ast.js
11136
+ var _a;
11137
+ var types = /* @__PURE__ */ new Set(["!", "?", "+", "*", "@"]);
11138
+ var isExtglobType = (c) => types.has(c);
11139
+ var isExtglobAST = (c) => isExtglobType(c.type);
11140
+ var adoptionMap = /* @__PURE__ */ new Map([
11141
+ ["!", ["@"]],
11142
+ ["?", ["?", "@"]],
11143
+ ["@", ["@"]],
11144
+ ["*", ["*", "+", "?", "@"]],
11145
+ ["+", ["+", "@"]]
11146
+ ]);
11147
+ var adoptionWithSpaceMap = /* @__PURE__ */ new Map([
11148
+ ["!", ["?"]],
11149
+ ["@", ["?"]],
11150
+ ["+", ["?", "*"]]
11151
+ ]);
11152
+ var adoptionAnyMap = /* @__PURE__ */ new Map([
11153
+ ["!", ["?", "@"]],
11154
+ ["?", ["?", "@"]],
11155
+ ["@", ["?", "@"]],
11156
+ ["*", ["*", "+", "?", "@"]],
11157
+ ["+", ["+", "@", "?", "*"]]
11158
+ ]);
11159
+ var usurpMap = /* @__PURE__ */ new Map([
11160
+ ["!", /* @__PURE__ */ new Map([["!", "@"]])],
11161
+ ["?", /* @__PURE__ */ new Map([["*", "*"], ["+", "*"]])],
11162
+ ["@", /* @__PURE__ */ new Map([["!", "!"], ["?", "?"], ["@", "@"], ["*", "*"], ["+", "+"]])],
11163
+ ["+", /* @__PURE__ */ new Map([["?", "*"], ["*", "*"]])]
11164
+ ]);
11165
+ var startNoTraversal = "(?!(?:^|/)\\.\\.?(?:$|/))";
11166
+ var startNoDot = "(?!\\.)";
11167
+ var addPatternStart = /* @__PURE__ */ new Set(["[", "."]);
11168
+ var justDots = /* @__PURE__ */ new Set(["..", "."]);
11169
+ var reSpecials = new Set("().*{}+?[]^$\\!");
11170
+ var regExpEscape = (s) => s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
11171
+ var qmark = "[^/]";
11172
+ var star = qmark + "*?";
11173
+ var starNoEmpty = qmark + "+?";
11174
+ var AST = class {
11175
+ type;
11176
+ #root;
11177
+ #hasMagic;
11178
+ #uflag = false;
11179
+ #parts = [];
11180
+ #parent;
11181
+ #parentIndex;
11182
+ #negs;
11183
+ #filledNegs = false;
11184
+ #options;
11185
+ #toString;
11186
+ // set to true if it's an extglob with no children
11187
+ // (which really means one child of '')
11188
+ #emptyExt = false;
11189
+ constructor(type, parent, options = {}) {
11190
+ this.type = type;
11191
+ if (type)
11192
+ this.#hasMagic = true;
11193
+ this.#parent = parent;
11194
+ this.#root = this.#parent ? this.#parent.#root : this;
11195
+ this.#options = this.#root === this ? options : this.#root.#options;
11196
+ this.#negs = this.#root === this ? [] : this.#root.#negs;
11197
+ if (type === "!" && !this.#root.#filledNegs)
11198
+ this.#negs.push(this);
11199
+ this.#parentIndex = this.#parent ? this.#parent.#parts.length : 0;
11200
+ }
11201
+ get hasMagic() {
11202
+ if (this.#hasMagic !== void 0)
11203
+ return this.#hasMagic;
11204
+ for (const p of this.#parts) {
11205
+ if (typeof p === "string")
11206
+ continue;
11207
+ if (p.type || p.hasMagic)
11208
+ return this.#hasMagic = true;
10956
11209
  }
10957
- return [];
11210
+ return this.#hasMagic;
10958
11211
  }
10959
- }
10960
- async function writeServerRegistry(servers) {
10961
- await mkdir5(getRegistryDir(), { recursive: true });
10962
- const data = { version: 1, servers };
10963
- const content = JSON.stringify(data, null, 2);
10964
- await writeFile3(REGISTRY_PATH, content, "utf-8");
10965
- const verification = await readFile6(REGISTRY_PATH, "utf-8");
10966
- const verified = JSON.parse(verification);
10967
- if (verified.servers.length !== servers.length) {
10968
- await writeFile3(REGISTRY_PATH, content, "utf-8");
11212
+ // reconstructs the pattern
11213
+ toString() {
11214
+ if (this.#toString !== void 0)
11215
+ return this.#toString;
11216
+ if (!this.type) {
11217
+ return this.#toString = this.#parts.map((p) => String(p)).join("");
11218
+ } else {
11219
+ return this.#toString = this.type + "(" + this.#parts.map((p) => String(p)).join("|") + ")";
11220
+ }
11221
+ }
11222
+ #fillNegs() {
11223
+ if (this !== this.#root)
11224
+ throw new Error("should only call on root");
11225
+ if (this.#filledNegs)
11226
+ return this;
11227
+ this.toString();
11228
+ this.#filledNegs = true;
11229
+ let n;
11230
+ while (n = this.#negs.pop()) {
11231
+ if (n.type !== "!")
11232
+ continue;
11233
+ let p = n;
11234
+ let pp = p.#parent;
11235
+ while (pp) {
11236
+ for (let i = p.#parentIndex + 1; !pp.type && i < pp.#parts.length; i++) {
11237
+ for (const part of n.#parts) {
11238
+ if (typeof part === "string") {
11239
+ throw new Error("string part in extglob AST??");
11240
+ }
11241
+ part.copyIn(pp.#parts[i]);
11242
+ }
11243
+ }
11244
+ p = pp;
11245
+ pp = p.#parent;
11246
+ }
11247
+ }
11248
+ return this;
10969
11249
  }
10970
- }
10971
- async function registerServer(entry) {
11250
+ push(...parts) {
11251
+ for (const p of parts) {
11252
+ if (p === "")
11253
+ continue;
11254
+ if (typeof p !== "string" && !(p instanceof _a && p.#parent === this)) {
11255
+ throw new Error("invalid part: " + p);
11256
+ }
11257
+ this.#parts.push(p);
11258
+ }
11259
+ }
11260
+ toJSON() {
11261
+ const ret = this.type === null ? this.#parts.slice().map((p) => typeof p === "string" ? p : p.toJSON()) : [this.type, ...this.#parts.map((p) => p.toJSON())];
11262
+ if (this.isStart() && !this.type)
11263
+ ret.unshift([]);
11264
+ if (this.isEnd() && (this === this.#root || this.#root.#filledNegs && this.#parent?.type === "!")) {
11265
+ ret.push({});
11266
+ }
11267
+ return ret;
11268
+ }
11269
+ isStart() {
11270
+ if (this.#root === this)
11271
+ return true;
11272
+ if (!this.#parent?.isStart())
11273
+ return false;
11274
+ if (this.#parentIndex === 0)
11275
+ return true;
11276
+ const p = this.#parent;
11277
+ for (let i = 0; i < this.#parentIndex; i++) {
11278
+ const pp = p.#parts[i];
11279
+ if (!(pp instanceof _a && pp.type === "!")) {
11280
+ return false;
11281
+ }
11282
+ }
11283
+ return true;
11284
+ }
11285
+ isEnd() {
11286
+ if (this.#root === this)
11287
+ return true;
11288
+ if (this.#parent?.type === "!")
11289
+ return true;
11290
+ if (!this.#parent?.isEnd())
11291
+ return false;
11292
+ if (!this.type)
11293
+ return this.#parent?.isEnd();
11294
+ const pl = this.#parent ? this.#parent.#parts.length : 0;
11295
+ return this.#parentIndex === pl - 1;
11296
+ }
11297
+ copyIn(part) {
11298
+ if (typeof part === "string")
11299
+ this.push(part);
11300
+ else
11301
+ this.push(part.clone(this));
11302
+ }
11303
+ clone(parent) {
11304
+ const c = new _a(this.type, parent);
11305
+ for (const p of this.#parts) {
11306
+ c.copyIn(p);
11307
+ }
11308
+ return c;
11309
+ }
11310
+ static #parseAST(str, ast, pos, opt, extDepth) {
11311
+ const maxDepth = opt.maxExtglobRecursion ?? 2;
11312
+ let escaping = false;
11313
+ let inBrace = false;
11314
+ let braceStart = -1;
11315
+ let braceNeg = false;
11316
+ if (ast.type === null) {
11317
+ let i2 = pos;
11318
+ let acc2 = "";
11319
+ while (i2 < str.length) {
11320
+ const c = str.charAt(i2++);
11321
+ if (escaping || c === "\\") {
11322
+ escaping = !escaping;
11323
+ acc2 += c;
11324
+ continue;
11325
+ }
11326
+ if (inBrace) {
11327
+ if (i2 === braceStart + 1) {
11328
+ if (c === "^" || c === "!") {
11329
+ braceNeg = true;
11330
+ }
11331
+ } else if (c === "]" && !(i2 === braceStart + 2 && braceNeg)) {
11332
+ inBrace = false;
11333
+ }
11334
+ acc2 += c;
11335
+ continue;
11336
+ } else if (c === "[") {
11337
+ inBrace = true;
11338
+ braceStart = i2;
11339
+ braceNeg = false;
11340
+ acc2 += c;
11341
+ continue;
11342
+ }
11343
+ const doRecurse = !opt.noext && isExtglobType(c) && str.charAt(i2) === "(" && extDepth <= maxDepth;
11344
+ if (doRecurse) {
11345
+ ast.push(acc2);
11346
+ acc2 = "";
11347
+ const ext2 = new _a(c, ast);
11348
+ i2 = _a.#parseAST(str, ext2, i2, opt, extDepth + 1);
11349
+ ast.push(ext2);
11350
+ continue;
11351
+ }
11352
+ acc2 += c;
11353
+ }
11354
+ ast.push(acc2);
11355
+ return i2;
11356
+ }
11357
+ let i = pos + 1;
11358
+ let part = new _a(null, ast);
11359
+ const parts = [];
11360
+ let acc = "";
11361
+ while (i < str.length) {
11362
+ const c = str.charAt(i++);
11363
+ if (escaping || c === "\\") {
11364
+ escaping = !escaping;
11365
+ acc += c;
11366
+ continue;
11367
+ }
11368
+ if (inBrace) {
11369
+ if (i === braceStart + 1) {
11370
+ if (c === "^" || c === "!") {
11371
+ braceNeg = true;
11372
+ }
11373
+ } else if (c === "]" && !(i === braceStart + 2 && braceNeg)) {
11374
+ inBrace = false;
11375
+ }
11376
+ acc += c;
11377
+ continue;
11378
+ } else if (c === "[") {
11379
+ inBrace = true;
11380
+ braceStart = i;
11381
+ braceNeg = false;
11382
+ acc += c;
11383
+ continue;
11384
+ }
11385
+ const doRecurse = isExtglobType(c) && str.charAt(i) === "(" && /* c8 ignore start - the maxDepth is sufficient here */
11386
+ (extDepth <= maxDepth || ast && ast.#canAdoptType(c));
11387
+ if (doRecurse) {
11388
+ const depthAdd = ast && ast.#canAdoptType(c) ? 0 : 1;
11389
+ part.push(acc);
11390
+ acc = "";
11391
+ const ext2 = new _a(c, part);
11392
+ part.push(ext2);
11393
+ i = _a.#parseAST(str, ext2, i, opt, extDepth + depthAdd);
11394
+ continue;
11395
+ }
11396
+ if (c === "|") {
11397
+ part.push(acc);
11398
+ acc = "";
11399
+ parts.push(part);
11400
+ part = new _a(null, ast);
11401
+ continue;
11402
+ }
11403
+ if (c === ")") {
11404
+ if (acc === "" && ast.#parts.length === 0) {
11405
+ ast.#emptyExt = true;
11406
+ }
11407
+ part.push(acc);
11408
+ acc = "";
11409
+ ast.push(...parts, part);
11410
+ return i;
11411
+ }
11412
+ acc += c;
11413
+ }
11414
+ ast.type = null;
11415
+ ast.#hasMagic = void 0;
11416
+ ast.#parts = [str.substring(pos - 1)];
11417
+ return i;
11418
+ }
11419
+ #canAdoptWithSpace(child) {
11420
+ return this.#canAdopt(child, adoptionWithSpaceMap);
11421
+ }
11422
+ #canAdopt(child, map = adoptionMap) {
11423
+ if (!child || typeof child !== "object" || child.type !== null || child.#parts.length !== 1 || this.type === null) {
11424
+ return false;
11425
+ }
11426
+ const gc = child.#parts[0];
11427
+ if (!gc || typeof gc !== "object" || gc.type === null) {
11428
+ return false;
11429
+ }
11430
+ return this.#canAdoptType(gc.type, map);
11431
+ }
11432
+ #canAdoptType(c, map = adoptionAnyMap) {
11433
+ return !!map.get(this.type)?.includes(c);
11434
+ }
11435
+ #adoptWithSpace(child, index) {
11436
+ const gc = child.#parts[0];
11437
+ const blank = new _a(null, gc, this.options);
11438
+ blank.#parts.push("");
11439
+ gc.push(blank);
11440
+ this.#adopt(child, index);
11441
+ }
11442
+ #adopt(child, index) {
11443
+ const gc = child.#parts[0];
11444
+ this.#parts.splice(index, 1, ...gc.#parts);
11445
+ for (const p of gc.#parts) {
11446
+ if (typeof p === "object")
11447
+ p.#parent = this;
11448
+ }
11449
+ this.#toString = void 0;
11450
+ }
11451
+ #canUsurpType(c) {
11452
+ const m = usurpMap.get(this.type);
11453
+ return !!m?.has(c);
11454
+ }
11455
+ #canUsurp(child) {
11456
+ if (!child || typeof child !== "object" || child.type !== null || child.#parts.length !== 1 || this.type === null || this.#parts.length !== 1) {
11457
+ return false;
11458
+ }
11459
+ const gc = child.#parts[0];
11460
+ if (!gc || typeof gc !== "object" || gc.type === null) {
11461
+ return false;
11462
+ }
11463
+ return this.#canUsurpType(gc.type);
11464
+ }
11465
+ #usurp(child) {
11466
+ const m = usurpMap.get(this.type);
11467
+ const gc = child.#parts[0];
11468
+ const nt = m?.get(gc.type);
11469
+ if (!nt)
11470
+ return false;
11471
+ this.#parts = gc.#parts;
11472
+ for (const p of this.#parts) {
11473
+ if (typeof p === "object")
11474
+ p.#parent = this;
11475
+ }
11476
+ this.type = nt;
11477
+ this.#toString = void 0;
11478
+ this.#emptyExt = false;
11479
+ }
11480
+ #flatten() {
11481
+ if (!isExtglobAST(this)) {
11482
+ for (const p of this.#parts) {
11483
+ if (typeof p === "object")
11484
+ p.#flatten();
11485
+ }
11486
+ } else {
11487
+ let iterations = 0;
11488
+ let done = false;
11489
+ do {
11490
+ done = true;
11491
+ for (let i = 0; i < this.#parts.length; i++) {
11492
+ const c = this.#parts[i];
11493
+ if (typeof c === "object") {
11494
+ c.#flatten();
11495
+ if (this.#canAdopt(c)) {
11496
+ done = false;
11497
+ this.#adopt(c, i);
11498
+ } else if (this.#canAdoptWithSpace(c)) {
11499
+ done = false;
11500
+ this.#adoptWithSpace(c, i);
11501
+ } else if (this.#canUsurp(c)) {
11502
+ done = false;
11503
+ this.#usurp(c);
11504
+ }
11505
+ }
11506
+ }
11507
+ } while (!done && ++iterations < 10);
11508
+ }
11509
+ this.#toString = void 0;
11510
+ }
11511
+ static fromGlob(pattern, options = {}) {
11512
+ const ast = new _a(null, void 0, options);
11513
+ _a.#parseAST(pattern, ast, 0, options, 0);
11514
+ return ast;
11515
+ }
11516
+ // returns the regular expression if there's magic, or the unescaped
11517
+ // string if not.
11518
+ toMMPattern() {
11519
+ if (this !== this.#root)
11520
+ return this.#root.toMMPattern();
11521
+ const glob2 = this.toString();
11522
+ const [re, body, hasMagic, uflag] = this.toRegExpSource();
11523
+ const anyMagic = hasMagic || this.#hasMagic || this.#options.nocase && !this.#options.nocaseMagicOnly && glob2.toUpperCase() !== glob2.toLowerCase();
11524
+ if (!anyMagic) {
11525
+ return body;
11526
+ }
11527
+ const flags = (this.#options.nocase ? "i" : "") + (uflag ? "u" : "");
11528
+ return Object.assign(new RegExp(`^${re}$`, flags), {
11529
+ _src: re,
11530
+ _glob: glob2
11531
+ });
11532
+ }
11533
+ get options() {
11534
+ return this.#options;
11535
+ }
11536
+ // returns the string match, the regexp source, whether there's magic
11537
+ // in the regexp (so a regular expression is required) and whether or
11538
+ // not the uflag is needed for the regular expression (for posix classes)
11539
+ // TODO: instead of injecting the start/end at this point, just return
11540
+ // the BODY of the regexp, along with the start/end portions suitable
11541
+ // for binding the start/end in either a joined full-path makeRe context
11542
+ // (where we bind to (^|/), or a standalone matchPart context (where
11543
+ // we bind to ^, and not /). Otherwise slashes get duped!
11544
+ //
11545
+ // In part-matching mode, the start is:
11546
+ // - if not isStart: nothing
11547
+ // - if traversal possible, but not allowed: ^(?!\.\.?$)
11548
+ // - if dots allowed or not possible: ^
11549
+ // - if dots possible and not allowed: ^(?!\.)
11550
+ // end is:
11551
+ // - if not isEnd(): nothing
11552
+ // - else: $
11553
+ //
11554
+ // In full-path matching mode, we put the slash at the START of the
11555
+ // pattern, so start is:
11556
+ // - if first pattern: same as part-matching mode
11557
+ // - if not isStart(): nothing
11558
+ // - if traversal possible, but not allowed: /(?!\.\.?(?:$|/))
11559
+ // - if dots allowed or not possible: /
11560
+ // - if dots possible and not allowed: /(?!\.)
11561
+ // end is:
11562
+ // - if last pattern, same as part-matching mode
11563
+ // - else nothing
11564
+ //
11565
+ // Always put the (?:$|/) on negated tails, though, because that has to be
11566
+ // there to bind the end of the negated pattern portion, and it's easier to
11567
+ // just stick it in now rather than try to inject it later in the middle of
11568
+ // the pattern.
11569
+ //
11570
+ // We can just always return the same end, and leave it up to the caller
11571
+ // to know whether it's going to be used joined or in parts.
11572
+ // And, if the start is adjusted slightly, can do the same there:
11573
+ // - if not isStart: nothing
11574
+ // - if traversal possible, but not allowed: (?:/|^)(?!\.\.?$)
11575
+ // - if dots allowed or not possible: (?:/|^)
11576
+ // - if dots possible and not allowed: (?:/|^)(?!\.)
11577
+ //
11578
+ // But it's better to have a simpler binding without a conditional, for
11579
+ // performance, so probably better to return both start options.
11580
+ //
11581
+ // Then the caller just ignores the end if it's not the first pattern,
11582
+ // and the start always gets applied.
11583
+ //
11584
+ // But that's always going to be $ if it's the ending pattern, or nothing,
11585
+ // so the caller can just attach $ at the end of the pattern when building.
11586
+ //
11587
+ // So the todo is:
11588
+ // - better detect what kind of start is needed
11589
+ // - return both flavors of starting pattern
11590
+ // - attach $ at the end of the pattern when creating the actual RegExp
11591
+ //
11592
+ // Ah, but wait, no, that all only applies to the root when the first pattern
11593
+ // is not an extglob. If the first pattern IS an extglob, then we need all
11594
+ // that dot prevention biz to live in the extglob portions, because eg
11595
+ // +(*|.x*) can match .xy but not .yx.
11596
+ //
11597
+ // So, return the two flavors if it's #root and the first child is not an
11598
+ // AST, otherwise leave it to the child AST to handle it, and there,
11599
+ // use the (?:^|/) style of start binding.
11600
+ //
11601
+ // Even simplified further:
11602
+ // - Since the start for a join is eg /(?!\.) and the start for a part
11603
+ // is ^(?!\.), we can just prepend (?!\.) to the pattern (either root
11604
+ // or start or whatever) and prepend ^ or / at the Regexp construction.
11605
+ toRegExpSource(allowDot) {
11606
+ const dot = allowDot ?? !!this.#options.dot;
11607
+ if (this.#root === this) {
11608
+ this.#flatten();
11609
+ this.#fillNegs();
11610
+ }
11611
+ if (!isExtglobAST(this)) {
11612
+ const noEmpty = this.isStart() && this.isEnd();
11613
+ const src = this.#parts.map((p) => {
11614
+ const [re, _, hasMagic, uflag] = typeof p === "string" ? _a.#parseGlob(p, this.#hasMagic, noEmpty) : p.toRegExpSource(allowDot);
11615
+ this.#hasMagic = this.#hasMagic || hasMagic;
11616
+ this.#uflag = this.#uflag || uflag;
11617
+ return re;
11618
+ }).join("");
11619
+ let start2 = "";
11620
+ if (this.isStart()) {
11621
+ if (typeof this.#parts[0] === "string") {
11622
+ const dotTravAllowed = this.#parts.length === 1 && justDots.has(this.#parts[0]);
11623
+ if (!dotTravAllowed) {
11624
+ const aps = addPatternStart;
11625
+ const needNoTrav = (
11626
+ // dots are allowed, and the pattern starts with [ or .
11627
+ dot && aps.has(src.charAt(0)) || // the pattern starts with \., and then [ or .
11628
+ src.startsWith("\\.") && aps.has(src.charAt(2)) || // the pattern starts with \.\., and then [ or .
11629
+ src.startsWith("\\.\\.") && aps.has(src.charAt(4))
11630
+ );
11631
+ const needNoDot = !dot && !allowDot && aps.has(src.charAt(0));
11632
+ start2 = needNoTrav ? startNoTraversal : needNoDot ? startNoDot : "";
11633
+ }
11634
+ }
11635
+ }
11636
+ let end = "";
11637
+ if (this.isEnd() && this.#root.#filledNegs && this.#parent?.type === "!") {
11638
+ end = "(?:$|\\/)";
11639
+ }
11640
+ const final2 = start2 + src + end;
11641
+ return [
11642
+ final2,
11643
+ unescape(src),
11644
+ this.#hasMagic = !!this.#hasMagic,
11645
+ this.#uflag
11646
+ ];
11647
+ }
11648
+ const repeated = this.type === "*" || this.type === "+";
11649
+ const start = this.type === "!" ? "(?:(?!(?:" : "(?:";
11650
+ let body = this.#partsToRegExp(dot);
11651
+ if (this.isStart() && this.isEnd() && !body && this.type !== "!") {
11652
+ const s = this.toString();
11653
+ const me = this;
11654
+ me.#parts = [s];
11655
+ me.type = null;
11656
+ me.#hasMagic = void 0;
11657
+ return [s, unescape(this.toString()), false, false];
11658
+ }
11659
+ let bodyDotAllowed = !repeated || allowDot || dot || !startNoDot ? "" : this.#partsToRegExp(true);
11660
+ if (bodyDotAllowed === body) {
11661
+ bodyDotAllowed = "";
11662
+ }
11663
+ if (bodyDotAllowed) {
11664
+ body = `(?:${body})(?:${bodyDotAllowed})*?`;
11665
+ }
11666
+ let final = "";
11667
+ if (this.type === "!" && this.#emptyExt) {
11668
+ final = (this.isStart() && !dot ? startNoDot : "") + starNoEmpty;
11669
+ } else {
11670
+ const close = this.type === "!" ? (
11671
+ // !() must match something,but !(x) can match ''
11672
+ "))" + (this.isStart() && !dot && !allowDot ? startNoDot : "") + star + ")"
11673
+ ) : this.type === "@" ? ")" : this.type === "?" ? ")?" : this.type === "+" && bodyDotAllowed ? ")" : this.type === "*" && bodyDotAllowed ? `)?` : `)${this.type}`;
11674
+ final = start + body + close;
11675
+ }
11676
+ return [
11677
+ final,
11678
+ unescape(body),
11679
+ this.#hasMagic = !!this.#hasMagic,
11680
+ this.#uflag
11681
+ ];
11682
+ }
11683
+ #partsToRegExp(dot) {
11684
+ return this.#parts.map((p) => {
11685
+ if (typeof p === "string") {
11686
+ throw new Error("string type in extglob ast??");
11687
+ }
11688
+ const [re, _, _hasMagic, uflag] = p.toRegExpSource(dot);
11689
+ this.#uflag = this.#uflag || uflag;
11690
+ return re;
11691
+ }).filter((p) => !(this.isStart() && this.isEnd()) || !!p).join("|");
11692
+ }
11693
+ static #parseGlob(glob2, hasMagic, noEmpty = false) {
11694
+ let escaping = false;
11695
+ let re = "";
11696
+ let uflag = false;
11697
+ let inStar = false;
11698
+ for (let i = 0; i < glob2.length; i++) {
11699
+ const c = glob2.charAt(i);
11700
+ if (escaping) {
11701
+ escaping = false;
11702
+ re += (reSpecials.has(c) ? "\\" : "") + c;
11703
+ inStar = false;
11704
+ continue;
11705
+ }
11706
+ if (c === "\\") {
11707
+ if (i === glob2.length - 1) {
11708
+ re += "\\\\";
11709
+ } else {
11710
+ escaping = true;
11711
+ }
11712
+ continue;
11713
+ }
11714
+ if (c === "[") {
11715
+ const [src, needUflag, consumed, magic] = parseClass(glob2, i);
11716
+ if (consumed) {
11717
+ re += src;
11718
+ uflag = uflag || needUflag;
11719
+ i += consumed - 1;
11720
+ hasMagic = hasMagic || magic;
11721
+ inStar = false;
11722
+ continue;
11723
+ }
11724
+ }
11725
+ if (c === "*") {
11726
+ if (inStar)
11727
+ continue;
11728
+ inStar = true;
11729
+ re += noEmpty && /^[*]+$/.test(glob2) ? starNoEmpty : star;
11730
+ hasMagic = true;
11731
+ continue;
11732
+ } else {
11733
+ inStar = false;
11734
+ }
11735
+ if (c === "?") {
11736
+ re += qmark;
11737
+ hasMagic = true;
11738
+ continue;
11739
+ }
11740
+ re += regExpEscape(c);
11741
+ }
11742
+ return [re, unescape(glob2), !!hasMagic, uflag];
11743
+ }
11744
+ };
11745
+ _a = AST;
11746
+
11747
+ // ../../node_modules/.pnpm/minimatch@9.0.9/node_modules/minimatch/dist/esm/escape.js
11748
+ var escape = (s, { windowsPathsNoEscape = false } = {}) => {
11749
+ return windowsPathsNoEscape ? s.replace(/[?*()[\]]/g, "[$&]") : s.replace(/[?*()[\]\\]/g, "\\$&");
11750
+ };
11751
+
11752
+ // ../../node_modules/.pnpm/minimatch@9.0.9/node_modules/minimatch/dist/esm/index.js
11753
+ var minimatch = (p, pattern, options = {}) => {
11754
+ assertValidPattern(pattern);
11755
+ if (!options.nocomment && pattern.charAt(0) === "#") {
11756
+ return false;
11757
+ }
11758
+ return new Minimatch(pattern, options).match(p);
11759
+ };
11760
+ var starDotExtRE = /^\*+([^+@!?\*\[\(]*)$/;
11761
+ var starDotExtTest = (ext2) => (f) => !f.startsWith(".") && f.endsWith(ext2);
11762
+ var starDotExtTestDot = (ext2) => (f) => f.endsWith(ext2);
11763
+ var starDotExtTestNocase = (ext2) => {
11764
+ ext2 = ext2.toLowerCase();
11765
+ return (f) => !f.startsWith(".") && f.toLowerCase().endsWith(ext2);
11766
+ };
11767
+ var starDotExtTestNocaseDot = (ext2) => {
11768
+ ext2 = ext2.toLowerCase();
11769
+ return (f) => f.toLowerCase().endsWith(ext2);
11770
+ };
11771
+ var starDotStarRE = /^\*+\.\*+$/;
11772
+ var starDotStarTest = (f) => !f.startsWith(".") && f.includes(".");
11773
+ var starDotStarTestDot = (f) => f !== "." && f !== ".." && f.includes(".");
11774
+ var dotStarRE = /^\.\*+$/;
11775
+ var dotStarTest = (f) => f !== "." && f !== ".." && f.startsWith(".");
11776
+ var starRE = /^\*+$/;
11777
+ var starTest = (f) => f.length !== 0 && !f.startsWith(".");
11778
+ var starTestDot = (f) => f.length !== 0 && f !== "." && f !== "..";
11779
+ var qmarksRE = /^\?+([^+@!?\*\[\(]*)?$/;
11780
+ var qmarksTestNocase = ([$0, ext2 = ""]) => {
11781
+ const noext = qmarksTestNoExt([$0]);
11782
+ if (!ext2)
11783
+ return noext;
11784
+ ext2 = ext2.toLowerCase();
11785
+ return (f) => noext(f) && f.toLowerCase().endsWith(ext2);
11786
+ };
11787
+ var qmarksTestNocaseDot = ([$0, ext2 = ""]) => {
11788
+ const noext = qmarksTestNoExtDot([$0]);
11789
+ if (!ext2)
11790
+ return noext;
11791
+ ext2 = ext2.toLowerCase();
11792
+ return (f) => noext(f) && f.toLowerCase().endsWith(ext2);
11793
+ };
11794
+ var qmarksTestDot = ([$0, ext2 = ""]) => {
11795
+ const noext = qmarksTestNoExtDot([$0]);
11796
+ return !ext2 ? noext : (f) => noext(f) && f.endsWith(ext2);
11797
+ };
11798
+ var qmarksTest = ([$0, ext2 = ""]) => {
11799
+ const noext = qmarksTestNoExt([$0]);
11800
+ return !ext2 ? noext : (f) => noext(f) && f.endsWith(ext2);
11801
+ };
11802
+ var qmarksTestNoExt = ([$0]) => {
11803
+ const len = $0.length;
11804
+ return (f) => f.length === len && !f.startsWith(".");
11805
+ };
11806
+ var qmarksTestNoExtDot = ([$0]) => {
11807
+ const len = $0.length;
11808
+ return (f) => f.length === len && f !== "." && f !== "..";
11809
+ };
11810
+ var defaultPlatform = typeof process === "object" && process ? typeof process.env === "object" && process.env && process.env.__MINIMATCH_TESTING_PLATFORM__ || process.platform : "posix";
11811
+ var path3 = {
11812
+ win32: { sep: "\\" },
11813
+ posix: { sep: "/" }
11814
+ };
11815
+ var sep = defaultPlatform === "win32" ? path3.win32.sep : path3.posix.sep;
11816
+ minimatch.sep = sep;
11817
+ var GLOBSTAR = /* @__PURE__ */ Symbol("globstar **");
11818
+ minimatch.GLOBSTAR = GLOBSTAR;
11819
+ var qmark2 = "[^/]";
11820
+ var star2 = qmark2 + "*?";
11821
+ var twoStarDot = "(?:(?!(?:\\/|^)(?:\\.{1,2})($|\\/)).)*?";
11822
+ var twoStarNoDot = "(?:(?!(?:\\/|^)\\.).)*?";
11823
+ var filter = (pattern, options = {}) => (p) => minimatch(p, pattern, options);
11824
+ minimatch.filter = filter;
11825
+ var ext = (a, b = {}) => Object.assign({}, a, b);
11826
+ var defaults = (def) => {
11827
+ if (!def || typeof def !== "object" || !Object.keys(def).length) {
11828
+ return minimatch;
11829
+ }
11830
+ const orig = minimatch;
11831
+ const m = (p, pattern, options = {}) => orig(p, pattern, ext(def, options));
11832
+ return Object.assign(m, {
11833
+ Minimatch: class Minimatch extends orig.Minimatch {
11834
+ constructor(pattern, options = {}) {
11835
+ super(pattern, ext(def, options));
11836
+ }
11837
+ static defaults(options) {
11838
+ return orig.defaults(ext(def, options)).Minimatch;
11839
+ }
11840
+ },
11841
+ AST: class AST extends orig.AST {
11842
+ /* c8 ignore start */
11843
+ constructor(type, parent, options = {}) {
11844
+ super(type, parent, ext(def, options));
11845
+ }
11846
+ /* c8 ignore stop */
11847
+ static fromGlob(pattern, options = {}) {
11848
+ return orig.AST.fromGlob(pattern, ext(def, options));
11849
+ }
11850
+ },
11851
+ unescape: (s, options = {}) => orig.unescape(s, ext(def, options)),
11852
+ escape: (s, options = {}) => orig.escape(s, ext(def, options)),
11853
+ filter: (pattern, options = {}) => orig.filter(pattern, ext(def, options)),
11854
+ defaults: (options) => orig.defaults(ext(def, options)),
11855
+ makeRe: (pattern, options = {}) => orig.makeRe(pattern, ext(def, options)),
11856
+ braceExpand: (pattern, options = {}) => orig.braceExpand(pattern, ext(def, options)),
11857
+ match: (list, pattern, options = {}) => orig.match(list, pattern, ext(def, options)),
11858
+ sep: orig.sep,
11859
+ GLOBSTAR
11860
+ });
11861
+ };
11862
+ minimatch.defaults = defaults;
11863
+ var braceExpand = (pattern, options = {}) => {
11864
+ assertValidPattern(pattern);
11865
+ if (options.nobrace || !/\{(?:(?!\{).)*\}/.test(pattern)) {
11866
+ return [pattern];
11867
+ }
11868
+ return (0, import_brace_expansion.default)(pattern);
11869
+ };
11870
+ minimatch.braceExpand = braceExpand;
11871
+ var makeRe = (pattern, options = {}) => new Minimatch(pattern, options).makeRe();
11872
+ minimatch.makeRe = makeRe;
11873
+ var match = (list, pattern, options = {}) => {
11874
+ const mm = new Minimatch(pattern, options);
11875
+ list = list.filter((f) => mm.match(f));
11876
+ if (mm.options.nonull && !list.length) {
11877
+ list.push(pattern);
11878
+ }
11879
+ return list;
11880
+ };
11881
+ minimatch.match = match;
11882
+ var globMagic = /[?*]|[+@!]\(.*?\)|\[|\]/;
11883
+ var regExpEscape2 = (s) => s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
11884
+ var Minimatch = class {
11885
+ options;
11886
+ set;
11887
+ pattern;
11888
+ windowsPathsNoEscape;
11889
+ nonegate;
11890
+ negate;
11891
+ comment;
11892
+ empty;
11893
+ preserveMultipleSlashes;
11894
+ partial;
11895
+ globSet;
11896
+ globParts;
11897
+ nocase;
11898
+ isWindows;
11899
+ platform;
11900
+ windowsNoMagicRoot;
11901
+ maxGlobstarRecursion;
11902
+ regexp;
11903
+ constructor(pattern, options = {}) {
11904
+ assertValidPattern(pattern);
11905
+ options = options || {};
11906
+ this.options = options;
11907
+ this.maxGlobstarRecursion = options.maxGlobstarRecursion ?? 200;
11908
+ this.pattern = pattern;
11909
+ this.platform = options.platform || defaultPlatform;
11910
+ this.isWindows = this.platform === "win32";
11911
+ this.windowsPathsNoEscape = !!options.windowsPathsNoEscape || options.allowWindowsEscape === false;
11912
+ if (this.windowsPathsNoEscape) {
11913
+ this.pattern = this.pattern.replace(/\\/g, "/");
11914
+ }
11915
+ this.preserveMultipleSlashes = !!options.preserveMultipleSlashes;
11916
+ this.regexp = null;
11917
+ this.negate = false;
11918
+ this.nonegate = !!options.nonegate;
11919
+ this.comment = false;
11920
+ this.empty = false;
11921
+ this.partial = !!options.partial;
11922
+ this.nocase = !!this.options.nocase;
11923
+ this.windowsNoMagicRoot = options.windowsNoMagicRoot !== void 0 ? options.windowsNoMagicRoot : !!(this.isWindows && this.nocase);
11924
+ this.globSet = [];
11925
+ this.globParts = [];
11926
+ this.set = [];
11927
+ this.make();
11928
+ }
11929
+ hasMagic() {
11930
+ if (this.options.magicalBraces && this.set.length > 1) {
11931
+ return true;
11932
+ }
11933
+ for (const pattern of this.set) {
11934
+ for (const part of pattern) {
11935
+ if (typeof part !== "string")
11936
+ return true;
11937
+ }
11938
+ }
11939
+ return false;
11940
+ }
11941
+ debug(..._) {
11942
+ }
11943
+ make() {
11944
+ const pattern = this.pattern;
11945
+ const options = this.options;
11946
+ if (!options.nocomment && pattern.charAt(0) === "#") {
11947
+ this.comment = true;
11948
+ return;
11949
+ }
11950
+ if (!pattern) {
11951
+ this.empty = true;
11952
+ return;
11953
+ }
11954
+ this.parseNegate();
11955
+ this.globSet = [...new Set(this.braceExpand())];
11956
+ if (options.debug) {
11957
+ this.debug = (...args) => console.error(...args);
11958
+ }
11959
+ this.debug(this.pattern, this.globSet);
11960
+ const rawGlobParts = this.globSet.map((s) => this.slashSplit(s));
11961
+ this.globParts = this.preprocess(rawGlobParts);
11962
+ this.debug(this.pattern, this.globParts);
11963
+ let set = this.globParts.map((s, _, __) => {
11964
+ if (this.isWindows && this.windowsNoMagicRoot) {
11965
+ const isUNC = s[0] === "" && s[1] === "" && (s[2] === "?" || !globMagic.test(s[2])) && !globMagic.test(s[3]);
11966
+ const isDrive = /^[a-z]:/i.test(s[0]);
11967
+ if (isUNC) {
11968
+ return [...s.slice(0, 4), ...s.slice(4).map((ss) => this.parse(ss))];
11969
+ } else if (isDrive) {
11970
+ return [s[0], ...s.slice(1).map((ss) => this.parse(ss))];
11971
+ }
11972
+ }
11973
+ return s.map((ss) => this.parse(ss));
11974
+ });
11975
+ this.debug(this.pattern, set);
11976
+ this.set = set.filter((s) => s.indexOf(false) === -1);
11977
+ if (this.isWindows) {
11978
+ for (let i = 0; i < this.set.length; i++) {
11979
+ const p = this.set[i];
11980
+ if (p[0] === "" && p[1] === "" && this.globParts[i][2] === "?" && typeof p[3] === "string" && /^[a-z]:$/i.test(p[3])) {
11981
+ p[2] = "?";
11982
+ }
11983
+ }
11984
+ }
11985
+ this.debug(this.pattern, this.set);
11986
+ }
11987
+ // various transforms to equivalent pattern sets that are
11988
+ // faster to process in a filesystem walk. The goal is to
11989
+ // eliminate what we can, and push all ** patterns as far
11990
+ // to the right as possible, even if it increases the number
11991
+ // of patterns that we have to process.
11992
+ preprocess(globParts) {
11993
+ if (this.options.noglobstar) {
11994
+ for (let i = 0; i < globParts.length; i++) {
11995
+ for (let j = 0; j < globParts[i].length; j++) {
11996
+ if (globParts[i][j] === "**") {
11997
+ globParts[i][j] = "*";
11998
+ }
11999
+ }
12000
+ }
12001
+ }
12002
+ const { optimizationLevel = 1 } = this.options;
12003
+ if (optimizationLevel >= 2) {
12004
+ globParts = this.firstPhasePreProcess(globParts);
12005
+ globParts = this.secondPhasePreProcess(globParts);
12006
+ } else if (optimizationLevel >= 1) {
12007
+ globParts = this.levelOneOptimize(globParts);
12008
+ } else {
12009
+ globParts = this.adjascentGlobstarOptimize(globParts);
12010
+ }
12011
+ return globParts;
12012
+ }
12013
+ // just get rid of adjascent ** portions
12014
+ adjascentGlobstarOptimize(globParts) {
12015
+ return globParts.map((parts) => {
12016
+ let gs = -1;
12017
+ while (-1 !== (gs = parts.indexOf("**", gs + 1))) {
12018
+ let i = gs;
12019
+ while (parts[i + 1] === "**") {
12020
+ i++;
12021
+ }
12022
+ if (i !== gs) {
12023
+ parts.splice(gs, i - gs);
12024
+ }
12025
+ }
12026
+ return parts;
12027
+ });
12028
+ }
12029
+ // get rid of adjascent ** and resolve .. portions
12030
+ levelOneOptimize(globParts) {
12031
+ return globParts.map((parts) => {
12032
+ parts = parts.reduce((set, part) => {
12033
+ const prev = set[set.length - 1];
12034
+ if (part === "**" && prev === "**") {
12035
+ return set;
12036
+ }
12037
+ if (part === "..") {
12038
+ if (prev && prev !== ".." && prev !== "." && prev !== "**") {
12039
+ set.pop();
12040
+ return set;
12041
+ }
12042
+ }
12043
+ set.push(part);
12044
+ return set;
12045
+ }, []);
12046
+ return parts.length === 0 ? [""] : parts;
12047
+ });
12048
+ }
12049
+ levelTwoFileOptimize(parts) {
12050
+ if (!Array.isArray(parts)) {
12051
+ parts = this.slashSplit(parts);
12052
+ }
12053
+ let didSomething = false;
12054
+ do {
12055
+ didSomething = false;
12056
+ if (!this.preserveMultipleSlashes) {
12057
+ for (let i = 1; i < parts.length - 1; i++) {
12058
+ const p = parts[i];
12059
+ if (i === 1 && p === "" && parts[0] === "")
12060
+ continue;
12061
+ if (p === "." || p === "") {
12062
+ didSomething = true;
12063
+ parts.splice(i, 1);
12064
+ i--;
12065
+ }
12066
+ }
12067
+ if (parts[0] === "." && parts.length === 2 && (parts[1] === "." || parts[1] === "")) {
12068
+ didSomething = true;
12069
+ parts.pop();
12070
+ }
12071
+ }
12072
+ let dd = 0;
12073
+ while (-1 !== (dd = parts.indexOf("..", dd + 1))) {
12074
+ const p = parts[dd - 1];
12075
+ if (p && p !== "." && p !== ".." && p !== "**") {
12076
+ didSomething = true;
12077
+ parts.splice(dd - 1, 2);
12078
+ dd -= 2;
12079
+ }
12080
+ }
12081
+ } while (didSomething);
12082
+ return parts.length === 0 ? [""] : parts;
12083
+ }
12084
+ // First phase: single-pattern processing
12085
+ // <pre> is 1 or more portions
12086
+ // <rest> is 1 or more portions
12087
+ // <p> is any portion other than ., .., '', or **
12088
+ // <e> is . or ''
12089
+ //
12090
+ // **/.. is *brutal* for filesystem walking performance, because
12091
+ // it effectively resets the recursive walk each time it occurs,
12092
+ // and ** cannot be reduced out by a .. pattern part like a regexp
12093
+ // or most strings (other than .., ., and '') can be.
12094
+ //
12095
+ // <pre>/**/../<p>/<p>/<rest> -> {<pre>/../<p>/<p>/<rest>,<pre>/**/<p>/<p>/<rest>}
12096
+ // <pre>/<e>/<rest> -> <pre>/<rest>
12097
+ // <pre>/<p>/../<rest> -> <pre>/<rest>
12098
+ // **/**/<rest> -> **/<rest>
12099
+ //
12100
+ // **/*/<rest> -> */**/<rest> <== not valid because ** doesn't follow
12101
+ // this WOULD be allowed if ** did follow symlinks, or * didn't
12102
+ firstPhasePreProcess(globParts) {
12103
+ let didSomething = false;
12104
+ do {
12105
+ didSomething = false;
12106
+ for (let parts of globParts) {
12107
+ let gs = -1;
12108
+ while (-1 !== (gs = parts.indexOf("**", gs + 1))) {
12109
+ let gss = gs;
12110
+ while (parts[gss + 1] === "**") {
12111
+ gss++;
12112
+ }
12113
+ if (gss > gs) {
12114
+ parts.splice(gs + 1, gss - gs);
12115
+ }
12116
+ let next = parts[gs + 1];
12117
+ const p = parts[gs + 2];
12118
+ const p2 = parts[gs + 3];
12119
+ if (next !== "..")
12120
+ continue;
12121
+ if (!p || p === "." || p === ".." || !p2 || p2 === "." || p2 === "..") {
12122
+ continue;
12123
+ }
12124
+ didSomething = true;
12125
+ parts.splice(gs, 1);
12126
+ const other = parts.slice(0);
12127
+ other[gs] = "**";
12128
+ globParts.push(other);
12129
+ gs--;
12130
+ }
12131
+ if (!this.preserveMultipleSlashes) {
12132
+ for (let i = 1; i < parts.length - 1; i++) {
12133
+ const p = parts[i];
12134
+ if (i === 1 && p === "" && parts[0] === "")
12135
+ continue;
12136
+ if (p === "." || p === "") {
12137
+ didSomething = true;
12138
+ parts.splice(i, 1);
12139
+ i--;
12140
+ }
12141
+ }
12142
+ if (parts[0] === "." && parts.length === 2 && (parts[1] === "." || parts[1] === "")) {
12143
+ didSomething = true;
12144
+ parts.pop();
12145
+ }
12146
+ }
12147
+ let dd = 0;
12148
+ while (-1 !== (dd = parts.indexOf("..", dd + 1))) {
12149
+ const p = parts[dd - 1];
12150
+ if (p && p !== "." && p !== ".." && p !== "**") {
12151
+ didSomething = true;
12152
+ const needDot = dd === 1 && parts[dd + 1] === "**";
12153
+ const splin = needDot ? ["."] : [];
12154
+ parts.splice(dd - 1, 2, ...splin);
12155
+ if (parts.length === 0)
12156
+ parts.push("");
12157
+ dd -= 2;
12158
+ }
12159
+ }
12160
+ }
12161
+ } while (didSomething);
12162
+ return globParts;
12163
+ }
12164
+ // second phase: multi-pattern dedupes
12165
+ // {<pre>/*/<rest>,<pre>/<p>/<rest>} -> <pre>/*/<rest>
12166
+ // {<pre>/<rest>,<pre>/<rest>} -> <pre>/<rest>
12167
+ // {<pre>/**/<rest>,<pre>/<rest>} -> <pre>/**/<rest>
12168
+ //
12169
+ // {<pre>/**/<rest>,<pre>/**/<p>/<rest>} -> <pre>/**/<rest>
12170
+ // ^-- not valid because ** doens't follow symlinks
12171
+ secondPhasePreProcess(globParts) {
12172
+ for (let i = 0; i < globParts.length - 1; i++) {
12173
+ for (let j = i + 1; j < globParts.length; j++) {
12174
+ const matched = this.partsMatch(globParts[i], globParts[j], !this.preserveMultipleSlashes);
12175
+ if (matched) {
12176
+ globParts[i] = [];
12177
+ globParts[j] = matched;
12178
+ break;
12179
+ }
12180
+ }
12181
+ }
12182
+ return globParts.filter((gs) => gs.length);
12183
+ }
12184
+ partsMatch(a, b, emptyGSMatch = false) {
12185
+ let ai = 0;
12186
+ let bi = 0;
12187
+ let result = [];
12188
+ let which = "";
12189
+ while (ai < a.length && bi < b.length) {
12190
+ if (a[ai] === b[bi]) {
12191
+ result.push(which === "b" ? b[bi] : a[ai]);
12192
+ ai++;
12193
+ bi++;
12194
+ } else if (emptyGSMatch && a[ai] === "**" && b[bi] === a[ai + 1]) {
12195
+ result.push(a[ai]);
12196
+ ai++;
12197
+ } else if (emptyGSMatch && b[bi] === "**" && a[ai] === b[bi + 1]) {
12198
+ result.push(b[bi]);
12199
+ bi++;
12200
+ } else if (a[ai] === "*" && b[bi] && (this.options.dot || !b[bi].startsWith(".")) && b[bi] !== "**") {
12201
+ if (which === "b")
12202
+ return false;
12203
+ which = "a";
12204
+ result.push(a[ai]);
12205
+ ai++;
12206
+ bi++;
12207
+ } else if (b[bi] === "*" && a[ai] && (this.options.dot || !a[ai].startsWith(".")) && a[ai] !== "**") {
12208
+ if (which === "a")
12209
+ return false;
12210
+ which = "b";
12211
+ result.push(b[bi]);
12212
+ ai++;
12213
+ bi++;
12214
+ } else {
12215
+ return false;
12216
+ }
12217
+ }
12218
+ return a.length === b.length && result;
12219
+ }
12220
+ parseNegate() {
12221
+ if (this.nonegate)
12222
+ return;
12223
+ const pattern = this.pattern;
12224
+ let negate = false;
12225
+ let negateOffset = 0;
12226
+ for (let i = 0; i < pattern.length && pattern.charAt(i) === "!"; i++) {
12227
+ negate = !negate;
12228
+ negateOffset++;
12229
+ }
12230
+ if (negateOffset)
12231
+ this.pattern = pattern.slice(negateOffset);
12232
+ this.negate = negate;
12233
+ }
12234
+ // set partial to true to test if, for example,
12235
+ // "/a/b" matches the start of "/*/b/*/d"
12236
+ // Partial means, if you run out of file before you run
12237
+ // out of pattern, then that's fine, as long as all
12238
+ // the parts match.
12239
+ matchOne(file, pattern, partial = false) {
12240
+ let fileStartIndex = 0;
12241
+ let patternStartIndex = 0;
12242
+ if (this.isWindows) {
12243
+ const fileDrive = typeof file[0] === "string" && /^[a-z]:$/i.test(file[0]);
12244
+ const fileUNC = !fileDrive && file[0] === "" && file[1] === "" && file[2] === "?" && /^[a-z]:$/i.test(file[3]);
12245
+ const patternDrive = typeof pattern[0] === "string" && /^[a-z]:$/i.test(pattern[0]);
12246
+ const patternUNC = !patternDrive && pattern[0] === "" && pattern[1] === "" && pattern[2] === "?" && typeof pattern[3] === "string" && /^[a-z]:$/i.test(pattern[3]);
12247
+ const fdi = fileUNC ? 3 : fileDrive ? 0 : void 0;
12248
+ const pdi = patternUNC ? 3 : patternDrive ? 0 : void 0;
12249
+ if (typeof fdi === "number" && typeof pdi === "number") {
12250
+ const [fd, pd] = [
12251
+ file[fdi],
12252
+ pattern[pdi]
12253
+ ];
12254
+ if (fd.toLowerCase() === pd.toLowerCase()) {
12255
+ pattern[pdi] = fd;
12256
+ patternStartIndex = pdi;
12257
+ fileStartIndex = fdi;
12258
+ }
12259
+ }
12260
+ }
12261
+ const { optimizationLevel = 1 } = this.options;
12262
+ if (optimizationLevel >= 2) {
12263
+ file = this.levelTwoFileOptimize(file);
12264
+ }
12265
+ if (pattern.includes(GLOBSTAR)) {
12266
+ return this.#matchGlobstar(file, pattern, partial, fileStartIndex, patternStartIndex);
12267
+ }
12268
+ return this.#matchOne(file, pattern, partial, fileStartIndex, patternStartIndex);
12269
+ }
12270
+ #matchGlobstar(file, pattern, partial, fileIndex, patternIndex) {
12271
+ const firstgs = pattern.indexOf(GLOBSTAR, patternIndex);
12272
+ const lastgs = pattern.lastIndexOf(GLOBSTAR);
12273
+ const [head, body, tail] = partial ? [
12274
+ pattern.slice(patternIndex, firstgs),
12275
+ pattern.slice(firstgs + 1),
12276
+ []
12277
+ ] : [
12278
+ pattern.slice(patternIndex, firstgs),
12279
+ pattern.slice(firstgs + 1, lastgs),
12280
+ pattern.slice(lastgs + 1)
12281
+ ];
12282
+ if (head.length) {
12283
+ const fileHead = file.slice(fileIndex, fileIndex + head.length);
12284
+ if (!this.#matchOne(fileHead, head, partial, 0, 0))
12285
+ return false;
12286
+ fileIndex += head.length;
12287
+ }
12288
+ let fileTailMatch = 0;
12289
+ if (tail.length) {
12290
+ if (tail.length + fileIndex > file.length)
12291
+ return false;
12292
+ let tailStart = file.length - tail.length;
12293
+ if (this.#matchOne(file, tail, partial, tailStart, 0)) {
12294
+ fileTailMatch = tail.length;
12295
+ } else {
12296
+ if (file[file.length - 1] !== "" || fileIndex + tail.length === file.length) {
12297
+ return false;
12298
+ }
12299
+ tailStart--;
12300
+ if (!this.#matchOne(file, tail, partial, tailStart, 0))
12301
+ return false;
12302
+ fileTailMatch = tail.length + 1;
12303
+ }
12304
+ }
12305
+ if (!body.length) {
12306
+ let sawSome = !!fileTailMatch;
12307
+ for (let i2 = fileIndex; i2 < file.length - fileTailMatch; i2++) {
12308
+ const f = String(file[i2]);
12309
+ sawSome = true;
12310
+ if (f === "." || f === ".." || !this.options.dot && f.startsWith(".")) {
12311
+ return false;
12312
+ }
12313
+ }
12314
+ return partial || sawSome;
12315
+ }
12316
+ const bodySegments = [[[], 0]];
12317
+ let currentBody = bodySegments[0];
12318
+ let nonGsParts = 0;
12319
+ const nonGsPartsSums = [0];
12320
+ for (const b of body) {
12321
+ if (b === GLOBSTAR) {
12322
+ nonGsPartsSums.push(nonGsParts);
12323
+ currentBody = [[], 0];
12324
+ bodySegments.push(currentBody);
12325
+ } else {
12326
+ currentBody[0].push(b);
12327
+ nonGsParts++;
12328
+ }
12329
+ }
12330
+ let i = bodySegments.length - 1;
12331
+ const fileLength = file.length - fileTailMatch;
12332
+ for (const b of bodySegments) {
12333
+ b[1] = fileLength - (nonGsPartsSums[i--] + b[0].length);
12334
+ }
12335
+ return !!this.#matchGlobStarBodySections(file, bodySegments, fileIndex, 0, partial, 0, !!fileTailMatch);
12336
+ }
12337
+ #matchGlobStarBodySections(file, bodySegments, fileIndex, bodyIndex, partial, globStarDepth, sawTail) {
12338
+ const bs = bodySegments[bodyIndex];
12339
+ if (!bs) {
12340
+ for (let i = fileIndex; i < file.length; i++) {
12341
+ sawTail = true;
12342
+ const f = file[i];
12343
+ if (f === "." || f === ".." || !this.options.dot && f.startsWith(".")) {
12344
+ return false;
12345
+ }
12346
+ }
12347
+ return sawTail;
12348
+ }
12349
+ const [body, after] = bs;
12350
+ while (fileIndex <= after) {
12351
+ const m = this.#matchOne(file.slice(0, fileIndex + body.length), body, partial, fileIndex, 0);
12352
+ if (m && globStarDepth < this.maxGlobstarRecursion) {
12353
+ const sub = this.#matchGlobStarBodySections(file, bodySegments, fileIndex + body.length, bodyIndex + 1, partial, globStarDepth + 1, sawTail);
12354
+ if (sub !== false)
12355
+ return sub;
12356
+ }
12357
+ const f = file[fileIndex];
12358
+ if (f === "." || f === ".." || !this.options.dot && f.startsWith(".")) {
12359
+ return false;
12360
+ }
12361
+ fileIndex++;
12362
+ }
12363
+ return partial || null;
12364
+ }
12365
+ #matchOne(file, pattern, partial, fileIndex, patternIndex) {
12366
+ let fi;
12367
+ let pi;
12368
+ let pl;
12369
+ let fl;
12370
+ for (fi = fileIndex, pi = patternIndex, fl = file.length, pl = pattern.length; fi < fl && pi < pl; fi++, pi++) {
12371
+ this.debug("matchOne loop");
12372
+ let p = pattern[pi];
12373
+ let f = file[fi];
12374
+ this.debug(pattern, p, f);
12375
+ if (p === false || p === GLOBSTAR)
12376
+ return false;
12377
+ let hit;
12378
+ if (typeof p === "string") {
12379
+ hit = f === p;
12380
+ this.debug("string match", p, f, hit);
12381
+ } else {
12382
+ hit = p.test(f);
12383
+ this.debug("pattern match", p, f, hit);
12384
+ }
12385
+ if (!hit)
12386
+ return false;
12387
+ }
12388
+ if (fi === fl && pi === pl) {
12389
+ return true;
12390
+ } else if (fi === fl) {
12391
+ return partial;
12392
+ } else if (pi === pl) {
12393
+ return fi === fl - 1 && file[fi] === "";
12394
+ } else {
12395
+ throw new Error("wtf?");
12396
+ }
12397
+ }
12398
+ braceExpand() {
12399
+ return braceExpand(this.pattern, this.options);
12400
+ }
12401
+ parse(pattern) {
12402
+ assertValidPattern(pattern);
12403
+ const options = this.options;
12404
+ if (pattern === "**")
12405
+ return GLOBSTAR;
12406
+ if (pattern === "")
12407
+ return "";
12408
+ let m;
12409
+ let fastTest = null;
12410
+ if (m = pattern.match(starRE)) {
12411
+ fastTest = options.dot ? starTestDot : starTest;
12412
+ } else if (m = pattern.match(starDotExtRE)) {
12413
+ fastTest = (options.nocase ? options.dot ? starDotExtTestNocaseDot : starDotExtTestNocase : options.dot ? starDotExtTestDot : starDotExtTest)(m[1]);
12414
+ } else if (m = pattern.match(qmarksRE)) {
12415
+ fastTest = (options.nocase ? options.dot ? qmarksTestNocaseDot : qmarksTestNocase : options.dot ? qmarksTestDot : qmarksTest)(m);
12416
+ } else if (m = pattern.match(starDotStarRE)) {
12417
+ fastTest = options.dot ? starDotStarTestDot : starDotStarTest;
12418
+ } else if (m = pattern.match(dotStarRE)) {
12419
+ fastTest = dotStarTest;
12420
+ }
12421
+ const re = AST.fromGlob(pattern, this.options).toMMPattern();
12422
+ if (fastTest && typeof re === "object") {
12423
+ Reflect.defineProperty(re, "test", { value: fastTest });
12424
+ }
12425
+ return re;
12426
+ }
12427
+ makeRe() {
12428
+ if (this.regexp || this.regexp === false)
12429
+ return this.regexp;
12430
+ const set = this.set;
12431
+ if (!set.length) {
12432
+ this.regexp = false;
12433
+ return this.regexp;
12434
+ }
12435
+ const options = this.options;
12436
+ const twoStar = options.noglobstar ? star2 : options.dot ? twoStarDot : twoStarNoDot;
12437
+ const flags = new Set(options.nocase ? ["i"] : []);
12438
+ let re = set.map((pattern) => {
12439
+ const pp = pattern.map((p) => {
12440
+ if (p instanceof RegExp) {
12441
+ for (const f of p.flags.split(""))
12442
+ flags.add(f);
12443
+ }
12444
+ return typeof p === "string" ? regExpEscape2(p) : p === GLOBSTAR ? GLOBSTAR : p._src;
12445
+ });
12446
+ pp.forEach((p, i) => {
12447
+ const next = pp[i + 1];
12448
+ const prev = pp[i - 1];
12449
+ if (p !== GLOBSTAR || prev === GLOBSTAR) {
12450
+ return;
12451
+ }
12452
+ if (prev === void 0) {
12453
+ if (next !== void 0 && next !== GLOBSTAR) {
12454
+ pp[i + 1] = "(?:\\/|" + twoStar + "\\/)?" + next;
12455
+ } else {
12456
+ pp[i] = twoStar;
12457
+ }
12458
+ } else if (next === void 0) {
12459
+ pp[i - 1] = prev + "(?:\\/|" + twoStar + ")?";
12460
+ } else if (next !== GLOBSTAR) {
12461
+ pp[i - 1] = prev + "(?:\\/|\\/" + twoStar + "\\/)" + next;
12462
+ pp[i + 1] = GLOBSTAR;
12463
+ }
12464
+ });
12465
+ return pp.filter((p) => p !== GLOBSTAR).join("/");
12466
+ }).join("|");
12467
+ const [open2, close] = set.length > 1 ? ["(?:", ")"] : ["", ""];
12468
+ re = "^" + open2 + re + close + "$";
12469
+ if (this.negate)
12470
+ re = "^(?!" + re + ").+$";
12471
+ try {
12472
+ this.regexp = new RegExp(re, [...flags].join(""));
12473
+ } catch (ex) {
12474
+ this.regexp = false;
12475
+ }
12476
+ return this.regexp;
12477
+ }
12478
+ slashSplit(p) {
12479
+ if (this.preserveMultipleSlashes) {
12480
+ return p.split("/");
12481
+ } else if (this.isWindows && /^\/\/[^\/]+/.test(p)) {
12482
+ return ["", ...p.split(/\/+/)];
12483
+ } else {
12484
+ return p.split(/\/+/);
12485
+ }
12486
+ }
12487
+ match(f, partial = this.partial) {
12488
+ this.debug("match", f, this.pattern);
12489
+ if (this.comment) {
12490
+ return false;
12491
+ }
12492
+ if (this.empty) {
12493
+ return f === "";
12494
+ }
12495
+ if (f === "/" && partial) {
12496
+ return true;
12497
+ }
12498
+ const options = this.options;
12499
+ if (this.isWindows) {
12500
+ f = f.split("\\").join("/");
12501
+ }
12502
+ const ff = this.slashSplit(f);
12503
+ this.debug(this.pattern, "split", ff);
12504
+ const set = this.set;
12505
+ this.debug(this.pattern, "set", set);
12506
+ let filename = ff[ff.length - 1];
12507
+ if (!filename) {
12508
+ for (let i = ff.length - 2; !filename && i >= 0; i--) {
12509
+ filename = ff[i];
12510
+ }
12511
+ }
12512
+ for (let i = 0; i < set.length; i++) {
12513
+ const pattern = set[i];
12514
+ let file = ff;
12515
+ if (options.matchBase && pattern.length === 1) {
12516
+ file = [filename];
12517
+ }
12518
+ const hit = this.matchOne(file, pattern, partial);
12519
+ if (hit) {
12520
+ if (options.flipNegate) {
12521
+ return true;
12522
+ }
12523
+ return !this.negate;
12524
+ }
12525
+ }
12526
+ if (options.flipNegate) {
12527
+ return false;
12528
+ }
12529
+ return this.negate;
12530
+ }
12531
+ static defaults(def) {
12532
+ return minimatch.defaults(def).Minimatch;
12533
+ }
12534
+ };
12535
+ minimatch.AST = AST;
12536
+ minimatch.Minimatch = Minimatch;
12537
+ minimatch.escape = escape;
12538
+ minimatch.unescape = unescape;
12539
+
12540
+ // ../../packages/flint-server/dist/index.js
12541
+ import { parse as parseYaml } from "yaml";
12542
+ import { existsSync as existsSync10, watch as watch3 } from "fs";
12543
+ import { stat as stat22 } from "fs/promises";
12544
+ import path22 from "path";
12545
+ import { mkdir as mkdir5, readFile as readFile22, writeFile as writeFile3 } from "fs/promises";
12546
+ import { homedir as homedir6 } from "os";
12547
+ import { join as join11, resolve as resolve7 } from "path";
12548
+ import { existsSync as existsSync23 } from "fs";
12549
+ import { stat as stat32, readFile as readFile32 } from "fs/promises";
12550
+ import path32 from "path";
12551
+ import { existsSync as existsSync33 } from "fs";
12552
+ import { spawn as spawn22 } from "child_process";
12553
+ import { readFile as readFile42 } from "fs/promises";
12554
+ import path42 from "path";
12555
+ import { readdir as readdir2 } from "fs/promises";
12556
+ import path5 from "path";
12557
+ import { readdir as readdir22 } from "fs/promises";
12558
+ import { join as join23 } from "path";
12559
+ import { mkdir as mkdir22, readFile as readFile52, rename as rename2, writeFile as writeFile22, readdir as readdir3 } from "fs/promises";
12560
+ import path6 from "path";
12561
+ import { randomUUID as randomUUID22 } from "crypto";
12562
+ import { writeFile as writeFile32, mkdir as mkdir32, readdir as readdir4, readFile as readFile62, stat as stat42 } from "fs/promises";
12563
+ import { join as join33 } from "path";
12564
+ var DEFAULT_EVENT_LOG_SIZE = 200;
12565
+ function computeRuntimeId(flintPath) {
12566
+ const resolved = path4.resolve(flintPath);
12567
+ return createHash2("sha1").update(resolved).digest("hex").slice(0, 10);
12568
+ }
12569
+ function createRuntime(options) {
12570
+ return new FlintRuntimeImpl(options);
12571
+ }
12572
+ var FlintRuntimeImpl = class {
12573
+ id;
12574
+ flintPath;
12575
+ hooksPath;
12576
+ logger;
12577
+ eventLogSize;
12578
+ emitter = new EventEmitter();
12579
+ watcher = null;
12580
+ hooksConfig = { hooks: {} };
12581
+ eventLog = [];
12582
+ frontmatterCache = /* @__PURE__ */ new Map();
12583
+ sessionCache = /* @__PURE__ */ new Map();
12584
+ startedAt = null;
12585
+ constructor(options) {
12586
+ this.flintPath = path4.resolve(options.flintPath);
12587
+ this.hooksPath = options.hooksPath ? path4.resolve(options.hooksPath) : path4.join(this.flintPath, "flint-hooks.toml");
12588
+ this.id = computeRuntimeId(this.flintPath);
12589
+ this.eventLogSize = options.eventLogSize ?? DEFAULT_EVENT_LOG_SIZE;
12590
+ this.logger = options.logger ?? {
12591
+ debug: (...args) => console.debug("[flint-runtime]", ...args),
12592
+ info: (...args) => console.info("[flint-runtime]", ...args),
12593
+ warn: (...args) => console.warn("[flint-runtime]", ...args),
12594
+ error: (...args) => console.error("[flint-runtime]", ...args)
12595
+ };
12596
+ }
12597
+ on(event, handler) {
12598
+ this.emitter.on(event, handler);
12599
+ }
12600
+ off(event, handler) {
12601
+ this.emitter.off(event, handler);
12602
+ }
12603
+ async start() {
12604
+ if (this.watcher) {
12605
+ return;
12606
+ }
12607
+ await this.reloadHooks();
12608
+ await this.seedCaches();
12609
+ const relativeHooksPath = path4.relative(this.flintPath, this.hooksPath);
12610
+ const watchPatterns = [
12611
+ "Mesh/**/*.md",
12612
+ ".flint/sessions/*.json",
12613
+ relativeHooksPath || "flint-hooks.toml"
12614
+ ];
12615
+ this.watcher = chokidar.watch(watchPatterns, {
12616
+ cwd: this.flintPath,
12617
+ ignoreInitial: true,
12618
+ awaitWriteFinish: {
12619
+ stabilityThreshold: 200,
12620
+ pollInterval: 50
12621
+ }
12622
+ });
12623
+ this.watcher.on("add", (filePath) => this.handleWatchEvent("add", filePath));
12624
+ this.watcher.on("change", (filePath) => this.handleWatchEvent("change", filePath));
12625
+ this.watcher.on("unlink", (filePath) => this.handleWatchEvent("unlink", filePath));
12626
+ this.startedAt = (/* @__PURE__ */ new Date()).toISOString();
12627
+ await this.emitEvent("RuntimeStart", {
12628
+ startedAt: this.startedAt
12629
+ });
12630
+ }
12631
+ async stop() {
12632
+ if (!this.watcher) {
12633
+ return;
12634
+ }
12635
+ await this.emitEvent("RuntimeStop", {
12636
+ stoppedAt: (/* @__PURE__ */ new Date()).toISOString()
12637
+ });
12638
+ await this.watcher.close();
12639
+ this.watcher = null;
12640
+ }
12641
+ async reloadHooks() {
12642
+ this.hooksConfig = await loadHooksConfig(this.hooksPath, this.logger);
12643
+ }
12644
+ getStatus() {
12645
+ return {
12646
+ id: this.id,
12647
+ flintPath: this.flintPath,
12648
+ hooksPath: this.hooksPath,
12649
+ startedAt: this.startedAt,
12650
+ watching: this.watcher !== null,
12651
+ hookCount: countHooks(this.hooksConfig)
12652
+ };
12653
+ }
12654
+ getEventLog() {
12655
+ return [...this.eventLog];
12656
+ }
12657
+ async seedCaches() {
12658
+ const meshFiles = await glob("Mesh/**/*.md", {
12659
+ cwd: this.flintPath,
12660
+ nodir: true
12661
+ });
12662
+ await Promise.all(
12663
+ meshFiles.map(async (filePath) => {
12664
+ const snapshot = await this.readFrontmatterSnapshot(filePath);
12665
+ if (snapshot) {
12666
+ this.frontmatterCache.set(filePath, snapshot);
12667
+ }
12668
+ })
12669
+ );
12670
+ const sessionFiles = await glob(".flint/sessions/*.json", {
12671
+ cwd: this.flintPath,
12672
+ nodir: true
12673
+ });
12674
+ await Promise.all(
12675
+ sessionFiles.map(async (filePath) => {
12676
+ const snapshot = await this.readSessionSnapshot(filePath);
12677
+ if (snapshot) {
12678
+ const sessionId = path4.basename(filePath, ".json");
12679
+ this.sessionCache.set(sessionId, snapshot);
12680
+ }
12681
+ })
12682
+ );
12683
+ }
12684
+ async handleWatchEvent(event, filePath) {
12685
+ const normalized = normalizePath(filePath);
12686
+ if (normalized === normalizePath(path4.relative(this.flintPath, this.hooksPath))) {
12687
+ if (event === "change") {
12688
+ this.logger.info?.("Reloading hooks config");
12689
+ await this.reloadHooks();
12690
+ }
12691
+ return;
12692
+ }
12693
+ if (normalized.startsWith("Mesh/")) {
12694
+ if (event === "unlink") {
12695
+ this.frontmatterCache.delete(normalized);
12696
+ return;
12697
+ }
12698
+ await this.handleMeshFileChange(normalized);
12699
+ return;
12700
+ }
12701
+ if (normalized.startsWith(".flint/sessions/")) {
12702
+ if (event === "unlink") {
12703
+ const sessionId = path4.basename(normalized, ".json");
12704
+ this.sessionCache.delete(sessionId);
12705
+ return;
12706
+ }
12707
+ await this.handleSessionFileChange(normalized);
12708
+ return;
12709
+ }
12710
+ }
12711
+ async handleMeshFileChange(relativePath) {
12712
+ const snapshot = await this.readFrontmatterSnapshot(relativePath);
12713
+ if (!snapshot) {
12714
+ return;
12715
+ }
12716
+ const previous = this.frontmatterCache.get(relativePath);
12717
+ this.frontmatterCache.set(relativePath, snapshot);
12718
+ await this.emitEvent("FileChanged", {
12719
+ path: relativePath,
12720
+ absolutePath: path4.join(this.flintPath, relativePath),
12721
+ frontmatter: snapshot,
12722
+ previousFrontmatter: previous ?? null
12723
+ });
12724
+ if (!previous) {
12725
+ return;
12726
+ }
12727
+ if (previous.status !== snapshot.status) {
12728
+ await this.emitEvent("StatusChanged", {
12729
+ path: relativePath,
12730
+ absolutePath: path4.join(this.flintPath, relativePath),
12731
+ field: "status",
12732
+ from: previous.status ?? null,
12733
+ to: snapshot.status ?? null,
12734
+ tags: snapshot.tags
12735
+ });
12736
+ }
12737
+ const addedTags = snapshot.tags.filter((tag) => !previous.tags.includes(tag));
12738
+ const removedTags = previous.tags.filter((tag) => !snapshot.tags.includes(tag));
12739
+ for (const tag of addedTags) {
12740
+ await this.emitEvent("TagAdded", {
12741
+ path: relativePath,
12742
+ absolutePath: path4.join(this.flintPath, relativePath),
12743
+ tag,
12744
+ tags: snapshot.tags
12745
+ });
12746
+ }
12747
+ for (const tag of removedTags) {
12748
+ await this.emitEvent("TagRemoved", {
12749
+ path: relativePath,
12750
+ absolutePath: path4.join(this.flintPath, relativePath),
12751
+ tag,
12752
+ tags: snapshot.tags
12753
+ });
12754
+ }
12755
+ }
12756
+ async handleSessionFileChange(relativePath) {
12757
+ const snapshot = await this.readSessionSnapshot(relativePath);
12758
+ if (!snapshot) {
12759
+ return;
12760
+ }
12761
+ const sessionId = path4.basename(relativePath, ".json");
12762
+ const previous = this.sessionCache.get(sessionId);
12763
+ this.sessionCache.set(sessionId, snapshot);
12764
+ if (!previous && snapshot.status === "active") {
12765
+ await this.emitEvent("AgentStart", {
12766
+ sessionId,
12767
+ status: snapshot.status,
12768
+ model: snapshot.model,
12769
+ goal: snapshot.goal
12770
+ });
12771
+ return;
12772
+ }
12773
+ if (previous?.status !== snapshot.status) {
12774
+ if (snapshot.status === "active") {
12775
+ await this.emitEvent("AgentStart", {
12776
+ sessionId,
12777
+ status: snapshot.status,
12778
+ model: snapshot.model,
12779
+ goal: snapshot.goal
12780
+ });
12781
+ } else if (snapshot.status) {
12782
+ await this.emitEvent("AgentComplete", {
12783
+ sessionId,
12784
+ status: snapshot.status,
12785
+ model: snapshot.model,
12786
+ goal: snapshot.goal
12787
+ });
12788
+ }
12789
+ }
12790
+ }
12791
+ async emitEvent(type, payload) {
12792
+ const event = {
12793
+ id: randomUUID3(),
12794
+ type,
12795
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
12796
+ payload
12797
+ };
12798
+ this.eventLog.push(event);
12799
+ if (this.eventLog.length > this.eventLogSize) {
12800
+ this.eventLog.shift();
12801
+ }
12802
+ this.emitter.emit(type, event);
12803
+ await this.runHooks(type, event);
12804
+ }
12805
+ async runHooks(type, event) {
12806
+ const hooks = (this.hooksConfig.hooks ?? {})[type] ?? [];
12807
+ if (!hooks.length) {
12808
+ return;
12809
+ }
12810
+ for (const hook of hooks) {
12811
+ if (!hookMatches(type, hook, event.payload)) {
12812
+ continue;
12813
+ }
12814
+ try {
12815
+ await executeHook({
12816
+ hook,
12817
+ event,
12818
+ flintPath: this.flintPath,
12819
+ logger: this.logger
12820
+ });
12821
+ } catch (error3) {
12822
+ this.logger.error?.("Hook execution failed", error3);
12823
+ }
12824
+ }
12825
+ }
12826
+ async readFrontmatterSnapshot(relativePath) {
12827
+ const absolutePath = path4.join(this.flintPath, relativePath);
12828
+ const content = await safeReadFile(absolutePath);
12829
+ if (!content) {
12830
+ return null;
12831
+ }
12832
+ const { frontmatter } = parseFrontmatter(content);
12833
+ const tags = extractTags(frontmatter);
12834
+ const status = frontmatter?.status ? String(frontmatter.status) : void 0;
12835
+ return { status, tags };
12836
+ }
12837
+ async readSessionSnapshot(relativePath) {
12838
+ const absolutePath = path4.join(this.flintPath, relativePath);
12839
+ const content = await safeReadFile(absolutePath);
12840
+ if (!content) {
12841
+ return null;
12842
+ }
12843
+ try {
12844
+ const parsed = JSON.parse(content);
12845
+ return {
12846
+ status: typeof parsed.status === "string" ? parsed.status : void 0,
12847
+ model: typeof parsed.model === "string" ? parsed.model : void 0,
12848
+ goal: typeof parsed.goal === "string" ? parsed.goal : void 0
12849
+ };
12850
+ } catch {
12851
+ return null;
12852
+ }
12853
+ }
12854
+ };
12855
+ function normalizePath(filePath) {
12856
+ return filePath.replace(/\\/g, "/");
12857
+ }
12858
+ async function safeReadFile(filePath) {
12859
+ try {
12860
+ const fileStats = await stat4(filePath);
12861
+ if (!fileStats.isFile()) {
12862
+ return null;
12863
+ }
12864
+ return await readFile6(filePath, "utf-8");
12865
+ } catch {
12866
+ return null;
12867
+ }
12868
+ }
12869
+ function parseFrontmatter(content) {
12870
+ const match2 = content.match(/^---\n([\s\S]*?)\n---\n?/);
12871
+ if (!match2) {
12872
+ return { frontmatter: null, body: content };
12873
+ }
12874
+ const raw = match2[1] ?? "";
12875
+ let frontmatter = {};
12876
+ try {
12877
+ const parsed = parseYaml(raw);
12878
+ if (parsed && typeof parsed === "object") {
12879
+ frontmatter = parsed;
12880
+ }
12881
+ } catch {
12882
+ frontmatter = {};
12883
+ }
12884
+ const body = content.slice(match2[0].length);
12885
+ return { frontmatter, body };
12886
+ }
12887
+ function extractTags(frontmatter) {
12888
+ if (!frontmatter || frontmatter.tags === void 0) {
12889
+ return [];
12890
+ }
12891
+ const tags = frontmatter.tags;
12892
+ if (Array.isArray(tags)) {
12893
+ return tags.map((tag) => String(tag));
12894
+ }
12895
+ if (typeof tags === "string") {
12896
+ return [tags];
12897
+ }
12898
+ return [];
12899
+ }
12900
+ async function loadHooksConfig(hooksPath, logger) {
12901
+ try {
12902
+ const content = await readFile6(hooksPath, "utf-8");
12903
+ const parsed = parse(content);
12904
+ if (parsed && typeof parsed === "object") {
12905
+ return parsed;
12906
+ }
12907
+ } catch (error3) {
12908
+ if (error3.code !== "ENOENT") {
12909
+ logger.warn?.("Failed to read hooks config", error3);
12910
+ }
12911
+ }
12912
+ return { hooks: {} };
12913
+ }
12914
+ function countHooks(config) {
12915
+ const hooks = config.hooks ?? {};
12916
+ return Object.values(hooks).reduce((count, entries) => count + entries.length, 0);
12917
+ }
12918
+ function hookMatches(type, hook, payload) {
12919
+ const matcher = hook.matcher;
12920
+ if (!matcher) {
12921
+ return true;
12922
+ }
12923
+ if (typeof matcher === "string") {
12924
+ if (type === "FileChanged") {
12925
+ const targetPath = typeof payload.path === "string" ? payload.path : "";
12926
+ return minimatch(targetPath, matcher, { dot: true });
12927
+ }
12928
+ return true;
12929
+ }
12930
+ if (matcher.tag) {
12931
+ const tags = Array.isArray(payload.tags) ? payload.tags.map(String) : [];
12932
+ if (!tags.includes(matcher.tag)) {
12933
+ return false;
12934
+ }
12935
+ }
12936
+ const fieldValue = typeof payload.field === "string" ? payload.field : void 0;
12937
+ if (matcher.field && matcher.field !== fieldValue) {
12938
+ return false;
12939
+ }
12940
+ const fromValue = typeof payload.from === "string" ? payload.from : void 0;
12941
+ if (matcher.from && matcher.from !== fromValue) {
12942
+ return false;
12943
+ }
12944
+ const toValue = typeof payload.to === "string" ? payload.to : void 0;
12945
+ if (matcher.to && matcher.to !== toValue) {
12946
+ return false;
12947
+ }
12948
+ return true;
12949
+ }
12950
+ async function executeHook(options) {
12951
+ const { hook, event, flintPath, logger } = options;
12952
+ const command = resolveHookCommand(hook.command, flintPath);
12953
+ logger.debug?.("Running hook", hook.command);
12954
+ await new Promise((resolve22, reject) => {
12955
+ const envPathEntries = [
12956
+ path4.join(flintPath, "node_modules", ".bin"),
12957
+ path4.join(process.cwd(), "node_modules", ".bin"),
12958
+ process.env.PATH
12959
+ ].filter(Boolean);
12960
+ const child = spawn5(command, {
12961
+ cwd: flintPath,
12962
+ env: {
12963
+ ...process.env,
12964
+ PATH: envPathEntries.join(path4.delimiter)
12965
+ },
12966
+ shell: true,
12967
+ stdio: ["pipe", "pipe", "pipe"]
12968
+ });
12969
+ let stdout = "";
12970
+ let stderr = "";
12971
+ child.stdout?.on("data", (data) => {
12972
+ stdout += String(data);
12973
+ });
12974
+ child.stderr?.on("data", (data) => {
12975
+ stderr += String(data);
12976
+ });
12977
+ const timeoutMs = hook.timeout ? hook.timeout * 1e3 : void 0;
12978
+ let timeoutId = null;
12979
+ if (timeoutMs) {
12980
+ timeoutId = setTimeout(() => {
12981
+ child.kill("SIGKILL");
12982
+ reject(new Error(`Hook timed out after ${hook.timeout}s: ${hook.command}`));
12983
+ }, timeoutMs);
12984
+ }
12985
+ child.on("error", (error3) => {
12986
+ if (timeoutId) {
12987
+ clearTimeout(timeoutId);
12988
+ }
12989
+ reject(error3);
12990
+ });
12991
+ child.on("close", (code) => {
12992
+ if (timeoutId) {
12993
+ clearTimeout(timeoutId);
12994
+ }
12995
+ if (code === 0) {
12996
+ if (stdout.trim()) {
12997
+ logger.info?.(`Hook output: ${stdout.trim()}`);
12998
+ }
12999
+ resolve22();
13000
+ return;
13001
+ }
13002
+ if (code === 2) {
13003
+ logger.warn?.(`Hook blocked: ${hook.command}`);
13004
+ if (stderr.trim()) {
13005
+ logger.warn?.(stderr.trim());
13006
+ }
13007
+ resolve22();
13008
+ return;
13009
+ }
13010
+ const error3 = new Error(`Hook failed (${code ?? "unknown"}): ${hook.command}`);
13011
+ if (stderr.trim()) {
13012
+ logger.error?.(stderr.trim());
13013
+ }
13014
+ reject(error3);
13015
+ });
13016
+ child.stdin?.write(JSON.stringify({
13017
+ event,
13018
+ flint: { path: flintPath }
13019
+ }));
13020
+ child.stdin?.end();
13021
+ });
13022
+ }
13023
+ function resolveHookCommand(command, flintPath) {
13024
+ const trimmed = command.trim();
13025
+ if (!trimmed) {
13026
+ return trimmed;
13027
+ }
13028
+ const parts = trimmed.split(/\s+/);
13029
+ const target = parts[0] ?? "";
13030
+ const rest = parts.slice(1).join(" ");
13031
+ const extension = path4.extname(target);
13032
+ if (!extension) {
13033
+ return trimmed;
13034
+ }
13035
+ const resolvedTarget = path4.isAbsolute(target) ? target : path4.join(flintPath, target);
13036
+ const quotedTarget = quoteIfNeeded(resolvedTarget);
13037
+ const suffix = rest ? ` ${rest}` : "";
13038
+ if (extension === ".ts") {
13039
+ return `tsx ${quotedTarget}${suffix}`;
13040
+ }
13041
+ if (extension === ".py") {
13042
+ return `python3 ${quotedTarget}${suffix}`;
13043
+ }
13044
+ if (extension === ".sh") {
13045
+ return `bash ${quotedTarget}${suffix}`;
13046
+ }
13047
+ return trimmed;
13048
+ }
13049
+ function quoteIfNeeded(value) {
13050
+ if (value.includes(" ")) {
13051
+ return `"${value.replace(/"/g, '\\"')}"`;
13052
+ }
13053
+ return value;
13054
+ }
13055
+ function sendApiError(reply, status, error3, message, extra = {}) {
13056
+ return reply.code(status).send({ error: error3, message, ...extra });
13057
+ }
13058
+ var CONTENT_TYPES = {
13059
+ ".css": "text/css; charset=utf-8",
13060
+ ".html": "text/html; charset=utf-8",
13061
+ ".js": "application/javascript; charset=utf-8",
13062
+ ".json": "application/json; charset=utf-8",
13063
+ ".map": "application/json; charset=utf-8",
13064
+ ".mjs": "application/javascript; charset=utf-8",
13065
+ ".png": "image/png",
13066
+ ".svg": "image/svg+xml",
13067
+ ".tsx": "text/plain; charset=utf-8",
13068
+ ".txt": "text/plain; charset=utf-8",
13069
+ ".woff": "font/woff",
13070
+ ".woff2": "font/woff2"
13071
+ };
13072
+ function contentTypeFor(filePath) {
13073
+ return CONTENT_TYPES[path22.extname(filePath).toLowerCase()] ?? "application/octet-stream";
13074
+ }
13075
+ function isImmutableAsset(filePath) {
13076
+ return /\.[a-f0-9]{8,}\./i.test(path22.basename(filePath));
13077
+ }
13078
+ async function resolveFlintPath4(inputPath) {
13079
+ const resolved = path22.resolve(inputPath);
13080
+ const flintToml = path22.join(resolved, "flint.toml");
13081
+ const flintState = path22.join(resolved, ".flint");
13082
+ const hasConfig = await exists3(flintToml);
13083
+ const hasState = await exists3(flintState);
13084
+ if (!hasConfig && !hasState) {
13085
+ throw new Error(`Not a Flint workspace: ${resolved}`);
13086
+ }
13087
+ return resolved;
13088
+ }
13089
+ async function exists3(targetPath) {
13090
+ try {
13091
+ await stat22(targetPath);
13092
+ return true;
13093
+ } catch {
13094
+ return false;
13095
+ }
13096
+ }
13097
+ function toError(error3, fallbackMessage) {
13098
+ if (error3 instanceof Error) {
13099
+ return error3;
13100
+ }
13101
+ return new Error(typeof error3 === "string" ? error3 : fallbackMessage);
13102
+ }
13103
+ function isUnsupportedRecursiveWatchError(error3) {
13104
+ const code = typeof error3 === "object" && error3 !== null && "code" in error3 ? String(error3.code ?? "") : "";
13105
+ return code === "ERR_FEATURE_UNAVAILABLE_ON_PLATFORM" || code === "ENOSYS" || code === "ENOTSUP";
13106
+ }
13107
+ function createResilientWatcher({
13108
+ label,
13109
+ targetPath,
13110
+ recursive = false,
13111
+ retryMs = 1e3,
13112
+ onChange
13113
+ }) {
13114
+ let watcher = null;
13115
+ let retryTimer = null;
13116
+ let closed = false;
13117
+ const scheduleRestart = () => {
13118
+ if (closed || retryTimer) {
13119
+ return;
13120
+ }
13121
+ retryTimer = setTimeout(() => {
13122
+ retryTimer = null;
13123
+ start();
13124
+ }, retryMs);
13125
+ retryTimer.unref?.();
13126
+ };
13127
+ const handleWatchError = (error3) => {
13128
+ const resolved = toError(error3, `${label} watcher failed`);
13129
+ const unsupported = recursive && isUnsupportedRecursiveWatchError(error3);
13130
+ watcher?.close();
13131
+ watcher = null;
13132
+ if (unsupported) {
13133
+ console.warn(`[flint-server] ${label} watcher disabled: recursive fs.watch is not supported on this platform.`);
13134
+ return;
13135
+ }
13136
+ console.warn(`[flint-server] ${label} watcher error: ${resolved.message}. Retrying.`);
13137
+ scheduleRestart();
13138
+ };
13139
+ const start = () => {
13140
+ if (closed) {
13141
+ return;
13142
+ }
13143
+ if (!existsSync10(targetPath)) {
13144
+ scheduleRestart();
13145
+ return;
13146
+ }
13147
+ try {
13148
+ watcher = watch3(targetPath, { recursive }, (_eventType, filename) => {
13149
+ onChange(filename);
13150
+ });
13151
+ watcher.on("error", handleWatchError);
13152
+ } catch (error3) {
13153
+ handleWatchError(error3);
13154
+ }
13155
+ };
13156
+ start();
13157
+ return {
13158
+ close() {
13159
+ closed = true;
13160
+ if (retryTimer) {
13161
+ clearTimeout(retryTimer);
13162
+ retryTimer = null;
13163
+ }
13164
+ watcher?.close();
13165
+ watcher = null;
13166
+ }
13167
+ };
13168
+ }
13169
+ var RuntimeManager = class {
13170
+ runtimes = /* @__PURE__ */ new Map();
13171
+ async startRuntime(flintPath) {
13172
+ const resolved = await resolveFlintPath4(flintPath);
13173
+ const runtimeId = computeRuntimeId(resolved);
13174
+ const existing = this.runtimes.get(runtimeId);
13175
+ if (existing) {
13176
+ return existing.getStatus();
13177
+ }
13178
+ const runtime2 = createRuntime({ flintPath: resolved });
13179
+ await runtime2.start();
13180
+ this.runtimes.set(runtimeId, runtime2);
13181
+ return runtime2.getStatus();
13182
+ }
13183
+ listRuntimes() {
13184
+ return Array.from(this.runtimes.values()).map((runtime2) => runtime2.getStatus());
13185
+ }
13186
+ getRuntime(id) {
13187
+ return this.runtimes.get(id);
13188
+ }
13189
+ async stopRuntime(id) {
13190
+ const runtime2 = this.runtimes.get(id);
13191
+ if (!runtime2) {
13192
+ return false;
13193
+ }
13194
+ await runtime2.stop();
13195
+ this.runtimes.delete(id);
13196
+ return true;
13197
+ }
13198
+ async stopAll() {
13199
+ const entries = Array.from(this.runtimes.entries());
13200
+ await Promise.all(entries.map(async ([id, runtime2]) => {
13201
+ await runtime2.stop();
13202
+ this.runtimes.delete(id);
13203
+ }));
13204
+ }
13205
+ };
13206
+ var REGISTRY_PATH = join11(homedir6(), ".nuucognition", "servers.json");
13207
+ function getRegistryDir() {
13208
+ return join11(homedir6(), ".nuucognition");
13209
+ }
13210
+ async function readServerRegistry() {
13211
+ try {
13212
+ const content = await readFile22(REGISTRY_PATH, "utf-8");
13213
+ const data = JSON.parse(content);
13214
+ return data.servers ?? [];
13215
+ } catch (error3) {
13216
+ if (error3.code === "ENOENT") {
13217
+ return [];
13218
+ }
13219
+ return [];
13220
+ }
13221
+ }
13222
+ async function writeServerRegistry(servers) {
13223
+ await mkdir5(getRegistryDir(), { recursive: true });
13224
+ const data = { version: 1, servers };
13225
+ const content = JSON.stringify(data, null, 2);
13226
+ await writeFile3(REGISTRY_PATH, content, "utf-8");
13227
+ const verification = await readFile22(REGISTRY_PATH, "utf-8");
13228
+ const verified = JSON.parse(verification);
13229
+ if (verified.servers.length !== servers.length) {
13230
+ await writeFile3(REGISTRY_PATH, content, "utf-8");
13231
+ }
13232
+ }
13233
+ async function registerServer(entry) {
10972
13234
  const servers = await readServerRegistry();
10973
13235
  const resolvedPath = resolve7(entry.flintPath);
10974
13236
  const filtered = servers.filter((s) => resolve7(s.flintPath) !== resolvedPath);
@@ -11092,26 +13354,39 @@ function registerPlatesRoutes(app, ctx) {
11092
13354
  ...id ? { id } : {}
11093
13355
  });
11094
13356
  }
13357
+ function toPlateSummary(plate) {
13358
+ return {
13359
+ name: plate.manifest.name,
13360
+ title: plate.manifest.title,
13361
+ version: plate.manifest.version ?? "0.1.0",
13362
+ description: plate.manifest.description,
13363
+ icon: plate.manifest.icon,
13364
+ shard: plate.manifest.shard,
13365
+ handles: (plate.manifest.handles ?? []).map((handle) => ({
13366
+ tag: handle.tag,
13367
+ default: handle.default === true
13368
+ })),
13369
+ actions: (plate.manifest.actions ?? []).map((action) => ({
13370
+ id: action.id,
13371
+ label: action.label,
13372
+ description: action.description,
13373
+ icon: action.icon
13374
+ })),
13375
+ built: plate.built,
13376
+ stale: plate.stale,
13377
+ tools: (plate.manifest.tools ?? []).map((tool) => ({
13378
+ name: tool.name,
13379
+ description: tool.description
13380
+ }))
13381
+ };
13382
+ }
11095
13383
  app.get("/api/plates", async (_request, reply) => {
11096
13384
  if (!ctx.flintPath) {
11097
13385
  return sendApiError(reply, 500, "not_found", "No Flint workspace configured");
11098
13386
  }
11099
13387
  try {
11100
13388
  const plates = await listPlates(ctx.flintPath);
11101
- return plates.map((plate) => ({
11102
- name: plate.manifest.name,
11103
- title: plate.manifest.title,
11104
- version: plate.manifest.version ?? "0.1.0",
11105
- description: plate.manifest.description,
11106
- icon: plate.manifest.icon,
11107
- shard: plate.manifest.shard,
11108
- built: plate.built,
11109
- stale: plate.stale,
11110
- tools: (plate.manifest.tools ?? []).map((tool) => ({
11111
- name: tool.name,
11112
- description: tool.description
11113
- }))
11114
- }));
13389
+ return plates.map((plate) => toPlateSummary(plate));
11115
13390
  } catch (error3) {
11116
13391
  const message = error3 instanceof Error ? error3.message : String(error3);
11117
13392
  return sendApiError(reply, 500, "validation_error", message);
@@ -11125,20 +13400,7 @@ function registerPlatesRoutes(app, ctx) {
11125
13400
  if (!plate) {
11126
13401
  return sendApiError(reply, 404, "not_found", `Plate "${request.params.name}" was not found`);
11127
13402
  }
11128
- return {
11129
- name: plate.manifest.name,
11130
- title: plate.manifest.title,
11131
- version: plate.manifest.version ?? "0.1.0",
11132
- description: plate.manifest.description,
11133
- icon: plate.manifest.icon,
11134
- shard: plate.manifest.shard,
11135
- built: plate.built,
11136
- stale: plate.stale,
11137
- tools: (plate.manifest.tools ?? []).map((tool) => ({
11138
- name: tool.name,
11139
- description: tool.description
11140
- }))
11141
- };
13403
+ return toPlateSummary(plate);
11142
13404
  });
11143
13405
  async function servePlateAsset(plateName, requestedPath, reply) {
11144
13406
  if (!ctx.flintPath) {
@@ -11148,18 +13410,18 @@ function registerPlatesRoutes(app, ctx) {
11148
13410
  if (!plate) {
11149
13411
  return sendApiError(reply, 404, "not_found", `Plate "${plateName}" was not found`);
11150
13412
  }
11151
- const entryPath = path22.resolve(plate.path, plate.manifest.entry);
11152
- const distRoot = path22.dirname(entryPath);
11153
- if (!await stat22(distRoot).catch(() => null)) {
13413
+ const entryPath = path32.resolve(plate.path, plate.manifest.entry);
13414
+ const distRoot = path32.dirname(entryPath);
13415
+ if (!await stat32(distRoot).catch(() => null)) {
11154
13416
  return sendApiError(reply, 404, "plate_not_built", `Plate "${plate.manifest.name}" has not been built`, {
11155
13417
  plate: plate.manifest.name
11156
13418
  });
11157
13419
  }
11158
- const targetPath = requestedPath && requestedPath.length > 0 ? path22.resolve(distRoot, requestedPath) : entryPath;
11159
- if (!targetPath.startsWith(distRoot) || !await stat22(targetPath).catch(() => null)) {
13420
+ const targetPath = requestedPath && requestedPath.length > 0 ? path32.resolve(distRoot, requestedPath) : entryPath;
13421
+ if (!targetPath.startsWith(distRoot) || !await stat32(targetPath).catch(() => null)) {
11160
13422
  return sendApiError(reply, 404, "not_found", `Asset "${requestedPath ?? "/"}" was not found`);
11161
13423
  }
11162
- const content = await readFile22(targetPath);
13424
+ const content = await readFile32(targetPath);
11163
13425
  reply.header("Content-Type", contentTypeFor(targetPath));
11164
13426
  reply.header("Cache-Control", isImmutableAsset(targetPath) ? "public, max-age=31536000, immutable" : "no-store");
11165
13427
  return reply.send(content);
@@ -11237,7 +13499,7 @@ function registerPlatesRoutes(app, ctx) {
11237
13499
  template: request.body.template,
11238
13500
  data: request.body.data
11239
13501
  });
11240
- const absolutePath = path22.join(ctx.flintPath, artifact.path);
13502
+ const absolutePath = path32.join(ctx.flintPath, artifact.path);
11241
13503
  suppressPath(absolutePath);
11242
13504
  trackArtifactPath(absolutePath);
11243
13505
  broadcastArtifactEvent("artifact.created", artifact);
@@ -11260,7 +13522,7 @@ function registerPlatesRoutes(app, ctx) {
11260
13522
  if (!artifact) {
11261
13523
  return sendApiError(reply, 404, "not_found", `Artifact "${request.params.id}" was not found`);
11262
13524
  }
11263
- trackArtifactPath(path22.join(ctx.flintPath, artifact.path));
13525
+ trackArtifactPath(path32.join(ctx.flintPath, artifact.path));
11264
13526
  broadcastArtifactEvent("artifact.updated", artifact);
11265
13527
  return artifact;
11266
13528
  });
@@ -11302,7 +13564,7 @@ function registerPlatesRoutes(app, ctx) {
11302
13564
  return sendApiError(reply, 404, "not_found", `Artifact "${request.params.id}" was not found`);
11303
13565
  }
11304
13566
  if (ctx.flintPath) {
11305
- const newPath = path22.join(ctx.flintPath, result.artifact.path);
13567
+ const newPath = path32.join(ctx.flintPath, result.artifact.path);
11306
13568
  suppressPath(newPath);
11307
13569
  trackArtifactPath(newPath);
11308
13570
  }
@@ -11361,13 +13623,13 @@ function registerPlatesRoutes(app, ctx) {
11361
13623
  const fileDebounceTimers = /* @__PURE__ */ new Map();
11362
13624
  const SKIP_DIRS = /* @__PURE__ */ new Set(["Agents", "Archive", "node_modules", ".git"]);
11363
13625
  function shouldSkipPath(relativePath) {
11364
- const parts = relativePath.split(path22.sep);
13626
+ const parts = relativePath.split(path32.sep);
11365
13627
  return parts.some((p) => SKIP_DIRS.has(p));
11366
13628
  }
11367
13629
  const handleFileChange = (baseDir, filename) => {
11368
13630
  if (!filename || !ctx.flintPath) return;
11369
13631
  if (!filename.endsWith(".md")) return;
11370
- const absolutePath = path22.join(baseDir, filename);
13632
+ const absolutePath = path32.join(baseDir, filename);
11371
13633
  if (shouldSkipPath(filename)) return;
11372
13634
  if (suppressedPaths.has(absolutePath)) return;
11373
13635
  const existing = fileDebounceTimers.get(absolutePath);
@@ -11383,7 +13645,7 @@ function registerPlatesRoutes(app, ctx) {
11383
13645
  trackArtifactPath(absolutePath);
11384
13646
  broadcastArtifactEvent(event, artifact);
11385
13647
  } else {
11386
- const relPath = path22.relative(ctx.flintPath, absolutePath).replace(/\\/g, "/");
13648
+ const relPath = path32.relative(ctx.flintPath, absolutePath).replace(/\\/g, "/");
11387
13649
  untrackArtifactPath(absolutePath);
11388
13650
  broadcastArtifactDeletion(relPath);
11389
13651
  }
@@ -11392,11 +13654,11 @@ function registerPlatesRoutes(app, ctx) {
11392
13654
  }, 50));
11393
13655
  };
11394
13656
  if (ctx.flintPath) {
11395
- const meshDir = path22.join(ctx.flintPath, "Mesh");
11396
- const shardsDir = path22.join(ctx.flintPath, "Shards");
13657
+ const meshDir = path32.join(ctx.flintPath, "Mesh");
13658
+ const shardsDir = path32.join(ctx.flintPath, "Shards");
11397
13659
  void queryArtifacts(ctx.flintPath, { includeShards: true, limit: 1e4 }).then((result) => {
11398
13660
  for (const artifact of result.items) {
11399
- trackArtifactPath(path22.join(ctx.flintPath, artifact.path));
13661
+ trackArtifactPath(path32.join(ctx.flintPath, artifact.path));
11400
13662
  }
11401
13663
  }).catch(() => {
11402
13664
  });
@@ -11522,7 +13784,7 @@ async function readSessionTranscript(session, cwd) {
11522
13784
  if (!transcriptPath) {
11523
13785
  return { entries: [], turns: [], usage: null };
11524
13786
  }
11525
- const content = await readFile32(transcriptPath, "utf-8").catch(() => null);
13787
+ const content = await readFile42(transcriptPath, "utf-8").catch(() => null);
11526
13788
  if (content == null) {
11527
13789
  return { entries: [], turns: [], usage: null };
11528
13790
  }
@@ -11817,7 +14079,7 @@ function registerOrbhRoutes(app, ctx, options) {
11817
14079
  prompt: prompt6,
11818
14080
  extraArgs: session.runtime === "claude" ? ["--chrome"] : []
11819
14081
  });
11820
- const child = spawn5(harness.name, args, {
14082
+ const child = spawn22(harness.name, args, {
11821
14083
  cwd: ctx.flintPath,
11822
14084
  detached: true,
11823
14085
  stdio: ["ignore", "ignore", "pipe"],
@@ -12233,7 +14495,7 @@ async function buildFlintIdentity(ctx) {
12233
14495
  ]);
12234
14496
  const sessions = ctx.orbhSessionsDir ? listSessions2(ctx.orbhSessionsDir) : [];
12235
14497
  const activeSessions = sessions.filter((session) => ACTIVE_SESSION_STATUSES.has(session.status)).length;
12236
- const name = config?.flint?.name ?? registryEntry?.name ?? path32.basename(ctx.flintPath);
14498
+ const name = config?.flint?.name ?? registryEntry?.name ?? path42.basename(ctx.flintPath);
12237
14499
  return {
12238
14500
  name,
12239
14501
  flintId: flintJson?.id ?? null,
@@ -12290,12 +14552,12 @@ function registerWorkspaceRoutes(app, ctx) {
12290
14552
  return;
12291
14553
  }
12292
14554
  for (const entry of entries) {
12293
- const fullPath = path4.join(dir, entry.name);
14555
+ const fullPath = path5.join(dir, entry.name);
12294
14556
  if (entry.isDirectory()) {
12295
14557
  if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist") continue;
12296
14558
  await walk(fullPath);
12297
14559
  } else if (entry.name.endsWith(".md")) {
12298
- allFiles.push(path4.relative(ctx.flintPath, fullPath));
14560
+ allFiles.push(path5.relative(ctx.flintPath, fullPath));
12299
14561
  }
12300
14562
  }
12301
14563
  }
@@ -12449,16 +14711,16 @@ function registerShardsRoutes(app, ctx) {
12449
14711
  return sendApiError(reply, 500, "no_workspace", "No Flint workspace configured");
12450
14712
  }
12451
14713
  const installed = await getInstalledShardsWithVersions(ctx.flintPath);
12452
- const match = resolveInstalledShardInfo(installed, request.params.identifier);
12453
- if (!match) {
14714
+ const match2 = resolveInstalledShardInfo(installed, request.params.identifier);
14715
+ if (!match2) {
12454
14716
  return sendApiError(reply, 404, "not_found", `Shard "${request.params.identifier}" not found`);
12455
14717
  }
12456
14718
  const allResults = await checkShardHealth(ctx.flintPath);
12457
14719
  const shardResults = allResults.filter(
12458
- (r) => r.check.includes(match.folderName) || r.check.includes(match.name)
14720
+ (r) => r.check.includes(match2.folderName) || r.check.includes(match2.name)
12459
14721
  );
12460
14722
  return {
12461
- shard: match.name,
14723
+ shard: match2.name,
12462
14724
  results: shardResults.map((r) => ({
12463
14725
  check: r.check,
12464
14726
  status: r.status,
@@ -12492,14 +14754,14 @@ function registerShardsRoutes(app, ctx) {
12492
14754
  return sendApiError(reply, 500, "no_workspace", "No Flint workspace configured");
12493
14755
  }
12494
14756
  const installed = await getInstalledShardsWithVersions(ctx.flintPath);
12495
- const match = resolveInstalledShardInfo(installed, request.params.identifier);
12496
- if (!match) {
14757
+ const match2 = resolveInstalledShardInfo(installed, request.params.identifier);
14758
+ if (!match2) {
12497
14759
  return sendApiError(reply, 404, "not_found", `Shard "${request.params.identifier}" not found`);
12498
14760
  }
12499
14761
  try {
12500
- const results = await healShard(ctx.flintPath, match.folderName);
14762
+ const results = await healShard(ctx.flintPath, match2.folderName);
12501
14763
  return {
12502
- shard: match.name,
14764
+ shard: match2.name,
12503
14765
  repairs: results.map((r) => ({
12504
14766
  check: r.check,
12505
14767
  status: r.status,
@@ -12533,6 +14795,152 @@ function registerShardsRoutes(app, ctx) {
12533
14795
  }
12534
14796
  });
12535
14797
  }
14798
+ function steelDir(flintPath) {
14799
+ return path6.join(flintPath, ".steel");
14800
+ }
14801
+ function preferencesPath(flintPath) {
14802
+ return path6.join(steelDir(flintPath), "preferences.json");
14803
+ }
14804
+ function plateStateDir(flintPath, plateName) {
14805
+ return path6.join(steelDir(flintPath), "plates", plateName);
14806
+ }
14807
+ function plateStatePath(flintPath, plateName, key) {
14808
+ return path6.join(plateStateDir(flintPath, plateName), `${key}.json`);
14809
+ }
14810
+ function plateBoardsDir(flintPath, plateName) {
14811
+ return path6.join(plateStateDir(flintPath, plateName), "boards");
14812
+ }
14813
+ function plateBoardPath(flintPath, plateName, board) {
14814
+ return path6.join(plateBoardsDir(flintPath, plateName), `${board}.json`);
14815
+ }
14816
+ async function readJsonFile(filePath) {
14817
+ try {
14818
+ const raw = await readFile52(filePath, "utf-8");
14819
+ return JSON.parse(raw);
14820
+ } catch {
14821
+ return null;
14822
+ }
14823
+ }
14824
+ async function writeJsonFile(filePath, data) {
14825
+ await mkdir22(path6.dirname(filePath), { recursive: true });
14826
+ const tempPath = `${filePath}.tmp-${process.pid}-${Date.now()}`;
14827
+ await writeFile22(tempPath, JSON.stringify(data, null, 2), "utf-8");
14828
+ await rename2(tempPath, filePath);
14829
+ }
14830
+ function registerSteelRoutes(app, ctx) {
14831
+ app.get("/api/steel/preferences", async (_request, reply) => {
14832
+ if (!ctx.flintPath) {
14833
+ return sendApiError(reply, 500, "no_workspace", "No Flint workspace configured");
14834
+ }
14835
+ const prefs = await readJsonFile(preferencesPath(ctx.flintPath));
14836
+ return prefs ?? {};
14837
+ });
14838
+ app.put("/api/steel/preferences", async (request, reply) => {
14839
+ if (!ctx.flintPath) {
14840
+ return sendApiError(reply, 500, "no_workspace", "No Flint workspace configured");
14841
+ }
14842
+ const body = request.body;
14843
+ await writeJsonFile(preferencesPath(ctx.flintPath), {
14844
+ ...body,
14845
+ updated: (/* @__PURE__ */ new Date()).toISOString()
14846
+ });
14847
+ return { ok: true };
14848
+ });
14849
+ app.get(
14850
+ "/api/steel/plates/:name/state/:key",
14851
+ async (request, reply) => {
14852
+ if (!ctx.flintPath) {
14853
+ return sendApiError(reply, 500, "no_workspace", "No Flint workspace configured");
14854
+ }
14855
+ const { name, key } = request.params;
14856
+ const data = await readJsonFile(plateStatePath(ctx.flintPath, name, key));
14857
+ return data ?? {};
14858
+ }
14859
+ );
14860
+ app.put(
14861
+ "/api/steel/plates/:name/state/:key",
14862
+ async (request, reply) => {
14863
+ if (!ctx.flintPath) {
14864
+ return sendApiError(reply, 500, "no_workspace", "No Flint workspace configured");
14865
+ }
14866
+ const { name, key } = request.params;
14867
+ const body = request.body;
14868
+ await writeJsonFile(plateStatePath(ctx.flintPath, name, key), {
14869
+ ...body,
14870
+ updated: (/* @__PURE__ */ new Date()).toISOString()
14871
+ });
14872
+ return { ok: true };
14873
+ }
14874
+ );
14875
+ app.get(
14876
+ "/api/steel/plates/:name/state",
14877
+ async (request, reply) => {
14878
+ if (!ctx.flintPath) {
14879
+ return sendApiError(reply, 500, "no_workspace", "No Flint workspace configured");
14880
+ }
14881
+ const { name } = request.params;
14882
+ const dir = plateStateDir(ctx.flintPath, name);
14883
+ if (!await exists3(dir)) return {};
14884
+ const entries = {};
14885
+ try {
14886
+ const files = await readdir3(dir, { withFileTypes: true });
14887
+ for (const file of files) {
14888
+ if (!file.isFile() || !file.name.endsWith(".json")) continue;
14889
+ const key = file.name.replace(/\.json$/, "");
14890
+ entries[key] = await readJsonFile(path6.join(dir, file.name));
14891
+ }
14892
+ } catch {
14893
+ }
14894
+ return entries;
14895
+ }
14896
+ );
14897
+ app.get(
14898
+ "/api/steel/plates/:name/boards",
14899
+ async (request, reply) => {
14900
+ if (!ctx.flintPath) {
14901
+ return sendApiError(reply, 500, "no_workspace", "No Flint workspace configured");
14902
+ }
14903
+ const { name } = request.params;
14904
+ const dir = plateBoardsDir(ctx.flintPath, name);
14905
+ if (!await exists3(dir)) return [];
14906
+ try {
14907
+ const files = await readdir3(dir);
14908
+ return files.filter((f) => f.endsWith(".json")).map((f) => f.replace(/\.json$/, ""));
14909
+ } catch {
14910
+ return [];
14911
+ }
14912
+ }
14913
+ );
14914
+ app.get(
14915
+ "/api/steel/plates/:name/boards/:board",
14916
+ async (request, reply) => {
14917
+ if (!ctx.flintPath) {
14918
+ return sendApiError(reply, 500, "no_workspace", "No Flint workspace configured");
14919
+ }
14920
+ const { name, board } = request.params;
14921
+ const data = await readJsonFile(plateBoardPath(ctx.flintPath, name, board));
14922
+ if (!data) {
14923
+ return sendApiError(reply, 404, "not_found", `Board config '${board}' not found for plate '${name}'`);
14924
+ }
14925
+ return data;
14926
+ }
14927
+ );
14928
+ app.put(
14929
+ "/api/steel/plates/:name/boards/:board",
14930
+ async (request, reply) => {
14931
+ if (!ctx.flintPath) {
14932
+ return sendApiError(reply, 500, "no_workspace", "No Flint workspace configured");
14933
+ }
14934
+ const { name, board } = request.params;
14935
+ const body = request.body;
14936
+ await writeJsonFile(plateBoardPath(ctx.flintPath, name, board), {
14937
+ ...body,
14938
+ updated: (/* @__PURE__ */ new Date()).toISOString()
14939
+ });
14940
+ return { ok: true };
14941
+ }
14942
+ );
14943
+ }
12536
14944
  var MAX_ENTRIES = 1e3;
12537
14945
  var nextId = 1;
12538
14946
  var buffer = [];
@@ -12542,29 +14950,29 @@ function pushEntry(entry) {
12542
14950
  }
12543
14951
  buffer.push(entry);
12544
14952
  }
12545
- function getLogEntries(filter) {
14953
+ function getLogEntries(filter2) {
12546
14954
  let result = buffer;
12547
- if (filter?.method) {
12548
- const method = filter.method.toUpperCase();
14955
+ if (filter2?.method) {
14956
+ const method = filter2.method.toUpperCase();
12549
14957
  result = result.filter((entry) => entry.method === method);
12550
14958
  }
12551
- if (filter?.minStatus != null) {
12552
- const minStatus = filter.minStatus;
14959
+ if (filter2?.minStatus != null) {
14960
+ const minStatus = filter2.minStatus;
12553
14961
  result = result.filter((entry) => entry.statusCode >= minStatus);
12554
14962
  }
12555
- if (filter?.maxStatus != null) {
12556
- const maxStatus = filter.maxStatus;
14963
+ if (filter2?.maxStatus != null) {
14964
+ const maxStatus = filter2.maxStatus;
12557
14965
  result = result.filter((entry) => entry.statusCode <= maxStatus);
12558
14966
  }
12559
- if (filter?.pathPattern) {
12560
- const pattern = filter.pathPattern.toLowerCase();
14967
+ if (filter2?.pathPattern) {
14968
+ const pattern = filter2.pathPattern.toLowerCase();
12561
14969
  result = result.filter((entry) => entry.path.toLowerCase().includes(pattern));
12562
14970
  }
12563
- if (filter?.since) {
12564
- result = result.filter((entry) => entry.timestamp >= filter.since);
14971
+ if (filter2?.since) {
14972
+ result = result.filter((entry) => entry.timestamp >= filter2.since);
12565
14973
  }
12566
- if (filter?.limit && filter.limit > 0) {
12567
- result = result.slice(-filter.limit);
14974
+ if (filter2?.limit && filter2.limit > 0) {
14975
+ result = result.slice(-filter2.limit);
12568
14976
  }
12569
14977
  return result;
12570
14978
  }
@@ -12573,8 +14981,8 @@ var EXCLUDED_PATHS = [
12573
14981
  "/events/stream",
12574
14982
  "/health"
12575
14983
  ];
12576
- function shouldLog(path62) {
12577
- return !EXCLUDED_PATHS.some((entry) => path62 === entry || path62.startsWith(`${entry}?`));
14984
+ function shouldLog(path82) {
14985
+ return !EXCLUDED_PATHS.some((entry) => path82 === entry || path82.startsWith(`${entry}?`));
12578
14986
  }
12579
14987
  var INTERESTING_REQUEST_HEADERS = [
12580
14988
  "accept",
@@ -12621,14 +15029,14 @@ function registerLogsRoutes(app, ctx) {
12621
15029
  return;
12622
15030
  }
12623
15031
  const queryIndex = fullUrl.indexOf("?");
12624
- const path62 = queryIndex >= 0 ? fullUrl.slice(0, queryIndex) : fullUrl;
15032
+ const path82 = queryIndex >= 0 ? fullUrl.slice(0, queryIndex) : fullUrl;
12625
15033
  const queryString = queryIndex >= 0 ? fullUrl.slice(queryIndex + 1) : null;
12626
15034
  const entry = {
12627
15035
  id: nextId++,
12628
15036
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
12629
15037
  method: request.method,
12630
15038
  url: fullUrl,
12631
- path: path62,
15039
+ path: path82,
12632
15040
  queryString,
12633
15041
  statusCode: reply.statusCode,
12634
15042
  responseTimeMs: Math.round(reply.elapsedTime * 100) / 100,
@@ -12899,7 +15307,7 @@ function registerEventStreamRoutes(app, ctx) {
12899
15307
  const raw = reply.raw;
12900
15308
  raw.writeHead(200, buildSseHeaders(request));
12901
15309
  const subscriber = {
12902
- id: randomUUID3(),
15310
+ id: randomUUID22(),
12903
15311
  raw,
12904
15312
  channels: new Set(channels),
12905
15313
  sessionIds,
@@ -13020,17 +15428,17 @@ var LiveTranscriptWriter = class {
13020
15428
  const agentsDir = join33(this.flintPath, "Mesh", "Agents");
13021
15429
  let runtimeDirs;
13022
15430
  try {
13023
- runtimeDirs = await readdir3(agentsDir);
15431
+ runtimeDirs = await readdir4(agentsDir);
13024
15432
  } catch {
13025
15433
  return;
13026
15434
  }
13027
15435
  for (const dir of runtimeDirs) {
13028
15436
  const dirPath = join33(agentsDir, dir);
13029
- const dirStat = await stat32(dirPath).catch(() => null);
15437
+ const dirStat = await stat42(dirPath).catch(() => null);
13030
15438
  if (!dirStat?.isDirectory()) continue;
13031
15439
  let files;
13032
15440
  try {
13033
- files = await readdir3(dirPath);
15441
+ files = await readdir4(dirPath);
13034
15442
  } catch {
13035
15443
  continue;
13036
15444
  }
@@ -13039,7 +15447,7 @@ var LiveTranscriptWriter = class {
13039
15447
  const filePath = join33(dirPath, file);
13040
15448
  let content;
13041
15449
  try {
13042
- content = await readFile42(filePath, "utf-8");
15450
+ content = await readFile62(filePath, "utf-8");
13043
15451
  } catch {
13044
15452
  continue;
13045
15453
  }
@@ -13057,7 +15465,7 @@ var LiveTranscriptWriter = class {
13057
15465
  const finalStatus = session?.status ?? "unknown";
13058
15466
  const statusUpdated = updatedContent.replace(/^status: .+$/m, `status: ${finalStatus}`);
13059
15467
  this.suppress(filePath);
13060
- await writeFile22(filePath, statusUpdated, "utf-8").catch(() => {
15468
+ await writeFile32(filePath, statusUpdated, "utf-8").catch(() => {
13061
15469
  });
13062
15470
  console.log(`[flint-server] finalized orphaned live transcript: ${file}`);
13063
15471
  }
@@ -13108,12 +15516,12 @@ var LiveTranscriptWriter = class {
13108
15516
  const outputDir = join33(this.flintPath, "Mesh", "Agents", dir);
13109
15517
  const outputPath = join33(outputDir, `${sessionId}.md`);
13110
15518
  try {
13111
- await mkdir22(outputDir, { recursive: true });
15519
+ await mkdir32(outputDir, { recursive: true });
13112
15520
  const frontmatter = buildLiveFrontmatter(session, live);
13113
15521
  const body = formatTranscriptMarkdown(entries);
13114
15522
  const markdown = frontmatter + body;
13115
15523
  this.suppress(outputPath);
13116
- await writeFile22(outputPath, markdown, "utf-8");
15524
+ await writeFile32(outputPath, markdown, "utf-8");
13117
15525
  this.writtenPaths.add(outputPath);
13118
15526
  } catch (error3) {
13119
15527
  console.warn(
@@ -13159,9 +15567,9 @@ async function shutdownPairedSteelHost(steelUrl) {
13159
15567
  async function startFlintServer(options = {}) {
13160
15568
  const host = "127.0.0.1";
13161
15569
  const port = options.port ?? 13040;
13162
- const flintPath = options.flintPath ? path5.resolve(options.flintPath) : void 0;
15570
+ const flintPath = options.flintPath ? path7.resolve(options.flintPath) : void 0;
13163
15571
  const runtimeManager = new RuntimeManager();
13164
- const orbhSessionsDir = flintPath ? path5.join(flintPath, ".flint", "sessions") : null;
15572
+ const orbhSessionsDir = flintPath ? path7.join(flintPath, ".flint", "sessions") : null;
13165
15573
  const channelRegistry = new ChannelRegistry();
13166
15574
  const app = Fastify({
13167
15575
  logger: options.logger ?? false,
@@ -13185,10 +15593,10 @@ async function startFlintServer(options = {}) {
13185
15593
  suppressedPaths,
13186
15594
  suppressPath
13187
15595
  };
13188
- const __dirname4 = path5.dirname(fileURLToPath2(import.meta.url));
13189
- const dashboardDist = path5.resolve(__dirname4, "..", "..", "..", "apps", "flint-dashboard", "dist");
15596
+ const __dirname4 = path7.dirname(fileURLToPath2(import.meta.url));
15597
+ const dashboardDist = path7.resolve(__dirname4, "..", "..", "..", "apps", "flint-dashboard", "dist");
13190
15598
  try {
13191
- await stat4(dashboardDist);
15599
+ await stat5(dashboardDist);
13192
15600
  await app.register(fastifyStatic, {
13193
15601
  root: dashboardDist,
13194
15602
  prefix: "/",
@@ -13218,6 +15626,7 @@ async function startFlintServer(options = {}) {
13218
15626
  registerIdentityRoutes(app, ctx);
13219
15627
  registerDashboardRoutes(app, ctx);
13220
15628
  registerShardsRoutes(app, ctx);
15629
+ registerSteelRoutes(app, ctx);
13221
15630
  registerWorkspaceRoutes(app, ctx);
13222
15631
  let liveTranscriptWriter = null;
13223
15632
  if (flintPath) {
@@ -13254,7 +15663,7 @@ async function startFlintServer(options = {}) {
13254
15663
  readFlintToml(flintPath)
13255
15664
  ]);
13256
15665
  registryFlintId = flintJson?.id ?? null;
13257
- registryName = config?.flint?.name ?? path5.basename(flintPath);
15666
+ registryName = config?.flint?.name ?? path7.basename(flintPath);
13258
15667
  } catch {
13259
15668
  }
13260
15669
  await registerServer({
@@ -13275,7 +15684,7 @@ async function startFlintServer(options = {}) {
13275
15684
  console.log(`[flint-server] ${needsBuild.length} plate(s) need building...`);
13276
15685
  for (const plate of needsBuild) {
13277
15686
  try {
13278
- const nodeModulesExists = await stat4(join43(plate.path, "node_modules")).then(() => true, () => false);
15687
+ const nodeModulesExists = await stat5(join43(plate.path, "node_modules")).then(() => true, () => false);
13279
15688
  if (!nodeModulesExists) {
13280
15689
  console.log(`[flint-server] installing deps for ${plate.manifest.title}...`);
13281
15690
  const installResult = await installPlateDeps(flintPath, plate.manifest.name);
@@ -13413,12 +15822,12 @@ serverCommand.command("dev").description("Start the server in dev mode with auto
13413
15822
  let serverPkgDir;
13414
15823
  try {
13415
15824
  const serverPkgJson = require2.resolve(`${FLINT_SERVER_PACKAGE}/package.json`);
13416
- serverPkgDir = path6.dirname(serverPkgJson);
15825
+ serverPkgDir = path8.dirname(serverPkgJson);
13417
15826
  } catch {
13418
15827
  console.error(pc25.red("Error: flint-server package not found."));
13419
15828
  process.exit(1);
13420
15829
  }
13421
- const devEntry = path6.join(serverPkgDir, "src", "dev.ts");
15830
+ const devEntry = path8.join(serverPkgDir, "src", "dev.ts");
13422
15831
  try {
13423
15832
  await stat6(devEntry);
13424
15833
  } catch {
@@ -13536,11 +15945,11 @@ serverCommand.command("list").description("List all running Flint servers from t
13536
15945
  // src/commands/runtime.ts
13537
15946
  import { Command as Command23 } from "commander";
13538
15947
  import pc26 from "picocolors";
13539
- import path7 from "path";
15948
+ import path9 from "path";
13540
15949
  var runtimeCommand = new Command23("runtime").description("Manage Flint runtimes");
13541
15950
  runtimeCommand.command("start [flintPath]").description("Start runtime for a Flint").option("--server <url>", "Server URL", "http://127.0.0.1:13040").action(async (flintPath, options) => {
13542
15951
  const serverUrl = options.server;
13543
- const resolvedPath = flintPath ? path7.resolve(flintPath) : await findFlintRoot(process.cwd());
15952
+ const resolvedPath = flintPath ? path9.resolve(flintPath) : await findFlintRoot(process.cwd());
13544
15953
  if (!resolvedPath) {
13545
15954
  console.error(pc26.red("Error: Not inside a Flint workspace. Provide a path or cd into one."));
13546
15955
  process.exit(1);
@@ -13572,7 +15981,7 @@ runtimeCommand.command("stop [runtimeId]").description("Stop a running runtime")
13572
15981
  let id = runtimeId;
13573
15982
  try {
13574
15983
  if (!id) {
13575
- const lookupPath = options.path ? path7.resolve(options.path) : await findFlintRoot(process.cwd());
15984
+ const lookupPath = options.path ? path9.resolve(options.path) : await findFlintRoot(process.cwd());
13576
15985
  if (!lookupPath) {
13577
15986
  console.error(pc26.red("Error: Provide a runtime ID or Flint path."));
13578
15987
  process.exit(1);
@@ -13583,10 +15992,10 @@ runtimeCommand.command("stop [runtimeId]").description("Stop a running runtime")
13583
15992
  process.exit(1);
13584
15993
  }
13585
15994
  const payload = await listResponse.json();
13586
- const match = (payload.runtimes ?? []).find(
15995
+ const match2 = (payload.runtimes ?? []).find(
13587
15996
  (runtime2) => runtime2.flintPath === lookupPath
13588
15997
  );
13589
- id = match?.id;
15998
+ id = match2?.id;
13590
15999
  }
13591
16000
  if (!id) {
13592
16001
  console.error(pc26.red("Error: Runtime not found."));
@@ -13706,23 +16115,23 @@ async function exportSession(flintPath, sessionId) {
13706
16115
  }
13707
16116
 
13708
16117
  // src/commands/export-codex-session.ts
13709
- import { writeFile as writeFile5, mkdir as mkdir7, readFile as readFile8, readdir as readdir4, stat as stat8 } from "fs/promises";
16118
+ import { writeFile as writeFile5, mkdir as mkdir7, readFile as readFile8, readdir as readdir5, stat as stat8 } from "fs/promises";
13710
16119
  import { join as join13 } from "path";
13711
16120
  import { homedir as homedir8 } from "os";
13712
16121
  import pc28 from "picocolors";
13713
16122
  async function findCodexTranscript(sessionId, startedAfter) {
13714
16123
  const sessionsDir = join13(homedir8(), ".codex", "sessions");
13715
16124
  try {
13716
- const years = await readdir4(sessionsDir);
16125
+ const years = await readdir5(sessionsDir);
13717
16126
  for (const year of years.reverse()) {
13718
16127
  const yearDir = join13(sessionsDir, year);
13719
- const months = await readdir4(yearDir).catch(() => []);
16128
+ const months = await readdir5(yearDir).catch(() => []);
13720
16129
  for (const month of months.reverse()) {
13721
16130
  const monthDir = join13(yearDir, month);
13722
- const days = await readdir4(monthDir).catch(() => []);
16131
+ const days = await readdir5(monthDir).catch(() => []);
13723
16132
  for (const day of days.reverse()) {
13724
16133
  const dayDir = join13(monthDir, day);
13725
- const files = await readdir4(dayDir).catch(() => []);
16134
+ const files = await readdir5(dayDir).catch(() => []);
13726
16135
  for (const file of files) {
13727
16136
  if (!file.endsWith(".jsonl")) continue;
13728
16137
  if (file.includes(sessionId)) {
@@ -14189,8 +16598,8 @@ import { readdirSync as readdirSync6, existsSync as existsSync12, statSync as st
14189
16598
  import { join as join15, basename as basename5 } from "path";
14190
16599
  function extractNumberFromFile(filename, typeName) {
14191
16600
  const regex = new RegExp(`^\\(${typeName}\\)\\s+(\\d+)`, "i");
14192
- const match = filename.match(regex);
14193
- return match ? parseInt(match[1], 10) : null;
16601
+ const match2 = filename.match(regex);
16602
+ return match2 ? parseInt(match2[1], 10) : null;
14194
16603
  }
14195
16604
  function collectFilesRecursively(dirPath) {
14196
16605
  const files = [];
@@ -14585,9 +16994,9 @@ import pc35 from "picocolors";
14585
16994
  import { randomUUID as randomUUID5 } from "crypto";
14586
16995
  import { copyFile as copyFile2, mkdir as mkdir8, writeFile as writeFile6, unlink as unlink2, stat as stat10 } from "fs/promises";
14587
16996
  import { join as join17, basename as basename6, resolve as resolve10 } from "path";
14588
- async function exists4(path8) {
16997
+ async function exists4(path10) {
14589
16998
  try {
14590
- await stat10(path8);
16999
+ await stat10(path10);
14591
17000
  return true;
14592
17001
  } catch {
14593
17002
  return false;
@@ -14664,7 +17073,7 @@ var sendCommand = new Command30("send").description("Send files to another Flint
14664
17073
  console.log();
14665
17074
  let sourceFlintName = "Unknown";
14666
17075
  try {
14667
- const { readFlintToml: readFlintToml3 } = await import("./dist-RGQKIZQW.js");
17076
+ const { readFlintToml: readFlintToml3 } = await import("./dist-EAYA2DAP.js");
14668
17077
  const toml = await readFlintToml3(flintPath);
14669
17078
  if (toml?.flint?.name) {
14670
17079
  sourceFlintName = toml.flint.name;
@@ -14930,8 +17339,8 @@ async function validateEntries(entries) {
14930
17339
  continue;
14931
17340
  }
14932
17341
  seenPaths.set(entry.path, entry);
14933
- const exists5 = await checkPathExists(entry.path);
14934
- if (!exists5) {
17342
+ const exists6 = await checkPathExists(entry.path);
17343
+ if (!exists6) {
14935
17344
  issues.push({
14936
17345
  type: "broken_path",
14937
17346
  entry,
@@ -16994,14 +19403,141 @@ orbCommand.command("respond").description("Answer a pending question on a sessio
16994
19403
  }
16995
19404
  });
16996
19405
 
19406
+ // src/commands/steel.ts
19407
+ import { Command as Command37 } from "commander";
19408
+ import pc42 from "picocolors";
19409
+ import { readFile as readFile9, readdir as readdir6, rm as rm5 } from "fs/promises";
19410
+ import { join as join19 } from "path";
19411
+ async function exists5(path10) {
19412
+ try {
19413
+ const { stat: stat11 } = await import("fs/promises");
19414
+ await stat11(path10);
19415
+ return true;
19416
+ } catch {
19417
+ return false;
19418
+ }
19419
+ }
19420
+ async function readJsonFile2(filePath) {
19421
+ try {
19422
+ const raw = await readFile9(filePath, "utf-8");
19423
+ return JSON.parse(raw);
19424
+ } catch {
19425
+ return null;
19426
+ }
19427
+ }
19428
+ var steelCommand = new Command37("steel").description("Manage Steel UI state (.steel/ directory)").addCommand(
19429
+ new Command37("preferences").description("Show Steel preferences").option("-p, --path <dir>", "Path to flint (default: auto-detect)").option("--reset", "Clear all Steel preferences").action(async (options) => {
19430
+ try {
19431
+ const flintPath = options.path || await findFlintRoot(process.cwd());
19432
+ if (!flintPath) {
19433
+ console.error(pc42.red("Error: Not inside a Flint. Use --path or cd into a Flint."));
19434
+ process.exit(1);
19435
+ }
19436
+ const prefsPath = join19(flintPath, ".steel", "preferences.json");
19437
+ if (options.reset) {
19438
+ if (await exists5(prefsPath)) {
19439
+ await rm5(prefsPath);
19440
+ console.log(pc42.green("Steel preferences cleared."));
19441
+ } else {
19442
+ console.log(pc42.dim("No preferences file found."));
19443
+ }
19444
+ return;
19445
+ }
19446
+ const prefs = await readJsonFile2(prefsPath);
19447
+ if (!prefs) {
19448
+ console.log(pc42.dim("No Steel preferences set."));
19449
+ return;
19450
+ }
19451
+ console.log(JSON.stringify(prefs, null, 2));
19452
+ } catch (err) {
19453
+ const message = err instanceof Error ? err.message : String(err);
19454
+ console.error(pc42.red(`Error: ${message}`));
19455
+ process.exit(1);
19456
+ }
19457
+ })
19458
+ ).addCommand(
19459
+ new Command37("state").description("Show plate state").argument("<plate-name>", "Name of the plate").option("-p, --path <dir>", "Path to flint (default: auto-detect)").option("--reset", "Clear all state for this plate").action(async (plateName, options) => {
19460
+ try {
19461
+ const flintPath = options.path || await findFlintRoot(process.cwd());
19462
+ if (!flintPath) {
19463
+ console.error(pc42.red("Error: Not inside a Flint. Use --path or cd into a Flint."));
19464
+ process.exit(1);
19465
+ }
19466
+ const plateDir = join19(flintPath, ".steel", "plates", plateName);
19467
+ if (options.reset) {
19468
+ if (await exists5(plateDir)) {
19469
+ await rm5(plateDir, { recursive: true });
19470
+ console.log(pc42.green(`State cleared for plate: ${plateName}`));
19471
+ } else {
19472
+ console.log(pc42.dim(`No state found for plate: ${plateName}`));
19473
+ }
19474
+ return;
19475
+ }
19476
+ if (!await exists5(plateDir)) {
19477
+ console.log(pc42.dim(`No state found for plate: ${plateName}`));
19478
+ return;
19479
+ }
19480
+ const files = await readdir6(plateDir, { withFileTypes: true });
19481
+ const stateFiles = files.filter((f) => f.isFile() && f.name.endsWith(".json"));
19482
+ if (stateFiles.length === 0) {
19483
+ console.log(pc42.dim(`No state files for plate: ${plateName}`));
19484
+ return;
19485
+ }
19486
+ console.log(pc42.bold(`Plate state: ${plateName}`));
19487
+ console.log();
19488
+ for (const file of stateFiles) {
19489
+ const key = file.name.replace(/\.json$/, "");
19490
+ const data = await readJsonFile2(join19(plateDir, file.name));
19491
+ console.log(`${pc42.cyan(key)}:`);
19492
+ console.log(JSON.stringify(data, null, 2));
19493
+ console.log();
19494
+ }
19495
+ } catch (err) {
19496
+ const message = err instanceof Error ? err.message : String(err);
19497
+ console.error(pc42.red(`Error: ${message}`));
19498
+ process.exit(1);
19499
+ }
19500
+ })
19501
+ ).addCommand(
19502
+ new Command37("boards").description("List board/view configs for a plate").argument("<plate-name>", "Name of the plate").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (plateName, options) => {
19503
+ try {
19504
+ const flintPath = options.path || await findFlintRoot(process.cwd());
19505
+ if (!flintPath) {
19506
+ console.error(pc42.red("Error: Not inside a Flint. Use --path or cd into a Flint."));
19507
+ process.exit(1);
19508
+ }
19509
+ const boardsDir = join19(flintPath, ".steel", "plates", plateName, "boards");
19510
+ if (!await exists5(boardsDir)) {
19511
+ console.log(pc42.dim(`No board configs found for plate: ${plateName}`));
19512
+ return;
19513
+ }
19514
+ const files = await readdir6(boardsDir);
19515
+ const configs = files.filter((f) => f.endsWith(".json"));
19516
+ if (configs.length === 0) {
19517
+ console.log(pc42.dim(`No board configs found for plate: ${plateName}`));
19518
+ return;
19519
+ }
19520
+ console.log(pc42.bold(`Board configs: ${plateName}`));
19521
+ for (const file of configs) {
19522
+ const name = file.replace(/\.json$/, "");
19523
+ console.log(` ${pc42.cyan(name)}`);
19524
+ }
19525
+ } catch (err) {
19526
+ const message = err instanceof Error ? err.message : String(err);
19527
+ console.error(pc42.red(`Error: ${message}`));
19528
+ process.exit(1);
19529
+ }
19530
+ })
19531
+ );
19532
+
16997
19533
  // src/index.ts
16998
19534
  var __dirname3 = dirname4(fileURLToPath4(import.meta.url));
16999
- var pkg = JSON.parse(readFileSync11(join19(__dirname3, "..", "package.json"), "utf-8"));
19535
+ var pkg = JSON.parse(readFileSync11(join20(__dirname3, "..", "package.json"), "utf-8"));
17000
19536
  var runtime = resolveRuntimeSync({ cliname: "flint" });
17001
19537
  var devAvailable = runtime.mode === "dev";
17002
19538
  var newDir = getConfigDir("flint");
17003
- var oldDir = join19(homedir11(), ".flint");
17004
- var intermediateDir = join19(homedir11(), ".nuucognition", ".flint");
19539
+ var oldDir = join20(homedir11(), ".flint");
19540
+ var intermediateDir = join20(homedir11(), ".nuucognition", ".flint");
17005
19541
  function migrateDir(sourceDir, label) {
17006
19542
  if (!existsSync15(sourceDir)) return false;
17007
19543
  try {
@@ -17011,15 +19547,15 @@ function migrateDir(sourceDir, label) {
17011
19547
  mkdirSync5(newDir, { recursive: true });
17012
19548
  let migrated = 0;
17013
19549
  for (const entry of filesToMigrate) {
17014
- const src = join19(sourceDir, entry);
17015
- const dest = join19(newDir, entry);
19550
+ const src = join20(sourceDir, entry);
19551
+ const dest = join20(newDir, entry);
17016
19552
  if (!existsSync15(dest)) {
17017
19553
  cpSync(src, dest, { recursive: true });
17018
19554
  migrated++;
17019
19555
  }
17020
19556
  }
17021
19557
  if (migrated > 0) {
17022
- console.log(pc42.yellow(`Migrated ${migrated} item(s) from ${label} to ~/.nuucognition/flint/`));
19558
+ console.log(pc43.yellow(`Migrated ${migrated} item(s) from ${label} to ~/.nuucognition/flint/`));
17023
19559
  }
17024
19560
  return migrated > 0;
17025
19561
  } catch {
@@ -17055,7 +19591,7 @@ var authConfig = {
17055
19591
  defaultEnv: devAvailable ? "dev" : "prod",
17056
19592
  devAvailable
17057
19593
  };
17058
- var program = new Command37();
19594
+ var program = new Command38();
17059
19595
  program.name("flint").description("Flint cognitive workspace CLI").version(pkg.version).enablePositionalOptions().option("--verbose", "Show stack traces for errors");
17060
19596
  program.addCommand(createLoginCommand(authConfig));
17061
19597
  program.addCommand(createLogoutCommand(authConfig));
@@ -17095,6 +19631,7 @@ var COMMAND_MAP = [
17095
19631
  { featureId: "code", command: codeCommand },
17096
19632
  { featureId: "tinderbox", command: tinderboxCommand },
17097
19633
  { featureId: "orb", command: orbCommand },
19634
+ { featureId: "steel", command: steelCommand },
17098
19635
  // Dev commands
17099
19636
  { featureId: "runtime", command: runtimeCommand }
17100
19637
  ];
@@ -17109,11 +19646,11 @@ program.on("command:*", (operands) => {
17109
19646
  if (feature && !isFeatureEnabled(FEATURES, cmdName, runtime)) {
17110
19647
  error(`Feature '${cmdName}' requires dev mode.`);
17111
19648
  console.log("");
17112
- console.log(pc42.dim("Dev features are only available when running the dev binary."));
19649
+ console.log(pc43.dim("Dev features are only available when running the dev binary."));
17113
19650
  process.exit(1);
17114
19651
  }
17115
19652
  error(`Unknown command: ${cmdName}`);
17116
- console.log(pc42.dim(`Run 'flint --help' for available commands`));
19653
+ console.log(pc43.dim(`Run 'flint --help' for available commands`));
17117
19654
  process.exit(1);
17118
19655
  });
17119
19656
  await program.parseAsync(process.argv);