@nuucognition/flint-cli 0.2.0-beta.1 → 0.2.0-beta.2

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
@@ -41,7 +41,11 @@ import {
41
41
  toKebabCase,
42
42
  writeFlintJson,
43
43
  writeFlintToml
44
- } from "./chunk-5YLBX2W6.js";
44
+ } from "./chunk-RAH2IR2Z.js";
45
+ import {
46
+ exists,
47
+ runConcurrent
48
+ } from "./chunk-V7YA5RXL.js";
45
49
  import {
46
50
  cleanRegistryFile,
47
51
  findFlintByName,
@@ -49,22 +53,23 @@ import {
49
53
  getFlintRegistry,
50
54
  getFlintRegistryPath,
51
55
  getGlobalFlintDir,
56
+ isFlintNameTaken,
52
57
  registerFlint,
53
58
  registerFlintByPath,
54
59
  unregisterFlint,
55
60
  updateFlintEntry,
56
61
  upsertFlintEntry
57
- } from "./chunk-UNMULXL5.js";
62
+ } from "./chunk-VEO4E5HX.js";
58
63
  import {
59
64
  buildExport,
60
65
  cleanupStaleExports,
61
66
  scanExportEligible,
62
67
  scanExports
63
- } from "./chunk-VO4ZYDCW.js";
68
+ } from "./chunk-K5QP4OME.js";
64
69
 
65
70
  // src/index.ts
66
- import { Command as Command30 } from "commander";
67
- import { readFileSync as readFileSync2, existsSync as existsSync6, cpSync, mkdirSync, readdirSync as readdirSync2 } from "fs";
71
+ import { Command as Command29 } from "commander";
72
+ import { readFileSync as readFileSync2, existsSync as existsSync7, cpSync, mkdirSync, readdirSync as readdirSync2 } from "fs";
68
73
  import { fileURLToPath as fileURLToPath5 } from "url";
69
74
  import { dirname as dirname10, join as join35 } from "path";
70
75
  import { homedir as homedir5 } from "os";
