@flydocs/cli 0.6.0-alpha.32 → 0.6.0-alpha.33

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/cli.js CHANGED
@@ -15,7 +15,7 @@ var CLI_VERSION, CLI_NAME, PACKAGE_NAME, POSTHOG_API_KEY;
15
15
  var init_constants = __esm({
16
16
  "src/lib/constants.ts"() {
17
17
  "use strict";
18
- CLI_VERSION = "0.6.0-alpha.32";
18
+ CLI_VERSION = "0.6.0-alpha.33";
19
19
  CLI_NAME = "flydocs";
20
20
  PACKAGE_NAME = "@flydocs/cli";
21
21
  POSTHOG_API_KEY = "phc_v1MSJTQDFkMS90CBh3mxIz3v8bYCCnKU6v1ir6bz0Xn";
@@ -281,7 +281,7 @@ var init_types = __esm({
281
281
  // src/lib/config-integrity.ts
282
282
  import { createHash } from "crypto";
283
283
  function computeConfigHash(config) {
284
- const { configHash: _, ...rest } = config;
284
+ const { configHash: _, artifactOverrides: _overrides, ...rest } = config;
285
285
  const serialized = JSON.stringify(rest, Object.keys(rest).sort());
286
286
  return `sha256:${createHash("sha256").update(serialized, "utf-8").digest("hex")}`;
287
287
  }
@@ -423,7 +423,7 @@ async function installOwnedSkills(templateDir, targetDir, _tier) {
423
423
  async function replaceOwnedSkills(templateDir, targetDir, _tier) {
424
424
  const skillsDir = join4(targetDir, ".claude", "skills");
425
425
  const templateSkillsDir = join4(templateDir, ".claude", "skills");
426
- const { rm: rm7 } = await import("fs/promises");
426
+ const { rm: rm9 } = await import("fs/promises");
427
427
  await replaceDirectory(
428
428
  join4(templateSkillsDir, OWNED_SKILL),
429
429
  join4(skillsDir, OWNED_SKILL)
@@ -431,7 +431,7 @@ async function replaceOwnedSkills(templateDir, targetDir, _tier) {
431
431
  for (const legacy of LEGACY_SKILLS) {
432
432
  const legacyPath = join4(skillsDir, legacy);
433
433
  if (await pathExists(legacyPath)) {
434
- await rm7(legacyPath, { recursive: true, force: true });
434
+ await rm9(legacyPath, { recursive: true, force: true });
435
435
  }
436
436
  }
437
437
  const readmeSrc = join4(templateSkillsDir, "README.md");
@@ -440,9 +440,9 @@ async function replaceOwnedSkills(templateDir, targetDir, _tier) {
440
440
  }
441
441
  }
442
442
  async function copyCursorRules(targetDir) {
443
- const { mkdir: mkdir15 } = await import("fs/promises");
443
+ const { mkdir: mkdir16 } = await import("fs/promises");
444
444
  const rulesDir = join4(targetDir, ".cursor", "rules");
445
- await mkdir15(rulesDir, { recursive: true });
445
+ await mkdir16(rulesDir, { recursive: true });
446
446
  const workflowRule = join4(
447
447
  targetDir,
448
448
  ".claude",
@@ -453,11 +453,11 @@ async function copyCursorRules(targetDir) {
453
453
  if (await pathExists(workflowRule)) {
454
454
  await copyFile(workflowRule, join4(rulesDir, "flydocs-workflow.mdc"));
455
455
  }
456
- const { rm: rm7 } = await import("fs/promises");
456
+ const { rm: rm9 } = await import("fs/promises");
457
457
  for (const legacy of ["flydocs-mechanism.mdc", "flydocs-context7.mdc"]) {
458
458
  const legacyRule = join4(rulesDir, legacy);
459
459
  if (await pathExists(legacyRule)) {
460
- await rm7(legacyRule, { force: true });
460
+ await rm9(legacyRule, { force: true });
461
461
  }
462
462
  }
463
463
  }
@@ -3102,29 +3102,125 @@ var init_relay_client = __esm({
3102
3102
  }
3103
3103
  });
3104
3104
 
3105
+ // src/lib/managed-paths.ts
3106
+ import { join as join18 } from "path";
3107
+ import { readdir as readdir4, rm as rm4, unlink } from "fs/promises";
3108
+ function isSkipped(path, skipPaths) {
3109
+ return skipPaths.some((skip) => path === skip || path.startsWith(skip));
3110
+ }
3111
+ async function wipeManagedPaths(targetDir, skipPaths = []) {
3112
+ let deleted = 0;
3113
+ let skipped = 0;
3114
+ for (const dir of MANAGED_DIRECTORIES) {
3115
+ const fullPath = join18(targetDir, dir);
3116
+ if (isSkipped(dir + "/", skipPaths) || isSkipped(dir, skipPaths)) {
3117
+ if (await pathExists(fullPath)) {
3118
+ skipped++;
3119
+ }
3120
+ continue;
3121
+ }
3122
+ if (await pathExists(fullPath)) {
3123
+ await rm4(fullPath, { recursive: true, force: true });
3124
+ deleted++;
3125
+ }
3126
+ }
3127
+ for (const file of MANAGED_FILES) {
3128
+ if (isSkipped(file, skipPaths)) {
3129
+ skipped++;
3130
+ continue;
3131
+ }
3132
+ const fullPath = join18(targetDir, file);
3133
+ if (await pathExists(fullPath)) {
3134
+ await unlink(fullPath);
3135
+ deleted++;
3136
+ }
3137
+ }
3138
+ const skillsDir = join18(targetDir, ".claude", "skills");
3139
+ if (await pathExists(skillsDir)) {
3140
+ const entries = await readdir4(skillsDir, { withFileTypes: true });
3141
+ for (const entry of entries) {
3142
+ if (!entry.isDirectory()) continue;
3143
+ if (!entry.name.startsWith(CORE_SKILL_PREFIX)) continue;
3144
+ const skillPath = `.claude/skills/${entry.name}/`;
3145
+ if (isSkipped(skillPath, skipPaths)) {
3146
+ skipped++;
3147
+ continue;
3148
+ }
3149
+ await rm4(join18(skillsDir, entry.name), { recursive: true, force: true });
3150
+ deleted++;
3151
+ }
3152
+ }
3153
+ if (deleted > 0) {
3154
+ printStatus(`Wiped ${deleted} managed path(s)`);
3155
+ }
3156
+ if (skipped > 0) {
3157
+ printInfo(`Preserved ${skipped} path(s) via skipPaths override`);
3158
+ }
3159
+ return { deleted, skipped };
3160
+ }
3161
+ var MANAGED_DIRECTORIES, MANAGED_FILES, CORE_SKILL_PREFIX;
3162
+ var init_managed_paths = __esm({
3163
+ "src/lib/managed-paths.ts"() {
3164
+ "use strict";
3165
+ init_fs_ops();
3166
+ init_ui();
3167
+ MANAGED_DIRECTORIES = [
3168
+ ".claude/hooks",
3169
+ ".claude/commands",
3170
+ ".claude/agents",
3171
+ ".cursor/rules",
3172
+ ".cursor/commands",
3173
+ ".cursor/agents"
3174
+ ];
3175
+ MANAGED_FILES = [
3176
+ ".claude/settings.json",
3177
+ ".claude/CLAUDE.md",
3178
+ ".cursor/hooks.json",
3179
+ "AGENTS.md"
3180
+ ];
3181
+ CORE_SKILL_PREFIX = "flydocs-";
3182
+ }
3183
+ });
3184
+
3105
3185
  // src/lib/artifacts.ts
3106
3186
  import { mkdir as mkdir9, writeFile as writeFile11 } from "fs/promises";
3107
- import { join as join18, dirname as dirname3 } from "path";
3108
- async function syncArtifacts(targetDir, apiKey, workspaceId, currentVersion) {
3187
+ import { join as join19, dirname as dirname3 } from "path";
3188
+ function isPathSkipped(artifactPath, skipPaths) {
3189
+ return skipPaths.some(
3190
+ (skip) => artifactPath === skip || artifactPath.startsWith(skip)
3191
+ );
3192
+ }
3193
+ async function syncArtifacts(targetDir, apiKey, workspaceId, currentVersion, skipPaths = []) {
3109
3194
  const response = await fetchArtifacts(apiKey, currentVersion);
3110
3195
  if (response.artifacts.length === 0) {
3111
- return { written: 0, version: currentVersion };
3196
+ return { written: 0, skipped: 0, version: currentVersion };
3112
3197
  }
3113
3198
  let written = 0;
3199
+ let skipped = 0;
3114
3200
  for (const artifact of response.artifacts) {
3201
+ if (skipPaths.length > 0 && isPathSkipped(artifact.path, skipPaths)) {
3202
+ skipped++;
3203
+ continue;
3204
+ }
3115
3205
  await writeArtifact(targetDir, artifact);
3116
3206
  written++;
3117
3207
  }
3118
3208
  printStatus(
3119
3209
  `Synced ${written} artifact(s) (v${currentVersion} \u2192 v${response.version})`
3120
3210
  );
3121
- return { written, version: response.version };
3211
+ if (skipped > 0) {
3212
+ printInfo(`Skipped ${skipped} artifact(s) via artifactOverrides.skipPaths`);
3213
+ }
3214
+ return { written, skipped, version: response.version };
3122
3215
  }
3123
- async function syncAgentConfigs(targetDir, apiKey, workspaceId) {
3216
+ async function syncAgentConfigs(targetDir, apiKey, workspaceId, skipPaths = []) {
3124
3217
  const response = await fetchAgentConfigs(apiKey, workspaceId);
3125
3218
  let written = 0;
3126
3219
  for (const file of response.files) {
3127
- const filePath = join18(targetDir, file.path);
3220
+ if (skipPaths.length > 0 && isPathSkipped(file.path, skipPaths)) {
3221
+ continue;
3222
+ }
3223
+ const filePath = join19(targetDir, file.path);
3128
3224
  await mkdir9(dirname3(filePath), { recursive: true });
3129
3225
  await writeFile11(filePath, file.content, "utf-8");
3130
3226
  written++;
@@ -3135,24 +3231,37 @@ async function syncAgentConfigs(targetDir, apiKey, workspaceId) {
3135
3231
  return written;
3136
3232
  }
3137
3233
  async function writeArtifact(targetDir, artifact) {
3138
- const filePath = join18(targetDir, artifact.path);
3234
+ const filePath = join19(targetDir, artifact.path);
3139
3235
  await mkdir9(dirname3(filePath), { recursive: true });
3140
3236
  await writeFile11(filePath, artifact.content, "utf-8");
3141
3237
  }
3142
- async function syncAllArtifacts(targetDir, apiKey, workspaceId, currentArtifactVersion) {
3238
+ async function syncAllArtifacts(targetDir, apiKey, workspaceId, currentArtifactVersion, skipPaths = []) {
3143
3239
  const changes = [];
3144
3240
  let artifactVersion = currentArtifactVersion;
3241
+ const { deleted, skipped } = await wipeManagedPaths(targetDir, skipPaths);
3242
+ if (deleted > 0) {
3243
+ changes.push(`Wiped ${deleted} managed path(s)`);
3244
+ }
3245
+ if (skipped > 0) {
3246
+ changes.push(`Preserved ${skipped} path(s) (skipPaths override)`);
3247
+ }
3145
3248
  try {
3146
3249
  const result = await syncArtifacts(
3147
3250
  targetDir,
3148
3251
  apiKey,
3149
3252
  workspaceId,
3150
- currentArtifactVersion
3253
+ currentArtifactVersion,
3254
+ skipPaths
3151
3255
  );
3152
3256
  if (result.written > 0) {
3153
3257
  changes.push(`Synced ${result.written} artifact(s)`);
3154
3258
  artifactVersion = result.version;
3155
3259
  }
3260
+ if (result.skipped > 0) {
3261
+ changes.push(
3262
+ `Skipped ${result.skipped} artifact(s) (skipPaths override)`
3263
+ );
3264
+ }
3156
3265
  } catch (err) {
3157
3266
  if (err instanceof RelayError) {
3158
3267
  printWarning(
@@ -3163,7 +3272,12 @@ async function syncAllArtifacts(targetDir, apiKey, workspaceId, currentArtifactV
3163
3272
  }
3164
3273
  }
3165
3274
  try {
3166
- const configCount = await syncAgentConfigs(targetDir, apiKey, workspaceId);
3275
+ const configCount = await syncAgentConfigs(
3276
+ targetDir,
3277
+ apiKey,
3278
+ workspaceId,
3279
+ skipPaths
3280
+ );
3167
3281
  if (configCount > 0) {
3168
3282
  changes.push(`Wrote ${configCount} agent config(s)`);
3169
3283
  }
@@ -3183,6 +3297,7 @@ var init_artifacts = __esm({
3183
3297
  "use strict";
3184
3298
  init_ui();
3185
3299
  init_relay_client();
3300
+ init_managed_paths();
3186
3301
  }
3187
3302
  });
3188
3303
 
@@ -3195,11 +3310,11 @@ __export(cleanup_exports, {
3195
3310
  });
3196
3311
  import { defineCommand as defineCommand2 } from "citty";
3197
3312
  import pc7 from "picocolors";
3198
- import { join as join19 } from "path";
3199
- import { readFile as readFile13, writeFile as writeFile12, rm as rm4 } from "fs/promises";
3313
+ import { join as join20 } from "path";
3314
+ import { readFile as readFile13, writeFile as writeFile12, rm as rm5 } from "fs/promises";
3200
3315
  async function scanArtifacts(targetDir) {
3201
3316
  const actions = [];
3202
- const localMePath = join19(targetDir, ".flydocs", "me.json");
3317
+ const localMePath = join20(targetDir, ".flydocs", "me.json");
3203
3318
  if (await pathExists(localMePath) && await pathExists(globalMePath())) {
3204
3319
  actions.push({
3205
3320
  description: "Remove .flydocs/me.json (migrated to ~/.flydocs/me.json)",
@@ -3207,7 +3322,7 @@ async function scanArtifacts(targetDir) {
3207
3322
  type: "file"
3208
3323
  });
3209
3324
  }
3210
- const validationCachePath = join19(
3325
+ const validationCachePath = join20(
3211
3326
  targetDir,
3212
3327
  ".flydocs",
3213
3328
  "validation-cache.json"
@@ -3221,7 +3336,7 @@ async function scanArtifacts(targetDir) {
3221
3336
  }
3222
3337
  const hasGlobalCreds = await pathExists(credentialsPath());
3223
3338
  for (const envFile of [".env", ".env.local"]) {
3224
- const envPath = join19(targetDir, envFile);
3339
+ const envPath = join20(targetDir, envFile);
3225
3340
  if (!await pathExists(envPath)) continue;
3226
3341
  const content = await readFile13(envPath, "utf-8");
3227
3342
  const lines = content.split("\n");
@@ -3246,7 +3361,7 @@ async function scanArtifacts(targetDir) {
3246
3361
  try {
3247
3362
  const config = await readAnyConfig(targetDir);
3248
3363
  const rawContent = await readFile13(
3249
- join19(targetDir, ".flydocs", "config.json"),
3364
+ join20(targetDir, ".flydocs", "config.json"),
3250
3365
  "utf-8"
3251
3366
  );
3252
3367
  const raw = JSON.parse(rawContent);
@@ -3255,7 +3370,7 @@ async function scanArtifacts(targetDir) {
3255
3370
  if (field in raw) {
3256
3371
  actions.push({
3257
3372
  description: `Remove ghost field "${field}" from config.json`,
3258
- path: join19(targetDir, ".flydocs", "config.json"),
3373
+ path: join20(targetDir, ".flydocs", "config.json"),
3259
3374
  type: "field"
3260
3375
  });
3261
3376
  }
@@ -3274,7 +3389,7 @@ async function scanArtifacts(targetDir) {
3274
3389
  if (field in raw) {
3275
3390
  actions.push({
3276
3391
  description: `Remove v1 field "${field}" from config.json (server-owned in v2)`,
3277
- path: join19(targetDir, ".flydocs", "config.json"),
3392
+ path: join20(targetDir, ".flydocs", "config.json"),
3278
3393
  type: "field"
3279
3394
  });
3280
3395
  }
@@ -3289,7 +3404,7 @@ async function executeCleanup(targetDir, actions) {
3289
3404
  const lineRemovals = actions.filter((a) => a.type === "line");
3290
3405
  const fieldRemovals = actions.filter((a) => a.type === "field");
3291
3406
  for (const action of fileRemovals) {
3292
- await rm4(action.path, { force: true });
3407
+ await rm5(action.path, { force: true });
3293
3408
  }
3294
3409
  const envFiles = /* @__PURE__ */ new Map();
3295
3410
  for (const action of lineRemovals) {
@@ -3307,13 +3422,13 @@ async function executeCleanup(targetDir, actions) {
3307
3422
  (l) => l.trim().length > 0 && !l.trim().startsWith("#")
3308
3423
  );
3309
3424
  if (!hasContent) {
3310
- await rm4(envPath, { force: true });
3425
+ await rm5(envPath, { force: true });
3311
3426
  } else {
3312
3427
  await writeFile12(envPath, filtered.join("\n"), "utf-8");
3313
3428
  }
3314
3429
  }
3315
3430
  if (fieldRemovals.length > 0) {
3316
- const configPath = join19(targetDir, ".flydocs", "config.json");
3431
+ const configPath = join20(targetDir, ".flydocs", "config.json");
3317
3432
  const content = await readFile13(configPath, "utf-8");
3318
3433
  const config = JSON.parse(content);
3319
3434
  for (const action of fieldRemovals) {
@@ -3360,7 +3475,7 @@ var init_cleanup = __esm({
3360
3475
  console.log(` ${pc7.bold("FlyDocs Cleanup")}`);
3361
3476
  console.log();
3362
3477
  const hasConfig = await pathExists(
3363
- join19(targetDir, ".flydocs", "config.json")
3478
+ join20(targetDir, ".flydocs", "config.json")
3364
3479
  );
3365
3480
  if (!hasConfig) {
3366
3481
  printError("No .flydocs/config.json found. Run flydocs init first.");
@@ -3404,16 +3519,16 @@ var init_cleanup = __esm({
3404
3519
  });
3405
3520
 
3406
3521
  // src/lib/ide-archive.ts
3407
- import { readFile as readFile14, writeFile as writeFile13, mkdir as mkdir10, readdir as readdir4 } from "fs/promises";
3408
- import { join as join20, basename } from "path";
3522
+ import { readFile as readFile14, writeFile as writeFile13, mkdir as mkdir10, readdir as readdir5 } from "fs/promises";
3523
+ import { join as join21, basename } from "path";
3409
3524
  async function archiveIdeConfigs(targetDir) {
3410
3525
  const archived = [];
3411
3526
  for (const cfg of SINGLE_FILE_CONFIGS) {
3412
- const absSource = join20(targetDir, cfg.source);
3527
+ const absSource = join21(targetDir, cfg.source);
3413
3528
  if (!await pathExists(absSource)) continue;
3414
3529
  const content = await readFile14(absSource, "utf-8");
3415
- const absDest = join20(targetDir, cfg.archive);
3416
- await mkdir10(join20(absDest, ".."), { recursive: true });
3530
+ const absDest = join21(targetDir, cfg.archive);
3531
+ await mkdir10(join21(absDest, ".."), { recursive: true });
3417
3532
  await writeFile13(absDest, content, "utf-8");
3418
3533
  archived.push({
3419
3534
  sourcePath: cfg.source,
@@ -3422,17 +3537,17 @@ async function archiveIdeConfigs(targetDir) {
3422
3537
  });
3423
3538
  printStatus(`Archived ${cfg.source}`);
3424
3539
  }
3425
- const cursorRulesDir = join20(targetDir, ".cursor", "rules");
3540
+ const cursorRulesDir = join21(targetDir, ".cursor", "rules");
3426
3541
  if (await pathExists(cursorRulesDir)) {
3427
3542
  let entries;
3428
3543
  try {
3429
- entries = await readdir4(cursorRulesDir);
3544
+ entries = await readdir5(cursorRulesDir);
3430
3545
  } catch {
3431
3546
  entries = [];
3432
3547
  }
3433
3548
  const mdFiles = entries.filter((f) => f.endsWith(".md"));
3434
3549
  if (mdFiles.length > 0) {
3435
- const archiveSubdir = join20(
3550
+ const archiveSubdir = join21(
3436
3551
  targetDir,
3437
3552
  "flydocs",
3438
3553
  "knowledge",
@@ -3441,10 +3556,10 @@ async function archiveIdeConfigs(targetDir) {
3441
3556
  );
3442
3557
  await mkdir10(archiveSubdir, { recursive: true });
3443
3558
  for (const file of mdFiles) {
3444
- const absSource = join20(cursorRulesDir, file);
3559
+ const absSource = join21(cursorRulesDir, file);
3445
3560
  const content = await readFile14(absSource, "utf-8");
3446
3561
  const archivePath = `flydocs/knowledge/archived/cursor-rules/${basename(file)}`;
3447
- const absDest = join20(targetDir, archivePath);
3562
+ const absDest = join21(targetDir, archivePath);
3448
3563
  await writeFile13(absDest, content, "utf-8");
3449
3564
  archived.push({
3450
3565
  sourcePath: `.cursor/rules/${file}`,
@@ -3477,10 +3592,10 @@ var init_ide_archive = __esm({
3477
3592
  });
3478
3593
 
3479
3594
  // src/lib/workspace.ts
3480
- import { readFile as readFile15, writeFile as writeFile14, readdir as readdir5, stat as stat2 } from "fs/promises";
3481
- import { join as join21, dirname as dirname4, relative, resolve as resolve3 } from "path";
3595
+ import { readFile as readFile15, writeFile as writeFile14, readdir as readdir6, stat as stat2 } from "fs/promises";
3596
+ import { join as join22, dirname as dirname4, relative, resolve as resolve3 } from "path";
3482
3597
  async function readWorkspaceFile(dir) {
3483
- const filePath = join21(dir, WORKSPACE_FILENAME);
3598
+ const filePath = join22(dir, WORKSPACE_FILENAME);
3484
3599
  if (!await pathExists(filePath)) return null;
3485
3600
  const content = await readFile15(filePath, "utf-8");
3486
3601
  const parsed = JSON.parse(content);
@@ -3488,21 +3603,21 @@ async function readWorkspaceFile(dir) {
3488
3603
  return parsed;
3489
3604
  }
3490
3605
  async function writeWorkspaceFile(dir, workspace) {
3491
- const filePath = join21(dir, WORKSPACE_FILENAME);
3606
+ const filePath = join22(dir, WORKSPACE_FILENAME);
3492
3607
  const content = JSON.stringify(workspace, null, 2) + "\n";
3493
3608
  await writeFile14(filePath, content, "utf-8");
3494
3609
  }
3495
3610
  async function detectSiblingRepos(parentDir) {
3496
3611
  const repos = {};
3497
- const entries = await readdir5(parentDir);
3612
+ const entries = await readdir6(parentDir);
3498
3613
  for (const entry of entries) {
3499
3614
  if (entry.startsWith(".")) continue;
3500
- const entryPath = join21(parentDir, entry);
3615
+ const entryPath = join22(parentDir, entry);
3501
3616
  const entryStat = await stat2(entryPath).catch(() => null);
3502
3617
  if (!entryStat?.isDirectory()) continue;
3503
- const hasGit = await pathExists(join21(entryPath, ".git"));
3618
+ const hasGit = await pathExists(join22(entryPath, ".git"));
3504
3619
  const hasFlydocs = await pathExists(
3505
- join21(entryPath, ".flydocs", "config.json")
3620
+ join22(entryPath, ".flydocs", "config.json")
3506
3621
  );
3507
3622
  if (hasGit || hasFlydocs) {
3508
3623
  repos[entry] = { path: `./${entry}` };
@@ -3517,7 +3632,7 @@ async function readSiblingDescriptors(workspaceDir, repos) {
3517
3632
  const descriptors = [];
3518
3633
  for (const [name, entry] of Object.entries(repos)) {
3519
3634
  const repoDir = resolve3(workspaceDir, entry.path);
3520
- const serviceJsonPath = join21(repoDir, "flydocs", "context", "service.json");
3635
+ const serviceJsonPath = join22(repoDir, "flydocs", "context", "service.json");
3521
3636
  if (!await pathExists(serviceJsonPath)) continue;
3522
3637
  try {
3523
3638
  const content = await readFile15(serviceJsonPath, "utf-8");
@@ -3632,7 +3747,7 @@ __export(scan_exports, {
3632
3747
  import { defineCommand as defineCommand3 } from "citty";
3633
3748
  import { spinner } from "@clack/prompts";
3634
3749
  import pc8 from "picocolors";
3635
- import { join as join22 } from "path";
3750
+ import { join as join23 } from "path";
3636
3751
  import { mkdir as mkdir11, writeFile as writeFile15 } from "fs/promises";
3637
3752
  async function resolveRepoName(targetDir, repoArg) {
3638
3753
  if (repoArg) return repoArg;
@@ -3661,15 +3776,15 @@ async function resolveRepoName(targetDir, repoArg) {
3661
3776
  }
3662
3777
  async function writeScanResults(targetDir, response) {
3663
3778
  const written = [];
3664
- const contextDir = join22(targetDir, "flydocs", "context");
3779
+ const contextDir = join23(targetDir, "flydocs", "context");
3665
3780
  await mkdir11(contextDir, { recursive: true });
3666
3781
  if (response.projectMd) {
3667
- const projectMdPath = join22(contextDir, "project.md");
3782
+ const projectMdPath = join23(contextDir, "project.md");
3668
3783
  await writeFile15(projectMdPath, response.projectMd, "utf-8");
3669
3784
  written.push("flydocs/context/project.md");
3670
3785
  }
3671
3786
  if (response.serviceJson) {
3672
- const serviceJsonPath = join22(contextDir, "service.json");
3787
+ const serviceJsonPath = join23(contextDir, "service.json");
3673
3788
  await writeFile15(
3674
3789
  serviceJsonPath,
3675
3790
  JSON.stringify(response.serviceJson, null, 2) + "\n",
@@ -3825,7 +3940,7 @@ __export(init_exports, {
3825
3940
  import { defineCommand as defineCommand4 } from "citty";
3826
3941
  import { text as text2, confirm as confirm3, select as select2, isCancel as isCancel4, cancel as cancel3 } from "@clack/prompts";
3827
3942
  import pc9 from "picocolors";
3828
- import { join as join23 } from "path";
3943
+ import { join as join24 } from "path";
3829
3944
  import { mkdir as mkdir12, writeFile as writeFile16 } from "fs/promises";
3830
3945
  import { execFile } from "child_process";
3831
3946
  import { promisify } from "util";
@@ -3906,7 +4021,7 @@ async function resolveAndValidateKey(keyArg, targetDir) {
3906
4021
  }
3907
4022
  async function pullServerConfig(apiKey, targetDir, workspaceId, forceIncludeContext = false) {
3908
4023
  printInfo("Pulling config from server...");
3909
- const isFirstInit = forceIncludeContext || !await pathExists(join23(targetDir, ".flydocs", "config.json"));
4024
+ const isFirstInit = forceIncludeContext || !await pathExists(join24(targetDir, ".flydocs", "config.json"));
3910
4025
  try {
3911
4026
  const response = await fetchConfigV2(apiKey, {
3912
4027
  includeContext: isFirstInit,
@@ -3935,7 +4050,7 @@ async function initSingleRepo(targetDir, apiKey, serverResponse, options = {}) {
3935
4050
  const actions = [];
3936
4051
  const skipped = [];
3937
4052
  const { childRepoMode = false } = options;
3938
- await mkdir12(join23(targetDir, ".flydocs"), { recursive: true });
4053
+ await mkdir12(join24(targetDir, ".flydocs"), { recursive: true });
3939
4054
  const configWithHash = applyConfigHash(serverResponse.config);
3940
4055
  await writeConfig(targetDir, configWithHash);
3941
4056
  actions.push("Wrote .flydocs/config.json (from server)");
@@ -3948,16 +4063,16 @@ async function initSingleRepo(targetDir, apiKey, serverResponse, options = {}) {
3948
4063
  actions.push("Wrote ~/.flydocs/me.json");
3949
4064
  }
3950
4065
  if (serverResponse.context) {
3951
- const contextDir = join23(targetDir, "flydocs", "context");
4066
+ const contextDir = join24(targetDir, "flydocs", "context");
3952
4067
  await mkdir12(contextDir, { recursive: true });
3953
- const projectMdPath = join23(contextDir, "project.md");
4068
+ const projectMdPath = join24(contextDir, "project.md");
3954
4069
  if (!await pathExists(projectMdPath)) {
3955
4070
  await writeFile16(projectMdPath, serverResponse.context.projectMd, "utf-8");
3956
4071
  actions.push("Wrote flydocs/context/project.md");
3957
4072
  } else {
3958
4073
  skipped.push("flydocs/context/project.md (already exists)");
3959
4074
  }
3960
- const serviceJsonPath = join23(contextDir, "service.json");
4075
+ const serviceJsonPath = join24(contextDir, "service.json");
3961
4076
  if (serverResponse.context.serviceJson && !await pathExists(serviceJsonPath)) {
3962
4077
  await writeFile16(
3963
4078
  serviceJsonPath,
@@ -4004,26 +4119,26 @@ async function initSingleRepo(targetDir, apiKey, serverResponse, options = {}) {
4004
4119
  };
4005
4120
  }
4006
4121
  async function cleanServerManagedFiles(targetDir) {
4007
- const { rm: rm7 } = await import("fs/promises");
4122
+ const { rm: rm9 } = await import("fs/promises");
4008
4123
  let cleaned = 0;
4009
4124
  for (const dir of SERVER_MANAGED_DIRS) {
4010
- const fullPath = join23(targetDir, dir);
4125
+ const fullPath = join24(targetDir, dir);
4011
4126
  if (await pathExists(fullPath)) {
4012
- await rm7(fullPath, { recursive: true, force: true });
4127
+ await rm9(fullPath, { recursive: true, force: true });
4013
4128
  cleaned++;
4014
4129
  }
4015
4130
  }
4016
4131
  for (const file of SERVER_MANAGED_FILES) {
4017
- const fullPath = join23(targetDir, file);
4132
+ const fullPath = join24(targetDir, file);
4018
4133
  if (await pathExists(fullPath)) {
4019
- await rm7(fullPath, { force: true });
4134
+ await rm9(fullPath, { force: true });
4020
4135
  cleaned++;
4021
4136
  }
4022
4137
  }
4023
4138
  return cleaned;
4024
4139
  }
4025
4140
  async function checkGitFreshness(repoDir) {
4026
- const hasGit = await pathExists(join23(repoDir, ".git"));
4141
+ const hasGit = await pathExists(join24(repoDir, ".git"));
4027
4142
  if (!hasGit) return;
4028
4143
  try {
4029
4144
  await execFileAsync("git", ["-C", repoDir, "fetch", "--quiet"], {
@@ -4052,7 +4167,7 @@ async function checkGitFreshness(repoDir) {
4052
4167
  }
4053
4168
  }
4054
4169
  async function isEmptyOrNonRepo(dir) {
4055
- const hasGit = await pathExists(join23(dir, ".git"));
4170
+ const hasGit = await pathExists(join24(dir, ".git"));
4056
4171
  if (hasGit) return false;
4057
4172
  const siblings = await detectSiblingRepos(dir);
4058
4173
  if (Object.keys(siblings).length >= 2) return false;
@@ -4122,9 +4237,9 @@ async function runCloneAndInit(targetDir, keyArg, repos, apiKey, workspaceId) {
4122
4237
  for (let i = 0; i < repos.length; i++) {
4123
4238
  const repo = repos[i];
4124
4239
  const shortName = repoNames[i];
4125
- const cloneDir = join23(targetDir, shortName);
4240
+ const cloneDir = join24(targetDir, shortName);
4126
4241
  console.log();
4127
- if (await pathExists(join23(cloneDir, ".git"))) {
4242
+ if (await pathExists(join24(cloneDir, ".git"))) {
4128
4243
  printInfo(`${pc9.bold(shortName)} already cloned, initializing...`);
4129
4244
  await checkGitFreshness(cloneDir);
4130
4245
  } else {
@@ -4167,8 +4282,8 @@ async function runCloneAndInit(targetDir, keyArg, repos, apiKey, workspaceId) {
4167
4282
  );
4168
4283
  await writeWorkspaceFile(targetDir, workspaceFile);
4169
4284
  allActions.push(`.flydocs-workspace.json (${repos.length} repos)`);
4170
- const contextDir = join23(targetDir, "flydocs", "context");
4171
- const workspaceMdPath = join23(contextDir, "workspace.md");
4285
+ const contextDir = join24(targetDir, "flydocs", "context");
4286
+ const workspaceMdPath = join24(contextDir, "workspace.md");
4172
4287
  if (!await pathExists(workspaceMdPath)) {
4173
4288
  await mkdir12(contextDir, { recursive: true });
4174
4289
  const content = firstResponse.context?.workspaceMd ?? await generateWorkspaceMd(targetDir, workspaceFile);
@@ -4187,7 +4302,7 @@ async function runCloneAndInit(targetDir, keyArg, repos, apiKey, workspaceId) {
4187
4302
  }
4188
4303
  }
4189
4304
  async function isParentDirectory(dir) {
4190
- const hasGit = await pathExists(join23(dir, ".git"));
4305
+ const hasGit = await pathExists(join24(dir, ".git"));
4191
4306
  if (hasGit) return false;
4192
4307
  const repos = await detectSiblingRepos(dir);
4193
4308
  return Object.keys(repos).length >= 2;
@@ -4207,7 +4322,7 @@ async function runMultiRepoInit(parentDir, keyArg) {
4207
4322
  cancel3("Init cancelled.");
4208
4323
  process.exit(0);
4209
4324
  }
4210
- const firstRepoDir = join23(parentDir, repoNames[0]);
4325
+ const firstRepoDir = join24(parentDir, repoNames[0]);
4211
4326
  const { apiKey, workspaceId } = await resolveAndValidateKey(
4212
4327
  keyArg,
4213
4328
  firstRepoDir
@@ -4240,7 +4355,7 @@ async function runMultiRepoInit(parentDir, keyArg) {
4240
4355
  await ensureGitignore(parentDir);
4241
4356
  allActions.push("Updated workspace root .gitignore");
4242
4357
  for (const repoName of repoNames) {
4243
- const repoDir = join23(parentDir, repoName);
4358
+ const repoDir = join24(parentDir, repoName);
4244
4359
  console.log();
4245
4360
  printInfo(`Initializing ${pc9.bold(repoName)}...`);
4246
4361
  await checkGitFreshness(repoDir);
@@ -4272,8 +4387,8 @@ async function runMultiRepoInit(parentDir, keyArg) {
4272
4387
  await writeWorkspaceFile(parentDir, workspaceFile);
4273
4388
  allActions.push(`.flydocs-workspace.json (${repoNames.length} repos)`);
4274
4389
  }
4275
- const contextDir = join23(parentDir, "flydocs", "context");
4276
- const workspaceMdPath = join23(contextDir, "workspace.md");
4390
+ const contextDir = join24(parentDir, "flydocs", "context");
4391
+ const workspaceMdPath = join24(contextDir, "workspace.md");
4277
4392
  if (await pathExists(workspaceMdPath)) {
4278
4393
  allSkipped.push("flydocs/context/workspace.md (already exists)");
4279
4394
  } else {
@@ -4426,7 +4541,7 @@ var init_init = __esm({
4426
4541
  actions.unshift("Stored credential globally (~/.flydocs/credentials)");
4427
4542
  const topology = serverResponse.config.topology;
4428
4543
  if (topology?.type === 4 && topology.label === "sibling-repos") {
4429
- const parentDir = join23(targetDir, "..");
4544
+ const parentDir = join24(targetDir, "..");
4430
4545
  const existing = await readWorkspaceFile(parentDir);
4431
4546
  if (existing) {
4432
4547
  skipped.push(".flydocs-workspace.json (already exists)");
@@ -4547,16 +4662,320 @@ var init_init = __esm({
4547
4662
  }
4548
4663
  });
4549
4664
 
4665
+ // src/lib/skill-conflicts.ts
4666
+ import { join as join25 } from "path";
4667
+ import { readdir as readdir7, rm as rm6, cp as cp2, mkdir as mkdir13 } from "fs/promises";
4668
+ import { select as select3, isCancel as isCancel5 } from "@clack/prompts";
4669
+ async function resolveSkillConflicts(targetDir, keptPaths = []) {
4670
+ const result = {
4671
+ newKeptPaths: [],
4672
+ archived: 0,
4673
+ deleted: 0
4674
+ };
4675
+ const skillsDir = join25(targetDir, ".claude", "skills");
4676
+ if (!await pathExists(skillsDir)) return result;
4677
+ const entries = await readdir7(skillsDir, { withFileTypes: true });
4678
+ for (const entry of entries) {
4679
+ if (!entry.isDirectory()) continue;
4680
+ if (entry.name.startsWith(CORE_SKILL_PREFIX2)) continue;
4681
+ const relPath = `.claude/skills/${entry.name}`;
4682
+ if (keptPaths.includes(relPath) || keptPaths.includes(relPath + "/")) {
4683
+ continue;
4684
+ }
4685
+ await promptConflict(targetDir, skillsDir, entry.name, relPath, result);
4686
+ }
4687
+ if (result.archived > 0 || result.deleted > 0 || result.newKeptPaths.length > 0) {
4688
+ const parts = [];
4689
+ if (result.archived > 0) parts.push(`${result.archived} archived`);
4690
+ if (result.deleted > 0) parts.push(`${result.deleted} deleted`);
4691
+ if (result.newKeptPaths.length > 0)
4692
+ parts.push(`${result.newKeptPaths.length} kept`);
4693
+ printInfo(`Non-core skills: ${parts.join(", ")}`);
4694
+ }
4695
+ return result;
4696
+ }
4697
+ async function promptConflict(targetDir, skillsDir, name, relPath, result) {
4698
+ const choice = await select3({
4699
+ message: `Found non-managed skill: ${name}. What should we do?`,
4700
+ options: [
4701
+ {
4702
+ value: "keep",
4703
+ label: "Keep \u2014 leave in place, don't ask again"
4704
+ },
4705
+ {
4706
+ value: "archive",
4707
+ label: "Archive \u2014 move to flydocs/knowledge/archived/skills/"
4708
+ },
4709
+ {
4710
+ value: "delete",
4711
+ label: "Delete \u2014 remove permanently"
4712
+ }
4713
+ ]
4714
+ });
4715
+ if (isCancel5(choice)) {
4716
+ result.newKeptPaths.push(relPath);
4717
+ return;
4718
+ }
4719
+ const fullPath = join25(skillsDir, name);
4720
+ switch (choice) {
4721
+ case "keep":
4722
+ result.newKeptPaths.push(relPath);
4723
+ printInfo(`Keeping ${name} (won't ask again)`);
4724
+ break;
4725
+ case "archive": {
4726
+ const archiveDir = join25(
4727
+ targetDir,
4728
+ "flydocs",
4729
+ "knowledge",
4730
+ "archived",
4731
+ "skills"
4732
+ );
4733
+ await mkdir13(archiveDir, { recursive: true });
4734
+ const archiveDest = join25(archiveDir, name);
4735
+ if (await pathExists(archiveDest)) {
4736
+ await rm6(archiveDest, { recursive: true, force: true });
4737
+ }
4738
+ await cp2(fullPath, archiveDest, { recursive: true });
4739
+ await rm6(fullPath, { recursive: true, force: true });
4740
+ result.archived++;
4741
+ printStatus(`Archived ${name} \u2192 flydocs/knowledge/archived/skills/`);
4742
+ break;
4743
+ }
4744
+ case "delete":
4745
+ await rm6(fullPath, { recursive: true, force: true });
4746
+ result.deleted++;
4747
+ printStatus(`Deleted ${name}`);
4748
+ break;
4749
+ }
4750
+ }
4751
+ var CORE_SKILL_PREFIX2;
4752
+ var init_skill_conflicts = __esm({
4753
+ "src/lib/skill-conflicts.ts"() {
4754
+ "use strict";
4755
+ init_fs_ops();
4756
+ init_ui();
4757
+ CORE_SKILL_PREFIX2 = "flydocs-";
4758
+ }
4759
+ });
4760
+
4761
+ // src/commands/sync.ts
4762
+ var sync_exports = {};
4763
+ __export(sync_exports, {
4764
+ default: () => sync_default,
4765
+ runSync: () => runSync
4766
+ });
4767
+ import { defineCommand as defineCommand5 } from "citty";
4768
+ import pc10 from "picocolors";
4769
+ import { join as join26, resolve as resolve4 } from "path";
4770
+ import { mkdir as mkdir14, writeFile as writeFile17 } from "fs/promises";
4771
+ async function runSync(targetDir) {
4772
+ const changes = [];
4773
+ printInfo("Syncing with server...");
4774
+ const resolved = await resolveApiKey(void 0, targetDir);
4775
+ if (!resolved) {
4776
+ printError("No API key found. Run `flydocs auth` or `flydocs init` first.");
4777
+ process.exit(1);
4778
+ }
4779
+ const apiKey = resolved.key;
4780
+ const cred = await readGlobalCredential();
4781
+ const workspaceId = cred?.workspaceId;
4782
+ if (!workspaceId) {
4783
+ printError(
4784
+ "No workspace ID found. Run `flydocs init` to set up your workspace."
4785
+ );
4786
+ process.exit(1);
4787
+ }
4788
+ let currentTemplateVersion = 0;
4789
+ let currentArtifactVersion = 0;
4790
+ let localOverrides;
4791
+ try {
4792
+ const currentConfig = await readAnyConfig(targetDir);
4793
+ if (isConfigV2(currentConfig)) {
4794
+ currentTemplateVersion = currentConfig.configVersion ?? 0;
4795
+ currentArtifactVersion = currentConfig.artifactVersion ?? 0;
4796
+ localOverrides = currentConfig.artifactOverrides;
4797
+ }
4798
+ } catch {
4799
+ }
4800
+ let serverResponse;
4801
+ try {
4802
+ serverResponse = await fetchConfigV2(apiKey, { workspaceId });
4803
+ } catch (err) {
4804
+ if (err instanceof RelayError) {
4805
+ printWarning(`Server unavailable (${err.status}), using cached config.`);
4806
+ } else {
4807
+ printWarning("Server unreachable, using cached config.");
4808
+ }
4809
+ console.log(` ${pc10.dim("Config may be stale. Retry when connected.")}`);
4810
+ return changes;
4811
+ }
4812
+ if (!serverResponse.valid) {
4813
+ printWarning("Server returned invalid config. Keeping current config.");
4814
+ return changes;
4815
+ }
4816
+ await mkdir14(join26(targetDir, ".flydocs"), { recursive: true });
4817
+ const serverConfig = serverResponse.config;
4818
+ if (localOverrides) {
4819
+ serverConfig.artifactOverrides = localOverrides;
4820
+ }
4821
+ const configWithHash = applyConfigHash(serverConfig);
4822
+ await writeConfig(targetDir, configWithHash);
4823
+ changes.push("Updated .flydocs/config.json");
4824
+ const serverTemplateVersion = serverResponse.templates.version;
4825
+ if (serverTemplateVersion > currentTemplateVersion) {
4826
+ try {
4827
+ const templatesResponse = await fetchTemplates(
4828
+ apiKey,
4829
+ currentTemplateVersion,
4830
+ workspaceId
4831
+ );
4832
+ if (templatesResponse.templates.length > 0) {
4833
+ const templatesDir = join26(
4834
+ targetDir,
4835
+ ".claude",
4836
+ "skills",
4837
+ "flydocs-workflow",
4838
+ "templates"
4839
+ );
4840
+ await mkdir14(templatesDir, { recursive: true });
4841
+ for (const template of templatesResponse.templates) {
4842
+ const filename = `${template.type}.md`;
4843
+ const subdir = template.category === "issue" ? "issues" : template.category === "pr" ? "pr" : template.category === "comment" ? "." : ".";
4844
+ const templateDir = join26(templatesDir, subdir);
4845
+ await mkdir14(templateDir, { recursive: true });
4846
+ await writeFile17(
4847
+ join26(templateDir, filename),
4848
+ template.content,
4849
+ "utf-8"
4850
+ );
4851
+ }
4852
+ changes.push(
4853
+ `Updated ${templatesResponse.templates.length} templates (v${currentTemplateVersion} \u2192 v${serverTemplateVersion})`
4854
+ );
4855
+ }
4856
+ } catch (err) {
4857
+ if (err instanceof RelayError) {
4858
+ printWarning("Could not fetch templates. Will retry on next sync.");
4859
+ } else {
4860
+ printWarning("Template sync failed. Will retry on next sync.");
4861
+ }
4862
+ }
4863
+ }
4864
+ const serverArtifactVersion = serverResponse.artifactVersion ?? 0;
4865
+ const skipPaths = localOverrides?.skipPaths ?? [];
4866
+ if (serverArtifactVersion > currentArtifactVersion) {
4867
+ const artifactWriteRoot = await resolveArtifactWriteRoot(
4868
+ targetDir,
4869
+ serverResponse.config
4870
+ );
4871
+ const { changes: artifactChanges } = await syncAllArtifacts(
4872
+ artifactWriteRoot,
4873
+ apiKey,
4874
+ workspaceId,
4875
+ currentArtifactVersion,
4876
+ skipPaths
4877
+ );
4878
+ changes.push(...artifactChanges);
4879
+ if (artifactWriteRoot !== targetDir) {
4880
+ changes.push(`Artifacts written to workspace root`);
4881
+ }
4882
+ const keptPaths = localOverrides?.keptPaths ?? [];
4883
+ const conflicts = await resolveSkillConflicts(artifactWriteRoot, keptPaths);
4884
+ if (conflicts.newKeptPaths.length > 0) {
4885
+ try {
4886
+ const updatedConfig = await readAnyConfig(targetDir);
4887
+ if (isConfigV2(updatedConfig)) {
4888
+ const existingKept = updatedConfig.artifactOverrides?.keptPaths ?? [];
4889
+ const mergedKept = [
4890
+ .../* @__PURE__ */ new Set([...existingKept, ...conflicts.newKeptPaths])
4891
+ ];
4892
+ updatedConfig.artifactOverrides = {
4893
+ ...updatedConfig.artifactOverrides,
4894
+ skipPaths: updatedConfig.artifactOverrides?.skipPaths ?? [],
4895
+ keptPaths: mergedKept
4896
+ };
4897
+ const hashed = applyConfigHash(updatedConfig);
4898
+ await writeConfig(targetDir, hashed);
4899
+ changes.push(
4900
+ `Persisted ${conflicts.newKeptPaths.length} kept path(s) to config`
4901
+ );
4902
+ }
4903
+ } catch {
4904
+ }
4905
+ }
4906
+ if (conflicts.archived > 0) {
4907
+ changes.push(`Archived ${conflicts.archived} non-core skill(s)`);
4908
+ }
4909
+ if (conflicts.deleted > 0) {
4910
+ changes.push(`Deleted ${conflicts.deleted} non-core skill(s)`);
4911
+ }
4912
+ }
4913
+ await migrateGitignore(targetDir);
4914
+ return changes;
4915
+ }
4916
+ async function resolveArtifactWriteRoot(targetDir, config) {
4917
+ const topology = config.topology;
4918
+ if (topology && topology.type === 4 && topology.label === "sibling-repos") {
4919
+ const parentDir = join26(targetDir, "..");
4920
+ const workspaceFile = await readWorkspaceFile(parentDir);
4921
+ if (workspaceFile) {
4922
+ return resolve4(parentDir);
4923
+ }
4924
+ }
4925
+ return targetDir;
4926
+ }
4927
+ var sync_default;
4928
+ var init_sync = __esm({
4929
+ "src/commands/sync.ts"() {
4930
+ "use strict";
4931
+ init_ui();
4932
+ init_global_config();
4933
+ init_config();
4934
+ init_config_integrity();
4935
+ init_types();
4936
+ init_gitignore();
4937
+ init_artifacts();
4938
+ init_workspace();
4939
+ init_relay_client();
4940
+ init_skill_conflicts();
4941
+ sync_default = defineCommand5({
4942
+ meta: {
4943
+ name: "sync",
4944
+ description: "Pull latest config and templates from server"
4945
+ },
4946
+ args: {
4947
+ path: {
4948
+ type: "string",
4949
+ description: "Path to project directory"
4950
+ }
4951
+ },
4952
+ async run({ args }) {
4953
+ const targetDir = args.path ?? process.cwd();
4954
+ console.log();
4955
+ const changes = await runSync(targetDir);
4956
+ if (changes.length === 0) {
4957
+ printStatus("Already up to date.");
4958
+ } else {
4959
+ for (const change of changes) {
4960
+ printStatus(change);
4961
+ }
4962
+ }
4963
+ console.log();
4964
+ }
4965
+ });
4966
+ }
4967
+ });
4968
+
4550
4969
  // src/commands/update.ts
4551
4970
  var update_exports = {};
4552
4971
  __export(update_exports, {
4553
4972
  default: () => update_default
4554
4973
  });
4555
- import { defineCommand as defineCommand5 } from "citty";
4556
- import { resolve as resolve4, join as join24 } from "path";
4557
- import { mkdir as mkdir13, cp as cp2, readFile as readFile16, readdir as readdir6, rm as rm5 } from "fs/promises";
4558
- import { select as select3, text as text3, confirm as confirm4, isCancel as isCancel5, cancel as cancel4 } from "@clack/prompts";
4559
- import pc10 from "picocolors";
4974
+ import { defineCommand as defineCommand6 } from "citty";
4975
+ import { resolve as resolve5, join as join27 } from "path";
4976
+ import { mkdir as mkdir15, cp as cp3, readFile as readFile16, readdir as readdir8, rm as rm7 } from "fs/promises";
4977
+ import { select as select4, text as text3, confirm as confirm4, isCancel as isCancel6, cancel as cancel4 } from "@clack/prompts";
4978
+ import pc11 from "picocolors";
4560
4979
  var update_default;
4561
4980
  var init_update = __esm({
4562
4981
  "src/commands/update.ts"() {
@@ -4575,7 +4994,11 @@ var init_update = __esm({
4575
4994
  init_update_check();
4576
4995
  init_telemetry();
4577
4996
  init_integrity();
4578
- update_default = defineCommand5({
4997
+ init_config();
4998
+ init_types();
4999
+ init_managed_paths();
5000
+ init_sync();
5001
+ update_default = defineCommand6({
4579
5002
  meta: {
4580
5003
  name: "update",
4581
5004
  description: "Update an existing FlyDocs installation"
@@ -4620,11 +5043,11 @@ var init_update = __esm({
4620
5043
  await capture("update_started", { template_version: version });
4621
5044
  let targetDir;
4622
5045
  if (args.path) {
4623
- targetDir = resolve4(args.path.replace(/^~/, process.env.HOME ?? "~"));
5046
+ targetDir = resolve5(args.path.replace(/^~/, process.env.HOME ?? "~"));
4624
5047
  } else if (args.here) {
4625
5048
  targetDir = process.cwd();
4626
5049
  } else {
4627
- const choice = await select3({
5050
+ const choice = await select4({
4628
5051
  message: "Which project would you like to update?",
4629
5052
  options: [
4630
5053
  {
@@ -4637,7 +5060,7 @@ var init_update = __esm({
4637
5060
  }
4638
5061
  ]
4639
5062
  });
4640
- if (isCancel5(choice)) {
5063
+ if (isCancel6(choice)) {
4641
5064
  cancel4("Update cancelled.");
4642
5065
  process.exit(0);
4643
5066
  }
@@ -4647,11 +5070,11 @@ var init_update = __esm({
4647
5070
  const enteredPath = await text3({
4648
5071
  message: "Enter project path:"
4649
5072
  });
4650
- if (isCancel5(enteredPath)) {
5073
+ if (isCancel6(enteredPath)) {
4651
5074
  cancel4("Update cancelled.");
4652
5075
  process.exit(0);
4653
5076
  }
4654
- targetDir = resolve4(
5077
+ targetDir = resolve5(
4655
5078
  enteredPath.replace(/^~/, process.env.HOME ?? "~")
4656
5079
  );
4657
5080
  }
@@ -4660,11 +5083,11 @@ var init_update = __esm({
4660
5083
  printError(`Directory does not exist: ${targetDir}`);
4661
5084
  process.exit(1);
4662
5085
  }
4663
- targetDir = resolve4(targetDir);
5086
+ targetDir = resolve5(targetDir);
4664
5087
  process.chdir(targetDir);
4665
- const hasVersion = await pathExists(join24(targetDir, ".flydocs", "version"));
5088
+ const hasVersion = await pathExists(join27(targetDir, ".flydocs", "version"));
4666
5089
  const hasConfig = await pathExists(
4667
- join24(targetDir, ".flydocs", "config.json")
5090
+ join27(targetDir, ".flydocs", "config.json")
4668
5091
  );
4669
5092
  if (!hasVersion && !hasConfig) {
4670
5093
  printError(`Not a FlyDocs project: ${targetDir}`);
@@ -4676,7 +5099,7 @@ var init_update = __esm({
4676
5099
  let currentVersion = "0.1.0";
4677
5100
  if (hasVersion) {
4678
5101
  const vContent = await readFile16(
4679
- join24(targetDir, ".flydocs", "version"),
5102
+ join27(targetDir, ".flydocs", "version"),
4680
5103
  "utf-8"
4681
5104
  );
4682
5105
  currentVersion = vContent.trim();
@@ -4698,7 +5121,7 @@ var init_update = __esm({
4698
5121
  const shouldContinue = await confirm4({
4699
5122
  message: "Continue anyway?"
4700
5123
  });
4701
- if (isCancel5(shouldContinue) || !shouldContinue) {
5124
+ if (isCancel6(shouldContinue) || !shouldContinue) {
4702
5125
  process.exit(0);
4703
5126
  }
4704
5127
  }
@@ -4710,35 +5133,65 @@ var init_update = __esm({
4710
5133
  });
4711
5134
  console.log(`Updating: v${currentVersion} \u2192 v${version}`);
4712
5135
  console.log();
4713
- const changelogPath = join24(templateDir, "CHANGELOG.md");
5136
+ const changelogPath = join27(templateDir, "CHANGELOG.md");
4714
5137
  const whatsNew = await getWhatsNew(changelogPath, currentVersion, version);
4715
5138
  if (whatsNew.length > 0) {
4716
- console.log(pc10.cyan("What's new:"));
5139
+ console.log(pc11.cyan("What's new:"));
4717
5140
  console.log();
4718
5141
  for (const entry of whatsNew) {
4719
5142
  console.log(` ${entry}`);
4720
5143
  }
4721
5144
  console.log();
4722
5145
  }
5146
+ if (hasConfig) {
5147
+ try {
5148
+ const existingConfig = await readAnyConfig(targetDir);
5149
+ if (isConfigV2(existingConfig)) {
5150
+ printInfo(
5151
+ "Cloud project detected \u2014 running sync flow (wipe-and-replace)"
5152
+ );
5153
+ console.log();
5154
+ const syncChanges = await runSync(targetDir);
5155
+ if (syncChanges.length > 0) {
5156
+ for (const change of syncChanges) {
5157
+ printStatus(change);
5158
+ }
5159
+ }
5160
+ console.log();
5161
+ console.log(
5162
+ ` ${pc11.dim("Tip: use")} ${pc11.cyan("flydocs sync")} ${pc11.dim("for file-only refresh (no CLI update).")}`
5163
+ );
5164
+ await capture("update_completed", {
5165
+ current_version: currentVersion,
5166
+ version,
5167
+ tier: "cloud",
5168
+ mode: "sync-delegate"
5169
+ });
5170
+ await flush();
5171
+ return;
5172
+ }
5173
+ } catch {
5174
+ }
5175
+ }
4723
5176
  const now = /* @__PURE__ */ new Date();
4724
5177
  const ts = `${now.getFullYear()}${String(now.getMonth() + 1).padStart(2, "0")}${String(now.getDate()).padStart(2, "0")}-${String(now.getHours()).padStart(2, "0")}${String(now.getMinutes()).padStart(2, "0")}${String(now.getSeconds()).padStart(2, "0")}`;
4725
- const backupDir = join24(targetDir, ".flydocs", `backup-${ts}`);
4726
- await mkdir13(backupDir, { recursive: true });
5178
+ const backupDir = join27(targetDir, ".flydocs", `backup-${ts}`);
5179
+ await mkdir15(backupDir, { recursive: true });
4727
5180
  if (hasConfig) {
4728
- await cp2(
4729
- join24(targetDir, ".flydocs", "config.json"),
4730
- join24(backupDir, "config.json")
5181
+ await cp3(
5182
+ join27(targetDir, ".flydocs", "config.json"),
5183
+ join27(backupDir, "config.json")
4731
5184
  );
4732
5185
  printStatus(`Config backed up to .flydocs/backup-${ts}/`);
4733
5186
  }
4734
5187
  try {
4735
- const flydocsDir = join24(targetDir, ".flydocs");
4736
- const entries = await readdir6(flydocsDir);
5188
+ const flydocsDir = join27(targetDir, ".flydocs");
5189
+ const entries = await readdir8(flydocsDir);
4737
5190
  const backups = entries.filter((e) => e.startsWith("backup-")).sort();
4738
5191
  if (backups.length > 3) {
4739
5192
  const toRemove = backups.slice(0, backups.length - 3);
4740
5193
  for (const old of toRemove) {
4741
- await rm5(join24(flydocsDir, old), { recursive: true, force: true });
5194
+ await rm7(join27(flydocsDir, old), { recursive: true, force: true });
4742
5195
  }
4743
5196
  }
4744
5197
  } catch {
@@ -4775,19 +5228,21 @@ var init_update = __esm({
4775
5228
  effectiveTier = preserved.tier;
4776
5229
  }
4777
5230
  await ensureDirectories(targetDir, effectiveTier);
5231
+ console.log("Wiping server-managed paths...");
5232
+ await wipeManagedPaths(targetDir);
4778
5233
  console.log("Replacing framework directories...");
4779
5234
  await replaceDirectory(
4780
- join24(templateDir, ".flydocs", "templates"),
4781
- join24(targetDir, ".flydocs", "templates")
5235
+ join27(templateDir, ".flydocs", "templates"),
5236
+ join27(targetDir, ".flydocs", "templates")
4782
5237
  );
4783
5238
  printStatus(".flydocs/templates");
4784
5239
  await replaceDirectory(
4785
- join24(templateDir, ".claude", "hooks"),
4786
- join24(targetDir, ".claude", "hooks")
5240
+ join27(templateDir, ".claude", "hooks"),
5241
+ join27(targetDir, ".claude", "hooks")
4787
5242
  );
4788
5243
  printStatus(".claude/hooks");
4789
5244
  const hasExistingAgents = await pathExists(
4790
- join24(targetDir, ".claude", "agents")
5245
+ join27(targetDir, ".claude", "agents")
4791
5246
  );
4792
5247
  let installAgents;
4793
5248
  if (args.yes) {
@@ -4796,7 +5251,7 @@ var init_update = __esm({
4796
5251
  installAgents = true;
4797
5252
  } else {
4798
5253
  console.log();
4799
- console.log(` ${pc10.bold(pc10.yellow("Sub-Agents (Recommended)"))}`);
5254
+ console.log(` ${pc11.bold(pc11.yellow("Sub-Agents (Recommended)"))}`);
4800
5255
  console.log();
4801
5256
  console.log(
4802
5257
  " Sub-agents are specialized roles (PM, implementation, review,"
@@ -4812,27 +5267,27 @@ var init_update = __esm({
4812
5267
  message: "Install sub-agents?",
4813
5268
  initialValue: true
4814
5269
  });
4815
- if (isCancel5(agentConfirm)) {
5270
+ if (isCancel6(agentConfirm)) {
4816
5271
  installAgents = false;
4817
5272
  } else {
4818
5273
  installAgents = agentConfirm;
4819
5274
  }
4820
5275
  }
4821
5276
  if (installAgents) {
4822
- const claudeAgentsSrc = join24(templateDir, ".claude", "agents");
5277
+ const claudeAgentsSrc = join27(templateDir, ".claude", "agents");
4823
5278
  if (await pathExists(claudeAgentsSrc)) {
4824
- await mkdir13(join24(targetDir, ".claude", "agents"), { recursive: true });
5279
+ await mkdir15(join27(targetDir, ".claude", "agents"), { recursive: true });
4825
5280
  await copyDirectoryContents(
4826
5281
  claudeAgentsSrc,
4827
- join24(targetDir, ".claude", "agents")
5282
+ join27(targetDir, ".claude", "agents")
4828
5283
  );
4829
5284
  }
4830
- const cursorAgentsSrc = join24(templateDir, ".cursor", "agents");
5285
+ const cursorAgentsSrc = join27(templateDir, ".cursor", "agents");
4831
5286
  if (await pathExists(cursorAgentsSrc)) {
4832
- await mkdir13(join24(targetDir, ".cursor", "agents"), { recursive: true });
5287
+ await mkdir15(join27(targetDir, ".cursor", "agents"), { recursive: true });
4833
5288
  await copyDirectoryContents(
4834
5289
  cursorAgentsSrc,
4835
- join24(targetDir, ".cursor", "agents")
5290
+ join27(targetDir, ".cursor", "agents")
4836
5291
  );
4837
5292
  }
4838
5293
  printStatus(
@@ -4846,58 +5301,58 @@ var init_update = __esm({
4846
5301
  console.log();
4847
5302
  console.log("Replacing framework files...");
4848
5303
  await copyFile(
4849
- join24(templateDir, ".claude", "CLAUDE.md"),
4850
- join24(targetDir, ".claude", "CLAUDE.md")
5304
+ join27(templateDir, ".claude", "CLAUDE.md"),
5305
+ join27(targetDir, ".claude", "CLAUDE.md")
4851
5306
  );
4852
5307
  await copyFile(
4853
- join24(templateDir, ".claude", "settings.json"),
4854
- join24(targetDir, ".claude", "settings.json")
5308
+ join27(templateDir, ".claude", "settings.json"),
5309
+ join27(targetDir, ".claude", "settings.json")
4855
5310
  );
4856
5311
  printStatus(".claude/CLAUDE.md, settings.json");
4857
5312
  await copyDirectoryContents(
4858
- join24(templateDir, ".claude", "commands"),
4859
- join24(targetDir, ".claude", "commands")
5313
+ join27(templateDir, ".claude", "commands"),
5314
+ join27(targetDir, ".claude", "commands")
4860
5315
  );
4861
5316
  await copyDirectoryContents(
4862
- join24(templateDir, ".claude", "commands"),
4863
- join24(targetDir, ".cursor", "commands")
5317
+ join27(templateDir, ".claude", "commands"),
5318
+ join27(targetDir, ".cursor", "commands")
4864
5319
  );
4865
5320
  printStatus(".claude/commands, .cursor/commands");
4866
- const skillsReadmeSrc = join24(templateDir, ".claude", "skills", "README.md");
5321
+ const skillsReadmeSrc = join27(templateDir, ".claude", "skills", "README.md");
4867
5322
  if (await pathExists(skillsReadmeSrc)) {
4868
5323
  await copyFile(
4869
5324
  skillsReadmeSrc,
4870
- join24(targetDir, ".claude", "skills", "README.md")
5325
+ join27(targetDir, ".claude", "skills", "README.md")
4871
5326
  );
4872
5327
  }
4873
5328
  printStatus(".claude/skills/README.md");
4874
5329
  await copyFile(
4875
- join24(templateDir, ".cursor", "hooks.json"),
4876
- join24(targetDir, ".cursor", "hooks.json")
5330
+ join27(templateDir, ".cursor", "hooks.json"),
5331
+ join27(targetDir, ".cursor", "hooks.json")
4877
5332
  );
4878
5333
  printStatus(".cursor/hooks.json");
4879
5334
  await copyFile(
4880
- join24(templateDir, "AGENTS.md"),
4881
- join24(targetDir, "AGENTS.md")
5335
+ join27(templateDir, "AGENTS.md"),
5336
+ join27(targetDir, "AGENTS.md")
4882
5337
  );
4883
5338
  printStatus("AGENTS.md");
4884
- const envExampleSrc = join24(templateDir, ".env.example");
5339
+ const envExampleSrc = join27(templateDir, ".env.example");
4885
5340
  if (await pathExists(envExampleSrc)) {
4886
- await copyFile(envExampleSrc, join24(targetDir, ".env.example"));
5341
+ await copyFile(envExampleSrc, join27(targetDir, ".env.example"));
4887
5342
  printStatus(".env.example");
4888
5343
  }
4889
- const knowledgeTemplatesDir = join24(
5344
+ const knowledgeTemplatesDir = join27(
4890
5345
  targetDir,
4891
5346
  "flydocs",
4892
5347
  "knowledge",
4893
5348
  "templates"
4894
5349
  );
4895
5350
  if (!await pathExists(knowledgeTemplatesDir)) {
4896
- await mkdir13(knowledgeTemplatesDir, { recursive: true });
5351
+ await mkdir15(knowledgeTemplatesDir, { recursive: true });
4897
5352
  }
4898
5353
  for (const tmpl of ["decision.md", "feature.md", "note.md"]) {
4899
- const src = join24(templateDir, "flydocs", "knowledge", "templates", tmpl);
4900
- const dest = join24(knowledgeTemplatesDir, tmpl);
5354
+ const src = join27(templateDir, "flydocs", "knowledge", "templates", tmpl);
5355
+ const dest = join27(knowledgeTemplatesDir, tmpl);
4901
5356
  if (await pathExists(src) && !await pathExists(dest)) {
4902
5357
  await copyFile(src, dest);
4903
5358
  }
@@ -4924,18 +5379,18 @@ var init_update = __esm({
4924
5379
  printWarning("Config merge failed \u2014 config.json preserved as-is");
4925
5380
  }
4926
5381
  await copyFile(
4927
- join24(templateDir, ".flydocs", "version"),
4928
- join24(targetDir, ".flydocs", "version")
5382
+ join27(templateDir, ".flydocs", "version"),
5383
+ join27(targetDir, ".flydocs", "version")
4929
5384
  );
4930
5385
  printStatus(`.flydocs/version \u2192 ${version}`);
4931
- const clSrc = join24(templateDir, "CHANGELOG.md");
5386
+ const clSrc = join27(templateDir, "CHANGELOG.md");
4932
5387
  if (await pathExists(clSrc)) {
4933
- await copyFile(clSrc, join24(targetDir, ".flydocs", "CHANGELOG.md"));
5388
+ await copyFile(clSrc, join27(targetDir, ".flydocs", "CHANGELOG.md"));
4934
5389
  printStatus(".flydocs/CHANGELOG.md");
4935
5390
  }
4936
- const mfSrc = join24(templateDir, "manifest.json");
5391
+ const mfSrc = join27(templateDir, "manifest.json");
4937
5392
  if (await pathExists(mfSrc)) {
4938
- await copyFile(mfSrc, join24(targetDir, ".flydocs", "manifest.json"));
5393
+ await copyFile(mfSrc, join27(targetDir, ".flydocs", "manifest.json"));
4939
5394
  printStatus(".flydocs/manifest.json");
4940
5395
  }
4941
5396
  await generateIntegrity(targetDir, version);
@@ -4997,22 +5452,22 @@ var uninstall_exports = {};
4997
5452
  __export(uninstall_exports, {
4998
5453
  default: () => uninstall_default
4999
5454
  });
5000
- import { defineCommand as defineCommand6 } from "citty";
5001
- import { resolve as resolve5, join as join25 } from "path";
5002
- import { readdir as readdir7, rm as rm6, rename as rename2 } from "fs/promises";
5003
- import { confirm as confirm5, select as select4, isCancel as isCancel6, cancel as cancel5 } from "@clack/prompts";
5004
- import pc11 from "picocolors";
5455
+ import { defineCommand as defineCommand7 } from "citty";
5456
+ import { resolve as resolve6, join as join28 } from "path";
5457
+ import { readdir as readdir9, rm as rm8, rename as rename2 } from "fs/promises";
5458
+ import { confirm as confirm5, select as select5, isCancel as isCancel7, cancel as cancel5 } from "@clack/prompts";
5459
+ import pc12 from "picocolors";
5005
5460
  async function removeOwnedSkills(targetDir) {
5006
- const skillsDir = join25(targetDir, ".claude", "skills");
5461
+ const skillsDir = join28(targetDir, ".claude", "skills");
5007
5462
  const removed = [];
5008
5463
  if (!await pathExists(skillsDir)) {
5009
5464
  return removed;
5010
5465
  }
5011
5466
  try {
5012
- const entries = await readdir7(skillsDir);
5467
+ const entries = await readdir9(skillsDir);
5013
5468
  for (const entry of entries) {
5014
5469
  if (entry.startsWith(OWNED_SKILL_PREFIX)) {
5015
- await rm6(join25(skillsDir, entry), { recursive: true, force: true });
5470
+ await rm8(join28(skillsDir, entry), { recursive: true, force: true });
5016
5471
  removed.push(`.claude/skills/${entry}`);
5017
5472
  }
5018
5473
  }
@@ -5021,16 +5476,16 @@ async function removeOwnedSkills(targetDir) {
5021
5476
  return removed;
5022
5477
  }
5023
5478
  async function removeOwnedCursorRules(targetDir) {
5024
- const rulesDir = join25(targetDir, ".cursor", "rules");
5479
+ const rulesDir = join28(targetDir, ".cursor", "rules");
5025
5480
  const removed = [];
5026
5481
  if (!await pathExists(rulesDir)) {
5027
5482
  return removed;
5028
5483
  }
5029
5484
  try {
5030
- const entries = await readdir7(rulesDir);
5485
+ const entries = await readdir9(rulesDir);
5031
5486
  for (const entry of entries) {
5032
5487
  if (entry.startsWith(OWNED_RULE_PREFIX) && entry.endsWith(".mdc")) {
5033
- await rm6(join25(rulesDir, entry), { force: true });
5488
+ await rm8(join28(rulesDir, entry), { force: true });
5034
5489
  removed.push(`.cursor/rules/${entry}`);
5035
5490
  }
5036
5491
  }
@@ -5040,7 +5495,7 @@ async function removeOwnedCursorRules(targetDir) {
5040
5495
  }
5041
5496
  async function isEmptyDir(dirPath) {
5042
5497
  try {
5043
- const entries = await readdir7(dirPath);
5498
+ const entries = await readdir9(dirPath);
5044
5499
  return entries.length === 0;
5045
5500
  } catch {
5046
5501
  return false;
@@ -5049,9 +5504,9 @@ async function isEmptyDir(dirPath) {
5049
5504
  async function cleanupEmptyParents(targetDir, dirs) {
5050
5505
  const cleaned = [];
5051
5506
  for (const dir of dirs) {
5052
- const fullPath = join25(targetDir, dir);
5507
+ const fullPath = join28(targetDir, dir);
5053
5508
  if (await pathExists(fullPath) && await isEmptyDir(fullPath)) {
5054
- await rm6(fullPath, { recursive: true, force: true });
5509
+ await rm8(fullPath, { recursive: true, force: true });
5055
5510
  cleaned.push(dir);
5056
5511
  }
5057
5512
  }
@@ -5081,7 +5536,7 @@ var init_uninstall = __esm({
5081
5536
  ];
5082
5537
  OWNED_SKILL_PREFIX = "flydocs-";
5083
5538
  OWNED_RULE_PREFIX = "flydocs-";
5084
- uninstall_default = defineCommand6({
5539
+ uninstall_default = defineCommand7({
5085
5540
  meta: {
5086
5541
  name: "uninstall",
5087
5542
  description: "Remove FlyDocs from a project directory"
@@ -5117,7 +5572,7 @@ var init_uninstall = __esm({
5117
5572
  printBanner(CLI_VERSION);
5118
5573
  let targetDir;
5119
5574
  if (args.path) {
5120
- targetDir = resolve5(args.path.replace(/^~/, process.env.HOME ?? "~"));
5575
+ targetDir = resolve6(args.path.replace(/^~/, process.env.HOME ?? "~"));
5121
5576
  } else if (args.here) {
5122
5577
  targetDir = process.cwd();
5123
5578
  } else {
@@ -5127,9 +5582,9 @@ var init_uninstall = __esm({
5127
5582
  printError(`Directory does not exist: ${targetDir}`);
5128
5583
  process.exit(1);
5129
5584
  }
5130
- targetDir = resolve5(targetDir);
5131
- const hasFlydocs = await pathExists(join25(targetDir, ".flydocs"));
5132
- const hasAgentsMd = await pathExists(join25(targetDir, "AGENTS.md"));
5585
+ targetDir = resolve6(targetDir);
5586
+ const hasFlydocs = await pathExists(join28(targetDir, ".flydocs"));
5587
+ const hasAgentsMd = await pathExists(join28(targetDir, "AGENTS.md"));
5133
5588
  if (!hasFlydocs && !hasAgentsMd) {
5134
5589
  printError(`Not a FlyDocs project: ${targetDir}`);
5135
5590
  printInfo("No .flydocs/ directory or AGENTS.md found.");
@@ -5141,12 +5596,12 @@ var init_uninstall = __esm({
5141
5596
  const removeAll = forceAll || args.all;
5142
5597
  const skipPrompts = forceAll || args.yes;
5143
5598
  let contentAction = "preserve";
5144
- const hasUserContent = await pathExists(join25(targetDir, "flydocs"));
5599
+ const hasUserContent = await pathExists(join28(targetDir, "flydocs"));
5145
5600
  if (hasUserContent) {
5146
5601
  if (removeAll) {
5147
5602
  contentAction = "remove";
5148
5603
  } else if (!skipPrompts) {
5149
- const choice = await select4({
5604
+ const choice = await select5({
5150
5605
  message: "What should happen to your flydocs/ content (project docs, knowledge base)?",
5151
5606
  options: [
5152
5607
  {
@@ -5166,7 +5621,7 @@ var init_uninstall = __esm({
5166
5621
  }
5167
5622
  ]
5168
5623
  });
5169
- if (isCancel6(choice)) {
5624
+ if (isCancel7(choice)) {
5170
5625
  cancel5("Uninstall cancelled.");
5171
5626
  process.exit(0);
5172
5627
  }
@@ -5175,39 +5630,39 @@ var init_uninstall = __esm({
5175
5630
  }
5176
5631
  if (!skipPrompts) {
5177
5632
  console.log();
5178
- console.log(pc11.bold("The following will be removed:"));
5633
+ console.log(pc12.bold("The following will be removed:"));
5179
5634
  console.log();
5180
5635
  console.log(" Framework files:");
5181
5636
  for (const [path] of ALWAYS_REMOVED) {
5182
- console.log(` ${pc11.dim(path)}`);
5637
+ console.log(` ${pc12.dim(path)}`);
5183
5638
  }
5184
- console.log(` ${pc11.dim(".claude/skills/flydocs-*")}`);
5185
- console.log(` ${pc11.dim(".cursor/rules/flydocs-*.mdc")}`);
5639
+ console.log(` ${pc12.dim(".claude/skills/flydocs-*")}`);
5640
+ console.log(` ${pc12.dim(".cursor/rules/flydocs-*.mdc")}`);
5186
5641
  if (hasUserContent) {
5187
5642
  if (contentAction === "archive") {
5188
5643
  console.log();
5189
5644
  console.log(
5190
- ` User content: ${pc11.yellow("flydocs/ -> flydocs-archive/")}`
5645
+ ` User content: ${pc12.yellow("flydocs/ -> flydocs-archive/")}`
5191
5646
  );
5192
5647
  } else if (contentAction === "remove") {
5193
5648
  console.log();
5194
- console.log(` User content: ${pc11.red("flydocs/ (deleted)")}`);
5649
+ console.log(` User content: ${pc12.red("flydocs/ (deleted)")}`);
5195
5650
  } else {
5196
5651
  console.log();
5197
- console.log(` User content: ${pc11.green("flydocs/ (preserved)")}`);
5652
+ console.log(` User content: ${pc12.green("flydocs/ (preserved)")}`);
5198
5653
  }
5199
5654
  }
5200
5655
  console.log();
5201
- console.log(pc11.bold("Preserved:"));
5656
+ console.log(pc12.bold("Preserved:"));
5202
5657
  console.log(
5203
- ` ${pc11.dim(".claude/skills/ (non-flydocs community skills)")}`
5658
+ ` ${pc12.dim(".claude/skills/ (non-flydocs community skills)")}`
5204
5659
  );
5205
- console.log(` ${pc11.dim(".env, .env.local")}`);
5660
+ console.log(` ${pc12.dim(".env, .env.local")}`);
5206
5661
  console.log();
5207
5662
  const shouldContinue = await confirm5({
5208
5663
  message: "Proceed with uninstall?"
5209
5664
  });
5210
- if (isCancel6(shouldContinue) || !shouldContinue) {
5665
+ if (isCancel7(shouldContinue) || !shouldContinue) {
5211
5666
  cancel5("Uninstall cancelled.");
5212
5667
  process.exit(0);
5213
5668
  }
@@ -5224,16 +5679,16 @@ var init_uninstall = __esm({
5224
5679
  const removedRules = await removeOwnedCursorRules(targetDir);
5225
5680
  result.removed.push(...removedRules);
5226
5681
  for (const [relativePath, type] of ALWAYS_REMOVED) {
5227
- const fullPath = join25(targetDir, relativePath);
5682
+ const fullPath = join28(targetDir, relativePath);
5228
5683
  if (!await pathExists(fullPath)) {
5229
5684
  result.skipped.push(relativePath);
5230
5685
  continue;
5231
5686
  }
5232
5687
  try {
5233
5688
  if (type === "dir") {
5234
- await rm6(fullPath, { recursive: true, force: true });
5689
+ await rm8(fullPath, { recursive: true, force: true });
5235
5690
  } else {
5236
- await rm6(fullPath, { force: true });
5691
+ await rm8(fullPath, { force: true });
5237
5692
  }
5238
5693
  result.removed.push(relativePath);
5239
5694
  } catch {
@@ -5242,16 +5697,16 @@ var init_uninstall = __esm({
5242
5697
  }
5243
5698
  }
5244
5699
  if (hasUserContent) {
5245
- const flydocsPath = join25(targetDir, "flydocs");
5700
+ const flydocsPath = join28(targetDir, "flydocs");
5246
5701
  if (contentAction === "archive") {
5247
- const archivePath = join25(targetDir, "flydocs-archive");
5702
+ const archivePath = join28(targetDir, "flydocs-archive");
5248
5703
  if (await pathExists(archivePath)) {
5249
- await rm6(archivePath, { recursive: true, force: true });
5704
+ await rm8(archivePath, { recursive: true, force: true });
5250
5705
  }
5251
5706
  await rename2(flydocsPath, archivePath);
5252
5707
  result.archived.push("flydocs/ -> flydocs-archive/");
5253
5708
  } else if (contentAction === "remove") {
5254
- await rm6(flydocsPath, { recursive: true, force: true });
5709
+ await rm8(flydocsPath, { recursive: true, force: true });
5255
5710
  result.removed.push("flydocs/");
5256
5711
  }
5257
5712
  }
@@ -5270,17 +5725,17 @@ var init_uninstall = __esm({
5270
5725
  result.restored = originals.map((f) => f.relativePath);
5271
5726
  }
5272
5727
  console.log();
5273
- console.log(pc11.bold("Uninstall Summary"));
5728
+ console.log(pc12.bold("Uninstall Summary"));
5274
5729
  console.log();
5275
5730
  if (result.removed.length > 0) {
5276
- console.log(` ${pc11.green("Removed")} (${result.removed.length}):`);
5731
+ console.log(` ${pc12.green("Removed")} (${result.removed.length}):`);
5277
5732
  for (const item of result.removed) {
5278
5733
  printStatus(item);
5279
5734
  }
5280
5735
  }
5281
5736
  if (result.archived.length > 0) {
5282
5737
  console.log();
5283
- console.log(` ${pc11.yellow("Archived")} (${result.archived.length}):`);
5738
+ console.log(` ${pc12.yellow("Archived")} (${result.archived.length}):`);
5284
5739
  for (const item of result.archived) {
5285
5740
  printInfo(item);
5286
5741
  }
@@ -5288,7 +5743,7 @@ var init_uninstall = __esm({
5288
5743
  if (result.restored.length > 0) {
5289
5744
  console.log();
5290
5745
  console.log(
5291
- ` ${pc11.green("Restored")} (${result.restored.length} pre-FlyDocs original(s)):`
5746
+ ` ${pc12.green("Restored")} (${result.restored.length} pre-FlyDocs original(s)):`
5292
5747
  );
5293
5748
  for (const item of result.restored) {
5294
5749
  printInfo(item);
@@ -5297,16 +5752,16 @@ var init_uninstall = __esm({
5297
5752
  if (result.skipped.length > 0) {
5298
5753
  console.log();
5299
5754
  console.log(
5300
- ` ${pc11.dim("Skipped")} (${result.skipped.length} \u2014 not found):`
5755
+ ` ${pc12.dim("Skipped")} (${result.skipped.length} \u2014 not found):`
5301
5756
  );
5302
5757
  for (const item of result.skipped) {
5303
- console.log(` ${pc11.dim(item)}`);
5758
+ console.log(` ${pc12.dim(item)}`);
5304
5759
  }
5305
5760
  }
5306
5761
  console.log();
5307
5762
  printStatus("FlyDocs has been removed from this project.");
5308
5763
  console.log();
5309
- printInfo(`To reinstall: ${pc11.cyan("npx @flydocs/cli install --here")}`);
5764
+ printInfo(`To reinstall: ${pc12.cyan("npx @flydocs/cli install --here")}`);
5310
5765
  console.log();
5311
5766
  }
5312
5767
  });
@@ -5318,28 +5773,28 @@ var setup_exports = {};
5318
5773
  __export(setup_exports, {
5319
5774
  default: () => setup_default
5320
5775
  });
5321
- import { defineCommand as defineCommand7 } from "citty";
5322
- import pc12 from "picocolors";
5776
+ import { defineCommand as defineCommand8 } from "citty";
5777
+ import pc13 from "picocolors";
5323
5778
  var setup_default;
5324
5779
  var init_setup = __esm({
5325
5780
  "src/commands/setup.ts"() {
5326
5781
  "use strict";
5327
- setup_default = defineCommand7({
5782
+ setup_default = defineCommand8({
5328
5783
  meta: {
5329
5784
  name: "setup",
5330
5785
  description: "Configure FlyDocs settings for this project"
5331
5786
  },
5332
5787
  run() {
5333
5788
  console.log();
5334
- console.log(` ${pc12.bold("FlyDocs Setup")}`);
5789
+ console.log(` ${pc13.bold("FlyDocs Setup")}`);
5335
5790
  console.log();
5336
5791
  console.log(` Setup runs inside your IDE as an interactive AI command.`);
5337
5792
  console.log();
5338
5793
  console.log(
5339
- ` ${pc12.cyan("Claude Code:")} Type ${pc12.bold("/flydocs-setup")} in chat`
5794
+ ` ${pc13.cyan("Claude Code:")} Type ${pc13.bold("/flydocs-setup")} in chat`
5340
5795
  );
5341
5796
  console.log(
5342
- ` ${pc12.cyan("Cursor:")} Type ${pc12.bold("/flydocs-setup")} in chat`
5797
+ ` ${pc13.cyan("Cursor:")} Type ${pc13.bold("/flydocs-setup")} in chat`
5343
5798
  );
5344
5799
  console.log();
5345
5800
  console.log(` This configures your project context, detects your stack,`);
@@ -5355,14 +5810,14 @@ var skills_exports = {};
5355
5810
  __export(skills_exports, {
5356
5811
  default: () => skills_default
5357
5812
  });
5358
- import { defineCommand as defineCommand8 } from "citty";
5359
- import pc13 from "picocolors";
5813
+ import { defineCommand as defineCommand9 } from "citty";
5814
+ import pc14 from "picocolors";
5360
5815
  var list, search, add, remove, skills_default;
5361
5816
  var init_skills2 = __esm({
5362
5817
  "src/commands/skills.ts"() {
5363
5818
  "use strict";
5364
5819
  init_skill_manager();
5365
- list = defineCommand8({
5820
+ list = defineCommand9({
5366
5821
  meta: {
5367
5822
  name: "list",
5368
5823
  description: "List installed skills"
@@ -5378,26 +5833,26 @@ var init_skills2 = __esm({
5378
5833
  console.log(`${total} skill(s) installed:`);
5379
5834
  if (result.platform.length > 0) {
5380
5835
  console.log();
5381
- console.log(pc13.bold("Platform"));
5836
+ console.log(pc14.bold("Platform"));
5382
5837
  for (const skill of result.platform) {
5383
5838
  console.log(
5384
- ` ${skill.name} ${pc13.dim(`(${skill.triggers} triggers)`)}`
5839
+ ` ${skill.name} ${pc14.dim(`(${skill.triggers} triggers)`)}`
5385
5840
  );
5386
5841
  }
5387
5842
  }
5388
5843
  if (result.community.length > 0) {
5389
5844
  console.log();
5390
- console.log(pc13.bold("Community"));
5845
+ console.log(pc14.bold("Community"));
5391
5846
  for (const skill of result.community) {
5392
5847
  console.log(
5393
- ` ${skill.name} ${pc13.dim(`(${skill.triggers} triggers)`)}`
5848
+ ` ${skill.name} ${pc14.dim(`(${skill.triggers} triggers)`)}`
5394
5849
  );
5395
5850
  }
5396
5851
  }
5397
5852
  console.log();
5398
5853
  }
5399
5854
  });
5400
- search = defineCommand8({
5855
+ search = defineCommand9({
5401
5856
  meta: {
5402
5857
  name: "search",
5403
5858
  description: "Search community skills"
@@ -5413,24 +5868,24 @@ var init_skills2 = __esm({
5413
5868
  const results = await searchCatalog(args.keyword);
5414
5869
  if (results.length === 0) {
5415
5870
  console.log(`No skills found for "${args.keyword}".`);
5416
- console.log(` Browse the catalog at: ${pc13.cyan("https://skills.sh/")}`);
5871
+ console.log(` Browse the catalog at: ${pc14.cyan("https://skills.sh/")}`);
5417
5872
  return;
5418
5873
  }
5419
5874
  console.log();
5420
5875
  console.log(`${results.length} skill(s) matching "${args.keyword}":`);
5421
5876
  console.log();
5422
5877
  for (const skill of results) {
5423
- console.log(` ${pc13.bold(skill.name)}`);
5878
+ console.log(` ${pc14.bold(skill.name)}`);
5424
5879
  console.log(` ${skill.description}`);
5425
- console.log(` ${pc13.dim(skill.repo)}`);
5880
+ console.log(` ${pc14.dim(skill.repo)}`);
5426
5881
  if (skill.tags.length > 0) {
5427
- console.log(` ${pc13.dim(skill.tags.join(", "))}`);
5882
+ console.log(` ${pc14.dim(skill.tags.join(", "))}`);
5428
5883
  }
5429
5884
  console.log();
5430
5885
  }
5431
5886
  }
5432
5887
  });
5433
- add = defineCommand8({
5888
+ add = defineCommand9({
5434
5889
  meta: {
5435
5890
  name: "add",
5436
5891
  description: "Install a community skill"
@@ -5446,7 +5901,7 @@ var init_skills2 = __esm({
5446
5901
  await addSkill(process.cwd(), args.source);
5447
5902
  }
5448
5903
  });
5449
- remove = defineCommand8({
5904
+ remove = defineCommand9({
5450
5905
  meta: {
5451
5906
  name: "remove",
5452
5907
  description: "Remove an installed community skill"
@@ -5462,7 +5917,7 @@ var init_skills2 = __esm({
5462
5917
  await removeSkill(process.cwd(), args.name);
5463
5918
  }
5464
5919
  });
5465
- skills_default = defineCommand8({
5920
+ skills_default = defineCommand9({
5466
5921
  meta: {
5467
5922
  name: "skills",
5468
5923
  description: "Manage FlyDocs skills (list, search, add, remove)"
@@ -5482,10 +5937,10 @@ var connect_exports = {};
5482
5937
  __export(connect_exports, {
5483
5938
  default: () => connect_default
5484
5939
  });
5485
- import { defineCommand as defineCommand9 } from "citty";
5486
- import { text as text4, confirm as confirm6, isCancel as isCancel7, cancel as cancel6 } from "@clack/prompts";
5487
- import pc14 from "picocolors";
5488
- import { join as join26 } from "path";
5940
+ import { defineCommand as defineCommand10 } from "citty";
5941
+ import { text as text4, confirm as confirm6, isCancel as isCancel8, cancel as cancel6 } from "@clack/prompts";
5942
+ import pc15 from "picocolors";
5943
+ import { join as join29 } from "path";
5489
5944
  var connect_default;
5490
5945
  var init_connect = __esm({
5491
5946
  "src/commands/connect.ts"() {
@@ -5495,7 +5950,7 @@ var init_connect = __esm({
5495
5950
  init_template();
5496
5951
  init_ui();
5497
5952
  init_api_key();
5498
- connect_default = defineCommand9({
5953
+ connect_default = defineCommand10({
5499
5954
  meta: {
5500
5955
  name: "connect",
5501
5956
  description: "Connect FlyDocs to a cloud provider"
@@ -5520,11 +5975,11 @@ var init_connect = __esm({
5520
5975
  },
5521
5976
  async run({ args }) {
5522
5977
  const targetDir = args.path ?? process.cwd();
5523
- const configPath = join26(targetDir, ".flydocs", "config.json");
5978
+ const configPath = join29(targetDir, ".flydocs", "config.json");
5524
5979
  if (!await pathExists(configPath)) {
5525
5980
  printError("Not a FlyDocs project (.flydocs/config.json not found).");
5526
5981
  console.log(
5527
- ` Run ${pc14.cyan("flydocs")} first to install FlyDocs in this project.`
5982
+ ` Run ${pc15.cyan("flydocs")} first to install FlyDocs in this project.`
5528
5983
  );
5529
5984
  process.exit(1);
5530
5985
  }
@@ -5535,16 +5990,16 @@ var init_connect = __esm({
5535
5990
  const reconnect = await confirm6({
5536
5991
  message: "Want to update your API key?"
5537
5992
  });
5538
- if (isCancel7(reconnect) || !reconnect) {
5993
+ if (isCancel8(reconnect) || !reconnect) {
5539
5994
  console.log(` No changes made.`);
5540
5995
  return;
5541
5996
  }
5542
5997
  }
5543
5998
  console.log();
5544
- console.log(` ${pc14.bold("Connect to FlyDocs Cloud")}`);
5999
+ console.log(` ${pc15.bold("Connect to FlyDocs Cloud")}`);
5545
6000
  console.log();
5546
6001
  console.log(
5547
- ` ${pc14.dim("Get your API key (fdk_...) from your FlyDocs dashboard")}`
6002
+ ` ${pc15.dim("Get your API key (fdk_...) from your FlyDocs dashboard")}`
5548
6003
  );
5549
6004
  console.log();
5550
6005
  let apiKey = args.key ?? "";
@@ -5560,7 +6015,7 @@ var init_connect = __esm({
5560
6015
  return void 0;
5561
6016
  }
5562
6017
  });
5563
- if (isCancel7(keyInput)) {
6018
+ if (isCancel8(keyInput)) {
5564
6019
  cancel6("Connection cancelled.");
5565
6020
  process.exit(0);
5566
6021
  }
@@ -5582,7 +6037,7 @@ var init_connect = __esm({
5582
6037
  console.log(` Check your key and try again.`);
5583
6038
  process.exit(1);
5584
6039
  }
5585
- printStatus(`Connected to ${pc14.bold(result.org)}`);
6040
+ printStatus(`Connected to ${pc15.bold(result.org)}`);
5586
6041
  } catch {
5587
6042
  printError(
5588
6043
  "Could not reach relay API. Check your network and try again."
@@ -5590,7 +6045,7 @@ var init_connect = __esm({
5590
6045
  process.exit(1);
5591
6046
  }
5592
6047
  const envFile = await storeEnvKey(targetDir, "FLYDOCS_API_KEY", apiKey);
5593
- printStatus(`API key stored in ${pc14.dim(envFile)}`);
6048
+ printStatus(`API key stored in ${pc15.dim(envFile)}`);
5594
6049
  } else {
5595
6050
  try {
5596
6051
  const result = await validateLinearKey(apiKey);
@@ -5600,7 +6055,7 @@ var init_connect = __esm({
5600
6055
  process.exit(1);
5601
6056
  }
5602
6057
  printStatus(
5603
- `Authenticated as ${pc14.bold(result.name)} (${result.email})`
6058
+ `Authenticated as ${pc15.bold(result.name)} (${result.email})`
5604
6059
  );
5605
6060
  } catch {
5606
6061
  printError("Invalid API key or network error.");
@@ -5608,7 +6063,7 @@ var init_connect = __esm({
5608
6063
  process.exit(1);
5609
6064
  }
5610
6065
  const envFile = await storeEnvKey(targetDir, "LINEAR_API_KEY", apiKey);
5611
- printStatus(`API key stored in ${pc14.dim(envFile)}`);
6066
+ printStatus(`API key stored in ${pc15.dim(envFile)}`);
5612
6067
  }
5613
6068
  const wasLocal = config.tier === "local";
5614
6069
  config.tier = "cloud";
@@ -5624,14 +6079,14 @@ var init_connect = __esm({
5624
6079
  }
5625
6080
  console.log();
5626
6081
  console.log(
5627
- ` ${pc14.bold("Connected!")} Your project is now on the cloud tier.`
6082
+ ` ${pc15.bold("Connected!")} Your project is now on the cloud tier.`
5628
6083
  );
5629
6084
  console.log();
5630
6085
  console.log(` Next steps:`);
5631
6086
  console.log(
5632
- ` 1. Run ${pc14.cyan("/flydocs-setup")} in your IDE to configure your project`
6087
+ ` 1. Run ${pc15.cyan("/flydocs-setup")} in your IDE to configure your project`
5633
6088
  );
5634
- console.log(` 2. Run ${pc14.cyan("/start-session")} to begin working`);
6089
+ console.log(` 2. Run ${pc15.cyan("/start-session")} to begin working`);
5635
6090
  console.log();
5636
6091
  }
5637
6092
  });
@@ -5643,9 +6098,9 @@ var auth_exports = {};
5643
6098
  __export(auth_exports, {
5644
6099
  default: () => auth_default
5645
6100
  });
5646
- import { defineCommand as defineCommand10 } from "citty";
5647
- import { text as text5, confirm as confirm7, isCancel as isCancel8, cancel as cancel7 } from "@clack/prompts";
5648
- import pc15 from "picocolors";
6101
+ import { defineCommand as defineCommand11 } from "citty";
6102
+ import { text as text5, confirm as confirm7, isCancel as isCancel9, cancel as cancel7 } from "@clack/prompts";
6103
+ import pc16 from "picocolors";
5649
6104
  var auth_default;
5650
6105
  var init_auth = __esm({
5651
6106
  "src/commands/auth.ts"() {
@@ -5653,7 +6108,7 @@ var init_auth = __esm({
5653
6108
  init_ui();
5654
6109
  init_api_key();
5655
6110
  init_global_config();
5656
- auth_default = defineCommand10({
6111
+ auth_default = defineCommand11({
5657
6112
  meta: {
5658
6113
  name: "auth",
5659
6114
  description: "Store API key globally (~/.flydocs/credentials)"
@@ -5667,25 +6122,25 @@ var init_auth = __esm({
5667
6122
  },
5668
6123
  async run({ args }) {
5669
6124
  console.log();
5670
- console.log(` ${pc15.bold("FlyDocs Authentication")}`);
6125
+ console.log(` ${pc16.bold("FlyDocs Authentication")}`);
5671
6126
  console.log();
5672
6127
  let apiKey = args.key ?? "";
5673
6128
  const existing = await readGlobalCredential();
5674
6129
  if (existing?.apiKey && !apiKey) {
5675
6130
  printInfo(
5676
- `Existing key found: ${pc15.dim(existing.apiKey.slice(0, 8) + "...")}`
6131
+ `Existing key found: ${pc16.dim(existing.apiKey.slice(0, 8) + "...")}`
5677
6132
  );
5678
6133
  const replace = await confirm7({
5679
6134
  message: "Replace with a new key?"
5680
6135
  });
5681
- if (isCancel8(replace) || !replace) {
6136
+ if (isCancel9(replace) || !replace) {
5682
6137
  console.log(` No changes made.`);
5683
6138
  return;
5684
6139
  }
5685
6140
  }
5686
6141
  if (!apiKey) {
5687
6142
  console.log(
5688
- ` ${pc15.dim("Get your API key (fdk_...) from your FlyDocs dashboard")}`
6143
+ ` ${pc16.dim("Get your API key (fdk_...) from your FlyDocs dashboard")}`
5689
6144
  );
5690
6145
  console.log();
5691
6146
  const keyInput = await text5({
@@ -5699,7 +6154,7 @@ var init_auth = __esm({
5699
6154
  return void 0;
5700
6155
  }
5701
6156
  });
5702
- if (isCancel8(keyInput)) {
6157
+ if (isCancel9(keyInput)) {
5703
6158
  cancel7("Authentication cancelled.");
5704
6159
  process.exit(0);
5705
6160
  }
@@ -5721,7 +6176,7 @@ var init_auth = __esm({
5721
6176
  printError("Invalid API key. Check your key and try again.");
5722
6177
  process.exit(1);
5723
6178
  }
5724
- printStatus(`Authenticated with ${pc15.bold(result.org)}`);
6179
+ printStatus(`Authenticated with ${pc16.bold(result.org)}`);
5725
6180
  } catch {
5726
6181
  printError(
5727
6182
  "Could not reach FlyDocs API. Check your network and try again."
@@ -5736,10 +6191,10 @@ var init_auth = __esm({
5736
6191
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
5737
6192
  lastValidated: (/* @__PURE__ */ new Date()).toISOString()
5738
6193
  });
5739
- printStatus(`Key stored at ${pc15.dim(credentialsPath())}`);
6194
+ printStatus(`Key stored at ${pc16.dim(credentialsPath())}`);
5740
6195
  await checkCredentialPermissions();
5741
6196
  console.log();
5742
- console.log(` ${pc15.bold("Authenticated!")} Key stored globally.`);
6197
+ console.log(` ${pc16.bold("Authenticated!")} Key stored globally.`);
5743
6198
  console.log(` All FlyDocs projects on this machine will use this key.`);
5744
6199
  console.log();
5745
6200
  }
@@ -5747,175 +6202,6 @@ var init_auth = __esm({
5747
6202
  }
5748
6203
  });
5749
6204
 
5750
- // src/commands/sync.ts
5751
- var sync_exports = {};
5752
- __export(sync_exports, {
5753
- default: () => sync_default
5754
- });
5755
- import { defineCommand as defineCommand11 } from "citty";
5756
- import pc16 from "picocolors";
5757
- import { join as join27, resolve as resolve6 } from "path";
5758
- import { mkdir as mkdir14, writeFile as writeFile17 } from "fs/promises";
5759
- async function resolveArtifactWriteRoot(targetDir, config) {
5760
- const topology = config.topology;
5761
- if (topology && topology.type === 4 && topology.label === "sibling-repos") {
5762
- const parentDir = join27(targetDir, "..");
5763
- const workspaceFile = await readWorkspaceFile(parentDir);
5764
- if (workspaceFile) {
5765
- return resolve6(parentDir);
5766
- }
5767
- }
5768
- return targetDir;
5769
- }
5770
- var sync_default;
5771
- var init_sync = __esm({
5772
- "src/commands/sync.ts"() {
5773
- "use strict";
5774
- init_ui();
5775
- init_global_config();
5776
- init_config();
5777
- init_config_integrity();
5778
- init_fs_ops();
5779
- init_types();
5780
- init_gitignore();
5781
- init_artifacts();
5782
- init_workspace();
5783
- init_relay_client();
5784
- sync_default = defineCommand11({
5785
- meta: {
5786
- name: "sync",
5787
- description: "Pull latest config and templates from server"
5788
- },
5789
- args: {
5790
- path: {
5791
- type: "string",
5792
- description: "Path to project directory"
5793
- }
5794
- },
5795
- async run({ args }) {
5796
- const targetDir = args.path ?? process.cwd();
5797
- const changes = [];
5798
- console.log();
5799
- printInfo("Syncing with server...");
5800
- const resolved = await resolveApiKey(void 0, targetDir);
5801
- if (!resolved) {
5802
- printError(
5803
- "No API key found. Run `flydocs auth` or `flydocs init` first."
5804
- );
5805
- process.exit(1);
5806
- }
5807
- const apiKey = resolved.key;
5808
- const cred = await readGlobalCredential();
5809
- const workspaceId = cred?.workspaceId;
5810
- if (!workspaceId) {
5811
- printError(
5812
- "No workspace ID found. Run `flydocs init` to set up your workspace."
5813
- );
5814
- process.exit(1);
5815
- }
5816
- let currentTemplateVersion = 0;
5817
- let currentArtifactVersion = 0;
5818
- try {
5819
- const currentConfig = await readAnyConfig(targetDir);
5820
- if (isConfigV2(currentConfig)) {
5821
- currentTemplateVersion = currentConfig.configVersion ?? 0;
5822
- currentArtifactVersion = currentConfig.artifactVersion ?? 0;
5823
- }
5824
- } catch {
5825
- }
5826
- let serverResponse;
5827
- try {
5828
- serverResponse = await fetchConfigV2(apiKey, { workspaceId });
5829
- } catch (err) {
5830
- if (err instanceof RelayError) {
5831
- printWarning(
5832
- `Server unavailable (${err.status}), using cached config.`
5833
- );
5834
- } else {
5835
- printWarning("Server unreachable, using cached config.");
5836
- }
5837
- console.log(` ${pc16.dim("Config may be stale. Retry when connected.")}`);
5838
- return;
5839
- }
5840
- if (!serverResponse.valid) {
5841
- printWarning("Server returned invalid config. Keeping current config.");
5842
- return;
5843
- }
5844
- await mkdir14(join27(targetDir, ".flydocs"), { recursive: true });
5845
- const configWithHash = applyConfigHash(serverResponse.config);
5846
- await writeConfig(targetDir, configWithHash);
5847
- changes.push("Updated .flydocs/config.json");
5848
- const serverTemplateVersion = serverResponse.templates.version;
5849
- if (serverTemplateVersion > currentTemplateVersion) {
5850
- try {
5851
- const templatesResponse = await fetchTemplates(
5852
- apiKey,
5853
- currentTemplateVersion,
5854
- workspaceId
5855
- );
5856
- if (templatesResponse.templates.length > 0) {
5857
- const templatesDir = join27(
5858
- targetDir,
5859
- ".claude",
5860
- "skills",
5861
- "flydocs-workflow",
5862
- "templates"
5863
- );
5864
- await mkdir14(templatesDir, { recursive: true });
5865
- for (const template of templatesResponse.templates) {
5866
- const filename = `${template.type}.md`;
5867
- const subdir = template.category === "issue" ? "issues" : template.category === "pr" ? "pr" : template.category === "comment" ? "." : ".";
5868
- const templateDir = join27(templatesDir, subdir);
5869
- await mkdir14(templateDir, { recursive: true });
5870
- await writeFile17(
5871
- join27(templateDir, filename),
5872
- template.content,
5873
- "utf-8"
5874
- );
5875
- }
5876
- changes.push(
5877
- `Updated ${templatesResponse.templates.length} templates (v${currentTemplateVersion} \u2192 v${serverTemplateVersion})`
5878
- );
5879
- }
5880
- } catch (err) {
5881
- if (err instanceof RelayError) {
5882
- printWarning("Could not fetch templates. Will retry on next sync.");
5883
- } else {
5884
- printWarning("Template sync failed. Will retry on next sync.");
5885
- }
5886
- }
5887
- }
5888
- const serverArtifactVersion = serverResponse.artifactVersion ?? 0;
5889
- if (serverArtifactVersion > currentArtifactVersion) {
5890
- const artifactWriteRoot = await resolveArtifactWriteRoot(
5891
- targetDir,
5892
- serverResponse.config
5893
- );
5894
- const { changes: artifactChanges } = await syncAllArtifacts(
5895
- artifactWriteRoot,
5896
- apiKey,
5897
- workspaceId,
5898
- currentArtifactVersion
5899
- );
5900
- changes.push(...artifactChanges);
5901
- if (artifactWriteRoot !== targetDir) {
5902
- changes.push(`Artifacts written to workspace root`);
5903
- }
5904
- }
5905
- await migrateGitignore(targetDir);
5906
- if (changes.length === 0) {
5907
- printStatus("Already up to date.");
5908
- } else {
5909
- for (const change of changes) {
5910
- printStatus(change);
5911
- }
5912
- }
5913
- console.log();
5914
- }
5915
- });
5916
- }
5917
- });
5918
-
5919
6205
  // src/commands/upgrade.ts
5920
6206
  var upgrade_exports = {};
5921
6207
  __export(upgrade_exports, {