@@ -1376,7 +1381,6 @@ function createFeaturesCommand(config) {
1376
1381
  var FEATURES = createFeatureRegistry([
1377
1382
  // === Production Commands ===
1378
1383
  { id: "init", tier: "prod", type: "command", description: "Create a new flint workspace", requiresAuth: false },
1379
- { id: "clone", tier: "prod", type: "command", description: "Clone a flint from a git repository", requiresAuth: false },
1380
1384
  { id: "list", tier: "prod", type: "command", description: "List flints and mesh content", requiresAuth: false },
1381
1385
  { id: "sync", tier: "prod", type: "command", description: "Synchronize flint with shards", requiresAuth: false },
1382
1386
  { id: "shard", tier: "prod", type: "command", description: "Shard management", requiresAuth: false },
@@ -1404,19 +1408,24 @@ var FEATURES = createFeatureRegistry([
1404
1408
  // === Dev Commands ===
1405
1409
  { id: "lattice", tier: "dev", type: "command", description: "Lattice integration", requiresAuth: false },
1406
1410
  { id: "agent", tier: "dev", type: "command", description: "AI agent integration", requiresAuth: false },
1407
- { id: "code", tier: "dev", type: "command", description: "Launch AI coding agents", requiresAuth: false },
1411
+ { id: "code", tier: "exp", type: "command", description: "Launch AI coding agents", requiresAuth: false },
1408
1412
  { id: "server", tier: "dev", type: "command", description: "Flint runtime server", requiresAuth: false },
1409
1413
  { id: "runtime", tier: "dev", type: "command", description: "Flint runtime management", requiresAuth: false },
1410
- { id: "completions", tier: "dev", type: "command", description: "Shell completions", requiresAuth: false },
1411
1414
  { id: "obsidian.push", tier: "dev", type: "function", description: "Push obsidian config changes to remote", requiresAuth: false },
1412
1415
  { id: "agent.start", tier: "dev", type: "function", description: "Start AI agent session", requiresAuth: false }
1413
1416
  ]);
1414
1417
 
1415
1418
  // src/commands/init.ts
1416
1419
  import { Command as Command3 } from "commander";
1417
- import pc5 from "picocolors";
1418
- import { execSync as execSync5 } from "child_process";
1420
+ import pc6 from "picocolors";
1421
+ import { execSync as execSync2 } from "child_process";
1419
1422
  import { platform as platform2 } from "os";
1423
+ import { resolve as resolve8, join as join19 } from "path";
1424
+ import { existsSync as existsSync2 } from "fs";
1425
+ import { mkdtemp as mkdtemp3, rm as rm8, rename as rename4 } from "fs/promises";
1426
+ import { tmpdir as tmpdir3 } from "os";
1427
+ import { exec as exec6 } from "child_process";
1428
+ import { promisify as promisify7 } from "util";
1420
1429
 
1421
1430
  // ../../packages/flint/dist/index.js
1422
1431
  import { mkdir as mkdir4, stat as stat22 } from "fs/promises";
@@ -1425,40 +1434,42 @@ import { join as join9, dirname as dirname4, basename } from "path";
1425
1434
  import { stat as stat32 } from "fs/promises";
1426
1435
  import { dirname as dirname22, join as join33 } from "path";
1427
1436
  import { join as join42 } from "path";
1428
- import { execSync } from "child_process";
1437
+ import { exec } from "child_process";
1438
+ import { promisify as promisify6 } from "util";
1429
1439
  import { readdir as readdir4, stat as stat42, access as access2 } from "fs/promises";
1430
1440
  import { join as join52, resolve } from "path";
1431
1441
  import { homedir as homedir3 } from "os";
1432
1442
  import { readFile as readFile4, writeFile as writeFile23, mkdir as mkdir33, stat as stat52, unlink as unlink3, access as access22 } from "fs/promises";
1433
1443
  import { join as join62 } from "path";
1434
- import { exec } from "child_process";
1435
- import { promisify as promisify6 } from "util";
1444
+ import { exec as exec2 } from "child_process";
1445
+ import { promisify as promisify22 } from "util";
1436
1446
  import { rm as rm5 } from "fs/promises";
1437
1447
  import { mkdir as mkdir5, readdir as readdir32, copyFile, rm as rm32, readFile as readFile32, writeFile as writeFile32, rmdir } from "fs/promises";
1438
1448
  import { join as join92, resolve as resolve3, dirname as dirname32 } from "path";
1439
1449
  import { randomUUID } from "crypto";
1440
1450
  import { parse as parseYaml2 } from "yaml";
1441
- import { access as access3 } from "fs/promises";
1442
1451
  import { join as join82, resolve as resolve2, isAbsolute } from "path";
1443
1452
  import { mkdtemp, rm as rm22 } from "fs/promises";
1444
1453
  import { tmpdir } from "os";
1445
- import { execSync as execSync2 } from "child_process";
1454
+ import { exec as exec3 } from "child_process";
1455
+ import { promisify as promisify32 } from "util";
1446
1456
  import { parse as parseYaml } from "yaml";
1447
1457
  import { readFile as readFile23 } from "fs/promises";
1448
1458
  import { join as join10 } from "path";
1449
1459
  import { readdir as readdir42, mkdir as mkdir6 } from "fs/promises";
1450
1460
  import { writeFile as writeFile4 } from "fs/promises";
1451
1461
  import { spawn } from "child_process";
1452
- import { readdir as readdir5, access as access4, constants } from "fs/promises";
1462
+ import { readdir as readdir5, access as access3, constants } from "fs/promises";
1453
1463
  import { join as join11, resolve as resolve4 } from "path";
1454
1464
  import { mkdir as mkdir7, readFile as readFile5, writeFile as writeFile5, rm as rm52, readdir as readdir6, copyFile as copyFile2 } from "fs/promises";
1455
1465
  import { join as join13, dirname as dirname42, resolve as resolve6, sep } from "path";
1456
- import { execSync as execSync4 } from "child_process";
1466
+ import { execSync } from "child_process";
1457
1467
  import { randomUUID as randomUUID2 } from "crypto";
1458
1468
  import { join as join12, resolve as resolve5, isAbsolute as isAbsolute2 } from "path";
1459
1469
  import { mkdtemp as mkdtemp2, rm as rm42 } from "fs/promises";
1460
1470
  import { tmpdir as tmpdir2 } from "os";
1461
- import { execSync as execSync3 } from "child_process";
1471
+ import { exec as exec4 } from "child_process";
1472
+ import { promisify as promisify42 } from "util";
1462
1473
  import { parse as parseYaml3 } from "yaml";
1463
1474
  import { readFile as readFile42 } from "fs/promises";
1464
1475
 
@@ -2459,16 +2470,16 @@ var __dirname2 = dirname2(fileURLToPath2(import.meta.url));
2459
2470
  // ../../packages/flint/dist/index.js
2460
2471
  import { rename as rename22 } from "fs/promises";
2461
2472
  import { basename as basename3, dirname as dirname6, join as join18 } from "path";
2462
- import { readFile as readFile6, writeFile as writeFile6, mkdir as mkdir8, access as access5, rm as rm6 } from "fs/promises";
2473
+ import { readFile as readFile6, writeFile as writeFile6, mkdir as mkdir8, access as access4, rm as rm6 } from "fs/promises";
2463
2474
  import { join as join14 } from "path";
2464
- import { exec as exec2 } from "child_process";
2465
- import { promisify as promisify22 } from "util";
2466
- import { readFile as readFile7, writeFile as writeFile7 } from "fs/promises";
2475
+ import { exec as exec5 } from "child_process";
2476
+ import { promisify as promisify52 } from "util";
2477
+ import { readFile as readFile7, writeFile as writeFile7, readdir as readdir7 } from "fs/promises";
2467
2478
  import { join as join15 } from "path";
2468
2479
  import { stat as stat8, mkdir as mkdir11 } from "fs/promises";
2469
- import { mkdir as mkdir10, readdir as readdir8, rm as rm7, cp as cp3, rename as rename3, access as access6 } from "fs/promises";
2480
+ import { mkdir as mkdir10, readdir as readdir9, rm as rm7, cp as cp3, rename as rename3, access as access5 } from "fs/promises";
2470
2481
  import { join as join17 } from "path";
2471
- import { readdir as readdir7, readFile as readFile8, mkdir as mkdir9 } from "fs/promises";
2482
+ import { readdir as readdir8, readFile as readFile8, mkdir as mkdir9 } from "fs/promises";
2472
2483
  import { join as join16, dirname as dirname5, resolve as resolve7, sep as sep2 } from "path";
2473
2484
  import { randomUUID as randomUUID3 } from "crypto";
2474
2485
  import { fileURLToPath as fileURLToPath3 } from "url";
@@ -2511,6 +2522,12 @@ async function createFlintStructure(options) {
2511
2522
  if (invalidChars.test(name)) {
2512
2523
  throw new Error(`Flint name contains invalid characters: ${name}`);
2513
2524
  }
2525
+ if (register) {
2526
+ const existing = await isFlintNameTaken(name);
2527
+ if (existing) {
2528
+ throw new Error(`A flint named "${name}" already exists at: ${existing.path}`);
2529
+ }
2530
+ }
2514
2531
  const folderName = formatFlintFolderName(name);
2515
2532
  const flintPath = join23(parentDir, folderName);
2516
2533
  try {
@@ -2571,10 +2588,11 @@ async function isInsideFlint(path3) {
2571
2588
  const flintRoot = await findFlintRoot(path3);
2572
2589
  return flintRoot !== null;
2573
2590
  }
2591
+ var execAsync = promisify6(exec);
2574
2592
  var OBSIDIAN_REPO_URL = "https://github.com/NUU-Cognition/flint-dot-obsidian.git";
2575
2593
  async function cloneObsidian(flintPath) {
2576
2594
  const obsidianDir = join42(flintPath, ".obsidian");
2577
- execSync(`git clone ${OBSIDIAN_REPO_URL} "${obsidianDir}"`, { stdio: "pipe" });
2595
+ await execAsync(`git clone ${OBSIDIAN_REPO_URL} "${obsidianDir}"`, { timeout: 6e4 });
2578
2596
  }
2579
2597
  async function isValidFlint(path3) {
2580
2598
  try {
@@ -2676,7 +2694,7 @@ async function discoverFlints(options) {
2676
2694
  }
2677
2695
  return results;
2678
2696
  }
2679
- var execAsync = promisify6(exec);
2697
+ var execAsync2 = promisify22(exec2);
2680
2698
  var LEGACY_WORKSPACE_CONFIG_FILENAME = "workspace.toml";
2681
2699
  function getWorkspaceReferencesDir(flintPath) {
2682
2700
  return join62(flintPath, "Workspace", "References");
@@ -2853,8 +2871,8 @@ async function createRepository(flintPath, name, url) {
2853
2871
  }
2854
2872
  await mkdir33(repoPath, { recursive: true });
2855
2873
  try {
2856
- await execAsync("git init", { cwd: repoPath });
2857
- await execAsync(`git remote add origin "${url}"`, { cwd: repoPath });
2874
+ await execAsync2("git init", { cwd: repoPath });
2875
+ await execAsync2(`git remote add origin "${url}"`, { cwd: repoPath });
2858
2876
  } catch (error3) {
2859
2877
  const message = error3 instanceof Error ? error3.message : String(error3);
2860
2878
  await rm5(repoPath, { recursive: true, force: true });
@@ -2870,7 +2888,7 @@ async function cloneRepository(flintPath, name, url) {
2870
2888
  throw new Error(`Repository folder already exists: ${repoPath}`);
2871
2889
  }
2872
2890
  try {
2873
- await execAsync(`git clone "${url}" "${repoPath}"`);
2891
+ await execAsync2(`git clone "${url}" "${repoPath}"`);
2874
2892
  } catch (error3) {
2875
2893
  const message = error3 instanceof Error ? error3.message : String(error3);
2876
2894
  throw new Error(`Failed to clone repository: ${message}`);
@@ -2888,7 +2906,7 @@ async function removeRepositoryFolder(flintPath, name) {
2888
2906
  async function updateRepository(flintPath, name, url) {
2889
2907
  const repoPath = getRepositoryPath(flintPath, name);
2890
2908
  if (await pathExists(repoPath)) {
2891
- await execAsync("git pull", { cwd: repoPath });
2909
+ await execAsync2("git pull", { cwd: repoPath });
2892
2910
  return repoPath;
2893
2911
  }
2894
2912
  return cloneRepository(flintPath, name, url);
@@ -2927,7 +2945,7 @@ async function cloneSourceRepository(flintPath, name, url) {
2927
2945
  throw new Error(`Source repository folder already exists: ${repoPath}`);
2928
2946
  }
2929
2947
  try {
2930
- await execAsync(`git clone --depth 1 "${url}" "${repoPath}"`);
2948
+ await execAsync2(`git clone --depth 1 "${url}" "${repoPath}"`);
2931
2949
  } catch (error3) {
2932
2950
  const message = error3 instanceof Error ? error3.message : String(error3);
2933
2951
  throw new Error(`Failed to clone source repository: ${message}`);
@@ -3013,14 +3031,7 @@ async function migrateWorkspaceConfig(flintPath) {
3013
3031
  }
3014
3032
  return result;
3015
3033
  }
3016
- async function exists(path3) {
3017
- try {
3018
- await access3(path3);
3019
- return true;
3020
- } catch {
3021
- return false;
3022
- }
3023
- }
3034
+ var execAsync3 = promisify32(exec3);
3024
3035
  function isOwnerRepo(s) {
3025
3036
  return /^[a-zA-Z0-9_.-]+\/[a-zA-Z0-9_.-]+$/.test(s);
3026
3037
  }
@@ -3075,8 +3086,7 @@ async function resolveShardSource(source, flintPath) {
3075
3086
  async function cloneAndResolve(url, source) {
3076
3087
  const tempDir = await mkdtemp(join82(tmpdir(), "flint-shard-"));
3077
3088
  try {
3078
- execSync2(`git clone --depth 1 ${url} "${tempDir}"`, {
3079
- stdio: "pipe",
3089
+ await execAsync3(`git clone --depth 1 ${url} "${tempDir}"`, {
3080
3090
  timeout: 6e4
3081
3091
  // 60 second timeout
3082
3092
  });
@@ -3141,40 +3151,10 @@ async function fetchRemoteShardVersion(source) {
3141
3151
  }
3142
3152
  return null;
3143
3153
  }
3144
- var _installingDeps = /* @__PURE__ */ new Set();
3145
- async function resolveDependency(flintPath, dep, installedNames, options = {}) {
3146
- if (!isOwnerRepo(dep)) return;
3147
- if (_installingDeps.has(dep)) return;
3148
- _installingDeps.add(dep);
3149
- try {
3150
- const declarations = await getShardDeclarations(flintPath);
3151
- const declValues = Object.values(declarations);
3152
- const alreadyDeclared = declValues.some((d) => d.source === dep);
3153
- if (alreadyDeclared) return;
3154
- const installedKebabSet = new Set(installedNames.map((f) => toKebabCase(f)));
3155
- const repoParts = dep.split("/");
3156
- const repoName = repoParts[1] || "";
3157
- const depKebab = repoName.startsWith("shard-") ? repoName.slice(6) : repoName;
3158
- if (depKebab && installedKebabSet.has(depKebab)) return;
3159
- const source = parseShardSource(dep);
3160
- const resolved = await resolveShardSource(source, flintPath);
3161
- try {
3162
- const manifestKebab = toKebabCase(resolved.manifest.name);
3163
- if (!installedKebabSet.has(manifestKebab)) {
3164
- await installShardFromSource(flintPath, resolved.path, resolved.manifest, {
3165
- force: options.force,
3166
- source: dep
3167
- });
3168
- }
3169
- } finally {
3170
- await cleanupResolvedSource(resolved);
3171
- }
3172
- } finally {
3173
- _installingDeps.delete(dep);
3174
- }
3175
- }
3176
3154
  async function cloneShardRepos(flintPath, repos) {
3177
- const { execSync: execSync52 } = await import("child_process");
3155
+ const { exec: exec62 } = await import("child_process");
3156
+ const { promisify: promisify62 } = await import("util");
3157
+ const execAsync62 = promisify62(exec62);
3178
3158
  const reposDir = join92(flintPath, "Shards", "(System) Repos");
3179
3159
  await mkdir5(reposDir, { recursive: true });
3180
3160
  const gitignorePath = join92(reposDir, ".gitignore");
@@ -3189,7 +3169,7 @@ async function cloneShardRepos(flintPath, repos) {
3189
3169
  const branchArgs = repo.branch ? ["--branch", repo.branch] : [];
3190
3170
  const args = ["clone", ...branchArgs, "--depth", "1", repo.url, repoPath];
3191
3171
  try {
3192
- execSync52(`git ${args.join(" ")}`, { stdio: "pipe" });
3172
+ await execAsync62(`git ${args.join(" ")}`, { timeout: 6e4 });
3193
3173
  } catch (err) {
3194
3174
  console.warn(`Failed to clone repo "${repo.name}" from ${repo.url}`);
3195
3175
  }
@@ -3202,7 +3182,9 @@ async function removeShardRepos(flintPath, repos) {
3202
3182
  }
3203
3183
  }
3204
3184
  async function pullShardRepos(flintPath, repos) {
3205
- const { execSync: execSync52 } = await import("child_process");
3185
+ const { exec: exec62 } = await import("child_process");
3186
+ const { promisify: promisify62 } = await import("util");
3187
+ const execAsync62 = promisify62(exec62);
3206
3188
  const reposDir = join92(flintPath, "Shards", "(System) Repos");
3207
3189
  for (const repo of repos) {
3208
3190
  const repoPath = join92(reposDir, repo.name);
@@ -3211,7 +3193,7 @@ async function pullShardRepos(flintPath, repos) {
3211
3193
  continue;
3212
3194
  }
3213
3195
  try {
3214
- execSync52("git pull", { cwd: repoPath, stdio: "pipe" });
3196
+ await execAsync62("git pull", { cwd: repoPath, timeout: 3e4 });
3215
3197
  } catch {
3216
3198
  console.warn(`Failed to pull repo "${repo.name}"`);
3217
3199
  }
@@ -3278,12 +3260,6 @@ async function installShardFromSource(flintPath, sourcePath, manifest, options =
3278
3260
  if (!resolvedDestPath.startsWith(resolvedFlintPath)) {
3279
3261
  throw new Error("Invalid shard path: outside flint directory");
3280
3262
  }
3281
- if (manifest.depends?.length) {
3282
- const installed = await listInstalledShards(flintPath);
3283
- for (const dep of manifest.depends) {
3284
- await resolveDependency(flintPath, dep, installed, { force: options.force });
3285
- }
3286
- }
3287
3263
  await rm32(destPath, { recursive: true, force: true });
3288
3264
  await mkdir5(destPath, { recursive: true });
3289
3265
  const shardYamlSrc = join92(sourcePath, "shard.yaml");
@@ -3291,12 +3267,9 @@ async function installShardFromSource(flintPath, sourcePath, manifest, options =
3291
3267
  if (await exists(shardYamlSrc)) {
3292
3268
  await copyFile(shardYamlSrc, shardYamlDest);
3293
3269
  }
3294
- const copyFolderPath = join92(sourcePath, "copy");
3295
- const hasLegacyCopyDir = await exists(copyFolderPath);
3296
- const shardFilesSource = hasLegacyCopyDir ? copyFolderPath : sourcePath;
3297
- const skipFiles = hasLegacyCopyDir ? [] : ["shard.yaml", "README.md", "install", ".git", "scripts"];
3298
- await copyDir(shardFilesSource, destPath, skipFiles);
3299
- const scriptsSrc = join92(sourcePath, hasLegacyCopyDir ? "copy/scripts" : "scripts");
3270
+ const skipFiles = ["shard.yaml", "README.md", "install", ".git", "scripts"];
3271
+ await copyDir(sourcePath, destPath, skipFiles);
3272
+ const scriptsSrc = join92(sourcePath, "scripts");
3300
3273
  if (await exists(scriptsSrc)) {
3301
3274
  await copyDir(scriptsSrc, join92(destPath, "scripts"));
3302
3275
  }
@@ -3322,7 +3295,7 @@ async function installShardFromSource(flintPath, sourcePath, manifest, options =
3322
3295
  continue;
3323
3296
  }
3324
3297
  if (await exists(destFilePath)) {
3325
- const mode = entry.mode ?? (entry.force ? "force" : "once");
3298
+ const mode = entry.mode ?? "once";
3326
3299
  if (mode === "once") {
3327
3300
  continue;
3328
3301
  }
@@ -3405,77 +3378,95 @@ async function updateShards(flintPath, options = {}) {
3405
3378
  return mode === "dev" || mode === "custom";
3406
3379
  }).map(([k]) => k)
3407
3380
  );
3408
- const results = [];
3409
- for (const info2 of installed) {
3410
- if (localSet.has(info2.name)) continue;
3411
- const declaration = declarations[info2.name];
3412
- const source = declaration?.source;
3413
- if (!options.reinstall && source && isOwnerRepo(source)) {
3414
- const parsed2 = parseShardSource(source);
3415
- const remoteVersion = await fetchRemoteShardVersion(parsed2);
3416
- if (remoteVersion && remoteVersion === info2.version) {
3417
- results.push({
3381
+ const updatableShards = installed.filter((info2) => !localSet.has(info2.name));
3382
+ const updateTasks = updatableShards.map((info2) => ({
3383
+ name: info2.folderName,
3384
+ run: async () => {
3385
+ const declaration = declarations[info2.name];
3386
+ const source = declaration?.source;
3387
+ if (!options.reinstall && source && isOwnerRepo(source)) {
3388
+ const parsed2 = parseShardSource(source);
3389
+ const remoteVersion = await fetchRemoteShardVersion(parsed2);
3390
+ if (remoteVersion && remoteVersion === info2.version) {
3391
+ return {
3392
+ name: info2.folderName,
3393
+ path: join92(flintPath, "Shards", info2.folderName),
3394
+ status: "skipped",
3395
+ localVersion: info2.version,
3396
+ remoteVersion,
3397
+ reason: "up to date"
3398
+ };
3399
+ }
3400
+ }
3401
+ const shardPath = join92(flintPath, "Shards", info2.folderName);
3402
+ const manifest = await readShardManifest(shardPath);
3403
+ if (manifest?.repos?.length) {
3404
+ await pullShardRepos(flintPath, manifest.repos);
3405
+ }
3406
+ if (!source || !isOwnerRepo(source)) {
3407
+ return {
3418
3408
  name: info2.folderName,
3419
3409
  path: join92(flintPath, "Shards", info2.folderName),
3420
3410
  status: "skipped",
3421
3411
  localVersion: info2.version,
3422
- remoteVersion,
3423
- reason: "up to date"
3412
+ reason: "no source configured"
3413
+ };
3414
+ }
3415
+ const parsed = parseShardSource(source);
3416
+ let resolved = null;
3417
+ try {
3418
+ resolved = await resolveShardSource(parsed, flintPath);
3419
+ } catch {
3420
+ return {
3421
+ name: info2.folderName,
3422
+ path: join92(flintPath, "Shards", info2.folderName),
3423
+ status: "failed",
3424
+ localVersion: info2.version,
3425
+ reason: "failed to resolve source"
3426
+ };
3427
+ }
3428
+ try {
3429
+ await installShardFromSource(flintPath, resolved.path, resolved.manifest, {
3430
+ force: true,
3431
+ source
3424
3432
  });
3425
- continue;
3433
+ return {
3434
+ name: info2.folderName,
3435
+ path: join92(flintPath, "Shards", info2.folderName),
3436
+ status: "updated",
3437
+ localVersion: info2.version,
3438
+ remoteVersion: resolved.manifest.version
3439
+ };
3440
+ } catch {
3441
+ return {
3442
+ name: info2.folderName,
3443
+ path: join92(flintPath, "Shards", info2.folderName),
3444
+ status: "failed",
3445
+ localVersion: info2.version,
3446
+ reason: "failed to install from source"
3447
+ };
3448
+ } finally {
3449
+ await cleanupResolvedSource(resolved);
3426
3450
  }
3427
3451
  }
3428
- const shardPath = join92(flintPath, "Shards", info2.folderName);
3429
- const manifest = await readShardManifest(shardPath);
3430
- if (manifest?.repos?.length) {
3431
- await pullShardRepos(flintPath, manifest.repos);
3432
- }
3433
- if (!source || !isOwnerRepo(source)) {
3434
- results.push({
3435
- name: info2.folderName,
3436
- path: join92(flintPath, "Shards", info2.folderName),
3437
- status: "skipped",
3438
- localVersion: info2.version,
3439
- reason: "no source configured"
3440
- });
3441
- continue;
3442
- }
3443
- const parsed = parseShardSource(source);
3444
- let resolved = null;
3445
- try {
3446
- resolved = await resolveShardSource(parsed, flintPath);
3447
- } catch {
3448
- results.push({
3449
- name: info2.folderName,
3450
- path: join92(flintPath, "Shards", info2.folderName),
3451
- status: "failed",
3452
- localVersion: info2.version,
3453
- reason: "failed to resolve source"
3454
- });
3455
- continue;
3456
- }
3457
- try {
3458
- await installShardFromSource(flintPath, resolved.path, resolved.manifest, {
3459
- force: true,
3460
- source
3461
- });
3462
- results.push({
3463
- name: info2.folderName,
3464
- path: join92(flintPath, "Shards", info2.folderName),
3465
- status: "updated",
3466
- localVersion: info2.version,
3467
- remoteVersion: resolved.manifest.version
3468
- });
3469
- } catch {
3452
+ }));
3453
+ const { runConcurrent: runConcurrent2 } = await import("./utils-BBA2XQZO-YU5SL3JY.js");
3454
+ const concurrentResults = await runConcurrent2(updateTasks, {
3455
+ concurrency: 5,
3456
+ onStart: options.onStart,
3457
+ onComplete: options.onComplete,
3458
+ onError: options.onError
3459
+ });
3460
+ const results = concurrentResults.filter((r) => r.status === "ok" && r.value).map((r) => r.value);
3461
+ for (const r of concurrentResults) {
3462
+ if (r.status === "error") {
3470
3463
  results.push({
3471
- name: info2.folderName,
3472
- path: join92(flintPath, "Shards", info2.folderName),
3464
+ name: r.name,
3465
+ path: join92(flintPath, "Shards", r.name),
3473
3466
  status: "failed",
3474
- localVersion: info2.version,
3475
- reason: "failed to install from source"
3467
+ localVersion: "",
3468
+ reason: r.error?.message || "Unknown error"
3476
3469
  });
3477
- } finally {
3478
- await cleanupResolvedSource(resolved);
3479
3470
  }
3480
3471
  }
3481
3472
  return results;
@@ -3571,7 +3562,7 @@ async function pullShard(flintPath, identifier, options) {
3571
3562
  if (!manifest) continue;
3572
3563
  const result = { name: folder, reposCloned: 0, reposPulled: 0, foldersCreated: 0, filesInstalled: 0 };
3573
3564
  if (manifest.repos?.length) {
3574
- const { execSync: execSync52 } = await import("child_process");
3565
+ const { execSync: execSync22 } = await import("child_process");
3575
3566
  const reposDir = join92(flintPath, "Shards", "(System) Repos");
3576
3567
  await mkdir5(reposDir, { recursive: true });
3577
3568
  const gitignorePath = join92(reposDir, ".gitignore");
@@ -3582,7 +3573,7 @@ async function pullShard(flintPath, identifier, options) {
3582
3573
  const repoPath = join92(reposDir, repo.name);
3583
3574
  if (await exists(repoPath)) {
3584
3575
  try {
3585
- execSync52("git pull", { cwd: repoPath, stdio: "pipe" });
3576
+ execSync22("git pull", { cwd: repoPath, stdio: "pipe" });
3586
3577
  result.reposPulled++;
3587
3578
  } catch {
3588
3579
  console.warn(`Failed to pull repo "${repo.name}"`);
@@ -3591,7 +3582,7 @@ async function pullShard(flintPath, identifier, options) {
3591
3582
  const branchArgs = repo.branch ? ["--branch", repo.branch] : [];
3592
3583
  const args = ["clone", ...branchArgs, "--depth", "1", repo.url, repoPath];
3593
3584
  try {
3594
- execSync52(`git ${args.join(" ")}`, { stdio: "pipe" });
3585
+ execSync22(`git ${args.join(" ")}`, { stdio: "pipe" });
3595
3586
  result.reposCloned++;
3596
3587
  } catch {
3597
3588
  console.warn(`Failed to clone repo "${repo.name}" from ${repo.url}`);
@@ -3620,7 +3611,7 @@ async function pullShard(flintPath, identifier, options) {
3620
3611
  const resolvedDestFilePath = resolve3(destFilePath);
3621
3612
  if (!resolvedDestFilePath.startsWith(resolvedFlintPath)) continue;
3622
3613
  if (await exists(destFilePath)) {
3623
- const mode = entry.mode ?? (entry.force ? "force" : "once");
3614
+ const mode = entry.mode ?? "once";
3624
3615
  if (!options?.force && mode === "once") continue;
3625
3616
  }
3626
3617
  let content;
@@ -3761,6 +3752,10 @@ State for the ${name} shard.
3761
3752
  `;
3762
3753
  await writeFile32(join92(stateDir, `(Shard) ${name}.md`), stateContent);
3763
3754
  }
3755
+ if (shardMode === "dev") {
3756
+ const { execSync: execSync22 } = await import("child_process");
3757
+ execSync22("git init", { cwd: shardPath, stdio: "pipe" });
3758
+ }
3764
3759
  await addShardToConfig(flintPath, folderName, `path:./Shards/${folderName}`, { mode: shardMode });
3765
3760
  return { name: folderName, path: shardPath };
3766
3761
  }
@@ -3795,24 +3790,121 @@ async function registerExistingShard(flintPath, folderName) {
3795
3790
  path: shardPath
3796
3791
  };
3797
3792
  }
3798
- function repoToKebab(dep) {
3799
- const parts = dep.split("/");
3800
- if (parts.length !== 2 || !parts[1]) return null;
3801
- const repo = parts[1];
3802
- return repo.startsWith("shard-") ? repo.slice(6) : repo;
3793
+ async function editShard(flintPath, folderName, source) {
3794
+ const { execSync: execSync22 } = await import("child_process");
3795
+ const { rename: rename32 } = await import("fs/promises");
3796
+ const shardPath = join92(flintPath, "Shards", folderName);
3797
+ if (!await exists(shardPath)) {
3798
+ throw new Error(`Shard folder not found: Shards/${folderName}`);
3799
+ }
3800
+ if (folderName.startsWith("(Dev)")) {
3801
+ throw new Error(`"${folderName}" is already a dev shard.`);
3802
+ }
3803
+ if (folderName.startsWith("(Custom)")) {
3804
+ throw new Error(`"${folderName}" is a custom shard. Custom shards cannot be transitioned to dev mode.`);
3805
+ }
3806
+ const baseName = folderName.replace(/^\([^)]*\)\s*/, "");
3807
+ const devFolderName = `(Dev) ${baseName}`;
3808
+ const devPath = join92(flintPath, "Shards", devFolderName);
3809
+ if (await exists(devPath)) {
3810
+ throw new Error(`Dev folder already exists: Shards/${devFolderName}`);
3811
+ }
3812
+ await rename32(shardPath, devPath);
3813
+ if (isOwnerRepo(source)) {
3814
+ const tmpDir = join92(flintPath, ".flint", "_tmp_edit_" + Date.now());
3815
+ try {
3816
+ execSync22(`git clone --depth 1 "${source.includes("github.com") ? source : `https://github.com/${source}.git`}" "${tmpDir}"`, { stdio: "pipe", timeout: 6e4 });
3817
+ await copyDir(join92(tmpDir, ".git"), join92(devPath, ".git"));
3818
+ } catch {
3819
+ execSync22("git init", { cwd: devPath, stdio: "pipe" });
3820
+ } finally {
3821
+ await rm32(tmpDir, { recursive: true, force: true });
3822
+ }
3823
+ } else {
3824
+ execSync22("git init", { cwd: devPath, stdio: "pipe" });
3825
+ }
3826
+ const kebab = toKebabCase(folderName);
3827
+ await removeShardFromConfig(flintPath, kebab);
3828
+ await addShardToConfig(flintPath, devFolderName, isOwnerRepo(source) ? source : `path:./Shards/${devFolderName}`, { mode: "dev" });
3829
+ return { name: devFolderName, path: devPath, oldFolder: folderName };
3803
3830
  }
3804
- function isDepInstalled(dep, installedKebabSet, installedFolders, declarations) {
3805
- if (isOwnerRepo(dep)) {
3806
- if (Object.values(declarations).some((d) => d.source === dep)) {
3807
- return true;
3831
+ async function freezeShard(flintPath, folderName) {
3832
+ const { execSync: execSync22 } = await import("child_process");
3833
+ const { rename: rename32 } = await import("fs/promises");
3834
+ const shardPath = join92(flintPath, "Shards", folderName);
3835
+ if (!await exists(shardPath)) {
3836
+ throw new Error(`Shard folder not found: Shards/${folderName}`);
3837
+ }
3838
+ if (!folderName.startsWith("(Dev)")) {
3839
+ throw new Error(`"${folderName}" is not a dev shard.`);
3840
+ }
3841
+ const gitDir = join92(shardPath, ".git");
3842
+ if (!await exists(gitDir)) {
3843
+ throw new Error(`"${folderName}" has no .git directory.`);
3844
+ }
3845
+ try {
3846
+ const status = execSync22("git status --porcelain", { cwd: shardPath, encoding: "utf-8" }).trim();
3847
+ if (status) {
3848
+ throw new Error(`"${folderName}" has uncommitted changes. Commit or stash them first.`);
3808
3849
  }
3809
- const kebab = repoToKebab(dep);
3810
- if (kebab && installedKebabSet.has(kebab)) {
3811
- return true;
3850
+ } catch (err) {
3851
+ if (err instanceof Error && err.message.includes("uncommitted changes")) throw err;
3852
+ }
3853
+ try {
3854
+ const remote = execSync22("git remote get-url origin", { cwd: shardPath, encoding: "utf-8" }).trim();
3855
+ if (remote) {
3856
+ const unpushed = execSync22("git log @{u}..HEAD --oneline", { cwd: shardPath, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
3857
+ if (unpushed) {
3858
+ throw new Error(`"${folderName}" has unpushed commits. Push them first.`);
3859
+ }
3812
3860
  }
3813
- return false;
3861
+ } catch (err) {
3862
+ if (err instanceof Error && err.message.includes("unpushed commits")) throw err;
3863
+ }
3864
+ const declarations = await getShardDeclarations(flintPath);
3865
+ const kebab = toKebabCase(folderName);
3866
+ const decl = declarations[kebab];
3867
+ const source = decl?.source || "";
3868
+ const baseName = folderName.replace(/^\(Dev\)\s*/, "");
3869
+ const normalPath = join92(flintPath, "Shards", baseName);
3870
+ if (await exists(normalPath)) {
3871
+ throw new Error(`Normal folder already exists: Shards/${baseName}`);
3872
+ }
3873
+ await rm32(gitDir, { recursive: true, force: true });
3874
+ await rename32(shardPath, normalPath);
3875
+ await removeShardFromConfig(flintPath, kebab);
3876
+ const normalSource = isOwnerRepo(source) ? source : `path:./Shards/${baseName}`;
3877
+ await addShardToConfig(flintPath, baseName, normalSource);
3878
+ return { name: baseName, path: normalPath, oldFolder: folderName };
3879
+ }
3880
+ async function addShardGitRemote(flintPath, folderName, url) {
3881
+ const { execSync: execSync22 } = await import("child_process");
3882
+ const shardPath = join92(flintPath, "Shards", folderName);
3883
+ if (!await exists(shardPath)) {
3884
+ throw new Error(`Shard folder not found: Shards/${folderName}`);
3885
+ }
3886
+ if (!folderName.startsWith("(Dev)")) {
3887
+ throw new Error(`"${folderName}" is not a dev shard. Only dev shards can have git remotes added.`);
3888
+ }
3889
+ const gitDir = join92(shardPath, ".git");
3890
+ if (!await exists(gitDir)) {
3891
+ throw new Error(`"${folderName}" has no .git directory. Run git init first.`);
3892
+ }
3893
+ try {
3894
+ const existing = execSync22("git remote get-url origin", { cwd: shardPath, encoding: "utf-8" }).trim();
3895
+ if (existing) {
3896
+ throw new Error(`"${folderName}" already has a remote: ${existing}. Use \`git remote set-url origin <url>\` to change it.`);
3897
+ }
3898
+ } catch (err) {
3899
+ if (err instanceof Error && err.message.includes("already has a remote")) throw err;
3814
3900
  }
3815
- return installedKebabSet.has(dep) || installedFolders.some((f) => toKebabCase(f) === dep);
3901
+ execSync22(`git remote add origin "${url}"`, { cwd: shardPath, stdio: "pipe" });
3902
+ const match = url.match(/(?:github\.com[/:])([\w.-]+\/[\w.-]+?)(?:\.git)?$/);
3903
+ const ownerRepo = match?.[1] || url;
3904
+ const kebab = toKebabCase(folderName);
3905
+ await removeShardFromConfig(flintPath, kebab);
3906
+ await addShardToConfig(flintPath, folderName, ownerRepo, { mode: "dev" });
3907
+ return { ownerRepo };
3816
3908
  }
3817
3909
  async function countFiles(dirPath) {
3818
3910
  try {
@@ -3882,12 +3974,11 @@ async function checkShardHealth(flintPath) {
3882
3974
  action: async () => {
3883
3975
  const name = folder.replace(/^\([^)]*\)\s*/, "");
3884
3976
  const shorthand = name.toLowerCase().replace(/\s+/g, "").slice(0, 4);
3885
- const yaml = `version: "0.1.0"
3977
+ const yaml = `shard-spec: "0.1.0"
3978
+ version: "0.1.0"
3886
3979
  name: ${name}
3887
3980
  shorthand: ${shorthand}
3888
3981
  description: ${name} shard
3889
- depends:
3890
- - core
3891
3982
  `;
3892
3983
  await writeFile4(join10(shardPath, "shard.yaml"), yaml);
3893
3984
  },
@@ -3929,36 +4020,6 @@ depends:
3929
4020
  }
3930
4021
  }
3931
4022
  }
3932
- const shardDeclarations = await getShardDeclarations(flintPath);
3933
- for (const folder of installedFolders) {
3934
- const shardPath = join10(flintPath, "Shards", folder);
3935
- const manifest = await readShardManifest(shardPath);
3936
- if (manifest?.depends) {
3937
- for (const dep of manifest.depends) {
3938
- const depInstalled = isDepInstalled(dep, installedKebabSet, installedFolders, shardDeclarations);
3939
- if (!depInstalled) {
3940
- const healAction = isOwnerRepo(dep) ? {
3941
- action: async () => {
3942
- const source = parseShardSource(dep);
3943
- const resolved = await resolveShardSource(source, flintPath);
3944
- try {
3945
- await installShardFromSource(flintPath, resolved.path, resolved.manifest, { source: dep });
3946
- } finally {
3947
- await cleanupResolvedSource(resolved);
3948
- }
3949
- },
3950
- actionLabel: `Install dependency ${dep}`
3951
- } : {};
3952
- results.push({
3953
- check: `${folder} \u2192 ${dep}`,
3954
- status: "warning",
3955
- message: `Dependency "${dep}" is not installed`,
3956
- ...healAction
3957
- });
3958
- }
3959
- }
3960
- }
3961
- }
3962
4023
  if (results.length === 0) {
3963
4024
  const count = installedFolders.length;
3964
4025
  results.push({
@@ -4071,33 +4132,6 @@ Describe the shard context here.
4071
4132
  }
4072
4133
  }
4073
4134
  }
4074
- if (manifest?.depends) {
4075
- const installedFolders = await listInstalledShards(flintPath);
4076
- const installedKebabSet = new Set(installedFolders.map((f) => toKebabCase(f)));
4077
- for (const dep of manifest.depends) {
4078
- const depInstalled = isDepInstalled(dep, installedKebabSet, installedFolders, declarations);
4079
- if (!depInstalled) {
4080
- const healAction = isOwnerRepo(dep) ? {
4081
- action: async () => {
4082
- const source = parseShardSource(dep);
4083
- const resolved = await resolveShardSource(source, flintPath);
4084
- try {
4085
- await installShardFromSource(flintPath, resolved.path, resolved.manifest, { source: dep });
4086
- } finally {
4087
- await cleanupResolvedSource(resolved);
4088
- }
4089
- },
4090
- actionLabel: `Install dependency ${dep}`
4091
- } : {};
4092
- results.push({
4093
- check: `dependency: ${dep}`,
4094
- status: "warning",
4095
- message: `Not installed`,
4096
- ...healAction
4097
- });
4098
- }
4099
- }
4100
- }
4101
4135
  const checkFilePrefix = async (dir, prefix) => {
4102
4136
  try {
4103
4137
  const entries = await readdir42(join10(shardPath, dir), { withFileTypes: true });
@@ -4128,6 +4162,20 @@ Describe the shard context here.
4128
4162
  }
4129
4163
  return results;
4130
4164
  }
4165
+ async function healAllShards(flintPath) {
4166
+ const allResults = {};
4167
+ const installedFolders = await listInstalledShards(flintPath);
4168
+ await Promise.all(installedFolders.map(async (folder) => {
4169
+ const results = await healShard(flintPath, folder);
4170
+ for (const result of results) {
4171
+ if (result.action) {
4172
+ await result.action();
4173
+ }
4174
+ }
4175
+ allResults[folder] = results;
4176
+ }));
4177
+ return allResults;
4178
+ }
4131
4179
  async function getShardInfo(flintPath, identifier) {
4132
4180
  const declarations = await getShardDeclarations(flintPath);
4133
4181
  const installed = await getInstalledShardsWithVersions(flintPath);
@@ -4145,10 +4193,9 @@ async function getShardInfo(flintPath, identifier) {
4145
4193
  version: match.version,
4146
4194
  description: manifest?.description || "",
4147
4195
  source: decl?.source || "unknown",
4148
- dev: decl ? resolveShardMode(decl) === "dev" || !!decl.dev : false,
4196
+ dev: decl ? resolveShardMode(decl) === "dev" : false,
4149
4197
  mode: decl ? resolveShardMode(decl) || "normal" : "normal",
4150
4198
  folderName: match.folderName,
4151
- depends: manifest?.depends || [],
4152
4199
  skillCount: await countFiles(join10(shardPath, "skills")),
4153
4200
  templateCount: await countFiles(join10(shardPath, "templates")),
4154
4201
  workflowCount: await countFiles(join10(shardPath, "workflows")),
@@ -4229,7 +4276,7 @@ async function findScript(scriptsDir, scriptName) {
4229
4276
  }
4230
4277
  async function isExecutable(filePath) {
4231
4278
  try {
4232
- await access4(filePath, constants.X_OK);
4279
+ await access3(filePath, constants.X_OK);
4233
4280
  return true;
4234
4281
  } catch {
4235
4282
  return false;
@@ -4302,12 +4349,7 @@ async function runShardScript(flintPath, shardIdentifier, scriptName, args = [])
4302
4349
  });
4303
4350
  });
4304
4351
  }
4305
- async function listBuiltinMods() {
4306
- return [];
4307
- }
4308
- async function getBuiltinMod(shorthand) {
4309
- return null;
4310
- }
4352
+ var execAsync4 = promisify42(exec4);
4311
4353
  function isOwnerRepo2(s) {
4312
4354
  return /^[a-zA-Z0-9_.-]+\/[a-zA-Z0-9_.-]+$/.test(s);
4313
4355
  }
@@ -4365,8 +4407,7 @@ async function resolveModSource(source, flintPath) {
4365
4407
  async function cloneAndResolve2(url, source) {
4366
4408
  const tempDir = await mkdtemp2(join12(tmpdir2(), "flint-mod-"));
4367
4409
  try {
4368
- execSync3(`git clone --depth 1 ${url} "${tempDir}"`, {
4369
- stdio: "pipe",
4410
+ await execAsync4(`git clone --depth 1 ${url} "${tempDir}"`, {
4370
4411
  timeout: 6e4
4371
4412
  // 60 second timeout
4372
4413
  });
@@ -4462,7 +4503,7 @@ function renderTemplate(template, variables) {
4462
4503
  }
4463
4504
  function runCommand(flintPath, command) {
4464
4505
  try {
4465
- execSync4(command, {
4506
+ execSync(command, {
4466
4507
  cwd: flintPath,
4467
4508
  stdio: "pipe",
4468
4509
  timeout: 3e4
@@ -4509,7 +4550,7 @@ async function processInstallEntries(flintPath, mod, variables, options) {
4509
4550
  continue;
4510
4551
  }
4511
4552
  if (await exists(destFilePath)) {
4512
- const mode = entry.mode ?? (entry.force ? "force" : "once");
4553
+ const mode = entry.mode ?? "once";
4513
4554
  if (!options?.force && mode === "once") continue;
4514
4555
  if (mode === "force" || options?.force) {
4515
4556
  try {
@@ -4567,16 +4608,7 @@ async function installMod(flintPath, shorthand, options = {}) {
4567
4608
  }
4568
4609
  }
4569
4610
  }
4570
- const mod = await getBuiltinMod(shorthand);
4571
- if (!mod) {
4572
- const available = await listBuiltinMods();
4573
- const shorthands = available.map((m) => m.shorthand).join(", ");
4574
- throw new Error(`Unknown mod: ${shorthand}. Available: ${shorthands || "none"}`);
4575
- }
4576
- return installModFromSource(flintPath, mod.path, mod, {
4577
- source: options.source || "builtin",
4578
- force: options.force
4579
- });
4611
+ throw new Error(`Unknown mod: ${shorthand}. Provide a source (owner/repo or path:./local).`);
4580
4612
  }
4581
4613
  async function installModFromSource(flintPath, sourcePath, mod, options = {}) {
4582
4614
  const destPath = join13(flintPath, "Mods", mod.name);
@@ -4661,11 +4693,7 @@ async function uninstallMod(flintPath, shorthand) {
4661
4693
  return { name: modName, removed: true };
4662
4694
  }
4663
4695
  async function listAvailableMods() {
4664
- return listBuiltinMods();
4665
- }
4666
- async function isModInstalled(flintPath, shorthand) {
4667
- const folder = await findInstalledModFolder(flintPath, shorthand);
4668
- return folder !== null;
4696
+ return [];
4669
4697
  }
4670
4698
  async function findInstalledModFolder(flintPath, identifier) {
4671
4699
  const modsDir = join13(flintPath, "Mods");
@@ -4751,27 +4779,13 @@ async function updateMods(flintPath, options = {}) {
4751
4779
  }
4752
4780
  }
4753
4781
  if (!source || source === "builtin") {
4754
- const mod = await getBuiltinMod(info2.shorthand);
4755
- if (mod) {
4756
- try {
4757
- await installMod(flintPath, mod.shorthand, { force: true, source: source || "builtin" });
4758
- results.push({
4759
- name: info2.name,
4760
- path: join13(flintPath, "Mods", info2.folderName),
4761
- status: "updated",
4762
- localVersion: info2.version,
4763
- remoteVersion: mod.version
4764
- });
4765
- } catch {
4766
- results.push({
4767
- name: info2.name,
4768
- path: join13(flintPath, "Mods", info2.folderName),
4769
- status: "failed",
4770
- localVersion: info2.version,
4771
- reason: "failed to reinstall from registry"
4772
- });
4773
- }
4774
- }
4782
+ results.push({
4783
+ name: info2.name,
4784
+ path: join13(flintPath, "Mods", info2.folderName),
4785
+ status: "failed",
4786
+ localVersion: info2.version,
4787
+ reason: "no source configured (builtin mods no longer supported)"
4788
+ });
4775
4789
  continue;
4776
4790
  }
4777
4791
  const parsed = parseModSource(source);
@@ -4890,22 +4904,6 @@ async function getModInfo(flintPath, identifier) {
4890
4904
  }
4891
4905
  } catch {
4892
4906
  }
4893
- const mod = await getBuiltinMod(identifier);
4894
- if (mod) {
4895
- return {
4896
- name: mod.name,
4897
- shorthand: mod.shorthand,
4898
- version: mod.version,
4899
- description: mod.description,
4900
- folderName: mod.name,
4901
- source: "builtin",
4902
- dev: false,
4903
- repos: mod.repos || [],
4904
- folders: mod.folders || [],
4905
- installEntries: mod.install?.length || 0,
4906
- commands: mod.commands || {}
4907
- };
4908
- }
4909
4907
  return null;
4910
4908
  }
4911
4909
  async function scaffoldNewMod(flintPath, name, shorthand, description) {
@@ -5019,14 +5017,14 @@ async function pullMod(flintPath, identifier, options) {
5019
5017
  const repoDir = join13(reposDir, repo.name);
5020
5018
  if (await exists(repoDir)) {
5021
5019
  try {
5022
- execSync4("git pull", { cwd: repoDir, stdio: "pipe", timeout: 3e4 });
5020
+ execSync("git pull", { cwd: repoDir, stdio: "pipe", timeout: 3e4 });
5023
5021
  result.reposPulled++;
5024
5022
  } catch {
5025
5023
  }
5026
5024
  } else {
5027
5025
  try {
5028
5026
  const branch = repo.branch ? `-b ${repo.branch}` : "";
5029
- execSync4(`git clone ${branch} "${repo.url}" "${repoDir}"`, { stdio: "pipe", timeout: 6e4 });
5027
+ execSync(`git clone ${branch} "${repo.url}" "${repoDir}"`, { stdio: "pipe", timeout: 6e4 });
5030
5028
  result.reposCloned++;
5031
5029
  } catch {
5032
5030
  }
@@ -5337,7 +5335,7 @@ async function runModScript(flintPath, identifier, scriptName, args = []) {
5337
5335
  cmd = `"${script.path}" ${args.join(" ")}`;
5338
5336
  }
5339
5337
  try {
5340
- const result = execSync4(cmd, {
5338
+ const result = execSync(cmd, {
5341
5339
  cwd: flintPath,
5342
5340
  timeout: 6e4,
5343
5341
  encoding: "utf-8"
@@ -5526,7 +5524,7 @@ async function getConnectionStatus(flintPath) {
5526
5524
  status.path = fulfillment.path;
5527
5525
  status.fulfilledAt = fulfillment.fulfilled;
5528
5526
  try {
5529
- await access5(fulfillment.path);
5527
+ await access4(fulfillment.path);
5530
5528
  const isFlint2 = await isInsideFlint(fulfillment.path);
5531
5529
  status.valid = isFlint2;
5532
5530
  } catch {
@@ -5613,12 +5611,16 @@ async function buildGitignoreEntries(flintPath) {
5613
5611
  const sections = [];
5614
5612
  sections.push({
5615
5613
  label: "Flint internals",
5616
- entries: [".flint/", ".obsidian/", ".mesh/"]
5614
+ entries: [".flint/", ".obsidian/", ".mesh/", ".orbh/"]
5615
+ });
5616
+ sections.push({
5617
+ label: "Subflints",
5618
+ entries: ["Subflints/"]
5617
5619
  });
5618
- const shardEntries = buildShardEntries(config);
5620
+ const shardEntries = await buildShardEntries(flintPath);
5619
5621
  if (shardEntries.length > 0) {
5620
5622
  sections.push({
5621
- label: "Shards (dev)",
5623
+ label: "Shards (git-managed)",
5622
5624
  entries: shardEntries
5623
5625
  });
5624
5626
  }
@@ -5655,18 +5657,20 @@ function buildWorkspaceEntries(config) {
5655
5657
  }
5656
5658
  return entries;
5657
5659
  }
5658
- function buildShardEntries(config) {
5659
- if (!config?.shards) return [];
5660
+ async function buildShardEntries(flintPath) {
5661
+ const shardsDir = join15(flintPath, "Shards");
5662
+ if (!await exists(shardsDir)) return [];
5660
5663
  const entries = [];
5661
- for (const [, decl] of Object.entries(config.shards)) {
5662
- if (typeof decl !== "object" || !("source" in decl)) continue;
5663
- const mode = resolveShardMode(decl);
5664
- if (mode === "dev" || mode === "custom") {
5665
- const match = decl.source.match(/^path:\.\/Shards\/(.+)$/);
5666
- if (match) {
5667
- entries.push(`Shards/${match[1]}/`);
5664
+ try {
5665
+ const folders = await readdir7(shardsDir, { withFileTypes: true });
5666
+ for (const folder of folders) {
5667
+ if (!folder.isDirectory() || folder.name.startsWith("(System)")) continue;
5668
+ const gitDir = join15(shardsDir, folder.name, ".git");
5669
+ if (await exists(gitDir)) {
5670
+ entries.push(`Shards/${folder.name}/`);
5668
5671
  }
5669
5672
  }
5673
+ } catch {
5670
5674
  }
5671
5675
  return entries.sort();
5672
5676
  }
@@ -5728,15 +5732,28 @@ ${MANAGED_SECTION_END}`;
5728
5732
  function escapeRegex(str) {
5729
5733
  return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
5730
5734
  }
5731
- var execAsync2 = promisify22(exec2);
5735
+ var execAsync5 = promisify52(exec5);
5732
5736
  async function isGitInitialized(flintPath) {
5733
5737
  try {
5734
- await execAsync2("git rev-parse --git-dir", { cwd: flintPath });
5738
+ await execAsync5("git rev-parse --git-dir", { cwd: flintPath });
5735
5739
  return true;
5736
5740
  } catch {
5737
5741
  return false;
5738
5742
  }
5739
5743
  }
5744
+ async function initGit(flintPath) {
5745
+ try {
5746
+ await execAsync5("git init", { cwd: flintPath });
5747
+ await createGitignore(flintPath);
5748
+ return { success: true, output: "Git initialized with .gitignore" };
5749
+ } catch (err) {
5750
+ return {
5751
+ success: false,
5752
+ output: "",
5753
+ error: err instanceof Error ? err.message : String(err)
5754
+ };
5755
+ }
5756
+ }
5740
5757
  async function getGitStatus(flintPath) {
5741
5758
  const initialized = await isGitInitialized(flintPath);
5742
5759
  if (!initialized) {
@@ -5749,10 +5766,10 @@ async function getGitStatus(flintPath) {
5749
5766
  };
5750
5767
  }
5751
5768
  try {
5752
- const { stdout: branchOut } = await execAsync2("git branch --show-current", {
5769
+ const { stdout: branchOut } = await execAsync5("git branch --show-current", {
5753
5770
  cwd: flintPath
5754
5771
  });
5755
- const { stdout: statusOut } = await execAsync2("git status --porcelain", {
5772
+ const { stdout: statusOut } = await execAsync5("git status --porcelain", {
5756
5773
  cwd: flintPath
5757
5774
  });
5758
5775
  const lines = statusOut.trim().split("\n").filter(Boolean);
@@ -5794,7 +5811,7 @@ async function runGit(flintPath, args) {
5794
5811
  const quotedArgs = args.map(
5795
5812
  (arg) => arg.includes(" ") ? `"${arg}"` : arg
5796
5813
  );
5797
- const { stdout, stderr } = await execAsync2(`git ${quotedArgs.join(" ")}`, {
5814
+ const { stdout, stderr } = await execAsync5(`git ${quotedArgs.join(" ")}`, {
5798
5815
  cwd: flintPath
5799
5816
  });
5800
5817
  return { success: true, output: stdout || stderr };
@@ -5843,7 +5860,7 @@ async function loadPresetFromDir(presetDir) {
5843
5860
  async function discoverPresetsFromDir(presetsDir) {
5844
5861
  const presets = /* @__PURE__ */ new Map();
5845
5862
  try {
5846
- const entries = await readdir7(presetsDir, { withFileTypes: true });
5863
+ const entries = await readdir8(presetsDir, { withFileTypes: true });
5847
5864
  for (const entry of entries) {
5848
5865
  if (!entry.isDirectory()) continue;
5849
5866
  const presetDir = join16(presetsDir, entry.name);
@@ -5908,7 +5925,7 @@ async function discoverSubflints(flintPath) {
5908
5925
  const discovered = [];
5909
5926
  let entries;
5910
5927
  try {
5911
- entries = await readdir8(subflintsDir, { withFileTypes: true });
5928
+ entries = await readdir9(subflintsDir, { withFileTypes: true });
5912
5929
  } catch (err) {
5913
5930
  if (err.code === "ENOENT") {
5914
5931
  return discovered;
@@ -5952,7 +5969,7 @@ async function createSubflint(flintPath, options) {
5952
5969
  }
5953
5970
  const subflintPath = getSubflintPath(flintPath, name);
5954
5971
  try {
5955
- await access6(subflintPath);
5972
+ await access5(subflintPath);
5956
5973
  throw new Error(`Subflint "${name}" already exists`);
5957
5974
  } catch (err) {
5958
5975
  if (err.code !== "ENOENT") {
@@ -5995,14 +6012,14 @@ async function promoteSubflint(flintPath, options) {
5995
6012
  }
5996
6013
  const sourcePath = subflint.path;
5997
6014
  try {
5998
- await access6(sourcePath);
6015
+ await access5(sourcePath);
5999
6016
  } catch {
6000
6017
  throw new Error(`Subflint path not found: ${sourcePath}`);
6001
6018
  }
6002
6019
  const targetPath = join17(destination, `(Flint) ${name}`);
6003
6020
  await mkdir10(destination, { recursive: true });
6004
6021
  try {
6005
- await access6(targetPath);
6022
+ await access5(targetPath);
6006
6023
  throw new Error(`Target already exists: ${targetPath}`);
6007
6024
  } catch (err) {
6008
6025
  if (err.code !== "ENOENT") {
@@ -6052,7 +6069,7 @@ async function syncSubflintName(flintPath, currentName) {
6052
6069
  }
6053
6070
  const targetPath = getSubflintPath(flintPath, configName);
6054
6071
  try {
6055
- await access6(targetPath);
6072
+ await access5(targetPath);
6056
6073
  throw new Error(
6057
6074
  `Cannot rename: subflint "${configName}" already exists at ${targetPath}`
6058
6075
  );
@@ -6081,7 +6098,7 @@ function getSubflintParentPath(flintPath) {
6081
6098
  }
6082
6099
  return dirname6(subflintsDir);
6083
6100
  }
6084
- async function syncFlint(flintPath) {
6101
+ async function syncFlint(flintPath, progress) {
6085
6102
  const result = {
6086
6103
  bootstrap: { created: false, directories: [] },
6087
6104
  migrations: { applied: [], skipped: [], failed: [] },
@@ -6163,28 +6180,76 @@ async function syncFlint(flintPath) {
6163
6180
  const shardsToInstall = requiredShardNames.filter((name) => !installedShardNames.has(name));
6164
6181
  const requiredShardSet = new Set(requiredShardNames);
6165
6182
  const shardsToUninstall = installedShards.filter((s) => !requiredShardSet.has(s.name)).map((s) => s.name);
6166
- for (const kebabName of shardsToInstall) {
6167
- const declaration = shardDeclarations[kebabName];
6168
- if (!declaration) continue;
6169
- if (declaration.dev) continue;
6170
- try {
6171
- const source = parseShardSource(declaration.source);
6172
- const resolved = await resolveShardSource(source, flintPath);
6173
- try {
6174
- await installShardFromSource(flintPath, resolved.path, resolved.manifest, {
6175
- force: true,
6176
- source: declaration.source
6177
- });
6178
- } finally {
6179
- await cleanupResolvedSource(resolved);
6180
- }
6181
- result.shards.installed.push(kebabName);
6182
- } catch (err) {
6183
- result.errors.push({
6184
- name: `shard:${kebabName}`,
6185
- error: err instanceof Error ? err.message : String(err)
6183
+ {
6184
+ const { exec: execCb } = await import("child_process");
6185
+ const { promisify: promisify62 } = await import("util");
6186
+ const execAsync62 = promisify62(execCb);
6187
+ const shardTasks = [];
6188
+ for (const kebabName of shardsToInstall) {
6189
+ const declaration = shardDeclarations[kebabName];
6190
+ if (!declaration) continue;
6191
+ const mode = declaration.mode;
6192
+ if (mode === "dev") {
6193
+ const source = declaration.source;
6194
+ if (source.startsWith("path:")) {
6195
+ result.errors.push({
6196
+ name: `shard:${kebabName}`,
6197
+ error: `Dev shard has no remote source (${source}) \u2014 cannot sync. Add a git remote first.`
6198
+ });
6199
+ continue;
6200
+ }
6201
+ shardTasks.push({
6202
+ name: kebabName,
6203
+ run: async () => {
6204
+ const folderName = `(Dev) ${kebabName.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ")}`;
6205
+ const devPath = join18(flintPath, "Shards", folderName);
6206
+ const cloneUrl = `https://github.com/${source}.git`;
6207
+ await execAsync62(`git clone "${cloneUrl}" "${devPath}"`, { timeout: 6e4 });
6208
+ }
6209
+ });
6210
+ continue;
6211
+ }
6212
+ if (mode === "custom") {
6213
+ result.errors.push({
6214
+ name: `shard:${kebabName}`,
6215
+ error: `Custom shard folder missing \u2014 custom shards should be committed to the repository.`
6216
+ });
6217
+ continue;
6218
+ }
6219
+ shardTasks.push({
6220
+ name: kebabName,
6221
+ run: async () => {
6222
+ const source = parseShardSource(declaration.source);
6223
+ const resolved = await resolveShardSource(source, flintPath);
6224
+ try {
6225
+ await installShardFromSource(flintPath, resolved.path, resolved.manifest, {
6226
+ force: true,
6227
+ source: declaration.source
6228
+ });
6229
+ } finally {
6230
+ await cleanupResolvedSource(resolved);
6231
+ }
6232
+ }
6186
6233
  });
6187
6234
  }
6235
+ progress?.onShardPhase?.(shardTasks.length);
6236
+ if (shardTasks.length > 0) {
6237
+ const shardResults = await runConcurrent(shardTasks, {
6238
+ onStart: progress?.onShardStart,
6239
+ onComplete: (name) => progress?.onShardDone?.(name, true),
6240
+ onError: (name) => progress?.onShardDone?.(name, false)
6241
+ });
6242
+ for (const r of shardResults) {
6243
+ if (r.status === "ok") {
6244
+ result.shards.installed.push(r.name);
6245
+ } else {
6246
+ result.errors.push({
6247
+ name: `shard:${r.name}`,
6248
+ error: r.error?.message || "Unknown error"
6249
+ });
6250
+ }
6251
+ }
6252
+ }
6188
6253
  }
6189
6254
  for (const kebabName of shardsToUninstall) {
6190
6255
  result.shards.orphaned.push(kebabName);
@@ -6209,16 +6274,29 @@ async function syncFlint(flintPath) {
6209
6274
  const installedModNames = new Set(installedMods.map((m) => toKebabCase(m.name)));
6210
6275
  const modsToInstall = [...declaredModNames].filter((name) => !installedModNames.has(name));
6211
6276
  const modsToUninstall = installedMods.filter((m) => !declaredModNames.has(toKebabCase(m.name))).map((m) => m.shorthand);
6212
- for (const kebabName of modsToInstall) {
6213
- const declaration = modDeclarations[kebabName];
6214
- try {
6215
- await installMod(flintPath, kebabName, { force: true, source: declaration?.source });
6216
- result.mods.installed.push(kebabName);
6217
- } catch (err) {
6218
- result.errors.push({
6219
- name: `mod:${kebabName}`,
6220
- error: err instanceof Error ? err.message : String(err)
6221
- });
6277
+ progress?.onModPhase?.(modsToInstall.length);
6278
+ if (modsToInstall.length > 0) {
6279
+ const modTasks = modsToInstall.map((kebabName) => ({
6280
+ name: kebabName,
6281
+ run: async () => {
6282
+ const declaration = modDeclarations[kebabName];
6283
+ await installMod(flintPath, kebabName, { force: true, source: declaration?.source });
6284
+ }
6285
+ }));
6286
+ const modResults = await runConcurrent(modTasks, {
6287
+ onStart: progress?.onModStart,
6288
+ onComplete: (name) => progress?.onModDone?.(name, true),
6289
+ onError: (name) => progress?.onModDone?.(name, false)
6290
+ });
6291
+ for (const r of modResults) {
6292
+ if (r.status === "ok") {
6293
+ result.mods.installed.push(r.name);
6294
+ } else {
6295
+ result.errors.push({
6296
+ name: `mod:${r.name}`,
6297
+ error: r.error?.message || "Unknown error"
6298
+ });
6299
+ }
6222
6300
  }
6223
6301
  }
6224
6302
  for (const shorthand of modsToUninstall) {
@@ -6239,18 +6317,18 @@ async function syncFlint(flintPath) {
6239
6317
  }
6240
6318
  result.modCommands = await runModSyncCommands(flintPath);
6241
6319
  const requiredImports = config.imports?.flints || config.imports?.required || [];
6242
- const { getFlintRegistry: getFlintRegistry2 } = await import("./registry-5QFQ3XPR-G7IB3KWS.js");
6243
- const { readdir: readdir92, readFile: fsReadFile2, writeFile: fsWriteFile2, rm: rm82, stat: fsStat } = await import("fs/promises");
6320
+ const { getFlintRegistry: getFlintRegistry2 } = await import("./registry-5PUMDGQP-YVSEVBB4.js");
6321
+ const { readdir: readdir102, readFile: fsReadFile2, writeFile: fsWriteFile2, rm: rm82, stat: fsStat } = await import("fs/promises");
6244
6322
  const requiredImportSet = new Set(requiredImports);
6245
6323
  const importsDir = join18(flintPath, "Imports");
6246
6324
  try {
6247
- const flintFolders = await readdir92(importsDir, { withFileTypes: true });
6325
+ const flintFolders = await readdir102(importsDir, { withFileTypes: true });
6248
6326
  for (const flintFolder of flintFolders) {
6249
6327
  if (!flintFolder.isDirectory()) continue;
6250
6328
  const flintFolderName = flintFolder.name;
6251
6329
  const flintName = flintFolderName.replace(/^\(Flint\)\s*/, "");
6252
6330
  const flintImportPath = join18(importsDir, flintFolderName);
6253
- const exportFolders = await readdir92(flintImportPath, { withFileTypes: true });
6331
+ const exportFolders = await readdir102(flintImportPath, { withFileTypes: true });
6254
6332
  for (const exportFolder of exportFolders) {
6255
6333
  if (!exportFolder.isDirectory()) continue;
6256
6334
  const exportFolderName = exportFolder.name;
@@ -6270,7 +6348,7 @@ async function syncFlint(flintPath) {
6270
6348
  }
6271
6349
  }
6272
6350
  }
6273
- const remainingExports = await readdir92(flintImportPath);
6351
+ const remainingExports = await readdir102(flintImportPath);
6274
6352
  if (remainingExports.length === 0) {
6275
6353
  try {
6276
6354
  await rm82(flintImportPath, { recursive: true });
@@ -6282,7 +6360,7 @@ async function syncFlint(flintPath) {
6282
6360
  }
6283
6361
  if (requiredImports.length > 0) {
6284
6362
  const registry = await getFlintRegistry2();
6285
- const { buildExportByName: buildExportByName2, scanExports: scanExports2 } = await import("./exports-CA5QHVI7-6IDFKMCF.js");
6363
+ const { buildExportByName: buildExportByName2, scanExports: scanExports2 } = await import("./exports-KXKBTYJ2-A3QWNDEB.js");
6286
6364
  for (const ref of requiredImports) {
6287
6365
  const parts = ref.split("/");
6288
6366
  if (parts.length !== 2) {
@@ -6305,7 +6383,7 @@ async function syncFlint(flintPath) {
6305
6383
  const manifests = await scanExports2(sourceFlint.path);
6306
6384
  const hasExportManifest = manifests.some((m) => m.name === exportName);
6307
6385
  if (!hasExportManifest) {
6308
- result.imports.push({ ref, status: "not_found", error: "Export not defined" });
6386
+ result.imports.push({ ref, status: "export_not_found", error: `export '${exportName}' not found in '${flintName}'` });
6309
6387
  continue;
6310
6388
  }
6311
6389
  try {
@@ -6335,7 +6413,7 @@ async function syncFlint(flintPath) {
6335
6413
  } catch {
6336
6414
  }
6337
6415
  await mkdir11(destPath, { recursive: true });
6338
- const entries = await readdir92(sourcePath, { withFileTypes: true });
6416
+ const entries = await readdir102(sourcePath, { withFileTypes: true });
6339
6417
  let fileCount = 0;
6340
6418
  for (const entry of entries) {
6341
6419
  if (entry.isFile() && entry.name !== "_manifest.json") {
@@ -6439,8 +6517,22 @@ async function syncFlint(flintPath) {
6439
6517
  }
6440
6518
  const connectionsMigration = await migrateConnections(currentFlintPath);
6441
6519
  result.connectionsMigrated = connectionsMigration.migrated;
6442
- await writeFlintToml(currentFlintPath, config);
6443
- await updateGitignore(currentFlintPath);
6520
+ try {
6521
+ await writeFlintToml(currentFlintPath, config);
6522
+ } catch (err) {
6523
+ result.errors.push({
6524
+ name: "flint.toml",
6525
+ error: `Failed to write flint.toml: ${err instanceof Error ? err.message : String(err)}`
6526
+ });
6527
+ }
6528
+ try {
6529
+ await updateGitignore(currentFlintPath);
6530
+ } catch (err) {
6531
+ result.errors.push({
6532
+ name: "gitignore",
6533
+ error: `Failed to update .gitignore: ${err instanceof Error ? err.message : String(err)}`
6534
+ });
6535
+ }
6444
6536
  try {
6445
6537
  await stampSynced(currentFlintPath);
6446
6538
  } catch {
@@ -6448,9 +6540,64 @@ async function syncFlint(flintPath) {
6448
6540
  return result;
6449
6541
  }
6450
6542
 
6543
+ // src/progress.ts
6544
+ import pc5 from "picocolors";
6545
+ function createProgressDisplay(label, total) {
6546
+ if (total === 0) {
6547
+ return { onStart() {
6548
+ }, onComplete() {
6549
+ }, onError() {
6550
+ }, finish() {
6551
+ } };
6552
+ }
6553
+ const isTTY = process.stdout.isTTY;
6554
+ let completed = 0;
6555
+ let failures = 0;
6556
+ let finished = false;
6557
+ let linesBelow = 0;
6558
+ console.log(pc5.bold(label));
6559
+ return {
6560
+ onStart(_name) {
6561
+ },
6562
+ onComplete(name) {
6563
+ completed++;
6564
+ linesBelow++;
6565
+ console.log(` ${pc5.green("\u2713")} ${name}`);
6566
+ },
6567
+ onError(name) {
6568
+ completed++;
6569
+ failures++;
6570
+ linesBelow++;
6571
+ console.log(` ${pc5.red("\u2717")} ${name}`);
6572
+ },
6573
+ finish() {
6574
+ if (finished) return;
6575
+ finished = true;
6576
+ const successes = completed - failures;
6577
+ let summary = `${pc5.bold(label)} `;
6578
+ if (failures === 0) {
6579
+ summary += pc5.green(`\u2713 ${successes} done`);
6580
+ } else {
6581
+ summary += `${pc5.green(`\u2713 ${successes} done`)} ${pc5.red(`\u2717 ${failures} failed`)}`;
6582
+ }
6583
+ if (isTTY) {
6584
+ const up = linesBelow + 1;
6585
+ process.stdout.write(
6586
+ `\x1B[${up}A\x1B[2K\r` + // clear line
6587
+ summary + // write summary
6588
+ `\x1B[${up}B\r`
6589
+ // back down to original position
6590
+ );
6591
+ } else {
6592
+ console.log(summary);
6593
+ }
6594
+ }
6595
+ };
6596
+ }
6597
+
6451
6598
  // src/utils.ts
6452
6599
  import { homedir as homedir4 } from "os";
6453
- import { access as access7 } from "fs/promises";
6600
+ import { access as access6 } from "fs/promises";
6454
6601
  import { createInterface } from "readline";
6455
6602
  function abbreviatePath(path3) {
6456
6603
  const home = homedir4();
@@ -6467,7 +6614,7 @@ function expandPath(path3) {
6467
6614
  }
6468
6615
  async function checkPathExists(path3) {
6469
6616
  try {
6470
- await access7(path3);
6617
+ await access6(path3);
6471
6618
  return true;
6472
6619
  } catch {
6473
6620
  return false;
@@ -6487,120 +6634,37 @@ async function confirm(message) {
6487
6634
  }
6488
6635
 
6489
6636
  // src/commands/init.ts
6637
+ var execAsync6 = promisify7(exec6);
6490
6638
  function openObsidianVaultChooser() {
6491
6639
  const os2 = platform2();
6492
6640
  const uri = "obsidian://choose-vault";
6493
6641
  try {
6494
6642
  if (os2 === "darwin") {
6495
- execSync5(`open "${uri}"`, { stdio: "pipe" });
6643
+ execSync2(`open "${uri}"`, { stdio: "pipe" });
6496
6644
  } else if (os2 === "win32") {
6497
- execSync5(`start "" "${uri}"`, { stdio: "pipe" });
6645
+ execSync2(`start "" "${uri}"`, { stdio: "pipe" });
6498
6646
  } else {
6499
- execSync5(`xdg-open "${uri}"`, { stdio: "pipe" });
6647
+ execSync2(`xdg-open "${uri}"`, { stdio: "pipe" });
6500
6648
  }
6501
6649
  } catch {
6502
6650
  }
6503
6651
  }
6504
- var initCommand = new Command3("init").description("Create a new Flint workspace").argument("[name]", "Name of the flint").option("-p, --path <dir>", "Parent directory (default: current directory)").option("--preset <name>", 'Use a preset (e.g., "default")').action(async (name, options) => {
6505
- if (!name) {
6506
- console.error(pc5.red("Error: Flint name is required"));
6507
- console.log("\nUsage: flint init <name> [options]");
6508
- process.exit(1);
6509
- }
6510
- const presetName = options.preset || "blank";
6511
- const preset = await getPreset(presetName);
6512
- if (!preset) {
6513
- const available = (await listPresets()).map((p) => p.name).join(", ");
6514
- console.error(pc5.red(`Error: Unknown preset "${presetName}"`));
6515
- console.log(`Available presets: ${available}`);
6516
- process.exit(1);
6652
+ function reportSyncResult(result) {
6653
+ if (result.obsidian.cloned) {
6654
+ console.log();
6655
+ success("Cloned .obsidian/");
6517
6656
  }
6518
- const shards = preset.shards;
6519
- const mods = preset.mods;
6520
- if (options.preset) {
6521
- console.log(`
6522
- Using preset: ${pc5.bold(preset.name)}`);
6657
+ if (!result.obsidian.cloned && result.shards.installed.length === 0 && result.mods.installed.length === 0 && result.errors.length === 0) {
6658
+ console.log(pc6.dim(" Already in sync"));
6523
6659
  }
6524
- console.log(`
6525
- Creating flint: ${pc5.bold(name)}`);
6526
- try {
6527
- const entry = await createFlint({
6528
- name,
6529
- parentDir: options.path,
6530
- shards,
6531
- mods
6532
- });
6533
- success(`Created (Flint) ${name}/`);
6534
- for (const dir of STANDARD_DIRECTORIES) {
6535
- success(`Created ${dir}/`);
6536
- }
6537
- success("Created .flint/");
6538
- success("Created flint.toml");
6539
- success("Created flint.lock");
6540
- success("Registered in ~/.flint/");
6541
- if (preset && preset.templates.length > 0) {
6542
- await applyPresetTemplates(entry.path, preset, name);
6543
- success(`Applied ${preset.templates.length} template(s) from preset`);
6544
- }
6545
- console.log(`
6546
- Flint created at: ${pc5.cyan(abbreviatePath(entry.path))}`);
6547
- console.log(pc5.bold("\nSyncing configured features...\n"));
6548
- const result = await syncFlint(entry.path);
6549
- if (result.obsidian.cloned) {
6550
- success("Cloned .obsidian/");
6551
- }
6552
- if (result.shards.installed.length > 0) {
6553
- console.log(pc5.green("\nShards installed:"));
6554
- for (const s of result.shards.installed) {
6555
- console.log(` ${pc5.green("+")} ${s}`);
6556
- }
6557
- }
6558
- if (result.mods.installed.length > 0) {
6559
- console.log(pc5.green("\nMods installed:"));
6560
- for (const s of result.mods.installed) {
6561
- console.log(` ${pc5.green("+")} ${s}`);
6562
- }
6563
- const cmdResults = await runModSyncCommands(entry.path);
6564
- const failedCmds = cmdResults.filter((r) => !r.success);
6565
- if (failedCmds.length > 0) {
6566
- console.log(pc5.yellow("\nMod command warnings:"));
6567
- for (const c of failedCmds) {
6568
- console.log(` ${pc5.yellow("!")} ${c.command}: ${c.error}`);
6569
- }
6570
- }
6571
- }
6572
- if (!result.obsidian.cloned && result.shards.installed.length === 0 && result.mods.installed.length === 0 && result.errors.length === 0) {
6573
- console.log(pc5.dim("Flint is already in sync."));
6574
- }
6575
- if (result.errors.length > 0) {
6576
- console.log(pc5.yellow("\nWarnings:"));
6577
- for (const e of result.errors) {
6578
- console.log(` ${pc5.yellow("!")} ${e.name}: ${e.error}`);
6579
- }
6580
- }
6581
- if (result.obsidian.cloned) {
6582
- console.log(pc5.dim("Opening Obsidian vault chooser..."));
6583
- openObsidianVaultChooser();
6584
- }
6660
+ if (result.errors.length > 0) {
6585
6661
  console.log();
6586
- } catch (err) {
6587
- const message = err instanceof Error ? err.message : String(err);
6588
- error(message);
6589
- process.exit(1);
6662
+ for (const e of result.errors) {
6663
+ console.log(` ${pc6.yellow("!")} ${e.name}: ${e.error}`);
6664
+ }
6590
6665
  }
6591
- });
6592
-
6593
- // src/commands/clone.ts
6594
- import { Command as Command4 } from "commander";
6595
- import pc6 from "picocolors";
6596
- import { resolve as resolve8, join as join19 } from "path";
6597
- import { existsSync as existsSync2 } from "fs";
6598
- import { mkdtemp as mkdtemp3, rm as rm8, rename as rename4 } from "fs/promises";
6599
- import { tmpdir as tmpdir3 } from "os";
6600
- import { exec as exec3 } from "child_process";
6601
- import { promisify as promisify7 } from "util";
6602
- var execAsync3 = promisify7(exec3);
6603
- var cloneCommand = new Command4("clone").description("Clone a flint from a git repository").argument("<url>", "Git repository URL").option("-p, --path <dir>", "Parent directory (default: current directory)").action(async (url, options) => {
6666
+ }
6667
+ async function handleFromGit(url, options) {
6604
6668
  const parentDir = resolve8(options.path || process.cwd());
6605
6669
  let tempDir = null;
6606
6670
  try {
@@ -6609,7 +6673,7 @@ Cloning ${pc6.cyan(url)}...
6609
6673
  `);
6610
6674
  tempDir = await mkdtemp3(join19(tmpdir3(), "flint-clone-"));
6611
6675
  try {
6612
- await execAsync3(`git clone "${url}" "${tempDir}"`, { timeout: 12e4 });
6676
+ await execAsync6(`git clone "${url}" "${tempDir}"`, { timeout: 12e4 });
6613
6677
  } catch (err) {
6614
6678
  const message = err instanceof Error ? err.message : String(err);
6615
6679
  throw new Error(`Git clone failed: ${message}`);
@@ -6625,6 +6689,13 @@ Cloning ${pc6.cyan(url)}...
6625
6689
  }
6626
6690
  const name = toml.flint.name;
6627
6691
  success(`Found flint: ${pc6.bold(name)}`);
6692
+ const existing = await isFlintNameTaken(name);
6693
+ if (existing) {
6694
+ throw new Error(
6695
+ `A flint named "${name}" already exists at: ${existing.path}
6696
+ Each flint must have a unique name for commands like 'flint open' and 'flint import' to work.`
6697
+ );
6698
+ }
6628
6699
  const prefix = getTypePrefix();
6629
6700
  const folderName = `${prefix} ${name}`;
6630
6701
  const finalPath = join19(parentDir, folderName);
@@ -6639,22 +6710,150 @@ Cloning ${pc6.cyan(url)}...
6639
6710
  console.log(`
6640
6711
  Flint cloned to: ${pc6.cyan(abbreviatePath(finalPath))}`);
6641
6712
  console.log(pc6.bold("\nSyncing...\n"));
6642
- const result = await syncFlint(finalPath);
6643
- if (result.obsidian.cloned) {
6644
- success("Cloned .obsidian/");
6713
+ let shardProgress;
6714
+ let modProgress;
6715
+ const progress = {
6716
+ onShardPhase(total) {
6717
+ if (total > 0) shardProgress = createProgressDisplay("Installing shards", total);
6718
+ },
6719
+ onShardStart(name2) {
6720
+ shardProgress?.onStart(name2);
6721
+ },
6722
+ onShardDone(name2, ok) {
6723
+ ok ? shardProgress?.onComplete(name2) : shardProgress?.onError(name2);
6724
+ },
6725
+ onModPhase(total) {
6726
+ shardProgress?.finish();
6727
+ if (total > 0) modProgress = createProgressDisplay("Installing mods", total);
6728
+ },
6729
+ onModStart(name2) {
6730
+ modProgress?.onStart(name2);
6731
+ },
6732
+ onModDone(name2, ok) {
6733
+ ok ? modProgress?.onComplete(name2) : modProgress?.onError(name2);
6734
+ }
6735
+ };
6736
+ const result = await syncFlint(finalPath, progress);
6737
+ shardProgress?.finish();
6738
+ modProgress?.finish();
6739
+ reportSyncResult(result);
6740
+ console.log(pc6.bold("\nHealing shards...\n"));
6741
+ const healResults = await healAllShards(finalPath);
6742
+ let totalHealed = 0;
6743
+ for (const [folder, results] of Object.entries(healResults)) {
6744
+ const actions = results.filter((r) => r.action);
6745
+ if (actions.length > 0) {
6746
+ totalHealed += actions.length;
6747
+ for (const r of actions) {
6748
+ console.log(` ${pc6.green("+")} ${folder}: ${r.actionLabel}`);
6749
+ }
6750
+ }
6751
+ }
6752
+ if (totalHealed > 0) {
6753
+ success(`Healed ${totalHealed} issue(s) across shards`);
6754
+ } else {
6755
+ console.log(pc6.dim("All shards healthy."));
6645
6756
  }
6646
- if (result.shards.installed.length > 0) {
6647
- console.log(pc6.green("\nShards installed:"));
6648
- for (const s of result.shards.installed) {
6649
- console.log(` ${pc6.green("+")} ${s}`);
6757
+ console.log(pc6.bold(`
6758
+ Ready to use!
6759
+ `));
6760
+ console.log(` cd ${abbreviatePath(finalPath)}`);
6761
+ console.log(` flint open ${pc6.dim("Open in Obsidian")}`);
6762
+ console.log(` flint sync ${pc6.dim("Update anytime")}`);
6763
+ console.log();
6764
+ } catch (err) {
6765
+ if (tempDir) {
6766
+ try {
6767
+ await rm8(tempDir, { recursive: true, force: true });
6768
+ } catch {
6650
6769
  }
6651
6770
  }
6652
- if (result.mods.installed.length > 0) {
6653
- console.log(pc6.green("\nMods installed:"));
6654
- for (const s of result.mods.installed) {
6655
- console.log(` ${pc6.green("+")} ${s}`);
6771
+ const message = err instanceof Error ? err.message : String(err);
6772
+ error(message);
6773
+ process.exit(1);
6774
+ }
6775
+ }
6776
+ var initCommand = new Command3("init").description("Create a new Flint workspace").argument("[name]", "Name of the flint").option("-p, --path <dir>", "Parent directory (default: current directory)").option("--preset <name>", 'Use a preset (e.g., "default")').option("--from-git <url>", "Clone a flint from a git repository").action(async (name, options) => {
6777
+ if (options.fromGit) {
6778
+ await handleFromGit(options.fromGit, options);
6779
+ return;
6780
+ }
6781
+ if (!name) {
6782
+ console.error(pc6.red("Error: Flint name is required"));
6783
+ console.log("\nUsage: flint init <name> [options]");
6784
+ console.log(" flint init --from-git <url> [options]");
6785
+ process.exit(1);
6786
+ }
6787
+ const presetName = options.preset || "blank";
6788
+ const preset = await getPreset(presetName);
6789
+ if (!preset) {
6790
+ const available = (await listPresets()).map((p) => p.name).join(", ");
6791
+ console.error(pc6.red(`Error: Unknown preset "${presetName}"`));
6792
+ console.log(`Available presets: ${available}`);
6793
+ process.exit(1);
6794
+ }
6795
+ const shards = preset.shards;
6796
+ const mods = preset.mods;
6797
+ if (options.preset) {
6798
+ console.log(`
6799
+ Using preset: ${pc6.bold(preset.name)}`);
6800
+ }
6801
+ console.log(`
6802
+ Creating flint: ${pc6.bold(name)}
6803
+ `);
6804
+ try {
6805
+ const entry = await createFlint({
6806
+ name,
6807
+ parentDir: options.path,
6808
+ shards,
6809
+ mods
6810
+ });
6811
+ const dirs = STANDARD_DIRECTORIES.join(", ");
6812
+ success(`Created (Flint) ${name}/`);
6813
+ console.log(pc6.dim(` ${dirs}, .flint/, flint.toml, flint.lock
6814
+ `));
6815
+ success("Registered in ~/.nuucognition/flint/");
6816
+ if (preset && preset.templates.length > 0) {
6817
+ await applyPresetTemplates(entry.path, preset, name);
6818
+ success(`Applied ${preset.templates.length} template(s) from preset`);
6819
+ }
6820
+ console.log(`
6821
+ ${pc6.cyan(abbreviatePath(entry.path))}
6822
+ `);
6823
+ if (shards.length > 0 || mods.length > 0) {
6824
+ console.log(pc6.bold("Syncing...\n"));
6825
+ }
6826
+ let initShardProgress;
6827
+ let initModProgress;
6828
+ const initProgress = {
6829
+ onShardPhase(total) {
6830
+ if (total > 0) initShardProgress = createProgressDisplay("Installing shards", total);
6831
+ },
6832
+ onShardStart(name2) {
6833
+ initShardProgress?.onStart(name2);
6834
+ },
6835
+ onShardDone(name2, ok) {
6836
+ ok ? initShardProgress?.onComplete(name2) : initShardProgress?.onError(name2);
6837
+ },
6838
+ onModPhase(total) {
6839
+ initShardProgress?.finish();
6840
+ if (total > 0) {
6841
+ console.log();
6842
+ initModProgress = createProgressDisplay("Installing mods", total);
6843
+ }
6844
+ },
6845
+ onModStart(name2) {
6846
+ initModProgress?.onStart(name2);
6847
+ },
6848
+ onModDone(name2, ok) {
6849
+ ok ? initModProgress?.onComplete(name2) : initModProgress?.onError(name2);
6656
6850
  }
6657
- const cmdResults = await runModSyncCommands(finalPath);
6851
+ };
6852
+ const result = await syncFlint(entry.path, initProgress);
6853
+ initShardProgress?.finish();
6854
+ initModProgress?.finish();
6855
+ if (result.mods.installed.length > 0) {
6856
+ const cmdResults = await runModSyncCommands(entry.path);
6658
6857
  const failedCmds = cmdResults.filter((r) => !r.success);
6659
6858
  if (failedCmds.length > 0) {
6660
6859
  console.log(pc6.yellow("\nMod command warnings:"));
@@ -6663,23 +6862,13 @@ Flint cloned to: ${pc6.cyan(abbreviatePath(finalPath))}`);
6663
6862
  }
6664
6863
  }
6665
6864
  }
6666
- if (!result.obsidian.cloned && result.shards.installed.length === 0 && result.mods.installed.length === 0 && result.errors.length === 0) {
6667
- console.log(pc6.dim("Flint is already in sync."));
6668
- }
6669
- if (result.errors.length > 0) {
6670
- console.log(pc6.yellow("\nWarnings:"));
6671
- for (const e of result.errors) {
6672
- console.log(` ${pc6.yellow("!")} ${e.name}: ${e.error}`);
6673
- }
6865
+ reportSyncResult(result);
6866
+ if (result.obsidian.cloned) {
6867
+ console.log(pc6.dim("\nOpening Obsidian vault chooser..."));
6868
+ openObsidianVaultChooser();
6674
6869
  }
6675
6870
  console.log();
6676
6871
  } catch (err) {
6677
- if (tempDir) {
6678
- try {
6679
- await rm8(tempDir, { recursive: true, force: true });
6680
- } catch {
6681
- }
6682
- }
6683
6872
  const message = err instanceof Error ? err.message : String(err);
6684
6873
  error(message);
6685
6874
  process.exit(1);
@@ -6687,7 +6876,7 @@ Flint cloned to: ${pc6.cyan(abbreviatePath(finalPath))}`);
6687
6876
  });
6688
6877
 
6689
6878
  // src/commands/list.ts
6690
- import { Command as Command5 } from "commander";
6879
+ import { Command as Command4 } from "commander";
6691
6880
  import pc7 from "picocolors";
6692
6881
  function stripAnsi(str) {
6693
6882
  return str.replace(/\x1b\[[0-9;]*m/g, "");
@@ -6745,7 +6934,7 @@ function measureNameCol(flints) {
6745
6934
  }
6746
6935
  return max + 3;
6747
6936
  }
6748
- var listCmd = new Command5("list").alias("ls").description("List all registered flints").option("--json", "Output as JSON").option("--full-path", "Show full paths (not abbreviated)").option("-s, --status", "Show valid/broken status for each entry").option("-g, --group", "Group flints by tag").option("-t, --tag <tag>", "Filter flints by tag").option("--search <query>", "Search flints by name or description").option("--tree", "Show parent/subflint hierarchy").option("--no-sub", "Hide subflints from output");
6937
+ var listCmd = new Command4("list").alias("ls").description("List all registered flints").option("--json", "Output as JSON").option("--full-path", "Show full paths (not abbreviated)").option("-s, --status", "Show valid/broken status for each entry").option("-g, --group", "Group flints by tag").option("-t, --tag <tag>", "Filter flints by tag").option("--search <query>", "Search flints by name or description").option("--tree", "Show parent/subflint hierarchy").option("--no-sub", "Hide subflints from output");
6749
6938
  var listCommand = listCmd.action(async (options) => {
6750
6939
  try {
6751
6940
  let flints = await getFlintRegistry();
@@ -6876,10 +7065,11 @@ var listCommand = listCmd.action(async (options) => {
6876
7065
  });
6877
7066
 
6878
7067
  // src/commands/shard.ts
6879
- import { Command as Command6 } from "commander";
7068
+ import { Command as Command5 } from "commander";
6880
7069
  import { spawn as spawn2 } from "child_process";
6881
7070
  import { join as join20 } from "path";
6882
7071
  import { existsSync as existsSync3 } from "fs";
7072
+ import { readFile as readFile9 } from "fs/promises";
6883
7073
  import pc8 from "picocolors";
6884
7074
  var SUBCOMMANDS = [
6885
7075
  "install",
@@ -6889,7 +7079,13 @@ var SUBCOMMANDS = [
6889
7079
  "pull",
6890
7080
  "create",
6891
7081
  "dev",
7082
+ "edit",
7083
+ "freeze",
7084
+ "git",
6892
7085
  "register",
7086
+ "publish",
7087
+ "unpublish",
7088
+ "published",
6893
7089
  "check",
6894
7090
  "heal",
6895
7091
  "info",
@@ -6926,7 +7122,7 @@ function resolveInstalledShard(installed, identifier) {
6926
7122
  return false;
6927
7123
  });
6928
7124
  }
6929
- var shardCommand = new Command6("shard").description("Manage shards \u2014 install, create, and maintain shard packages").argument("[name]", "Shard name for overview or script execution").argument("[script]", "Script name to run").argument("[args...]", "Script arguments").option("-p, --path <dir>", "Path to flint").allowUnknownOption().action(async (shorthand, script, args, options) => {
7125
+ var shardCommand = new Command5("shard").description("Manage shards \u2014 install, create, and maintain shard packages").argument("[name]", "Shard name for overview or script execution").argument("[script]", "Script name to run").argument("[args...]", "Script arguments").option("-p, --path <dir>", "Path to flint").allowUnknownOption().action(async (shorthand, script, args, options) => {
6930
7126
  if (!shorthand) {
6931
7127
  shardCommand.help();
6932
7128
  return;
@@ -6958,9 +7154,6 @@ Shard not found: "${shorthand}"`));
6958
7154
  if (counts.length > 0) {
6959
7155
  console.log(` ${pc8.dim("Contents:")} ${counts.join(", ")}`);
6960
7156
  }
6961
- if (detail2.depends.length > 0) {
6962
- console.log(` ${pc8.dim("Depends:")} ${detail2.depends.join(", ")}`);
6963
- }
6964
7157
  let scripts = [];
6965
7158
  try {
6966
7159
  scripts = await listShardScripts(flintPath, shorthand);
@@ -7022,7 +7215,7 @@ Shard not installed: "${shorthand}"`));
7022
7215
  handleError(err);
7023
7216
  }
7024
7217
  }).addCommand(
7025
- new Command6("install").description("Install a shard from a source (owner/repo or path:)").argument("<source>", "Source identifier (e.g. owner/repo, path:./local)").option("-f, --force", "Overwrite existing shard files").option("-p, --path <dir>", "Path to flint").action(async (source, options) => {
7218
+ new Command5("install").description("Install a shard from a source (owner/repo or path:)").argument("<source>", "Source identifier (e.g. owner/repo, path:./local)").option("-f, --force", "Overwrite existing shard files").option("-p, --path <dir>", "Path to flint").action(async (source, options) => {
7026
7219
  try {
7027
7220
  const flintPath = await resolveFlint(options.path);
7028
7221
  if (!isSourceIdentifier(source)) {
@@ -7058,7 +7251,7 @@ Installed ${pc8.bold(result.name)}`));
7058
7251
  }
7059
7252
  })
7060
7253
  ).addCommand(
7061
- new Command6("uninstall").description("Uninstall a shard and clean up its files").argument("<name>", "Shard name (e.g. reports, living-documents)").option("-p, --path <dir>", "Path to flint").action(async (shorthand, options) => {
7254
+ new Command5("uninstall").description("Uninstall a shard and clean up its files").argument("<name>", "Shard name (e.g. reports, living-documents)").option("-p, --path <dir>", "Path to flint").action(async (shorthand, options) => {
7062
7255
  try {
7063
7256
  const flintPath = await resolveFlint(options.path);
7064
7257
  const result = await uninstallShard(flintPath, shorthand);
@@ -7071,7 +7264,7 @@ Uninstalled ${pc8.bold(result.name)}`));
7071
7264
  }
7072
7265
  })
7073
7266
  ).addCommand(
7074
- new Command6("list").alias("ls").description("List installed shards").option("-s, --sources", "Show source declarations from flint.toml").option("-p, --path <dir>", "Path to flint").action(async (options) => {
7267
+ new Command5("list").alias("ls").description("List installed shards").option("-s, --sources", "Show source declarations from flint.toml").option("-p, --path <dir>", "Path to flint").action(async (options) => {
7075
7268
  try {
7076
7269
  const flintPath = await resolveFlint(options.path);
7077
7270
  if (options.sources) {
@@ -7105,7 +7298,7 @@ Uninstalled ${pc8.bold(result.name)}`));
7105
7298
  modeMap.set(k, resolveShardMode(d) || "normal");
7106
7299
  }
7107
7300
  console.log(pc8.bold("\nInstalled shards:\n"));
7108
- const { execSync: execSync7 } = await import("child_process");
7301
+ const { execSync: execSync4 } = await import("child_process");
7109
7302
  const gitRemotes = /* @__PURE__ */ new Map();
7110
7303
  for (const shard of installed) {
7111
7304
  if (modeMap.get(shard.name) !== "dev") continue;
@@ -7113,7 +7306,7 @@ Uninstalled ${pc8.bold(result.name)}`));
7113
7306
  const gitDir = join20(shardPath, ".git");
7114
7307
  if (!existsSync3(gitDir)) continue;
7115
7308
  try {
7116
- const url = execSync7("git remote get-url origin", { cwd: shardPath, encoding: "utf-8" }).trim();
7309
+ const url = execSync4("git remote get-url origin", { cwd: shardPath, encoding: "utf-8" }).trim();
7117
7310
  const match = url.match(/(?:github\.com[/:])([\w.-]+\/[\w.-]+?)(?:\.git)?$/);
7118
7311
  if (match) {
7119
7312
  gitRemotes.set(shard.name, match[1]);
@@ -7145,7 +7338,7 @@ Uninstalled ${pc8.bold(result.name)}`));
7145
7338
  }
7146
7339
  })
7147
7340
  ).addCommand(
7148
- new Command6("update").description("Update remote shards (skips dev and custom, checks remote version)").option("-p, --path <dir>", "Path to flint").option("--reinstall", "Force re-download and reinstall all remote shards regardless of version").action(async (options) => {
7341
+ new Command5("update").description("Update remote shards (skips dev and custom, checks remote version)").option("-p, --path <dir>", "Path to flint").option("--reinstall", "Force re-download and reinstall all remote shards regardless of version").action(async (options) => {
7149
7342
  try {
7150
7343
  const flintPath = await resolveFlint(options.path);
7151
7344
  const installed = await getInstalledShardsWithVersions(flintPath);
@@ -7165,11 +7358,15 @@ Uninstalled ${pc8.bold(result.name)}`));
7165
7358
  console.log();
7166
7359
  return;
7167
7360
  }
7168
- const mode = options.reinstall ? "Reinstalling" : "Checking";
7169
- console.log(pc8.bold(`
7170
- ${mode} ${updatable.length} shard(s)...
7171
- `));
7172
- const results = await updateShards(flintPath, { reinstall: options.reinstall });
7361
+ const mode = options.reinstall ? "Reinstalling" : "Updating";
7362
+ const progress = createProgressDisplay(`${mode} shards`, updatable.length);
7363
+ const results = await updateShards(flintPath, {
7364
+ reinstall: options.reinstall,
7365
+ onStart: (name) => progress.onStart(name),
7366
+ onComplete: (name) => progress.onComplete(name),
7367
+ onError: (name) => progress.onError(name)
7368
+ });
7369
+ progress.finish();
7173
7370
  const updated = results.filter((r) => r.status === "updated");
7174
7371
  const skippedResults = results.filter((r) => r.status === "skipped");
7175
7372
  const failed = results.filter((r) => r.status === "failed");
@@ -7197,7 +7394,7 @@ ${mode} ${updatable.length} shard(s)...
7197
7394
  }
7198
7395
  })
7199
7396
  ).addCommand(
7200
- new Command6("pull").description("Sync shard repos and install entries from manifest").argument("[name]", "Shard to pull (omit for all)").option("-p, --path <dir>", "Path to flint").action(async (shorthand, options) => {
7397
+ new Command5("pull").description("Sync shard repos and install entries from manifest").argument("[name]", "Shard to pull (omit for all)").option("-p, --path <dir>", "Path to flint").action(async (shorthand, options) => {
7201
7398
  try {
7202
7399
  const flintPath = await resolveFlint(options.path);
7203
7400
  if (shorthand) {
@@ -7234,7 +7431,7 @@ Pulling all shard repos...
7234
7431
  }
7235
7432
  })
7236
7433
  ).addCommand(
7237
- new Command6("create").description("Scaffold a new local shard (dev or custom)").argument("<mode>", 'Shard mode: "dev" (publishable) or "custom" (workspace-specific)').argument("<name>", 'Shard name (e.g. "Bookmarks", "Code Review")').option("-s, --shorthand <id>", "Shard shorthand identifier (default: derived from name)").option("-d, --description <text>", "Shard description").option("--setup", "Include a setup-<shorthand>.md file for one-time initialization").option("--state", "Create a (Shard) state file in Mesh/Shards/").option("-p, --path <dir>", "Path to flint").action(async (mode, name, options) => {
7434
+ new Command5("create").description("Scaffold a new local shard (dev or custom)").argument("<mode>", 'Shard mode: "dev" (publishable) or "custom" (workspace-specific)').argument("<name>", 'Shard name (e.g. "Bookmarks", "Code Review")').option("-s, --shorthand <id>", "Shard shorthand identifier (default: derived from name)").option("-d, --description <text>", "Shard description").option("--setup", "Include a setup-<shorthand>.md file for one-time initialization").option("--state", "Create a (Shard) state file in Mesh/Shards/").option("-p, --path <dir>", "Path to flint").action(async (mode, name, options) => {
7238
7435
  try {
7239
7436
  if (mode !== "dev" && mode !== "custom") {
7240
7437
  console.error(pc8.red(`
@@ -7274,7 +7471,7 @@ Created ${pc8.bold(result.name)} ${modeLabel}`));
7274
7471
  }
7275
7472
  })
7276
7473
  ).addCommand(
7277
- new Command6("dev").description("Clone an existing shard into a (Dev) folder for local editing").argument("<source>", "Source identifier (e.g. owner/repo, path:./local)").option("-p, --path <dir>", "Path to flint").action(async (source, options) => {
7474
+ new Command5("dev").description("Clone an existing shard into a (Dev) folder for local editing").argument("<source>", "Source identifier (e.g. owner/repo, path:./local)").option("-p, --path <dir>", "Path to flint").action(async (source, options) => {
7278
7475
  try {
7279
7476
  const flintPath = await resolveFlint(options.path);
7280
7477
  if (!isSourceIdentifier(source)) {
@@ -7303,7 +7500,87 @@ Cloned ${pc8.bold(result.name)} for development`));
7303
7500
  }
7304
7501
  })
7305
7502
  ).addCommand(
7306
- new Command6("register").description("Register an existing Shards/ folder as a dev shard in flint.toml").argument("<folder>", 'Folder name inside Shards/ (e.g. "(Dev) Bookmarks")').option("-p, --path <dir>", "Path to flint").action(async (folder, options) => {
7503
+ new Command5("edit").description("Transition a normal shard to dev mode (adds .git, renames to (Dev) prefix)").argument("<name>", "Shard name (e.g. reports, living-documents)").option("-p, --path <dir>", "Path to flint").action(async (name, options) => {
7504
+ try {
7505
+ const flintPath = await resolveFlint(options.path);
7506
+ const installed = await getInstalledShardsWithVersions(flintPath);
7507
+ const match = resolveInstalledShard(installed, name);
7508
+ if (!match) {
7509
+ console.error(pc8.red(`
7510
+ Shard "${name}" not found.`));
7511
+ console.log(pc8.dim(` Run ${pc8.cyan("flint shard list")} to see installed shards.`));
7512
+ console.log();
7513
+ return;
7514
+ }
7515
+ const declarations = await getShardDeclarations(flintPath);
7516
+ const decl = declarations[match.name];
7517
+ const source = decl?.source || "";
7518
+ console.log(pc8.dim(`
7519
+ Transitioning ${match.folderName} to dev mode...`));
7520
+ const result = await editShard(flintPath, match.folderName, source);
7521
+ await updateGitignore(flintPath);
7522
+ console.log(pc8.green(`
7523
+ ${pc8.bold(result.name)} is now in dev mode`));
7524
+ console.log(pc8.dim(` Old: Shards/${result.oldFolder}`));
7525
+ console.log(pc8.dim(` New: ${abbreviatePath(result.path)}`));
7526
+ console.log(pc8.dim(` Git: initialized`));
7527
+ console.log();
7528
+ } catch (err) {
7529
+ handleError(err);
7530
+ }
7531
+ })
7532
+ ).addCommand(
7533
+ new Command5("freeze").description("Transition a dev shard back to normal mode (removes .git, commits to parent)").argument("<name>", "Shard name (e.g. reports, living-documents)").option("-p, --path <dir>", "Path to flint").action(async (name, options) => {
7534
+ try {
7535
+ const flintPath = await resolveFlint(options.path);
7536
+ const installed = await getInstalledShardsWithVersions(flintPath);
7537
+ const match = resolveInstalledShard(installed, name);
7538
+ if (!match) {
7539
+ console.error(pc8.red(`
7540
+ Shard "${name}" not found.`));
7541
+ console.log(pc8.dim(` Run ${pc8.cyan("flint shard list")} to see installed shards.`));
7542
+ console.log();
7543
+ return;
7544
+ }
7545
+ console.log(pc8.dim(`
7546
+ Freezing ${match.folderName}...`));
7547
+ const result = await freezeShard(flintPath, match.folderName);
7548
+ await updateGitignore(flintPath);
7549
+ console.log(pc8.green(`
7550
+ ${pc8.bold(result.name)} is now a normal shard`));
7551
+ console.log(pc8.dim(` Old: Shards/${result.oldFolder}`));
7552
+ console.log(pc8.dim(` New: ${abbreviatePath(result.path)}`));
7553
+ console.log(pc8.dim(` Git: removed (now committed to parent flint)`));
7554
+ console.log();
7555
+ } catch (err) {
7556
+ handleError(err);
7557
+ }
7558
+ })
7559
+ ).addCommand(
7560
+ new Command5("git").description("Add a git remote to a dev shard and update its source declaration").argument("<name>", "Shard name (e.g. reports, living-documents)").argument("<url>", "Git remote URL (e.g., https://github.com/org/repo.git)").option("-p, --path <dir>", "Path to flint").action(async (name, url, options) => {
7561
+ try {
7562
+ const flintPath = await resolveFlint(options.path);
7563
+ const installed = await getInstalledShardsWithVersions(flintPath);
7564
+ const match = resolveInstalledShard(installed, name);
7565
+ if (!match) {
7566
+ console.error(pc8.red(`
7567
+ Shard "${name}" not found.`));
7568
+ console.log(pc8.dim(` Run ${pc8.cyan("flint shard list")} to see installed shards.`));
7569
+ console.log();
7570
+ return;
7571
+ }
7572
+ const result = await addShardGitRemote(flintPath, match.folderName, url);
7573
+ console.log(pc8.green(`
7574
+ Remote added to ${pc8.bold(match.folderName)}`));
7575
+ console.log(pc8.dim(` Remote: origin \u2192 ${url}`));
7576
+ console.log(pc8.dim(` Source: ${result.ownerRepo}`));
7577
+ console.log();
7578
+ } catch (err) {
7579
+ handleError(err);
7580
+ }
7581
+ })
7582
+ ).addCommand(
7583
+ new Command5("register").description("Register an existing Shards/ folder as a dev shard in flint.toml").argument("<folder>", 'Folder name inside Shards/ (e.g. "(Dev) Bookmarks")').option("-p, --path <dir>", "Path to flint").action(async (folder, options) => {
7307
7584
  try {
7308
7585
  const flintPath = await resolveFlint(options.path);
7309
7586
  const result = await registerExistingShard(flintPath, folder);
@@ -7319,7 +7596,7 @@ Registered ${pc8.bold(result.name)}`));
7319
7596
  }
7320
7597
  })
7321
7598
  ).addCommand(
7322
- new Command6("info").description("Show detailed information about a shard").argument("<name>", "Shard name (e.g. reports, living-documents)").option("-p, --path <dir>", "Path to flint").action(async (identifier, options) => {
7599
+ new Command5("info").description("Show detailed information about a shard").argument("<name>", "Shard name (e.g. reports, living-documents)").option("-p, --path <dir>", "Path to flint").action(async (identifier, options) => {
7323
7600
  try {
7324
7601
  const flintPath = await resolveFlint(options.path);
7325
7602
  const detail2 = await getShardInfo(flintPath, identifier);
@@ -7344,9 +7621,6 @@ Shard not found: "${identifier}"`));
7344
7621
  console.log(` Mode ${pc8.magenta("custom")}`);
7345
7622
  }
7346
7623
  console.log(` Folder Shards/${detail2.folderName}`);
7347
- if (detail2.depends.length > 0) {
7348
- console.log(` Depends ${detail2.depends.join(", ")}`);
7349
- }
7350
7624
  const counts = [];
7351
7625
  if (detail2.skillCount > 0) counts.push(`${detail2.skillCount} skill${detail2.skillCount !== 1 ? "s" : ""}`);
7352
7626
  if (detail2.templateCount > 0) counts.push(`${detail2.templateCount} template${detail2.templateCount !== 1 ? "s" : ""}`);
@@ -7368,7 +7642,7 @@ Shard not found: "${identifier}"`));
7368
7642
  }
7369
7643
  })
7370
7644
  ).addCommand(
7371
- new Command6("check").description("Check shard system integrity and report issues").option("-p, --path <dir>", "Path to flint").action(async (options) => {
7645
+ new Command5("check").description("Check shard system integrity and report issues").option("-p, --path <dir>", "Path to flint").action(async (options) => {
7372
7646
  try {
7373
7647
  const flintPath = await resolveFlint(options.path);
7374
7648
  console.log(pc8.bold("\nShard Health Check\n"));
@@ -7401,7 +7675,7 @@ Shard not found: "${identifier}"`));
7401
7675
  }
7402
7676
  })
7403
7677
  ).addCommand(
7404
- new Command6("heal").description("Check and fix a shard \u2014 ensures folders, manifest, naming, and dependencies").argument("<name>", "Shard name (e.g. reports, living-documents)").option("-n, --dry-run", "Preview fixes without applying them").option("-p, --path <dir>", "Path to flint").action(async (name, options) => {
7678
+ new Command5("heal").description("Check and fix a shard \u2014 ensures folders, manifest, naming, and declarations").argument("<name>", "Shard name (e.g. reports, living-documents)").option("-n, --dry-run", "Preview fixes without applying them").option("-p, --path <dir>", "Path to flint").action(async (name, options) => {
7405
7679
  try {
7406
7680
  const flintPath = await resolveFlint(options.path);
7407
7681
  const installed = await getInstalledShardsWithVersions(flintPath);
@@ -7455,7 +7729,7 @@ Healing ${match.folderName}...
7455
7729
  }
7456
7730
  })
7457
7731
  ).addCommand(
7458
- new Command6("add").description("Add a shard source to flint.toml without installing files").argument("<source>", "Source identifier (owner/repo)").option("-n, --name <name>", "Override the shard name in config").option("-p, --path <dir>", "Path to flint").action(async (source, options) => {
7732
+ new Command5("add").description("Add a shard source to flint.toml without installing files").argument("<source>", "Source identifier (owner/repo)").option("-n, --name <name>", "Override the shard name in config").option("-p, --path <dir>", "Path to flint").action(async (source, options) => {
7459
7733
  try {
7460
7734
  const flintPath = await resolveFlint(options.path);
7461
7735
  const normalizedSource = source;
@@ -7479,7 +7753,7 @@ Added ${pc8.bold(shardName)}`));
7479
7753
  }
7480
7754
  })
7481
7755
  ).addCommand(
7482
- new Command6("remove").description("Remove a shard declaration from flint.toml (does not delete files)").argument("<name>", "Shard name (e.g. reports, living-documents)").option("-p, --path <dir>", "Path to flint").action(async (shorthand, options) => {
7756
+ new Command5("remove").description("Remove a shard declaration from flint.toml (does not delete files)").argument("<name>", "Shard name (e.g. reports, living-documents)").option("-p, --path <dir>", "Path to flint").action(async (shorthand, options) => {
7483
7757
  try {
7484
7758
  const flintPath = await resolveFlint(options.path);
7485
7759
  await removeShardFromConfig(flintPath, shorthand);
@@ -7492,7 +7766,7 @@ Removed ${pc8.bold(shorthand)} from flint.toml`));
7492
7766
  }
7493
7767
  })
7494
7768
  ).addCommand(
7495
- new Command6("reinstall").description("Re-run install entries for a shard (useful for dev testing)").argument("<name>", "Shard name (e.g. reports, living-documents)").option("--force", "Override once entries (re-install all files)").option("-p, --path <dir>", "Path to flint").action(async (shorthand, options) => {
7769
+ new Command5("reinstall").description("Re-run install entries for a shard (useful for dev testing)").argument("<name>", "Shard name (e.g. reports, living-documents)").option("--force", "Override once entries (re-install all files)").option("-p, --path <dir>", "Path to flint").action(async (shorthand, options) => {
7496
7770
  try {
7497
7771
  const flintPath = await resolveFlint(options.path);
7498
7772
  console.log(pc8.bold(`
@@ -7524,9 +7798,9 @@ Reinstalling ${shorthand}...
7524
7798
  }
7525
7799
  })
7526
7800
  ).addCommand(
7527
- new Command6("gitinit").description("Initialize git repo for a dev shard and push to a remote").argument("<name>", "Shard name (e.g. reports, living-documents)").argument("<url>", "Git remote URL (e.g., https://github.com/org/repo.git)").option("-p, --path <dir>", "Path to flint").action(async (name, url, options) => {
7801
+ new Command5("gitinit").description("Initialize git repo for a dev shard and push to a remote").argument("<name>", "Shard name (e.g. reports, living-documents)").argument("<url>", "Git remote URL (e.g., https://github.com/org/repo.git)").option("-p, --path <dir>", "Path to flint").action(async (name, url, options) => {
7528
7802
  try {
7529
- const { execSync: execSync7 } = await import("child_process");
7803
+ const { execSync: execSync4 } = await import("child_process");
7530
7804
  const flintPath = await resolveFlint(options.path);
7531
7805
  const installed = await getInstalledShardsWithVersions(flintPath);
7532
7806
  const match = resolveInstalledShard(installed, name);
@@ -7554,21 +7828,29 @@ Shard "${name}" not found.`));
7554
7828
  }
7555
7829
  const shardPath = join20(flintPath, "Shards", match.folderName);
7556
7830
  const gitDir = join20(shardPath, ".git");
7557
- if (existsSync3(gitDir)) {
7558
- console.error(pc8.red(`
7559
- "${match.folderName}" already has a git repo. Use \`flint shard push\` instead.`));
7560
- console.log();
7561
- return;
7831
+ const hasGit = existsSync3(gitDir);
7832
+ if (hasGit) {
7833
+ try {
7834
+ const existing = execSync4("git remote get-url origin", { cwd: shardPath, stdio: "pipe" }).toString().trim();
7835
+ console.error(pc8.red(`
7836
+ "${match.folderName}" already has a remote: ${existing}`));
7837
+ console.log(pc8.dim(` Use ${pc8.cyan("flint shard push")} instead.`));
7838
+ console.log();
7839
+ return;
7840
+ } catch {
7841
+ }
7562
7842
  }
7563
7843
  console.log(pc8.bold(`
7564
7844
  Initializing ${match.folderName}...
7565
7845
  `));
7566
- execSync7("git init", { cwd: shardPath, stdio: "pipe" });
7567
- execSync7(`git remote add origin "${url}"`, { cwd: shardPath, stdio: "pipe" });
7568
- execSync7("git branch -M main", { cwd: shardPath, stdio: "pipe" });
7569
- execSync7("git add -A", { cwd: shardPath, stdio: "pipe" });
7570
- execSync7('git commit -m "initial commit"', { cwd: shardPath, stdio: "pipe" });
7571
- execSync7("git push -u origin main", { cwd: shardPath, stdio: "inherit" });
7846
+ if (!hasGit) {
7847
+ execSync4("git init", { cwd: shardPath, stdio: "pipe" });
7848
+ }
7849
+ execSync4(`git remote add origin "${url}"`, { cwd: shardPath, stdio: "pipe" });
7850
+ execSync4("git branch -M main", { cwd: shardPath, stdio: "pipe" });
7851
+ execSync4("git add -A", { cwd: shardPath, stdio: "pipe" });
7852
+ execSync4('git commit -m "initial commit"', { cwd: shardPath, stdio: "pipe" });
7853
+ execSync4("git push -u origin main", { cwd: shardPath, stdio: "inherit" });
7572
7854
  console.log(pc8.green(`
7573
7855
  ${pc8.bold(match.folderName)} pushed to ${pc8.dim(url)}`));
7574
7856
  console.log();
@@ -7577,9 +7859,9 @@ Initializing ${match.folderName}...
7577
7859
  }
7578
7860
  })
7579
7861
  ).addCommand(
7580
- new Command6("push").description("Commit and push a dev shard to its remote").argument("<name>", "Shard name (e.g. reports, living-documents)").option("-m, --message <msg>", "Commit message").option("-b, --bump <level>", "Bump version in shard.yaml (patch, minor, major)").option("-p, --path <dir>", "Path to flint").action(async (name, options) => {
7862
+ new Command5("push").description("Commit and push a dev shard to its remote").argument("<name>", "Shard name (e.g. reports, living-documents)").option("-m, --message <msg>", "Commit message").option("-b, --bump <level>", "Bump version in shard.yaml (patch, minor, major)").option("-p, --path <dir>", "Path to flint").action(async (name, options) => {
7581
7863
  try {
7582
- const { execSync: execSync7 } = await import("child_process");
7864
+ const { execSync: execSync4 } = await import("child_process");
7583
7865
  const flintPath = await resolveFlint(options.path);
7584
7866
  const installed = await getInstalledShardsWithVersions(flintPath);
7585
7867
  const match = resolveInstalledShard(installed, name);
@@ -7614,15 +7896,15 @@ Shard "${name}" not found.`));
7614
7896
  console.log();
7615
7897
  return;
7616
7898
  }
7617
- const status = execSync7("git status --porcelain", { cwd: shardPath, encoding: "utf-8" }).trim();
7899
+ const status = execSync4("git status --porcelain", { cwd: shardPath, encoding: "utf-8" }).trim();
7618
7900
  if (!status) {
7619
7901
  try {
7620
- const unpushed = execSync7("git log @{u}..HEAD --oneline", { cwd: shardPath, encoding: "utf-8" }).trim();
7902
+ const unpushed = execSync4("git log @{u}..HEAD --oneline", { cwd: shardPath, encoding: "utf-8" }).trim();
7621
7903
  if (unpushed) {
7622
7904
  console.log(pc8.bold(`
7623
7905
  Pushing ${match.folderName}...
7624
7906
  `));
7625
- execSync7("git push", { cwd: shardPath, stdio: "inherit" });
7907
+ execSync4("git push", { cwd: shardPath, stdio: "inherit" });
7626
7908
  console.log(pc8.green(`
7627
7909
  Pushed unpushed commits.`));
7628
7910
  console.log();
@@ -7644,9 +7926,9 @@ Invalid bump level "${level}". Use: patch, minor, or major.`));
7644
7926
  console.log();
7645
7927
  return;
7646
7928
  }
7647
- const { readFile: readFile11, writeFile: writeFile10 } = await import("fs/promises");
7929
+ const { readFile: readFile12, writeFile: writeFile10 } = await import("fs/promises");
7648
7930
  const yamlPath = join20(shardPath, "shard.yaml");
7649
- const yamlContent = await readFile11(yamlPath, "utf-8");
7931
+ const yamlContent = await readFile12(yamlPath, "utf-8");
7650
7932
  const versionMatch = yamlContent.match(/^version:\s*"?(\d+)\.(\d+)\.(\d+)"?/m);
7651
7933
  if (!versionMatch) {
7652
7934
  console.error(pc8.red(`
@@ -7666,13 +7948,13 @@ Could not parse version from shard.yaml.`));
7666
7948
  console.log(pc8.bold(`
7667
7949
  Pushing ${match.folderName}...
7668
7950
  `));
7669
- execSync7("git add -A", { cwd: shardPath, stdio: "pipe" });
7670
- execSync7(`git commit -m "${message.replace(/"/g, '\\"')}"`, { cwd: shardPath, stdio: "pipe" });
7951
+ execSync4("git add -A", { cwd: shardPath, stdio: "pipe" });
7952
+ execSync4(`git commit -m "${message.replace(/"/g, '\\"')}"`, { cwd: shardPath, stdio: "pipe" });
7671
7953
  try {
7672
- execSync7("git push", { cwd: shardPath, stdio: "inherit" });
7954
+ execSync4("git push", { cwd: shardPath, stdio: "inherit" });
7673
7955
  } catch {
7674
- const branch = execSync7("git branch --show-current", { cwd: shardPath, encoding: "utf-8" }).trim();
7675
- execSync7(`git push -u origin ${branch}`, { cwd: shardPath, stdio: "inherit" });
7956
+ const branch = execSync4("git branch --show-current", { cwd: shardPath, encoding: "utf-8" }).trim();
7957
+ execSync4(`git push -u origin ${branch}`, { cwd: shardPath, stdio: "inherit" });
7676
7958
  }
7677
7959
  console.log(pc8.green(`
7678
7960
  ${pc8.bold(match.folderName)} pushed.`));
@@ -7683,7 +7965,261 @@ Pushing ${match.folderName}...
7683
7965
  }
7684
7966
  })
7685
7967
  ).addCommand(
7686
- new Command6("scripts").description("List executable scripts provided by a shard").argument("<name>", "Shard name (e.g. projects, living-documents)").option("-p, --path <dir>", "Path to flint").action(async (shorthand, options) => {
7968
+ (() => {
7969
+ const publishRuntime = resolveRuntimeSync({ cliname: "flint" });
7970
+ const publishDevAvailable = publishRuntime.mode === "dev";
7971
+ const REGISTRY_URL_PROD = "https://amicable-dog-262.convex.site";
7972
+ const REGISTRY_URL_DEV = "https://grateful-sardine-809.convex.site";
7973
+ const ORGS_URL_PROD = "https://impressive-ptarmigan-132.convex.site";
7974
+ const ORGS_URL_DEV = "https://steady-lobster-998.convex.site";
7975
+ const cmd = new Command5("publish").description("Publish a shard to the NUU Shard Registry (requires login)").argument("<name>", "Shard name (e.g. reports, notepad)").option("--org <slug>", "Publish as an organisation").option("-p, --path <dir>", "Path to flint");
7976
+ if (publishDevAvailable) cmd.option("--dev", "Use dev environment");
7977
+ cmd.action(async (name, options) => {
7978
+ try {
7979
+ const flintPath = await resolveFlint(options.path);
7980
+ const installed = await getInstalledShardsWithVersions(flintPath);
7981
+ const match = resolveInstalledShard(installed, name);
7982
+ if (!match) {
7983
+ console.error(pc8.red(`
7984
+ Shard "${name}" not found.`));
7985
+ console.log(pc8.dim(` Run ${pc8.cyan("flint shard list")} to see installed shards.`));
7986
+ console.log();
7987
+ process.exit(1);
7988
+ }
7989
+ const shardPath = join20(flintPath, "Shards", match.folderName);
7990
+ const detail2 = await getShardInfo(flintPath, name);
7991
+ if (!detail2) {
7992
+ console.error(pc8.red(`
7993
+ Cannot read shard info for "${name}".`));
7994
+ process.exit(1);
7995
+ }
7996
+ const declarations = await getShardDeclarations(flintPath);
7997
+ const declaration = declarations[match.name];
7998
+ let repo = "";
7999
+ if (declaration?.source) {
8000
+ const parsed = parseShardSource(declaration.source);
8001
+ if (parsed.type === "github") {
8002
+ repo = `${parsed.owner}/${parsed.repo}`;
8003
+ }
8004
+ }
8005
+ if (!repo) {
8006
+ try {
8007
+ const { execSync: execSync4 } = await import("child_process");
8008
+ const gitDir = join20(shardPath, ".git");
8009
+ if (existsSync3(gitDir)) {
8010
+ const remoteUrl = execSync4("git remote get-url origin", { cwd: shardPath, encoding: "utf-8" }).trim();
8011
+ const ghMatch = remoteUrl.match(/github\.com[/:]([\w.-]+\/[\w.-]+?)(?:\.git)?$/);
8012
+ if (ghMatch) {
8013
+ repo = ghMatch[1];
8014
+ }
8015
+ }
8016
+ } catch {
8017
+ }
8018
+ }
8019
+ if (!repo) {
8020
+ console.error(pc8.red(`
8021
+ Cannot determine repo for "${name}".`));
8022
+ console.log(pc8.dim(" Ensure the shard has a GitHub source in flint.toml or a git remote."));
8023
+ console.log();
8024
+ process.exit(1);
8025
+ }
8026
+ let readme;
8027
+ const readmePath = join20(shardPath, "README.md");
8028
+ if (existsSync3(readmePath)) {
8029
+ readme = await readFile9(readmePath, "utf-8");
8030
+ }
8031
+ const env = options.dev ? "dev" : publishDevAvailable ? "dev" : "prod";
8032
+ const creds = await getValidAuth(
8033
+ {
8034
+ accountUrl: env === "dev" ? "https://dev-account.nuucognition.com" : "https://account.nuucognition.com",
8035
+ authEnv: env,
8036
+ cliname: "flint"
8037
+ },
8038
+ env
8039
+ );
8040
+ if (!creds) {
8041
+ error(`Not logged in. Run \`flint login${env === "dev" ? " --dev" : ""}\` to authenticate.`);
8042
+ process.exit(1);
8043
+ }
8044
+ let owner;
8045
+ let author;
8046
+ const orgSlug = options.org;
8047
+ if (orgSlug) {
8048
+ owner = orgSlug;
8049
+ const orgsUrl = env === "dev" ? ORGS_URL_DEV : ORGS_URL_PROD;
8050
+ const orgResponse = await fetch(`${orgsUrl}/api/orgs/${encodeURIComponent(orgSlug)}`, {
8051
+ headers: {
8052
+ "Content-Type": "application/json",
8053
+ Authorization: `Bearer ${creds.sessionToken}`
8054
+ }
8055
+ });
8056
+ if (!orgResponse.ok) {
8057
+ if (orgResponse.status === 401 || orgResponse.status === 403) {
8058
+ error(`You are not a member of organisation "${orgSlug}".`);
8059
+ } else if (orgResponse.status === 404) {
8060
+ error(`Organisation "${orgSlug}" not found.`);
8061
+ } else {
8062
+ error(`Failed to verify organisation "${orgSlug}" (HTTP ${orgResponse.status}).`);
8063
+ }
8064
+ process.exit(1);
8065
+ }
8066
+ const orgData = await orgResponse.json();
8067
+ author = orgData.org?.name || orgSlug;
8068
+ } else {
8069
+ const repoOwner = repo.split("/")[0];
8070
+ owner = repoOwner || creds.email.split("@")[0];
8071
+ }
8072
+ console.log(pc8.dim(`
8073
+ Publishing ${pc8.bold(detail2.name)} to shard registry...`));
8074
+ const registryUrl = env === "dev" ? REGISTRY_URL_DEV : REGISTRY_URL_PROD;
8075
+ const slug = `${owner}/${detail2.shorthand}`;
8076
+ const response = await fetch(`${registryUrl}/api/register`, {
8077
+ method: "POST",
8078
+ headers: {
8079
+ "Content-Type": "application/json",
8080
+ Authorization: `Bearer ${creds.sessionToken}`
8081
+ },
8082
+ body: JSON.stringify({
8083
+ repo,
8084
+ shorthand: detail2.shorthand,
8085
+ owner,
8086
+ name: detail2.name,
8087
+ description: detail2.description,
8088
+ readme,
8089
+ ...author ? { author } : {}
8090
+ })
8091
+ });
8092
+ const data = await response.json();
8093
+ if (!response.ok) {
8094
+ const msg = data.error?.message || `HTTP ${response.status}`;
8095
+ console.error(pc8.red(`
8096
+ Failed to publish: ${msg}`));
8097
+ console.log();
8098
+ process.exit(1);
8099
+ }
8100
+ console.log(pc8.green(`
8101
+ Published ${pc8.bold(detail2.name)} (${slug})`));
8102
+ console.log(pc8.dim(` Repo: ${repo}`));
8103
+ if (data.url) {
8104
+ console.log(pc8.dim(` URL: ${data.url}`));
8105
+ }
8106
+ console.log();
8107
+ } catch (err) {
8108
+ handleError(err);
8109
+ }
8110
+ });
8111
+ return cmd;
8112
+ })()
8113
+ ).addCommand(
8114
+ (() => {
8115
+ const unpubRuntime = resolveRuntimeSync({ cliname: "flint" });
8116
+ const unpubDevAvailable = unpubRuntime.mode === "dev";
8117
+ const REGISTRY_URL_PROD = "https://amicable-dog-262.convex.site";
8118
+ const REGISTRY_URL_DEV = "https://grateful-sardine-809.convex.site";
8119
+ const cmd = new Command5("unpublish").description("Remove a shard from the NUU Shard Registry (requires login)").argument("<slug>", "Shard slug (e.g. NUU-Cognition/notepad)").option("-p, --path <dir>", "Path to flint");
8120
+ if (unpubDevAvailable) cmd.option("--dev", "Use dev environment");
8121
+ cmd.action(async (slug, options) => {
8122
+ try {
8123
+ const env = options.dev ? "dev" : unpubDevAvailable ? "dev" : "prod";
8124
+ const creds = await getValidAuth(
8125
+ {
8126
+ accountUrl: env === "dev" ? "https://dev-account.nuucognition.com" : "https://account.nuucognition.com",
8127
+ authEnv: env,
8128
+ cliname: "flint"
8129
+ },
8130
+ env
8131
+ );
8132
+ if (!creds) {
8133
+ error(`Not logged in. Run \`flint login${env === "dev" ? " --dev" : ""}\` to authenticate.`);
8134
+ process.exit(1);
8135
+ }
8136
+ console.log(pc8.dim(`
8137
+ Unpublishing ${pc8.bold(slug)} from shard registry...`));
8138
+ const registryUrl = env === "dev" ? REGISTRY_URL_DEV : REGISTRY_URL_PROD;
8139
+ const response = await fetch(`${registryUrl}/api/register`, {
8140
+ method: "DELETE",
8141
+ headers: {
8142
+ "Content-Type": "application/json",
8143
+ Authorization: `Bearer ${creds.sessionToken}`
8144
+ },
8145
+ body: JSON.stringify({ slug })
8146
+ });
8147
+ const data = await response.json();
8148
+ if (!response.ok) {
8149
+ const msg = data.error?.message || `HTTP ${response.status}`;
8150
+ console.error(pc8.red(`
8151
+ Failed to unpublish: ${msg}`));
8152
+ console.log();
8153
+ process.exit(1);
8154
+ }
8155
+ success(`Unpublished ${pc8.bold(slug)} from shard registry.`);
8156
+ console.log();
8157
+ } catch (err) {
8158
+ handleError(err);
8159
+ }
8160
+ });
8161
+ return cmd;
8162
+ })()
8163
+ ).addCommand(
8164
+ (() => {
8165
+ const pubListRuntime = resolveRuntimeSync({ cliname: "flint" });
8166
+ const pubListDevAvailable = pubListRuntime.mode === "dev";
8167
+ const REGISTRY_URL_PROD = "https://amicable-dog-262.convex.site";
8168
+ const REGISTRY_URL_DEV = "https://grateful-sardine-809.convex.site";
8169
+ const cmd = new Command5("published").description("List your published shards on the NUU Shard Registry");
8170
+ if (pubListDevAvailable) cmd.option("--dev", "Use dev environment");
8171
+ cmd.action(async (options) => {
8172
+ try {
8173
+ const env = options.dev ? "dev" : pubListDevAvailable ? "dev" : "prod";
8174
+ const creds = await getValidAuth(
8175
+ {
8176
+ accountUrl: env === "dev" ? "https://dev-account.nuucognition.com" : "https://account.nuucognition.com",
8177
+ authEnv: env,
8178
+ cliname: "flint"
8179
+ },
8180
+ env
8181
+ );
8182
+ if (!creds) {
8183
+ error(`Not logged in. Run \`flint login${env === "dev" ? " --dev" : ""}\` to authenticate.`);
8184
+ process.exit(1);
8185
+ }
8186
+ const registryUrl = env === "dev" ? REGISTRY_URL_DEV : REGISTRY_URL_PROD;
8187
+ const response = await fetch(`${registryUrl}/api/my-shards`, {
8188
+ headers: {
8189
+ "Content-Type": "application/json",
8190
+ Authorization: `Bearer ${creds.sessionToken}`
8191
+ }
8192
+ });
8193
+ if (!response.ok) {
8194
+ const data2 = await response.json();
8195
+ const msg = data2.error?.message || `HTTP ${response.status}`;
8196
+ console.error(pc8.red(`
8197
+ Failed to fetch published shards: ${msg}`));
8198
+ console.log();
8199
+ process.exit(1);
8200
+ }
8201
+ const data = await response.json();
8202
+ if (!data.shards.length) {
8203
+ console.log(pc8.dim("\nNo published shards found."));
8204
+ console.log(pc8.dim(` Run ${pc8.cyan("flint shard publish <name>")} to publish a shard.`));
8205
+ console.log();
8206
+ return;
8207
+ }
8208
+ console.log(pc8.dim(`
8209
+ ${data.shards.length} published shard${data.shards.length === 1 ? "" : "s"}:
8210
+ `));
8211
+ for (const s of data.shards) {
8212
+ console.log(` ${pc8.bold(s.name)} ${pc8.dim(s.slug)} ${pc8.dim(s.repo)}`);
8213
+ }
8214
+ console.log();
8215
+ } catch (err) {
8216
+ handleError(err);
8217
+ }
8218
+ });
8219
+ return cmd;
8220
+ })()
8221
+ ).addCommand(
8222
+ new Command5("scripts").description("List executable scripts provided by a shard").argument("<name>", "Shard name (e.g. projects, living-documents)").option("-p, --path <dir>", "Path to flint").action(async (shorthand, options) => {
7687
8223
  try {
7688
8224
  const flintPath = await resolveFlint(options.path);
7689
8225
  const scripts = await listShardScripts(flintPath, shorthand);
@@ -7709,7 +8245,7 @@ Scripts for ${shorthand}:
7709
8245
  );
7710
8246
 
7711
8247
  // src/commands/mod.ts
7712
- import { Command as Command7 } from "commander";
8248
+ import { Command as Command6 } from "commander";
7713
8249
  import { spawn as spawn3 } from "child_process";
7714
8250
  import { join as join21 } from "path";
7715
8251
  import { existsSync as existsSync4 } from "fs";
@@ -7760,7 +8296,7 @@ function resolveInstalledMod(installed, identifier) {
7760
8296
  return false;
7761
8297
  });
7762
8298
  }
7763
- var modCommand = new Command7("mod").description("Manage mods \u2014 install, create, and maintain mod packages").argument("[identifier]", "Mod identifier for script execution").argument("[script]", "Script name to run").argument("[args...]", "Script arguments").option("-p, --path <dir>", "Path to flint").allowUnknownOption().action(async (identifier, script, args, options) => {
8299
+ var modCommand = new Command6("mod").description("Manage mods \u2014 install, create, and maintain mod packages").argument("[identifier]", "Mod identifier for script execution").argument("[script]", "Script name to run").argument("[args...]", "Script arguments").option("-p, --path <dir>", "Path to flint").allowUnknownOption().action(async (identifier, script, args, options) => {
7764
8300
  if (!identifier) {
7765
8301
  modCommand.help();
7766
8302
  return;
@@ -7854,7 +8390,7 @@ Mod not installed: "${identifier}"`));
7854
8390
  handleError2(err);
7855
8391
  }
7856
8392
  }).addCommand(
7857
- new Command7("install").description("Install a mod from a source (owner/repo, path:, or builtin shorthand)").argument("<source>", "Source identifier (e.g. owner/repo, path:./local, or builtin shorthand like cc)").option("-f, --force", "Overwrite existing files").option("-p, --path <dir>", "Path to flint").action(async (source, options) => {
8393
+ new Command6("install").description("Install a mod from a source (owner/repo, path:, or builtin shorthand)").argument("<source>", "Source identifier (e.g. owner/repo, path:./local, or builtin shorthand like cc)").option("-f, --force", "Overwrite existing files").option("-p, --path <dir>", "Path to flint").action(async (source, options) => {
7858
8394
  try {
7859
8395
  const flintPath = await resolveFlint2(options.path);
7860
8396
  if (isSourceIdentifier2(source)) {
@@ -7920,7 +8456,7 @@ Installed ${pc9.bold(result.name)}`));
7920
8456
  }
7921
8457
  })
7922
8458
  ).addCommand(
7923
- new Command7("uninstall").description("Uninstall a mod and clean up its files").argument("<shorthand>", "Mod shorthand or name").option("-p, --path <dir>", "Path to flint").action(async (shorthand, options) => {
8459
+ new Command6("uninstall").description("Uninstall a mod and clean up its files").argument("<shorthand>", "Mod shorthand or name").option("-p, --path <dir>", "Path to flint").action(async (shorthand, options) => {
7924
8460
  try {
7925
8461
  const flintPath = await resolveFlint2(options.path);
7926
8462
  const result = await uninstallMod(flintPath, shorthand);
@@ -7933,7 +8469,7 @@ Uninstalled ${pc9.bold(result.name)}`));
7933
8469
  }
7934
8470
  })
7935
8471
  ).addCommand(
7936
- new Command7("list").alias("ls").description("List installed or available mods").option("-a, --available", "Show mods available to install").option("-s, --sources", "Show source declarations from flint.toml").option("-p, --path <dir>", "Path to flint").action(async (options) => {
8472
+ new Command6("list").alias("ls").description("List installed or available mods").option("-a, --available", "Show mods available to install").option("-s, --sources", "Show source declarations from flint.toml").option("-p, --path <dir>", "Path to flint").action(async (options) => {
7937
8473
  try {
7938
8474
  if (options.available) {
7939
8475
  const available = await listAvailableMods();
@@ -7984,7 +8520,7 @@ Uninstalled ${pc9.bold(result.name)}`));
7984
8520
  Object.entries(declarations).filter(([, d]) => d.dev).map(([k]) => k)
7985
8521
  );
7986
8522
  console.log(pc9.bold("\nInstalled mods:\n"));
7987
- const { execSync: execSync7 } = await import("child_process");
8523
+ const { execSync: execSync4 } = await import("child_process");
7988
8524
  const gitRemotes = /* @__PURE__ */ new Map();
7989
8525
  for (const mod of installed) {
7990
8526
  const kebab = toKebabCase(mod.name);
@@ -7993,7 +8529,7 @@ Uninstalled ${pc9.bold(result.name)}`));
7993
8529
  const gitDir = join21(modPath, ".git");
7994
8530
  if (!existsSync4(gitDir)) continue;
7995
8531
  try {
7996
- const url = execSync7("git remote get-url origin", { cwd: modPath, encoding: "utf-8" }).trim();
8532
+ const url = execSync4("git remote get-url origin", { cwd: modPath, encoding: "utf-8" }).trim();
7997
8533
  const match = url.match(/(?:github\.com[/:])([\w.-]+\/[\w.-]+?)(?:\.git)?$/);
7998
8534
  if (match) {
7999
8535
  gitRemotes.set(mod.name, match[1]);
@@ -8023,7 +8559,7 @@ Uninstalled ${pc9.bold(result.name)}`));
8023
8559
  }
8024
8560
  })
8025
8561
  ).addCommand(
8026
- new Command7("update").description("Update non-dev mods (use --reinstall to force)").option("-p, --path <dir>", "Path to flint").option("--reinstall", "Force reinstall all non-dev mods").action(async (options) => {
8562
+ new Command6("update").description("Update non-dev mods (use --reinstall to force)").option("-p, --path <dir>", "Path to flint").option("--reinstall", "Force reinstall all non-dev mods").action(async (options) => {
8027
8563
  try {
8028
8564
  const flintPath = await resolveFlint2(options.path);
8029
8565
  const installed = await getInstalledMods(flintPath);
@@ -8076,7 +8612,7 @@ ${mode} ${updatable.length} mod(s)...
8076
8612
  }
8077
8613
  })
8078
8614
  ).addCommand(
8079
- new Command7("pull").description("Sync mod repos and install entries from manifest").argument("[identifier]", "Mod to pull (omit for all)").option("-p, --path <dir>", "Path to flint").action(async (identifier, options) => {
8615
+ new Command6("pull").description("Sync mod repos and install entries from manifest").argument("[identifier]", "Mod to pull (omit for all)").option("-p, --path <dir>", "Path to flint").action(async (identifier, options) => {
8080
8616
  try {
8081
8617
  const flintPath = await resolveFlint2(options.path);
8082
8618
  if (identifier) {
@@ -8113,7 +8649,7 @@ Pulling all mod repos...
8113
8649
  }
8114
8650
  })
8115
8651
  ).addCommand(
8116
- new Command7("create").description("Scaffold a new dev mod with standard structure").argument("<name>", 'Mod name (e.g. "Obsidian", "Docker")').option("-s, --shorthand <id>", "Mod shorthand identifier (default: derived from name)").option("-d, --description <text>", "Mod description").option("-p, --path <dir>", "Path to flint").action(async (name, options) => {
8652
+ new Command6("create").description("Scaffold a new dev mod with standard structure").argument("<name>", 'Mod name (e.g. "Obsidian", "Docker")').option("-s, --shorthand <id>", "Mod shorthand identifier (default: derived from name)").option("-d, --description <text>", "Mod description").option("-p, --path <dir>", "Path to flint").action(async (name, options) => {
8117
8653
  try {
8118
8654
  const flintPath = await resolveFlint2(options.path);
8119
8655
  const shorthand = options.shorthand || name.split(/\s+/).map((w) => w[0]).join("").toLowerCase().slice(0, 4) || name.toLowerCase().replace(/\s+/g, "").slice(0, 4);
@@ -8135,7 +8671,7 @@ Created ${pc9.bold(result.name)}`));
8135
8671
  }
8136
8672
  })
8137
8673
  ).addCommand(
8138
- new Command7("dev").description("Clone an existing mod into a (Dev) folder for local editing").argument("<source>", "Source identifier (e.g. owner/repo, path:./local, or builtin shorthand like cc)").option("-p, --path <dir>", "Path to flint").action(async (source, options) => {
8674
+ new Command6("dev").description("Clone an existing mod into a (Dev) folder for local editing").argument("<source>", "Source identifier (e.g. owner/repo, path:./local, or builtin shorthand like cc)").option("-p, --path <dir>", "Path to flint").action(async (source, options) => {
8139
8675
  try {
8140
8676
  const flintPath = await resolveFlint2(options.path);
8141
8677
  if (isSourceIdentifier2(source)) {
@@ -8172,31 +8708,18 @@ Cloned ${pc9.bold(result.name)} for development`));
8172
8708
  await cleanupResolvedModSource(resolved);
8173
8709
  }
8174
8710
  } else {
8175
- const mod = await getBuiltinMod(source);
8176
- if (!mod) {
8177
- const available = await listAvailableMods();
8178
- const shorthands = available.map((m) => m.shorthand).join(", ");
8179
- console.error(pc9.red(`
8180
- Unknown mod: "${source}"`));
8181
- console.log(pc9.dim(` Available: ${shorthands}`));
8182
- console.log();
8183
- process.exit(1);
8184
- }
8185
- console.log(pc9.dim(`
8186
- Cloning ${mod.name}...`));
8187
- const result = await cloneModToDev(flintPath, mod.path, mod);
8188
- await updateGitignore(flintPath);
8189
- console.log(pc9.green(`
8190
- Cloned ${pc9.bold(result.name)} for development`));
8191
- console.log(pc9.dim(` Path: ${abbreviatePath(result.path)}`));
8711
+ console.error(pc9.red(`
8712
+ Unknown mod source: "${source}"`));
8713
+ console.log(pc9.dim(` Provide an owner/repo source (e.g., "NUU-Cognition/flint-mod-agents")`));
8192
8714
  console.log();
8715
+ process.exit(1);
8193
8716
  }
8194
8717
  } catch (err) {
8195
8718
  handleError2(err);
8196
8719
  }
8197
8720
  })
8198
8721
  ).addCommand(
8199
- new Command7("register").description("Register an existing Mods/ folder as a dev mod in flint.toml").argument("<folder>", 'Folder name inside Mods/ (e.g., "(Dev) Docker")').option("-p, --path <dir>", "Path to flint").action(async (folder, options) => {
8722
+ new Command6("register").description("Register an existing Mods/ folder as a dev mod in flint.toml").argument("<folder>", 'Folder name inside Mods/ (e.g., "(Dev) Docker")').option("-p, --path <dir>", "Path to flint").action(async (folder, options) => {
8200
8723
  try {
8201
8724
  const flintPath = await resolveFlint2(options.path);
8202
8725
  const result = await registerExistingMod(flintPath, folder);
@@ -8212,7 +8735,7 @@ Registered ${pc9.bold(result.name)}`));
8212
8735
  }
8213
8736
  })
8214
8737
  ).addCommand(
8215
- new Command7("info").description("Show detailed information about a mod").argument("<name>", "Mod shorthand, name, or folder name").option("-p, --path <dir>", "Path to flint").action(async (identifier, options) => {
8738
+ new Command6("info").description("Show detailed information about a mod").argument("<name>", "Mod shorthand, name, or folder name").option("-p, --path <dir>", "Path to flint").action(async (identifier, options) => {
8216
8739
  try {
8217
8740
  const flintPath = await resolveFlint2(options.path);
8218
8741
  const detail2 = await getModInfo(flintPath, identifier);
@@ -8266,7 +8789,7 @@ Mod not found: "${identifier}"`));
8266
8789
  }
8267
8790
  })
8268
8791
  ).addCommand(
8269
- new Command7("check").description("Check mod system integrity and report issues").option("-p, --path <dir>", "Path to flint").action(async (options) => {
8792
+ new Command6("check").description("Check mod system integrity and report issues").option("-p, --path <dir>", "Path to flint").action(async (options) => {
8270
8793
  try {
8271
8794
  const flintPath = await resolveFlint2(options.path);
8272
8795
  console.log(pc9.bold("\nMod Health Check\n"));
@@ -8299,7 +8822,7 @@ Mod not found: "${identifier}"`));
8299
8822
  }
8300
8823
  })
8301
8824
  ).addCommand(
8302
- new Command7("heal").description("Check and fix a mod \u2014 ensures folders, manifest, naming, and dependencies").argument("<name>", "Mod name (e.g. claude-code, agents)").option("-n, --dry-run", "Preview fixes without applying them").option("-p, --path <dir>", "Path to flint").action(async (name, options) => {
8825
+ new Command6("heal").description("Check and fix a mod \u2014 ensures folders, manifest, naming, and dependencies").argument("<name>", "Mod name (e.g. claude-code, agents)").option("-n, --dry-run", "Preview fixes without applying them").option("-p, --path <dir>", "Path to flint").action(async (name, options) => {
8303
8826
  try {
8304
8827
  const flintPath = await resolveFlint2(options.path);
8305
8828
  const installed = await getInstalledMods(flintPath);
@@ -8353,7 +8876,7 @@ Healing ${match.folderName}...
8353
8876
  }
8354
8877
  })
8355
8878
  ).addCommand(
8356
- new Command7("add").description("Add a mod to flint.toml without installing files").argument("<source>", "Mod source (owner/repo, path:./local, or builtin shorthand)").option("-p, --path <dir>", "Path to flint").action(async (source, options) => {
8879
+ new Command6("add").description("Add a mod to flint.toml without installing files").argument("<source>", "Mod source (owner/repo, path:./local, or builtin shorthand)").option("-p, --path <dir>", "Path to flint").action(async (source, options) => {
8357
8880
  try {
8358
8881
  const flintPath = await resolveFlint2(options.path);
8359
8882
  let modName;
@@ -8376,7 +8899,7 @@ Added ${pc9.bold(modName)}`));
8376
8899
  }
8377
8900
  })
8378
8901
  ).addCommand(
8379
- new Command7("remove").description("Remove a mod declaration from flint.toml (does not delete files)").argument("<name>", "Mod name").option("-p, --path <dir>", "Path to flint").action(async (name, options) => {
8902
+ new Command6("remove").description("Remove a mod declaration from flint.toml (does not delete files)").argument("<name>", "Mod name").option("-p, --path <dir>", "Path to flint").action(async (name, options) => {
8380
8903
  try {
8381
8904
  const flintPath = await resolveFlint2(options.path);
8382
8905
  await removeModFromConfig(flintPath, name);
@@ -8389,7 +8912,7 @@ Removed ${pc9.bold(name)} from flint.toml`));
8389
8912
  }
8390
8913
  })
8391
8914
  ).addCommand(
8392
- new Command7("reinstall").description("Re-run install entries for a mod (useful for dev testing)").argument("<shorthand>", "Mod shorthand or name").option("--force", "Override once entries (re-install all files)").option("-p, --path <dir>", "Path to flint").action(async (shorthand, options) => {
8915
+ new Command6("reinstall").description("Re-run install entries for a mod (useful for dev testing)").argument("<shorthand>", "Mod shorthand or name").option("--force", "Override once entries (re-install all files)").option("-p, --path <dir>", "Path to flint").action(async (shorthand, options) => {
8393
8916
  try {
8394
8917
  const flintPath = await resolveFlint2(options.path);
8395
8918
  console.log(pc9.bold(`
@@ -8421,9 +8944,9 @@ Reinstalling ${shorthand}...
8421
8944
  }
8422
8945
  })
8423
8946
  ).addCommand(
8424
- new Command7("gitinit").description("Initialize git repo for a dev mod and push to a remote").argument("<name>", "Mod name (e.g. claude-code, agents)").argument("<url>", "Git remote URL (e.g., https://github.com/org/repo.git)").option("-p, --path <dir>", "Path to flint").action(async (name, url, options) => {
8947
+ new Command6("gitinit").description("Initialize git repo for a dev mod and push to a remote").argument("<name>", "Mod name (e.g. claude-code, agents)").argument("<url>", "Git remote URL (e.g., https://github.com/org/repo.git)").option("-p, --path <dir>", "Path to flint").action(async (name, url, options) => {
8425
8948
  try {
8426
- const { execSync: execSync7 } = await import("child_process");
8949
+ const { execSync: execSync4 } = await import("child_process");
8427
8950
  const flintPath = await resolveFlint2(options.path);
8428
8951
  const installed = await getInstalledMods(flintPath);
8429
8952
  const match = resolveInstalledMod(installed, name);
@@ -8453,12 +8976,12 @@ Mod "${name}" not found.`));
8453
8976
  console.log(pc9.bold(`
8454
8977
  Initializing ${match.folderName}...
8455
8978
  `));
8456
- execSync7("git init", { cwd: modPath, stdio: "pipe" });
8457
- execSync7(`git remote add origin "${url}"`, { cwd: modPath, stdio: "pipe" });
8458
- execSync7("git branch -M main", { cwd: modPath, stdio: "pipe" });
8459
- execSync7("git add -A", { cwd: modPath, stdio: "pipe" });
8460
- execSync7('git commit -m "initial commit"', { cwd: modPath, stdio: "pipe" });
8461
- execSync7("git push -u origin main", { cwd: modPath, stdio: "inherit" });
8979
+ execSync4("git init", { cwd: modPath, stdio: "pipe" });
8980
+ execSync4(`git remote add origin "${url}"`, { cwd: modPath, stdio: "pipe" });
8981
+ execSync4("git branch -M main", { cwd: modPath, stdio: "pipe" });
8982
+ execSync4("git add -A", { cwd: modPath, stdio: "pipe" });
8983
+ execSync4('git commit -m "initial commit"', { cwd: modPath, stdio: "pipe" });
8984
+ execSync4("git push -u origin main", { cwd: modPath, stdio: "inherit" });
8462
8985
  console.log(pc9.green(`
8463
8986
  ${pc9.bold(match.folderName)} pushed to ${pc9.dim(url)}`));
8464
8987
  console.log();
@@ -8467,9 +8990,9 @@ Initializing ${match.folderName}...
8467
8990
  }
8468
8991
  })
8469
8992
  ).addCommand(
8470
- new Command7("push").description("Commit and push a dev mod to its remote").argument("<name>", "Mod name (e.g. claude-code, agents)").option("-m, --message <msg>", "Commit message").option("-p, --path <dir>", "Path to flint").action(async (name, options) => {
8993
+ new Command6("push").description("Commit and push a dev mod to its remote").argument("<name>", "Mod name (e.g. claude-code, agents)").option("-m, --message <msg>", "Commit message").option("-p, --path <dir>", "Path to flint").action(async (name, options) => {
8471
8994
  try {
8472
- const { execSync: execSync7 } = await import("child_process");
8995
+ const { execSync: execSync4 } = await import("child_process");
8473
8996
  const flintPath = await resolveFlint2(options.path);
8474
8997
  const installed = await getInstalledMods(flintPath);
8475
8998
  const match = resolveInstalledMod(installed, name);
@@ -8497,15 +9020,15 @@ Mod "${name}" not found.`));
8497
9020
  console.log();
8498
9021
  return;
8499
9022
  }
8500
- const status = execSync7("git status --porcelain", { cwd: modPath, encoding: "utf-8" }).trim();
9023
+ const status = execSync4("git status --porcelain", { cwd: modPath, encoding: "utf-8" }).trim();
8501
9024
  if (!status) {
8502
9025
  try {
8503
- const unpushed = execSync7("git log @{u}..HEAD --oneline", { cwd: modPath, encoding: "utf-8" }).trim();
9026
+ const unpushed = execSync4("git log @{u}..HEAD --oneline", { cwd: modPath, encoding: "utf-8" }).trim();
8504
9027
  if (unpushed) {
8505
9028
  console.log(pc9.bold(`
8506
9029
  Pushing ${match.folderName}...
8507
9030
  `));
8508
- execSync7("git push", { cwd: modPath, stdio: "inherit" });
9031
+ execSync4("git push", { cwd: modPath, stdio: "inherit" });
8509
9032
  console.log(pc9.green(`
8510
9033
  Pushed unpushed commits.`));
8511
9034
  console.log();
@@ -8522,13 +9045,13 @@ No changes to push in "${match.folderName}".`));
8522
9045
  console.log(pc9.bold(`
8523
9046
  Pushing ${match.folderName}...
8524
9047
  `));
8525
- execSync7("git add -A", { cwd: modPath, stdio: "pipe" });
8526
- execSync7(`git commit -m "${message.replace(/"/g, '\\"')}"`, { cwd: modPath, stdio: "pipe" });
9048
+ execSync4("git add -A", { cwd: modPath, stdio: "pipe" });
9049
+ execSync4(`git commit -m "${message.replace(/"/g, '\\"')}"`, { cwd: modPath, stdio: "pipe" });
8527
9050
  try {
8528
- execSync7("git push", { cwd: modPath, stdio: "inherit" });
9051
+ execSync4("git push", { cwd: modPath, stdio: "inherit" });
8529
9052
  } catch {
8530
- const branch = execSync7("git branch --show-current", { cwd: modPath, encoding: "utf-8" }).trim();
8531
- execSync7(`git push -u origin ${branch}`, { cwd: modPath, stdio: "inherit" });
9053
+ const branch = execSync4("git branch --show-current", { cwd: modPath, encoding: "utf-8" }).trim();
9054
+ execSync4(`git push -u origin ${branch}`, { cwd: modPath, stdio: "inherit" });
8532
9055
  }
8533
9056
  console.log(pc9.green(`
8534
9057
  ${pc9.bold(match.folderName)} pushed.`));
@@ -8539,7 +9062,7 @@ Pushing ${match.folderName}...
8539
9062
  }
8540
9063
  })
8541
9064
  ).addCommand(
8542
- new Command7("scripts").description("List executable scripts provided by a mod").argument("<identifier>", "Mod shorthand (e.g., cc)").option("-p, --path <dir>", "Path to flint").action(async (identifier, options) => {
9065
+ new Command6("scripts").description("List executable scripts provided by a mod").argument("<identifier>", "Mod shorthand (e.g., cc)").option("-p, --path <dir>", "Path to flint").action(async (identifier, options) => {
8543
9066
  try {
8544
9067
  const flintPath = await resolveFlint2(options.path);
8545
9068
  const scripts = await listModScripts(flintPath, identifier);
@@ -8565,9 +9088,9 @@ Scripts for ${identifier}:
8565
9088
  );
8566
9089
 
8567
9090
  // src/commands/sync.ts
8568
- import { Command as Command8 } from "commander";
9091
+ import { Command as Command7 } from "commander";
8569
9092
  import pc10 from "picocolors";
8570
- var syncCommand = new Command8("sync").description("Sync shards and mods from flint.toml").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (options) => {
9093
+ var syncCommand = new Command7("sync").description("Sync shards and mods from flint.toml").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (options) => {
8571
9094
  try {
8572
9095
  const flintPath = options.path || await findFlintRoot(process.cwd());
8573
9096
  if (!flintPath) {
@@ -8577,7 +9100,39 @@ var syncCommand = new Command8("sync").description("Sync shards and mods from fl
8577
9100
  process.exit(1);
8578
9101
  }
8579
9102
  console.log(pc10.bold("\nSyncing flint...\n"));
8580
- const result = await syncFlint(flintPath);
9103
+ let shardProgress;
9104
+ let modProgress;
9105
+ const progress = {
9106
+ onShardPhase(total) {
9107
+ if (total > 0) {
9108
+ shardProgress = createProgressDisplay("Installing shards", total);
9109
+ }
9110
+ },
9111
+ onShardStart(name) {
9112
+ shardProgress?.onStart(name);
9113
+ },
9114
+ onShardDone(name, ok) {
9115
+ if (ok) shardProgress?.onComplete(name);
9116
+ else shardProgress?.onError(name);
9117
+ },
9118
+ onModPhase(total) {
9119
+ shardProgress?.finish();
9120
+ if (total > 0) {
9121
+ console.log();
9122
+ modProgress = createProgressDisplay("Installing mods", total);
9123
+ }
9124
+ },
9125
+ onModStart(name) {
9126
+ modProgress?.onStart(name);
9127
+ },
9128
+ onModDone(name, ok) {
9129
+ if (ok) modProgress?.onComplete(name);
9130
+ else modProgress?.onError(name);
9131
+ }
9132
+ };
9133
+ const result = await syncFlint(flintPath, progress);
9134
+ shardProgress?.finish();
9135
+ modProgress?.finish();
8581
9136
  if (result.bootstrap.created) {
8582
9137
  console.log(pc10.green("Bootstrap:"));
8583
9138
  console.log(` ${pc10.green("+")} Created .flint/ directory`);
@@ -8616,12 +9171,6 @@ var syncCommand = new Command8("sync").description("Sync shards and mods from fl
8616
9171
  }
8617
9172
  const hasShardChanges = result.shards.installed.length > 0 || result.shards.uninstalled.length > 0 || result.shards.orphaned.length > 0;
8618
9173
  const hasModChanges = result.mods.installed.length > 0 || result.mods.uninstalled.length > 0;
8619
- if (result.shards.installed.length > 0) {
8620
- console.log(pc10.green("Shards installed:"));
8621
- for (const s of result.shards.installed) {
8622
- console.log(` ${pc10.green("+")} ${s}`);
8623
- }
8624
- }
8625
9174
  if (result.shards.uninstalled.length > 0) {
8626
9175
  console.log(pc10.yellow("Shards removed:"));
8627
9176
  for (const s of result.shards.uninstalled) {
@@ -8635,12 +9184,6 @@ var syncCommand = new Command8("sync").description("Sync shards and mods from fl
8635
9184
  }
8636
9185
  console.log(pc10.dim(" Run `flint shard uninstall <shorthand>` to remove"));
8637
9186
  }
8638
- if (result.mods.installed.length > 0) {
8639
- console.log(pc10.green("Mods installed:"));
8640
- for (const s of result.mods.installed) {
8641
- console.log(` ${pc10.green("+")} ${s}`);
8642
- }
8643
- }
8644
9187
  if (result.mods.uninstalled.length > 0) {
8645
9188
  console.log(pc10.yellow("Mods removed:"));
8646
9189
  for (const s of result.mods.uninstalled) {
@@ -8683,6 +9226,9 @@ var syncCommand = new Command8("sync").description("Sync shards and mods from fl
8683
9226
  case "not_found":
8684
9227
  console.log(` ${pc10.yellow("\u26A0")} ${imp.ref} - flint not found in registry`);
8685
9228
  break;
9229
+ case "export_not_found":
9230
+ console.log(` ${pc10.yellow("\u26A0")} ${imp.ref} - ${imp.error}`);
9231
+ break;
8686
9232
  case "not_built":
8687
9233
  console.log(` ${pc10.yellow("\u26A0")} ${imp.ref} - export not built`);
8688
9234
  break;
@@ -8740,9 +9286,9 @@ var syncCommand = new Command8("sync").description("Sync shards and mods from fl
8740
9286
  });
8741
9287
 
8742
9288
  // src/commands/git.ts
8743
- import { Command as Command9 } from "commander";
9289
+ import { Command as Command8 } from "commander";
8744
9290
  import pc11 from "picocolors";
8745
- var gitCommand = new Command9("git").description("Git operations for the Flint").enablePositionalOptions().passThroughOptions().option("-p, --path <dir>", "Path to flint (default: auto-detect)").argument("[args...]", "Git arguments").action(async (args, options) => {
9291
+ var gitCommand = new Command8("git").description("Git operations for the Flint").enablePositionalOptions().passThroughOptions().option("-p, --path <dir>", "Path to flint (default: auto-detect)").argument("[args...]", "Git arguments").action(async (args, options) => {
8746
9292
  const flintPath = options.path || await findFlintRoot(process.cwd());
8747
9293
  if (!flintPath) {
8748
9294
  console.error(pc11.red("Error: Not inside a Flint."));
@@ -8768,21 +9314,19 @@ var gitCommand = new Command9("git").description("Git operations for the Flint")
8768
9314
  }
8769
9315
  });
8770
9316
  async function handleInit(flintPath) {
8771
- const modInstalled = await isModInstalled(flintPath, "git");
8772
- if (modInstalled) {
8773
- const initialized = await isGitInitialized(flintPath);
8774
- if (initialized) {
8775
- console.log(pc11.yellow("Git already initialized. Updating .gitignore..."));
8776
- await updateGitignore(flintPath);
8777
- console.log(pc11.green("Updated .gitignore"));
8778
- } else {
8779
- console.log(pc11.yellow("Git mod installed but git not initialized. Run `git init` manually."));
8780
- }
9317
+ const initialized = await isGitInitialized(flintPath);
9318
+ if (initialized) {
9319
+ console.log(pc11.yellow("Git already initialized. Updating .gitignore..."));
9320
+ await updateGitignore(flintPath);
9321
+ console.log(pc11.green("Updated .gitignore"));
8781
9322
  return;
8782
9323
  }
8783
9324
  try {
8784
- console.log(pc11.dim("Installing git mod..."));
8785
- await installMod(flintPath, "git", { source: "NUU-Cognition/flint-mod-git" });
9325
+ const result = await initGit(flintPath);
9326
+ if (!result.success) {
9327
+ console.error(pc11.red(`Error: ${result.error}`));
9328
+ process.exit(1);
9329
+ }
8786
9330
  console.log(pc11.green("Initialized git repository"));
8787
9331
  console.log(pc11.dim("Created .gitignore with Flint defaults"));
8788
9332
  } catch (err) {
@@ -8808,23 +9352,21 @@ async function handleGitInit(flintPath, args) {
8808
9352
  console.log(pc11.dim("Usage: flint git gitinit <repolink>"));
8809
9353
  process.exit(1);
8810
9354
  }
8811
- const modInstalled = await isModInstalled(flintPath, "git");
8812
- if (!modInstalled) {
9355
+ const initialized = await isGitInitialized(flintPath);
9356
+ if (!initialized) {
8813
9357
  try {
8814
- console.log(pc11.dim("Installing git mod..."));
8815
- await installMod(flintPath, "git", { source: "NUU-Cognition/flint-mod-git" });
9358
+ const result = await initGit(flintPath);
9359
+ if (!result.success) {
9360
+ console.error(pc11.red(`Failed to initialize git: ${result.error}`));
9361
+ process.exit(1);
9362
+ }
8816
9363
  console.log(pc11.green("\u2713 Initialized git repository"));
8817
9364
  } catch (err) {
8818
- console.error(pc11.red(`Failed to install git mod: ${err instanceof Error ? err.message : String(err)}`));
9365
+ console.error(pc11.red(`Failed to initialize git: ${err instanceof Error ? err.message : String(err)}`));
8819
9366
  process.exit(1);
8820
9367
  }
8821
9368
  } else {
8822
- const initialized = await isGitInitialized(flintPath);
8823
- if (!initialized) {
8824
- console.error(pc11.red("Git mod installed but git not initialized. Run `git init` manually."));
8825
- process.exit(1);
8826
- }
8827
- console.log(pc11.dim("Git mod already installed."));
9369
+ console.log(pc11.dim("Git already initialized."));
8828
9370
  }
8829
9371
  try {
8830
9372
  console.log(pc11.dim("Syncing flint..."));
@@ -8914,9 +9456,9 @@ async function showFlintGitStatus(flintPath) {
8914
9456
  }
8915
9457
 
8916
9458
  // src/commands/repair.ts
8917
- import { Command as Command10 } from "commander";
9459
+ import { Command as Command9 } from "commander";
8918
9460
  import pc12 from "picocolors";
8919
- import { mkdir as mkdir12, access as access8 } from "fs/promises";
9461
+ import { mkdir as mkdir12, access as access7 } from "fs/promises";
8920
9462
  import { join as join24, basename as basename2 } from "path";
8921
9463
  var REQUIRED_DIRS = [
8922
9464
  "Mesh",
@@ -8930,7 +9472,7 @@ var REQUIRED_DIRS = [
8930
9472
  ];
8931
9473
  async function exists2(path3) {
8932
9474
  try {
8933
- await access8(path3);
9475
+ await access7(path3);
8934
9476
  return true;
8935
9477
  } catch {
8936
9478
  return false;
@@ -9063,7 +9605,7 @@ function printResults(title, results) {
9063
9605
  }
9064
9606
  console.log();
9065
9607
  }
9066
- var repairCommand = new Command10("repair").description("Repair a flint to match current specifications").option("-p, --path <dir>", "Path to flint (default: auto-detect)").option("-n, --dry-run", "Show what would be fixed without making changes").action(async (options) => {
9608
+ var repairCommand = new Command9("repair").description("Repair a flint to match current specifications").option("-p, --path <dir>", "Path to flint (default: auto-detect)").option("-n, --dry-run", "Show what would be fixed without making changes").action(async (options) => {
9067
9609
  try {
9068
9610
  const flintPath = options.path || await findFlintRoot(process.cwd());
9069
9611
  if (!flintPath) {
@@ -9151,9 +9693,9 @@ var repairCommand = new Command10("repair").description("Repair a flint to match
9151
9693
  });
9152
9694
 
9153
9695
  // src/commands/export.ts
9154
- import { Command as Command11 } from "commander";
9696
+ import { Command as Command10 } from "commander";
9155
9697
  import pc13 from "picocolors";
9156
- import { readFile as readFile9, stat as stat7 } from "fs/promises";
9698
+ import { readFile as readFile10, stat as stat7 } from "fs/promises";
9157
9699
  import { join as join25, basename as basename4 } from "path";
9158
9700
  import { createInterface as createInterface2 } from "readline";
9159
9701
  async function exists3(path3) {
@@ -9208,7 +9750,7 @@ async function getExportStatus(flintPath) {
9208
9750
  if (!await exists3(manifestPath)) {
9209
9751
  manifestPath = join25(flintPath, "Exports", manifest.name, "_manifest.json");
9210
9752
  }
9211
- const manifestJson = JSON.parse(await readFile9(manifestPath, "utf-8"));
9753
+ const manifestJson = JSON.parse(await readFile10(manifestPath, "utf-8"));
9212
9754
  fileCount = manifestJson.files?.length || 0;
9213
9755
  } catch {
9214
9756
  }
@@ -9222,7 +9764,7 @@ async function getExportStatus(flintPath) {
9222
9764
  }
9223
9765
  return results;
9224
9766
  }
9225
- var listCommand2 = new Command11("list").description("List all declared exports").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (options) => {
9767
+ var listCommand2 = new Command10("list").description("List all declared exports").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (options) => {
9226
9768
  try {
9227
9769
  const flintPath = options.path || await findFlintRoot(process.cwd());
9228
9770
  if (!flintPath) {
@@ -9259,7 +9801,7 @@ var listCommand2 = new Command11("list").description("List all declared exports"
9259
9801
  process.exit(1);
9260
9802
  }
9261
9803
  });
9262
- var scanCommand = new Command11("scan").description("Find #export-tagged files not yet declared").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (options) => {
9804
+ var scanCommand = new Command10("scan").description("Find #export-tagged files not yet declared").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (options) => {
9263
9805
  try {
9264
9806
  const flintPath = options.path || await findFlintRoot(process.cwd());
9265
9807
  if (!flintPath) {
@@ -9301,9 +9843,23 @@ var scanCommand = new Command11("scan").description("Find #export-tagged files n
9301
9843
  });
9302
9844
  console.log(` ${pc13.green("\u2713")} Added ${pc13.cyan(exportName)}`);
9303
9845
  }
9846
+ const manifests = await scanExports(flintPath);
9847
+ if (manifests.length > 0) {
9848
+ console.log();
9849
+ console.log(pc13.bold("Building exports..."));
9850
+ console.log();
9851
+ const removed = await cleanupStaleExports(flintPath);
9852
+ for (const r of removed) {
9853
+ console.log(` ${pc13.yellow("-")} ${r} ${pc13.dim("(removed stale)")}`);
9854
+ }
9855
+ for (const manifest of manifests) {
9856
+ const result = await buildExport(manifest, flintPath);
9857
+ console.log(` ${pc13.green("\u2713")} Built ${pc13.cyan(result.name)} \u2014 ${result.filesCopied} files`);
9858
+ }
9859
+ }
9304
9860
  await refreshRegistryExports(flintPath);
9305
9861
  console.log();
9306
- console.log(pc13.dim("Use 'flint export build --all' to build exports."));
9862
+ console.log(pc13.green("Done!"));
9307
9863
  console.log();
9308
9864
  } catch (err) {
9309
9865
  const message = err instanceof Error ? err.message : String(err);
@@ -9311,7 +9867,7 @@ var scanCommand = new Command11("scan").description("Find #export-tagged files n
9311
9867
  process.exit(1);
9312
9868
  }
9313
9869
  });
9314
- var addCommand = new Command11("add").description("Declare a file as an export").argument("<file>", "Source file name (must have #export tag)").argument("<name>", "Export name").argument("[mode]", "Export mode", "mesh").option("-d, --depth <n>", "Export depth (default: 1 for mesh mode)", parseInt).option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (file, name, mode, options) => {
9870
+ var addCommand = new Command10("add").description("Declare a file as an export").argument("<file>", "Source file name (must have #export tag)").argument("<name>", "Export name").argument("[mode]", "Export mode", "mesh").option("-d, --depth <n>", "Export depth (default: 1 for mesh mode)", parseInt).option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (file, name, mode, options) => {
9315
9871
  try {
9316
9872
  const flintPath = options.path || await findFlintRoot(process.cwd());
9317
9873
  if (!flintPath) {
@@ -9357,7 +9913,7 @@ var addCommand = new Command11("add").description("Declare a file as an export")
9357
9913
  process.exit(1);
9358
9914
  }
9359
9915
  });
9360
- var removeCommand = new Command11("remove").description("Remove an export declaration").argument("<name>", "Export name to remove").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (name, options) => {
9916
+ var removeCommand = new Command10("remove").description("Remove an export declaration").argument("<name>", "Export name to remove").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (name, options) => {
9361
9917
  try {
9362
9918
  const flintPath = options.path || await findFlintRoot(process.cwd());
9363
9919
  if (!flintPath) {
@@ -9381,7 +9937,7 @@ var removeCommand = new Command11("remove").description("Remove an export declar
9381
9937
  process.exit(1);
9382
9938
  }
9383
9939
  });
9384
- var buildCommand = new Command11("build").description("Build exports").argument("[name]", "Name of export to build (omit for all)").option("-p, --path <dir>", "Path to flint (default: auto-detect)").option("--all", "Build all exports").action(async (name, options) => {
9940
+ var buildCommand = new Command10("build").description("Build exports").argument("[name]", "Name of export to build (omit for all)").option("-p, --path <dir>", "Path to flint (default: auto-detect)").option("--all", "Build all exports").action(async (name, options) => {
9385
9941
  try {
9386
9942
  const flintPath = options.path || await findFlintRoot(process.cwd());
9387
9943
  if (!flintPath) {
@@ -9437,7 +9993,7 @@ var buildCommand = new Command11("build").description("Build exports").argument(
9437
9993
  process.exit(1);
9438
9994
  }
9439
9995
  });
9440
- var statusCommand = new Command11("status").description("Show export build status").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (options) => {
9996
+ var statusCommand = new Command10("status").description("Show export build status").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (options) => {
9441
9997
  try {
9442
9998
  const flintPath = options.path || await findFlintRoot(process.cwd());
9443
9999
  if (!flintPath) {
@@ -9469,10 +10025,10 @@ var statusCommand = new Command11("status").description("Show export build statu
9469
10025
  process.exit(1);
9470
10026
  }
9471
10027
  });
9472
- var exportCommand = new Command11("export").description("Manage exports").addCommand(listCommand2).addCommand(scanCommand).addCommand(addCommand).addCommand(removeCommand).addCommand(buildCommand).addCommand(statusCommand);
10028
+ var exportCommand = new Command10("export").description("Manage exports").addCommand(listCommand2).addCommand(scanCommand).addCommand(addCommand).addCommand(removeCommand).addCommand(buildCommand).addCommand(statusCommand);
9473
10029
 
9474
10030
  // src/commands/import.ts
9475
- import { Command as Command12 } from "commander";
10031
+ import { Command as Command11 } from "commander";
9476
10032
  import pc14 from "picocolors";
9477
10033
  import { rm as rm9, stat as stat9 } from "fs/promises";
9478
10034
  import { join as join26, basename as basename5 } from "path";
@@ -9516,7 +10072,7 @@ async function exists4(path3) {
9516
10072
  return false;
9517
10073
  }
9518
10074
  }
9519
- var listCommand3 = new Command12("list").description("List available imports from registered flints").argument("[flint]", "Flint name to show exports from").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (flintName, options) => {
10075
+ var listCommand3 = new Command11("list").description("List available imports from registered flints").argument("[flint]", "Flint name to show exports from").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (flintName, options) => {
9520
10076
  try {
9521
10077
  const flintPath = options.path || await findFlintRoot(process.cwd());
9522
10078
  console.log();
@@ -9583,7 +10139,7 @@ var listCommand3 = new Command12("list").description("List available imports fro
9583
10139
  process.exit(1);
9584
10140
  }
9585
10141
  });
9586
- var addCommand2 = new Command12("add").description("Add an import to flint.toml").argument("<ref>", 'Import reference: "<flint>/<export>"').option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (ref, options) => {
10142
+ var addCommand2 = new Command11("add").description("Add an import to flint.toml").argument("<ref>", 'Import reference: "<flint>/<export>"').option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (ref, options) => {
9587
10143
  try {
9588
10144
  const flintPath = options.path || await findFlintRoot(process.cwd());
9589
10145
  if (!flintPath) {
@@ -9651,7 +10207,7 @@ var addCommand2 = new Command12("add").description("Add an import to flint.toml"
9651
10207
  process.exit(1);
9652
10208
  }
9653
10209
  });
9654
- var removeCommand2 = new Command12("remove").description("Remove an import from flint.toml").argument("<ref>", 'Import to remove: "<flint>/<export>"').option("-p, --path <dir>", "Path to flint (default: auto-detect)").option("--delete-files", "Also delete the imported files from Imports/").action(async (ref, options) => {
10210
+ var removeCommand2 = new Command11("remove").description("Remove an import from flint.toml").argument("<ref>", 'Import to remove: "<flint>/<export>"').option("-p, --path <dir>", "Path to flint (default: auto-detect)").option("--delete-files", "Also delete the imported files from Imports/").action(async (ref, options) => {
9655
10211
  try {
9656
10212
  const flintPath = options.path || await findFlintRoot(process.cwd());
9657
10213
  if (!flintPath) {
@@ -9694,8 +10250,8 @@ var removeCommand2 = new Command12("remove").description("Remove an import from
9694
10250
  if (deleted) {
9695
10251
  const parentPath = join26(flintPath, "Imports", `(Flint) ${flintName}`);
9696
10252
  try {
9697
- const { readdir: readdir10 } = await import("fs/promises");
9698
- const remaining = await readdir10(parentPath);
10253
+ const { readdir: readdir11 } = await import("fs/promises");
10254
+ const remaining = await readdir11(parentPath);
9699
10255
  if (remaining.length === 0) {
9700
10256
  await rm9(parentPath, { recursive: true });
9701
10257
  }
@@ -9710,16 +10266,16 @@ var removeCommand2 = new Command12("remove").description("Remove an import from
9710
10266
  process.exit(1);
9711
10267
  }
9712
10268
  });
9713
- var importCommand = new Command12("import").description("Manage imports from other flints").addCommand(listCommand3).addCommand(addCommand2).addCommand(removeCommand2);
10269
+ var importCommand = new Command11("import").description("Manage imports from other flints").addCommand(listCommand3).addCommand(addCommand2).addCommand(removeCommand2);
9714
10270
 
9715
10271
  // src/commands/open.ts
9716
- import { Command as Command13 } from "commander";
9717
- import { exec as exec4 } from "child_process";
10272
+ import { Command as Command12 } from "commander";
10273
+ import { exec as exec7 } from "child_process";
9718
10274
  import { promisify as promisify8 } from "util";
9719
10275
  import { resolve as resolve9 } from "path";
9720
10276
  import { platform as platform3 } from "os";
9721
10277
  import pc15 from "picocolors";
9722
- var execAsync4 = promisify8(exec4);
10278
+ var execAsync7 = promisify8(exec7);
9723
10279
  var APP_NAMES = {
9724
10280
  obsidian: {
9725
10281
  darwin: "Obsidian",
@@ -9747,20 +10303,20 @@ async function openInApp(appId, path3) {
9747
10303
  const appConfig = APP_NAMES[appId.toLowerCase()];
9748
10304
  if (os2 === "darwin") {
9749
10305
  const appName = appConfig?.darwin ?? appId;
9750
- await execAsync4(`open -a "${appName}" "${path3}"`);
10306
+ await execAsync7(`open -a "${appName}" "${path3}"`);
9751
10307
  } else if (os2 === "win32") {
9752
10308
  const appName = appConfig?.win32 ?? appId;
9753
- await execAsync4(`start "" "${appName}" "${path3}"`);
10309
+ await execAsync7(`start "" "${appName}" "${path3}"`);
9754
10310
  } else {
9755
10311
  const appName = appConfig?.linux ?? appId.toLowerCase();
9756
10312
  try {
9757
- await execAsync4(`${appName} "${path3}"`);
10313
+ await execAsync7(`${appName} "${path3}"`);
9758
10314
  } catch {
9759
- await execAsync4(`xdg-open "${path3}"`);
10315
+ await execAsync7(`xdg-open "${path3}"`);
9760
10316
  }
9761
10317
  }
9762
10318
  }
9763
- var openCommand = new Command13("open").argument("[flint-name]", "Name of the flint to open").description("Open a flint in configured applications").action(async (flintName) => {
10319
+ var openCommand = new Command12("open").argument("[flint-name]", "Name of the flint to open").description("Open a flint in configured applications").action(async (flintName) => {
9764
10320
  try {
9765
10321
  let flintPath;
9766
10322
  if (flintName) {
@@ -9817,13 +10373,13 @@ var openCommand = new Command13("open").argument("[flint-name]", "Name of the fl
9817
10373
  });
9818
10374
 
9819
10375
  // src/commands/agent.ts
9820
- import { Command as Command14 } from "commander";
10376
+ import { Command as Command13 } from "commander";
9821
10377
  import pc16 from "picocolors";
9822
10378
  import { spawn as spawn4 } from "child_process";
9823
10379
  import { join as join27, dirname as dirname7 } from "path";
9824
10380
  import { fileURLToPath as fileURLToPath4 } from "url";
9825
10381
  var __dirname4 = dirname7(fileURLToPath4(import.meta.url));
9826
- var agentCommand = new Command14("agent").description("Manage Flint agents");
10382
+ var agentCommand = new Command13("agent").description("Manage Flint agents");
9827
10383
  agentCommand.command("start").description("Start an agent session").option("-p, --path <dir>", "Path to flint mesh (default: auto-detect)").option("-b, --backend <type>", "Agent backend: pydantic | claude-code", "pydantic").option("-m, --model <model>", "Model to use (default: openai/gpt-4o-mini)").option("-g, --goal <goal>", "Initial goal for the agent").option("-s, --skill <skill>", "Skill file to execute").option("--dry-run", "Show what would happen without starting agent").action(async (options) => {
9828
10384
  try {
9829
10385
  const meshPath = options.path || await findFlintRoot(process.cwd());
@@ -10039,7 +10595,7 @@ async function startClaudeCodeAgent(meshPath, options) {
10039
10595
  }
10040
10596
 
10041
10597
  // src/commands/register.ts
10042
- import { Command as Command15 } from "commander";
10598
+ import { Command as Command14 } from "commander";
10043
10599
  import pc17 from "picocolors";
10044
10600
  import { createInterface as createInterface3 } from "readline";
10045
10601
  import { resolve as resolve10 } from "path";
@@ -10074,7 +10630,7 @@ async function promptSelect(flints) {
10074
10630
  });
10075
10631
  });
10076
10632
  }
10077
- var registerCommand = new Command15("register").description("Register an existing flint in the global registry").argument("[paths...]", "Paths to flints to register (defaults to current directory)").option("-s, --scan", "Scan for flints in the specified paths (or default locations)").option("-d, --depth <n>", "Max recursion depth for scan (default: 5)", "5").option("--dry-run", "Show what would be registered without doing it").option("-f, --force", "Re-register even if already registered (updates entry)").action(async (pathArgs, options) => {
10633
+ var registerCommand = new Command14("register").description("Register an existing flint in the global registry").argument("[paths...]", "Paths to flints to register (defaults to current directory)").option("-s, --scan", "Scan for flints in the specified paths (or default locations)").option("-d, --depth <n>", "Max recursion depth for scan (default: 5)", "5").option("--dry-run", "Show what would be registered without doing it").option("-f, --force", "Re-register even if already registered (updates entry)").action(async (pathArgs, options) => {
10078
10634
  try {
10079
10635
  const depth = parseInt(options.depth, 10) || 5;
10080
10636
  if (options.scan) {
@@ -10199,10 +10755,10 @@ var registerCommand = new Command15("register").description("Register an existin
10199
10755
  });
10200
10756
 
10201
10757
  // src/commands/unregister.ts
10202
- import { Command as Command16 } from "commander";
10758
+ import { Command as Command15 } from "commander";
10203
10759
  import pc18 from "picocolors";
10204
10760
  import { resolve as resolve11 } from "path";
10205
- var unregisterCommand = new Command16("unregister").description("Unregister a flint from the global registry").argument("[path]", "Path to the flint (defaults to current directory)").option("-f, --force", "Skip confirmation prompt").action(async (pathArg, options) => {
10761
+ var unregisterCommand = new Command15("unregister").description("Unregister a flint from the global registry").argument("[path]", "Path to the flint (defaults to current directory)").option("-f, --force", "Skip confirmation prompt").action(async (pathArg, options) => {
10206
10762
  try {
10207
10763
  let targetPath;
10208
10764
  if (pathArg) {
@@ -10248,9 +10804,9 @@ Flint to unregister:`);
10248
10804
  });
10249
10805
 
10250
10806
  // src/commands/registry.ts
10251
- import { Command as Command17 } from "commander";
10807
+ import { Command as Command16 } from "commander";
10252
10808
  import pc19 from "picocolors";
10253
- var validateCommand = new Command17("validate").description("Validate registry and remove broken entries").option("--dry-run", "Check only, do not remove broken entries").option("--json", "Output as JSON").option("-f, --force", "Skip confirmation prompt when removing entries").action(async (options) => {
10809
+ var validateCommand = new Command16("validate").description("Validate registry and remove broken entries").option("--dry-run", "Check only, do not remove broken entries").option("--json", "Output as JSON").option("-f, --force", "Skip confirmation prompt when removing entries").action(async (options) => {
10254
10810
  try {
10255
10811
  const cleanResult = await cleanRegistryFile();
10256
10812
  const flintEntries = await getFlintRegistry();
@@ -10352,7 +10908,7 @@ ${pc19.bold("Registry Validation")}
10352
10908
  process.exit(1);
10353
10909
  }
10354
10910
  });
10355
- var tagCommand = new Command17("tag").description("Add a tag to a registered flint").argument("<name>", "Flint name").argument("<tag>", "Tag to add").action(async (name, tag) => {
10911
+ var tagCommand = new Command16("tag").description("Add a tag to a registered flint").argument("<name>", "Flint name").argument("<tag>", "Tag to add").action(async (name, tag) => {
10356
10912
  try {
10357
10913
  const flint = await findFlintByName(name);
10358
10914
  if (!flint) {
@@ -10373,7 +10929,7 @@ var tagCommand = new Command17("tag").description("Add a tag to a registered fli
10373
10929
  process.exit(1);
10374
10930
  }
10375
10931
  });
10376
- var untagCommand = new Command17("untag").description("Remove a tag from a registered flint").argument("<name>", "Flint name").argument("<tag>", "Tag to remove").action(async (name, tag) => {
10932
+ var untagCommand = new Command16("untag").description("Remove a tag from a registered flint").argument("<name>", "Flint name").argument("<tag>", "Tag to remove").action(async (name, tag) => {
10377
10933
  try {
10378
10934
  const flint = await findFlintByName(name);
10379
10935
  if (!flint) {
@@ -10393,16 +10949,16 @@ var untagCommand = new Command17("untag").description("Remove a tag from a regis
10393
10949
  process.exit(1);
10394
10950
  }
10395
10951
  });
10396
- var registryCommand = new Command17("registry").description("Manage the flint registry").addCommand(validateCommand).addCommand(tagCommand).addCommand(untagCommand);
10952
+ var registryCommand = new Command16("registry").description("Manage the flint registry").addCommand(validateCommand).addCommand(tagCommand).addCommand(untagCommand);
10397
10953
 
10398
10954
  // src/commands/obsidian.ts
10399
- import { Command as Command18 } from "commander";
10955
+ import { Command as Command17 } from "commander";
10400
10956
  import pc20 from "picocolors";
10401
- import { execSync as execSync6 } from "child_process";
10957
+ import { execSync as execSync3, spawnSync } from "child_process";
10402
10958
  import { join as join28 } from "path";
10403
10959
  import { stat as stat10, rm as rm10 } from "fs/promises";
10404
10960
  var OBSIDIAN_REPO_URL2 = "https://github.com/NUU-Cognition/flint-dot-obsidian.git";
10405
- var obsidianCommand = new Command18("obsidian").description("Manage .obsidian configuration").option("-p, --path <dir>", "Path to flint (default: auto-detect)");
10961
+ var obsidianCommand = new Command17("obsidian").description("Manage .obsidian configuration").option("-p, --path <dir>", "Path to flint (default: auto-detect)");
10406
10962
  obsidianCommand.command("update").description("Force pull latest .obsidian from remote (discards local changes)").action(async () => {
10407
10963
  const options = obsidianCommand.opts();
10408
10964
  const flintPath = options.path || await findFlintRoot(process.cwd());
@@ -10420,8 +10976,8 @@ obsidianCommand.command("update").description("Force pull latest .obsidian from
10420
10976
  }
10421
10977
  console.log(pc20.dim("Fetching latest from remote..."));
10422
10978
  try {
10423
- execSync6("git fetch origin", { cwd: obsidianDir, stdio: "pipe" });
10424
- execSync6("git reset --hard origin/main", { cwd: obsidianDir, stdio: "pipe" });
10979
+ execSync3("git fetch origin", { cwd: obsidianDir, stdio: "pipe" });
10980
+ execSync3("git reset --hard origin/main", { cwd: obsidianDir, stdio: "pipe" });
10425
10981
  console.log(pc20.green("Updated .obsidian to latest from remote."));
10426
10982
  } catch (err) {
10427
10983
  const message = err instanceof Error ? err.message : String(err);
@@ -10446,17 +11002,19 @@ if (isFeatureEnabled(FEATURES, "obsidian.push", resolveRuntimeSync({ cliname: "f
10446
11002
  }
10447
11003
  console.log(pc20.dim("Staging changes..."));
10448
11004
  try {
10449
- execSync6("git add -A", { cwd: obsidianDir, stdio: "pipe" });
10450
- const status = execSync6("git status --porcelain", { cwd: obsidianDir, encoding: "utf-8" });
11005
+ execSync3("git add -A", { cwd: obsidianDir, stdio: "pipe" });
11006
+ const status = execSync3("git status --porcelain", { cwd: obsidianDir, encoding: "utf-8" });
10451
11007
  if (!status.trim()) {
10452
11008
  console.log(pc20.yellow("No changes to commit."));
10453
11009
  return;
10454
11010
  }
10455
11011
  console.log(pc20.dim("Committing..."));
10456
- const safeMessage = cmdOptions.message.replace(/"/g, '\\"');
10457
- execSync6(`git commit -m "${safeMessage}"`, { cwd: obsidianDir, stdio: "pipe" });
11012
+ const commitResult = spawnSync("git", ["commit", "-m", cmdOptions.message], { cwd: obsidianDir, stdio: "pipe" });
11013
+ if (commitResult.status !== 0) {
11014
+ throw new Error(commitResult.stderr?.toString() || "git commit failed");
11015
+ }
10458
11016
  console.log(pc20.dim("Pushing to remote..."));
10459
- execSync6("git push origin main", { cwd: obsidianDir, stdio: "pipe" });
11017
+ execSync3("git push origin main", { cwd: obsidianDir, stdio: "pipe" });
10460
11018
  console.log(pc20.green("Pushed .obsidian changes to remote."));
10461
11019
  } catch (err) {
10462
11020
  const message = err instanceof Error ? err.message : String(err);
@@ -10491,7 +11049,7 @@ obsidianCommand.command("reset").description("Delete and re-clone .obsidian from
10491
11049
  await rm10(obsidianDir, { recursive: true, force: true });
10492
11050
  }
10493
11051
  console.log(pc20.dim("Cloning .obsidian from template repo..."));
10494
- execSync6(`git clone ${OBSIDIAN_REPO_URL2} "${obsidianDir}"`, { stdio: "pipe" });
11052
+ execSync3(`git clone ${OBSIDIAN_REPO_URL2} "${obsidianDir}"`, { stdio: "pipe" });
10495
11053
  console.log(pc20.green("Reset .obsidian to fresh state from template repo."));
10496
11054
  } catch (err) {
10497
11055
  const message = err instanceof Error ? err.message : String(err);
@@ -10501,10 +11059,10 @@ obsidianCommand.command("reset").description("Delete and re-clone .obsidian from
10501
11059
  });
10502
11060
 
10503
11061
  // src/commands/config.ts
10504
- import { Command as Command19 } from "commander";
11062
+ import { Command as Command18 } from "commander";
10505
11063
  import pc21 from "picocolors";
10506
11064
  var CONFIG_PATH = getConfigPath("flint");
10507
- var configCommand = new Command19("config").description("Manage global Flint configuration").argument("[action]", "Action: get, set, or omit to view all").argument("[key]", "Config key (e.g., open.apps)").argument("[value]", "Value to set (JSON for arrays/objects)").action(async (action, key, value) => {
11065
+ var configCommand = new Command18("config").description("Manage global Flint configuration").argument("[action]", "Action: get, set, or omit to view all").argument("[key]", "Config key (e.g., open.apps)").argument("[value]", "Value to set (JSON for arrays/objects)").action(async (action, key, value) => {
10508
11066
  try {
10509
11067
  const config = resolveConfigSync({ cliname: "flint" });
10510
11068
  if (!action) {
@@ -10600,10 +11158,10 @@ function getNestedValue(obj, key) {
10600
11158
  }
10601
11159
 
10602
11160
  // src/commands/connection.ts
10603
- import { Command as Command20 } from "commander";
11161
+ import { Command as Command19 } from "commander";
10604
11162
  import pc22 from "picocolors";
10605
- var connectionCommand = new Command20("connection").description("Manage connections to other Flints").addCommand(
10606
- new Command20("add").description("Add a connection to another Flint (must be registered)").argument("<name>", "Name of the registered Flint to connect").option("-p, --path <dir>", "Path to flint (default: auto-detect)").option("--no-fulfill", "Only add declaration, do not auto-fulfill").action(async (targetName, options) => {
11163
+ var connectionCommand = new Command19("connection").description("Manage connections to other Flints").addCommand(
11164
+ new Command19("add").description("Add a connection to another Flint (must be registered)").argument("<name>", "Name of the registered Flint to connect").option("-p, --path <dir>", "Path to flint (default: auto-detect)").option("--no-fulfill", "Only add declaration, do not auto-fulfill").action(async (targetName, options) => {
10607
11165
  try {
10608
11166
  const flintPath = options.path || await findFlintRoot(process.cwd());
10609
11167
  if (!flintPath) {
@@ -10631,7 +11189,7 @@ Added connection to ${pc22.bold(status.name)}`));
10631
11189
  }
10632
11190
  })
10633
11191
  ).addCommand(
10634
- new Command20("remove").description("Remove a connection").argument("<name>", "Name of the connected Flint to remove").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (name, options) => {
11192
+ new Command19("remove").description("Remove a connection").argument("<name>", "Name of the connected Flint to remove").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (name, options) => {
10635
11193
  try {
10636
11194
  const flintPath = options.path || await findFlintRoot(process.cwd());
10637
11195
  if (!flintPath) {
@@ -10657,7 +11215,7 @@ Connection "${name}" not found`));
10657
11215
  }
10658
11216
  })
10659
11217
  ).addCommand(
10660
- new Command20("list").description("List all connections with status").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (options) => {
11218
+ new Command19("list").description("List all connections with status").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (options) => {
10661
11219
  try {
10662
11220
  const flintPath = options.path || await findFlintRoot(process.cwd());
10663
11221
  if (!flintPath) {
@@ -10707,7 +11265,7 @@ Connection "${name}" not found`));
10707
11265
  }
10708
11266
  })
10709
11267
  ).addCommand(
10710
- new Command20("fulfill").description("Fulfill a connection by setting its local path").argument("[name]", "Name of the connection to fulfill").option("-p, --path <dir>", "Path to flint (default: auto-detect)").option("--all", "Fulfill all unfulfilled connections interactively").option("--target <path>", "Path to the target Flint (auto-lookup from registry if omitted)").action(async (name, options) => {
11268
+ new Command19("fulfill").description("Fulfill a connection by setting its local path").argument("[name]", "Name of the connection to fulfill").option("-p, --path <dir>", "Path to flint (default: auto-detect)").option("--all", "Fulfill all unfulfilled connections interactively").option("--target <path>", "Path to the target Flint (auto-lookup from registry if omitted)").action(async (name, options) => {
10711
11269
  try {
10712
11270
  const flintPath = options.path || await findFlintRoot(process.cwd());
10713
11271
  if (!flintPath) {
@@ -10769,7 +11327,7 @@ Fulfilled connection to ${pc22.bold(fulfillment.name)}`));
10769
11327
  }
10770
11328
  })
10771
11329
  ).addCommand(
10772
- new Command20("status").description("Check connection status").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (options) => {
11330
+ new Command19("status").description("Check connection status").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (options) => {
10773
11331
  try {
10774
11332
  const flintPath = options.path || await findFlintRoot(process.cwd());
10775
11333
  if (!flintPath) {
@@ -10817,7 +11375,7 @@ Fulfilled connection to ${pc22.bold(fulfillment.name)}`));
10817
11375
  );
10818
11376
 
10819
11377
  // src/commands/workspace.ts
10820
- import { Command as Command21 } from "commander";
11378
+ import { Command as Command20 } from "commander";
10821
11379
  import pc23 from "picocolors";
10822
11380
  import { stat as stat11 } from "fs/promises";
10823
11381
  import * as readline from "readline";
@@ -10841,8 +11399,8 @@ async function pathExists2(path3) {
10841
11399
  return false;
10842
11400
  }
10843
11401
  }
10844
- var workspaceCommand = new Command21("workspace").description("Manage workspace references to external resources").addCommand(
10845
- new Command21("list").description("List workspace references").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (options) => {
11402
+ var workspaceCommand = new Command20("workspace").description("Manage workspace references to external resources").addCommand(
11403
+ new Command20("list").description("List workspace references").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (options) => {
10846
11404
  try {
10847
11405
  const flintPath = options.path || await findFlintRoot(process.cwd());
10848
11406
  if (!flintPath) {
@@ -10889,7 +11447,7 @@ var workspaceCommand = new Command21("workspace").description("Manage workspace
10889
11447
  }
10890
11448
  })
10891
11449
  ).addCommand(
10892
- new Command21("reference").description("Declare a workspace reference and optionally set its local path").argument("<name>", "Name for this workspace reference").argument("[targetPath]", "Path to the external resource (optional)").option("-t, --type <type>", "Type of reference (codebase, drive, api, database, service)", "codebase").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (name, targetPath, options) => {
11450
+ new Command20("reference").description("Declare a workspace reference and optionally set its local path").argument("<name>", "Name for this workspace reference").argument("[targetPath]", "Path to the external resource (optional)").option("-t, --type <type>", "Type of reference (codebase, drive, api, database, service)", "codebase").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (name, targetPath, options) => {
10893
11451
  try {
10894
11452
  const flintPath = options.path || await findFlintRoot(process.cwd());
10895
11453
  if (!flintPath) {
@@ -10928,7 +11486,7 @@ Declared workspace reference: ${pc23.bold(name)}`));
10928
11486
  }
10929
11487
  })
10930
11488
  ).addCommand(
10931
- new Command21("fulfill").description("Provide local paths for unfulfilled workspace references").argument("[name]", "Specific reference to fulfill (or all if omitted)").argument("[targetPath]", "Path to the resource (skips prompt if provided)").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (name, targetPath, options) => {
11489
+ new Command20("fulfill").description("Provide local paths for unfulfilled workspace references").argument("[name]", "Specific reference to fulfill (or all if omitted)").argument("[targetPath]", "Path to the resource (skips prompt if provided)").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (name, targetPath, options) => {
10932
11490
  try {
10933
11491
  const flintPath = options.path || await findFlintRoot(process.cwd());
10934
11492
  if (!flintPath) {
@@ -11011,7 +11569,7 @@ Workspace "${name}" is already fulfilled.`));
11011
11569
  }
11012
11570
  })
11013
11571
  ).addCommand(
11014
- new Command21("remove").description("Remove a workspace reference").argument("<name>", "Name of the workspace reference to remove").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (name, options) => {
11572
+ new Command20("remove").description("Remove a workspace reference").argument("<name>", "Name of the workspace reference to remove").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (name, options) => {
11015
11573
  try {
11016
11574
  const flintPath = options.path || await findFlintRoot(process.cwd());
11017
11575
  if (!flintPath) {
@@ -11039,7 +11597,7 @@ Removed workspace reference: ${pc23.bold(name)}`));
11039
11597
  }
11040
11598
  })
11041
11599
  ).addCommand(
11042
- new Command21("addrepo").description("Clone a full git repository into Workspace/Repositories/").argument("<name>", "Name for this repository").argument("<url>", "Git URL to clone").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (name, url, options) => {
11600
+ new Command20("addrepo").description("Clone a full git repository into Workspace/Repositories/").argument("<name>", "Name for this repository").argument("<url>", "Git URL to clone").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (name, url, options) => {
11043
11601
  try {
11044
11602
  const flintPath = options.path || await findFlintRoot(process.cwd());
11045
11603
  if (!flintPath) {
@@ -11066,7 +11624,7 @@ Added repository: ${pc23.bold(name)}`));
11066
11624
  }
11067
11625
  })
11068
11626
  ).addCommand(
11069
- new Command21("createrepo").description("Create a new git repository in Workspace/Repositories/ with a remote origin").argument("<name>", "Name for this repository").argument("<url>", "Git remote URL to set as origin").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (name, url, options) => {
11627
+ new Command20("createrepo").description("Create a new git repository in Workspace/Repositories/ with a remote origin").argument("<name>", "Name for this repository").argument("<url>", "Git remote URL to set as origin").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (name, url, options) => {
11070
11628
  try {
11071
11629
  const flintPath = options.path || await findFlintRoot(process.cwd());
11072
11630
  if (!flintPath) {
@@ -11093,7 +11651,7 @@ Created repository: ${pc23.bold(name)}`));
11093
11651
  }
11094
11652
  })
11095
11653
  ).addCommand(
11096
- new Command21("removerepo").description("Remove a cloned repository").argument("<name>", "Name of the repository to remove").option("-f, --force", "Skip confirmation prompt").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (name, options) => {
11654
+ new Command20("removerepo").description("Remove a cloned repository").argument("<name>", "Name of the repository to remove").option("-f, --force", "Skip confirmation prompt").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (name, options) => {
11097
11655
  try {
11098
11656
  const flintPath = options.path || await findFlintRoot(process.cwd());
11099
11657
  if (!flintPath) {
@@ -11129,7 +11687,7 @@ Removed repository: ${pc23.bold(name)}`));
11129
11687
  }
11130
11688
  })
11131
11689
  ).addCommand(
11132
- new Command21("updaterepo").description("Pull latest changes for a repository (or fresh clone with --fresh)").argument("<name>", "Name of the repository to update").option("-p, --path <dir>", "Path to flint (default: auto-detect)").option("--fresh", "Delete and re-clone instead of pulling").action(async (name, options) => {
11690
+ new Command20("updaterepo").description("Pull latest changes for a repository (or fresh clone with --fresh)").argument("<name>", "Name of the repository to update").option("-p, --path <dir>", "Path to flint (default: auto-detect)").option("--fresh", "Delete and re-clone instead of pulling").action(async (name, options) => {
11133
11691
  try {
11134
11692
  const flintPath = options.path || await findFlintRoot(process.cwd());
11135
11693
  if (!flintPath) {
@@ -11160,7 +11718,7 @@ Updated repository: ${pc23.bold(name)}`));
11160
11718
  }
11161
11719
  })
11162
11720
  ).addCommand(
11163
- new Command21("listrepo").description("List cloned repositories").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (options) => {
11721
+ new Command20("listrepo").description("List cloned repositories").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (options) => {
11164
11722
  try {
11165
11723
  const flintPath = options.path || await findFlintRoot(process.cwd());
11166
11724
  if (!flintPath) {
@@ -11205,7 +11763,7 @@ Updated repository: ${pc23.bold(name)}`));
11205
11763
  }
11206
11764
  })
11207
11765
  ).addCommand(
11208
- new Command21("addreferencerepo").description("Clone a reference copy of a git repository into Workspace/Sources/Repositories/").argument("<name>", "Name for this source repository").argument("<url>", "Git URL to clone").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (name, url, options) => {
11766
+ new Command20("addreferencerepo").description("Clone a reference copy of a git repository into Workspace/Sources/Repositories/").argument("<name>", "Name for this source repository").argument("<url>", "Git URL to clone").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (name, url, options) => {
11209
11767
  try {
11210
11768
  const flintPath = options.path || await findFlintRoot(process.cwd());
11211
11769
  if (!flintPath) {
@@ -11233,7 +11791,7 @@ Added reference repository: ${pc23.bold(name)}`));
11233
11791
  }
11234
11792
  })
11235
11793
  ).addCommand(
11236
- new Command21("removereferencerepo").description("Remove a reference repository").argument("<name>", "Name of the reference repository to remove").option("-f, --force", "Skip confirmation prompt").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (name, options) => {
11794
+ new Command20("removereferencerepo").description("Remove a reference repository").argument("<name>", "Name of the reference repository to remove").option("-f, --force", "Skip confirmation prompt").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (name, options) => {
11237
11795
  try {
11238
11796
  const flintPath = options.path || await findFlintRoot(process.cwd());
11239
11797
  if (!flintPath) {
@@ -11269,7 +11827,7 @@ Removed reference repository: ${pc23.bold(name)}`));
11269
11827
  }
11270
11828
  })
11271
11829
  ).addCommand(
11272
- new Command21("updatereferencerepo").description("Re-fetch a reference repository (delete and re-clone)").argument("<name>", "Name of the reference repository to update").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (name, options) => {
11830
+ new Command20("updatereferencerepo").description("Re-fetch a reference repository (delete and re-clone)").argument("<name>", "Name of the reference repository to update").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (name, options) => {
11273
11831
  try {
11274
11832
  const flintPath = options.path || await findFlintRoot(process.cwd());
11275
11833
  if (!flintPath) {
@@ -11300,7 +11858,7 @@ Updated reference repository: ${pc23.bold(name)}`));
11300
11858
  }
11301
11859
  })
11302
11860
  ).addCommand(
11303
- new Command21("listreferencerepo").description("List reference repositories").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (options) => {
11861
+ new Command20("listreferencerepo").description("List reference repositories").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (options) => {
11304
11862
  try {
11305
11863
  const flintPath = options.path || await findFlintRoot(process.cwd());
11306
11864
  if (!flintPath) {
@@ -11347,7 +11905,7 @@ Updated reference repository: ${pc23.bold(name)}`));
11347
11905
  );
11348
11906
 
11349
11907
  // src/commands/subflint.ts
11350
- import { Command as Command22 } from "commander";
11908
+ import { Command as Command21 } from "commander";
11351
11909
  import pc24 from "picocolors";
11352
11910
  import * as readline2 from "readline";
11353
11911
  import { spawn as spawn5 } from "child_process";
@@ -11393,7 +11951,7 @@ async function resolveParentFlintPath(pathOverride) {
11393
11951
  }
11394
11952
  return getParentFlintPath(detected) ?? detected;
11395
11953
  }
11396
- var subflintCommand = new Command22("subflint").description("Manage subflints (nested unregistered Flints)").argument("[name]", "Subflint name (wrapper mode)").argument("[command...]", "Command to run inside the subflint").option("-p, --path <dir>", "Path to parent flint (default: auto-detect)").allowUnknownOption(true).action(async (name, command, options, commandInstance) => {
11954
+ var subflintCommand = new Command21("subflint").description("Manage subflints (nested unregistered Flints)").argument("[name]", "Subflint name (wrapper mode)").argument("[command...]", "Command to run inside the subflint").option("-p, --path <dir>", "Path to parent flint (default: auto-detect)").allowUnknownOption(true).action(async (name, command, options, commandInstance) => {
11397
11955
  if (!name || command.length === 0) {
11398
11956
  commandInstance.help();
11399
11957
  return;
@@ -11435,7 +11993,7 @@ var subflintCommand = new Command22("subflint").description("Manage subflints (n
11435
11993
  process.exit(code ?? 1);
11436
11994
  });
11437
11995
  }).addCommand(
11438
- new Command22("create").description("Create a new subflint").argument("<name>", "Name of the subflint").option("-p, --path <dir>", "Path to flint (default: auto-detect)").option("--preset <preset>", "Preset to use (e.g., blank, vessel, spec)", "blank").option("-d, --description <desc>", "Description for the subflint").action(async (name, options) => {
11996
+ new Command21("create").description("Create a new subflint").argument("<name>", "Name of the subflint").option("-p, --path <dir>", "Path to flint (default: auto-detect)").option("--preset <preset>", "Preset to use (e.g., blank, vessel, spec)", "blank").option("-d, --description <desc>", "Description for the subflint").action(async (name, options) => {
11439
11997
  try {
11440
11998
  const flintPath = options.path || await findFlintRoot(process.cwd());
11441
11999
  if (!flintPath) {
@@ -11510,7 +12068,7 @@ Subflint created at: ${pc24.cyan(abbreviatePath(entry.path))}`);
11510
12068
  }
11511
12069
  })
11512
12070
  ).addCommand(
11513
- new Command22("list").description("List all subflints").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (options) => {
12071
+ new Command21("list").description("List all subflints").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (options) => {
11514
12072
  try {
11515
12073
  const flintPath = options.path || await findFlintRoot(process.cwd());
11516
12074
  if (!flintPath) {
@@ -11544,7 +12102,7 @@ Subflint created at: ${pc24.cyan(abbreviatePath(entry.path))}`);
11544
12102
  }
11545
12103
  })
11546
12104
  ).addCommand(
11547
- new Command22("sync").description("Discover subflints and report status").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (options) => {
12105
+ new Command21("sync").description("Discover subflints and report status").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (options) => {
11548
12106
  try {
11549
12107
  const flintPath = await resolveParentFlintPath(options.path);
11550
12108
  if (!flintPath) {
@@ -11573,7 +12131,7 @@ Discovered ${subflints.length} subflint(s):
11573
12131
  }
11574
12132
  })
11575
12133
  ).addCommand(
11576
- new Command22("remove").description("Remove a subflint").argument("<name>", "Name of the subflint to remove").option("-p, --path <dir>", "Path to flint (default: auto-detect)").option("-y, --yes", "Skip confirmation").action(async (name, options) => {
12134
+ new Command21("remove").description("Remove a subflint").argument("<name>", "Name of the subflint to remove").option("-p, --path <dir>", "Path to flint (default: auto-detect)").option("-y, --yes", "Skip confirmation").action(async (name, options) => {
11577
12135
  try {
11578
12136
  const flintPath = options.path || await findFlintRoot(process.cwd());
11579
12137
  if (!flintPath) {
@@ -11609,7 +12167,7 @@ Removed subflint ${pc24.bold(removed.name)}`));
11609
12167
  }
11610
12168
  })
11611
12169
  ).addCommand(
11612
- new Command22("promote").description("Promote a subflint to a registered Flint").argument("<name>", "Name of the subflint to promote").option("-p, --path <dir>", "Path to flint (default: auto-detect)").option("-t, --to <destination>", "Destination path for the promoted Flint").option("-d, --dest <destination>", "Alias for --to").action(async (name, options) => {
12170
+ new Command21("promote").description("Promote a subflint to a registered Flint").argument("<name>", "Name of the subflint to promote").option("-p, --path <dir>", "Path to flint (default: auto-detect)").option("-t, --to <destination>", "Destination path for the promoted Flint").option("-d, --dest <destination>", "Alias for --to").action(async (name, options) => {
11613
12171
  try {
11614
12172
  const flintPath = options.path || await findFlintRoot(process.cwd());
11615
12173
  if (!flintPath) {
@@ -11658,7 +12216,7 @@ Promoted ${pc24.bold(name)} to registered Flint`));
11658
12216
  );
11659
12217
 
11660
12218
  // src/commands/lattice.ts
11661
- import { Command as Command23 } from "commander";
12219
+ import { Command as Command22 } from "commander";
11662
12220
  import pc25 from "picocolors";
11663
12221
 
11664
12222
  // ../../packages/lattice/src/paths.ts
@@ -11695,7 +12253,7 @@ function resolveLatticePaths(latticePath, config) {
11695
12253
  }
11696
12254
 
11697
12255
  // ../../packages/lattice/src/config.ts
11698
- import { readFile as readFile10, writeFile as writeFile8, stat as stat12 } from "fs/promises";
12256
+ import { readFile as readFile11, writeFile as writeFile8, stat as stat12 } from "fs/promises";
11699
12257
 
11700
12258
  // ../../packages/lattice/src/utils.ts
11701
12259
  function toSlug(name) {
@@ -11716,7 +12274,7 @@ function toMeshFileName(latticeName, exportName, fileName) {
11716
12274
  async function readLatticeToml(latticePath) {
11717
12275
  const configPath = getLatticeConfigPath(latticePath);
11718
12276
  try {
11719
- const content = await readFile10(configPath, "utf-8");
12277
+ const content = await readFile11(configPath, "utf-8");
11720
12278
  return parse(content);
11721
12279
  } catch (error3) {
11722
12280
  if (error3.code === "ENOENT") {
@@ -11913,7 +12471,7 @@ async function runExport(latticePath, config, exportType) {
11913
12471
  }
11914
12472
 
11915
12473
  // ../../packages/lattice/src/sync.ts
11916
- import { mkdir as mkdir14, stat as stat14, writeFile as writeFile9, rm as rm11, readdir as readdir9, copyFile as copyFile3 } from "fs/promises";
12474
+ import { mkdir as mkdir14, stat as stat14, writeFile as writeFile9, rm as rm11, readdir as readdir10, copyFile as copyFile3 } from "fs/promises";
11917
12475
  import { join as join30 } from "path";
11918
12476
  async function fileExists3(path3) {
11919
12477
  try {
@@ -12067,7 +12625,7 @@ async function syncLatticeToMesh(latticePath, meshLatticeBase) {
12067
12625
  async function copyExportsToMesh(sourceDir, targetDir, latticeName, exportName, meshFiles) {
12068
12626
  let entries;
12069
12627
  try {
12070
- entries = await readdir9(sourceDir, { withFileTypes: true });
12628
+ entries = await readdir10(sourceDir, { withFileTypes: true });
12071
12629
  } catch {
12072
12630
  return;
12073
12631
  }
@@ -12103,8 +12661,8 @@ async function resolveFlintPath(pathOption) {
12103
12661
  }
12104
12662
  return flintPath;
12105
12663
  }
12106
- var latticeCommand = new Command23("lattice").description("Manage lattices configured in flint.toml").option("-p, --path <dir>", "Path to flint (default: auto-detect)").addCommand(
12107
- new Command23("list").description("List lattices configured in flint.toml").action(async function() {
12664
+ var latticeCommand = new Command22("lattice").description("Manage lattices configured in flint.toml").option("-p, --path <dir>", "Path to flint (default: auto-detect)").addCommand(
12665
+ new Command22("list").description("List lattices configured in flint.toml").action(async function() {
12108
12666
  const options = this.parent?.opts();
12109
12667
  const flintPath = await resolveFlintPath(options?.path);
12110
12668
  const config = await readFlintToml(flintPath);
@@ -12120,7 +12678,7 @@ var latticeCommand = new Command23("lattice").description("Manage lattices confi
12120
12678
  }
12121
12679
  })
12122
12680
  ).addCommand(
12123
- new Command23("sync").description("Sync lattice exports to Mesh/Lattice/").argument("[name]", "Lattice name").option("--all", "Sync all lattices").action(async function(name, options) {
12681
+ new Command22("sync").description("Sync lattice exports to Mesh/Lattice/").argument("[name]", "Lattice name").option("--all", "Sync all lattices").action(async function(name, options) {
12124
12682
  const parentOptions = this.parent?.opts();
12125
12683
  const flintPath = await resolveFlintPath(parentOptions?.path);
12126
12684
  const config = await readFlintToml(flintPath);
@@ -12170,7 +12728,7 @@ var latticeCommand = new Command23("lattice").description("Manage lattices confi
12170
12728
  }
12171
12729
  })
12172
12730
  ).addCommand(
12173
- new Command23("status").description("Check lattice connection status").argument("[name]", "Lattice name").option("--all", "Check all lattices").action(async function(name, options) {
12731
+ new Command22("status").description("Check lattice connection status").argument("[name]", "Lattice name").option("--all", "Check all lattices").action(async function(name, options) {
12174
12732
  const parentOptions = this.parent?.opts();
12175
12733
  const flintPath = await resolveFlintPath(parentOptions?.path);
12176
12734
  const config = await readFlintToml(flintPath);
@@ -12214,9 +12772,9 @@ var latticeCommand = new Command23("lattice").description("Manage lattices confi
12214
12772
  );
12215
12773
 
12216
12774
  // src/commands/server.ts
12217
- import { Command as Command24 } from "commander";
12775
+ import { Command as Command23 } from "commander";
12218
12776
  import pc26 from "picocolors";
12219
- var serverCommand = new Command24("server").description("Manage the local Flint server");
12777
+ var serverCommand = new Command23("server").description("Manage the local Flint server");
12220
12778
  serverCommand.command("start").description("Start the Flint server").option("-p, --port <port>", "Port to bind", "7433").option("--host <host>", "Host to bind", "127.0.0.1").action(async (options) => {
12221
12779
  const port = Number(options.port);
12222
12780
  const host = options.host;
@@ -12285,10 +12843,10 @@ serverCommand.command("stop").description("Stop the Flint server").option("--ser
12285
12843
  });
12286
12844
 
12287
12845
  // src/commands/runtime.ts
12288
- import { Command as Command25 } from "commander";
12846
+ import { Command as Command24 } from "commander";
12289
12847
  import pc27 from "picocolors";
12290
12848
  import path2 from "path";
12291
- var runtimeCommand = new Command25("runtime").description("Manage Flint runtimes");
12849
+ var runtimeCommand = new Command24("runtime").description("Manage Flint runtimes");
12292
12850
  runtimeCommand.command("start [flintPath]").description("Start runtime for a Flint").option("--server <url>", "Server URL", "http://127.0.0.1:7433").action(async (flintPath, options) => {
12293
12851
  const serverUrl = options.server;
12294
12852
  const resolvedPath = flintPath ? path2.resolve(flintPath) : await findFlintRoot(process.cwd());
@@ -12382,41 +12940,69 @@ ${pc27.bold("Active Runtimes")}
12382
12940
  });
12383
12941
 
12384
12942
  // src/commands/code.ts
12385
- import { Command as Command26 } from "commander";
12943
+ import { Command as Command25 } from "commander";
12386
12944
  import pc28 from "picocolors";
12387
12945
  import { spawn as spawn7 } from "child_process";
12388
12946
  import { createInterface as createInterface6 } from "readline";
12947
+ import { existsSync as existsSync5 } from "fs";
12389
12948
  var CLIENT_INFO = {
12390
12949
  name: "flint_code",
12391
12950
  title: "Flint Code",
12392
12951
  version: "0.1.0"
12393
12952
  };
12394
- async function getCodexThreadId(cwd) {
12953
+ async function bootstrapCodexSession(cwd, initPrompt) {
12395
12954
  return new Promise((resolve16, reject) => {
12396
12955
  const proc = spawn7("codex", ["app-server"], {
12397
- stdio: ["pipe", "pipe", "inherit"],
12956
+ stdio: ["pipe", "pipe", "pipe"],
12398
12957
  cwd
12399
12958
  });
12400
12959
  const rl = createInterface6({ input: proc.stdout });
12401
12960
  const send = (msg) => proc.stdin.write(`${JSON.stringify(msg)}
12402
12961
  `);
12403
- let msgId = 0;
12962
+ let threadId = null;
12963
+ let sessionPath = null;
12404
12964
  const timeout = setTimeout(() => {
12405
12965
  proc.kill();
12406
- reject(new Error("Timeout waiting for Codex thread ID"));
12966
+ reject(new Error("Timeout waiting for Codex session"));
12407
12967
  }, 3e4);
12968
+ const cleanup = () => {
12969
+ clearTimeout(timeout);
12970
+ rl.close();
12971
+ };
12972
+ let pollInterval = null;
12973
+ const startPolling = () => {
12974
+ pollInterval = setInterval(() => {
12975
+ if (sessionPath && existsSync5(sessionPath)) {
12976
+ if (pollInterval) clearInterval(pollInterval);
12977
+ send({ method: "turn/interrupt", id: 4, params: { threadId } });
12978
+ setTimeout(() => {
12979
+ cleanup();
12980
+ proc.kill();
12981
+ resolve16(threadId);
12982
+ }, 500);
12983
+ }
12984
+ }, 200);
12985
+ };
12408
12986
  rl.on("line", (line) => {
12409
12987
  try {
12410
12988
  const msg = JSON.parse(line);
12411
12989
  if (msg.id === 2 && msg.result?.thread?.id) {
12412
- clearTimeout(timeout);
12413
- rl.close();
12414
- proc.kill();
12415
- resolve16(msg.result.thread.id);
12990
+ threadId = msg.result.thread.id;
12991
+ sessionPath = msg.result.thread.path;
12992
+ send({
12993
+ method: "turn/start",
12994
+ id: 3,
12995
+ params: {
12996
+ threadId,
12997
+ input: [{ type: "text", text: initPrompt }]
12998
+ }
12999
+ });
13000
+ }
13001
+ if (msg.id === 3 && msg.result?.turn) {
13002
+ startPolling();
12416
13003
  }
12417
- if (msg.error && msg.id <= 2) {
12418
- clearTimeout(timeout);
12419
- rl.close();
13004
+ if (msg.error && msg.id <= 3) {
13005
+ cleanup();
12420
13006
  proc.kill();
12421
13007
  reject(new Error(msg.error.message));
12422
13008
  }
@@ -12424,19 +13010,15 @@ async function getCodexThreadId(cwd) {
12424
13010
  }
12425
13011
  });
12426
13012
  proc.on("error", (err) => {
12427
- clearTimeout(timeout);
13013
+ cleanup();
12428
13014
  reject(err);
12429
13015
  });
12430
- send({ method: "initialize", id: msgId++, params: { clientInfo: CLIENT_INFO } });
13016
+ send({ method: "initialize", id: 0, params: { clientInfo: CLIENT_INFO } });
12431
13017
  send({ method: "initialized", params: {} });
12432
- send({
12433
- method: "thread/start",
12434
- id: 2,
12435
- params: { cwd }
12436
- });
13018
+ send({ method: "thread/start", id: 2, params: { cwd } });
12437
13019
  });
12438
13020
  }
12439
- var codeCommand = new Command26("code").description("Launch AI coding agents in the current flint");
13021
+ var codeCommand = new Command25("code").description("Launch AI coding agents in the current flint");
12440
13022
  codeCommand.command("claude").description("Open Claude Code TUI").option("-p, --path <dir>", "Path to flint (default: auto-detect)").action(async (options) => {
12441
13023
  try {
12442
13024
  const flintPath = options.path || await findFlintRoot(process.cwd());
@@ -12483,10 +13065,11 @@ codeCommand.command("codex").description("Open Codex TUI with session tracking")
12483
13065
  );
12484
13066
  process.exit(1);
12485
13067
  }
13068
+ const bootstrapPrompt = "init, you are a codex session, please read init-f.md and (System) Flint Init.md";
12486
13069
  console.log(pc28.dim("Starting Codex session..."));
12487
13070
  let threadId;
12488
13071
  try {
12489
- threadId = await getCodexThreadId(flintPath);
13072
+ threadId = await bootstrapCodexSession(flintPath, bootstrapPrompt);
12490
13073
  } catch (err) {
12491
13074
  if (err.code === "ENOENT") {
12492
13075
  console.error(pc28.red("Error: Codex is not installed."));
@@ -12499,13 +13082,14 @@ codeCommand.command("codex").description("Open Codex TUI with session tracking")
12499
13082
  }
12500
13083
  console.log(pc28.green(`Session ID: ${threadId}`));
12501
13084
  console.log("");
12502
- const initPrompt = `init, you are a codex session, session id is ${threadId}`;
13085
+ const resumePrompt = `your session id is ${threadId}`;
12503
13086
  const child = spawn7("codex", [
12504
13087
  "resume",
12505
13088
  threadId,
12506
13089
  "-a",
12507
13090
  "never",
12508
- initPrompt
13091
+ "--full-auto",
13092
+ resumePrompt
12509
13093
  ], {
12510
13094
  cwd: flintPath,
12511
13095
  stdio: "inherit"
@@ -12525,9 +13109,9 @@ codeCommand.command("codex").description("Open Codex TUI with session tracking")
12525
13109
  });
12526
13110
 
12527
13111
  // src/commands/helper.ts
12528
- import { Command as Command27 } from "commander";
13112
+ import { Command as Command26 } from "commander";
12529
13113
  import pc29 from "picocolors";
12530
- import { readdirSync, existsSync as existsSync5, statSync } from "fs";
13114
+ import { readdirSync, existsSync as existsSync6, statSync } from "fs";
12531
13115
  import { join as join34, basename as basename8 } from "path";
12532
13116
  function extractNumberFromFile(filename, typeName) {
12533
13117
  const regex = new RegExp(`^\\(${typeName}\\)\\s+(\\d+)`, "i");
@@ -12536,7 +13120,7 @@ function extractNumberFromFile(filename, typeName) {
12536
13120
  }
12537
13121
  function collectFilesRecursively(dirPath) {
12538
13122
  const files = [];
12539
- if (!existsSync5(dirPath)) {
13123
+ if (!existsSync6(dirPath)) {
12540
13124
  return files;
12541
13125
  }
12542
13126
  const entries = readdirSync(dirPath);
@@ -12557,7 +13141,7 @@ function collectFilesRecursively(dirPath) {
12557
13141
  }
12558
13142
  function getNextNumber(flintPath, typeName) {
12559
13143
  const meshDir = join34(flintPath, "Mesh");
12560
- if (!existsSync5(meshDir)) {
13144
+ if (!existsSync6(meshDir)) {
12561
13145
  return 1;
12562
13146
  }
12563
13147
  const allFiles = collectFilesRecursively(meshDir);
@@ -12570,9 +13154,9 @@ function getNextNumber(flintPath, typeName) {
12570
13154
  function formatNumber(num, padding = 3) {
12571
13155
  return num.toString().padStart(padding, "0");
12572
13156
  }
12573
- var helperCommand = new Command27("helper").description("Helper utilities for Flint workflows").addCommand(
12574
- new Command27("type").description("Type-specific helpers").addCommand(
12575
- new Command27("newnumber").description("Get the next available number for a typed artifact").argument("<type>", "Type name (Task, Report, Notepad, Increment, etc.)").option("-p, --path <dir>", "Path to flint (default: auto-detect)").option("--raw", "Output raw number without padding").action(async (typeName, options) => {
13157
+ var helperCommand = new Command26("helper").description("Helper utilities for Flint workflows").addCommand(
13158
+ new Command26("type").description("Type-specific helpers").addCommand(
13159
+ new Command26("newnumber").description("Get the next available number for a typed artifact").argument("<type>", "Type name (Task, Report, Notepad, Increment, etc.)").option("-p, --path <dir>", "Path to flint (default: auto-detect)").option("--raw", "Output raw number without padding").action(async (typeName, options) => {
12576
13160
  try {
12577
13161
  const flintPath = options.path || await findFlintRoot(process.cwd());
12578
13162
  if (!flintPath) {
@@ -12595,7 +13179,7 @@ var helperCommand = new Command27("helper").description("Helper utilities for Fl
12595
13179
  );
12596
13180
 
12597
13181
  // src/commands/delete.ts
12598
- import { Command as Command28 } from "commander";
13182
+ import { Command as Command27 } from "commander";
12599
13183
  import pc30 from "picocolors";
12600
13184
  import { rm as rm12 } from "fs/promises";
12601
13185
  import { resolve as resolve15 } from "path";
@@ -12612,7 +13196,7 @@ async function prompt4(question) {
12612
13196
  });
12613
13197
  });
12614
13198
  }
12615
- var deleteCommand = new Command28("delete").description("Permanently delete a flint (folder + registry)").argument("[name-or-path]", "Flint name or path (defaults to current directory)").action(async (nameOrPath) => {
13199
+ var deleteCommand = new Command27("delete").description("Permanently delete a flint (folder + registry)").argument("[name-or-path]", "Flint name or path (defaults to current directory)").option("-f, --force", "Skip confirmation prompt").action(async (nameOrPath, options) => {
12616
13200
  try {
12617
13201
  let entry;
12618
13202
  if (nameOrPath) {
@@ -12638,18 +13222,20 @@ var deleteCommand = new Command28("delete").description("Permanently delete a fl
12638
13222
  process.exit(1);
12639
13223
  }
12640
13224
  }
12641
- console.log();
12642
- console.log(pc30.red(pc30.bold(" This will permanently delete:")));
12643
- console.log();
12644
- console.log(` Name: ${pc30.bold(entry.name)}`);
12645
- console.log(` Path: ${pc30.cyan(abbreviatePath(entry.path))}`);
12646
- console.log();
12647
- const answer = await prompt4(` Type ${pc30.bold(entry.name)} to confirm: `);
12648
- if (answer !== entry.name) {
13225
+ if (!options.force) {
12649
13226
  console.log();
12650
- console.log(pc30.dim(" Cancelled \u2014 name did not match."));
13227
+ console.log(pc30.red(pc30.bold(" This will permanently delete:")));
12651
13228
  console.log();
12652
- process.exit(0);
13229
+ console.log(` Name: ${pc30.bold(entry.name)}`);
13230
+ console.log(` Path: ${pc30.cyan(abbreviatePath(entry.path))}`);
13231
+ console.log();
13232
+ const answer = await prompt4(` Type ${pc30.bold(entry.name)} to confirm: `);
13233
+ if (answer !== entry.name) {
13234
+ console.log();
13235
+ console.log(pc30.dim(" Cancelled \u2014 name did not match."));
13236
+ console.log();
13237
+ process.exit(0);
13238
+ }
12653
13239
  }
12654
13240
  await unregisterFlint(entry.path);
12655
13241
  await rm12(entry.path, { recursive: true });
@@ -12670,7 +13256,7 @@ var featuresCommand = createFeaturesCommand({
12670
13256
  });
12671
13257
 
12672
13258
  // src/commands/org.ts
12673
- import { Command as Command29 } from "commander";
13259
+ import { Command as Command28 } from "commander";
12674
13260
  import pc31 from "picocolors";
12675
13261
  var ORGS_CONVEX_URL_PROD = "https://impressive-ptarmigan-132.convex.site";
12676
13262
  var ORGS_CONVEX_URL_DEV = "https://steady-lobster-998.convex.site";
@@ -12703,7 +13289,7 @@ async function requireAuth(env) {
12703
13289
  }
12704
13290
  var runtime = resolveRuntimeSync({ cliname: "flint" });
12705
13291
  var devAvailable = runtime.mode === "dev";
12706
- var orgCommand = new Command29("org").description("Organisation management");
13292
+ var orgCommand = new Command28("org").description("Organisation management");
12707
13293
  var registerCmd = orgCommand.command("register").description("Register this flint to an organisation").argument("<slug>", "Organisation slug");
12708
13294
  if (devAvailable) registerCmd.option("--dev", "Use dev environment");
12709
13295
  registerCmd.action(async (slug, options) => {
@@ -12758,7 +13344,7 @@ var newDir = getConfigDir("flint");
12758
13344
  var oldDir = join35(homedir5(), ".flint");
12759
13345
  var intermediateDir = join35(homedir5(), ".nuucognition", ".flint");
12760
13346
  function migrateDir(sourceDir, label) {
12761
- if (!existsSync6(sourceDir)) return false;
13347
+ if (!existsSync7(sourceDir)) return false;
12762
13348
  try {
12763
13349
  const entries = readdirSync2(sourceDir);
12764
13350
  const filesToMigrate = entries.filter((e) => !e.startsWith(".DS_Store"));
@@ -12768,7 +13354,7 @@ function migrateDir(sourceDir, label) {
12768
13354
  for (const entry of filesToMigrate) {
12769
13355
  const src = join35(sourceDir, entry);
12770
13356
  const dest = join35(newDir, entry);
12771
- if (!existsSync6(dest)) {
13357
+ if (!existsSync7(dest)) {
12772
13358
  cpSync(src, dest, { recursive: true });
12773
13359
  migrated++;
12774
13360
  }
@@ -12810,7 +13396,7 @@ var authConfig = {
12810
13396
  defaultEnv: devAvailable2 ? "dev" : "prod",
12811
13397
  devAvailable: devAvailable2
12812
13398
  };
12813
- var program = new Command30();
13399
+ var program = new Command29();
12814
13400
  program.name("flint").description("Flint cognitive workspace CLI").version(pkg.version).enablePositionalOptions().option("--verbose", "Show stack traces for errors");
12815
13401
  program.addCommand(createLoginCommand(authConfig));
12816
13402
  program.addCommand(createLogoutCommand(authConfig));
@@ -12818,7 +13404,6 @@ program.addCommand(createWhoamiCommand(authConfig));
12818
13404
  var COMMAND_MAP = [
12819
13405
  // Production commands
12820
13406
  { featureId: "init", command: initCommand },
12821
- { featureId: "clone", command: cloneCommand },
12822
13407
  { featureId: "list", command: listCommand },
12823
13408
  { featureId: "shard", command: shardCommand },
12824
13409
  { featureId: "sync", command: syncCommand },