@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 +694 -408
- package/package.json +1 -1
- package/template/.claude/CLAUDE.md +26 -0
- package/template/.claude/commands/flydocs-upgrade.md +3 -2
- package/template/.claude/commands/onboard.md +3 -2
- package/template/.claude/skills/flydocs-workflow/scripts/flydocs_api.py +38 -9
- package/template/.env.example +7 -4
- package/template/.flydocs/config.json +1 -1
- package/template/.flydocs/version +1 -1
- package/template/AGENTS.md +10 -0
- package/template/manifest.json +1 -1
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.
|
|
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:
|
|
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
|
|
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:
|
|
443
|
+
const { mkdir: mkdir16 } = await import("fs/promises");
|
|
444
444
|
const rulesDir = join4(targetDir, ".cursor", "rules");
|
|
445
|
-
await
|
|
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:
|
|
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
|
|
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
|
|
3108
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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(
|
|
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
|
|
3199
|
-
import { readFile as readFile13, writeFile as writeFile12, rm as
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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:
|
|
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:
|
|
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
|
|
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
|
|
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 =
|
|
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
|
-
|
|
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
|
|
3408
|
-
import { join as
|
|
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 =
|
|
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 =
|
|
3416
|
-
await mkdir10(
|
|
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 =
|
|
3540
|
+
const cursorRulesDir = join21(targetDir, ".cursor", "rules");
|
|
3426
3541
|
if (await pathExists(cursorRulesDir)) {
|
|
3427
3542
|
let entries;
|
|
3428
3543
|
try {
|
|
3429
|
-
entries = await
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
3481
|
-
import { join as
|
|
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 =
|
|
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 =
|
|
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
|
|
3612
|
+
const entries = await readdir6(parentDir);
|
|
3498
3613
|
for (const entry of entries) {
|
|
3499
3614
|
if (entry.startsWith(".")) continue;
|
|
3500
|
-
const entryPath =
|
|
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(
|
|
3618
|
+
const hasGit = await pathExists(join22(entryPath, ".git"));
|
|
3504
3619
|
const hasFlydocs = await pathExists(
|
|
3505
|
-
|
|
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 =
|
|
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
|
|
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 =
|
|
3779
|
+
const contextDir = join23(targetDir, "flydocs", "context");
|
|
3665
3780
|
await mkdir11(contextDir, { recursive: true });
|
|
3666
3781
|
if (response.projectMd) {
|
|
3667
|
-
const projectMdPath =
|
|
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 =
|
|
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
|
|
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(
|
|
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(
|
|
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 =
|
|
4066
|
+
const contextDir = join24(targetDir, "flydocs", "context");
|
|
3952
4067
|
await mkdir12(contextDir, { recursive: true });
|
|
3953
|
-
const projectMdPath =
|
|
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 =
|
|
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:
|
|
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 =
|
|
4125
|
+
const fullPath = join24(targetDir, dir);
|
|
4011
4126
|
if (await pathExists(fullPath)) {
|
|
4012
|
-
await
|
|
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 =
|
|
4132
|
+
const fullPath = join24(targetDir, file);
|
|
4018
4133
|
if (await pathExists(fullPath)) {
|
|
4019
|
-
await
|
|
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(
|
|
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(
|
|
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 =
|
|
4240
|
+
const cloneDir = join24(targetDir, shortName);
|
|
4126
4241
|
console.log();
|
|
4127
|
-
if (await pathExists(
|
|
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 =
|
|
4171
|
-
const workspaceMdPath =
|
|
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(
|
|
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 =
|
|
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 =
|
|
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 =
|
|
4276
|
-
const workspaceMdPath =
|
|
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 =
|
|
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
|
|
4556
|
-
import { resolve as
|
|
4557
|
-
import { mkdir as
|
|
4558
|
-
import { select as
|
|
4559
|
-
import
|
|
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
|
-
|
|
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 =
|
|
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
|
|
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 (
|
|
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 (
|
|
5073
|
+
if (isCancel6(enteredPath)) {
|
|
4651
5074
|
cancel4("Update cancelled.");
|
|
4652
5075
|
process.exit(0);
|
|
4653
5076
|
}
|
|
4654
|
-
targetDir =
|
|
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 =
|
|
5086
|
+
targetDir = resolve5(targetDir);
|
|
4664
5087
|
process.chdir(targetDir);
|
|
4665
|
-
const hasVersion = await pathExists(
|
|
5088
|
+
const hasVersion = await pathExists(join27(targetDir, ".flydocs", "version"));
|
|
4666
5089
|
const hasConfig = await pathExists(
|
|
4667
|
-
|
|
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
|
-
|
|
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 (
|
|
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 =
|
|
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(
|
|
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 =
|
|
4726
|
-
await
|
|
5178
|
+
const backupDir = join27(targetDir, ".flydocs", `backup-${ts}`);
|
|
5179
|
+
await mkdir15(backupDir, { recursive: true });
|
|
4727
5180
|
if (hasConfig) {
|
|
4728
|
-
await
|
|
4729
|
-
|
|
4730
|
-
|
|
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 =
|
|
4736
|
-
const entries = await
|
|
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
|
|
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
|
-
|
|
4781
|
-
|
|
5235
|
+
join27(templateDir, ".flydocs", "templates"),
|
|
5236
|
+
join27(targetDir, ".flydocs", "templates")
|
|
4782
5237
|
);
|
|
4783
5238
|
printStatus(".flydocs/templates");
|
|
4784
5239
|
await replaceDirectory(
|
|
4785
|
-
|
|
4786
|
-
|
|
5240
|
+
join27(templateDir, ".claude", "hooks"),
|
|
5241
|
+
join27(targetDir, ".claude", "hooks")
|
|
4787
5242
|
);
|
|
4788
5243
|
printStatus(".claude/hooks");
|
|
4789
5244
|
const hasExistingAgents = await pathExists(
|
|
4790
|
-
|
|
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(` ${
|
|
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 (
|
|
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 =
|
|
5277
|
+
const claudeAgentsSrc = join27(templateDir, ".claude", "agents");
|
|
4823
5278
|
if (await pathExists(claudeAgentsSrc)) {
|
|
4824
|
-
await
|
|
5279
|
+
await mkdir15(join27(targetDir, ".claude", "agents"), { recursive: true });
|
|
4825
5280
|
await copyDirectoryContents(
|
|
4826
5281
|
claudeAgentsSrc,
|
|
4827
|
-
|
|
5282
|
+
join27(targetDir, ".claude", "agents")
|
|
4828
5283
|
);
|
|
4829
5284
|
}
|
|
4830
|
-
const cursorAgentsSrc =
|
|
5285
|
+
const cursorAgentsSrc = join27(templateDir, ".cursor", "agents");
|
|
4831
5286
|
if (await pathExists(cursorAgentsSrc)) {
|
|
4832
|
-
await
|
|
5287
|
+
await mkdir15(join27(targetDir, ".cursor", "agents"), { recursive: true });
|
|
4833
5288
|
await copyDirectoryContents(
|
|
4834
5289
|
cursorAgentsSrc,
|
|
4835
|
-
|
|
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
|
-
|
|
4850
|
-
|
|
5304
|
+
join27(templateDir, ".claude", "CLAUDE.md"),
|
|
5305
|
+
join27(targetDir, ".claude", "CLAUDE.md")
|
|
4851
5306
|
);
|
|
4852
5307
|
await copyFile(
|
|
4853
|
-
|
|
4854
|
-
|
|
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
|
-
|
|
4859
|
-
|
|
5313
|
+
join27(templateDir, ".claude", "commands"),
|
|
5314
|
+
join27(targetDir, ".claude", "commands")
|
|
4860
5315
|
);
|
|
4861
5316
|
await copyDirectoryContents(
|
|
4862
|
-
|
|
4863
|
-
|
|
5317
|
+
join27(templateDir, ".claude", "commands"),
|
|
5318
|
+
join27(targetDir, ".cursor", "commands")
|
|
4864
5319
|
);
|
|
4865
5320
|
printStatus(".claude/commands, .cursor/commands");
|
|
4866
|
-
const skillsReadmeSrc =
|
|
5321
|
+
const skillsReadmeSrc = join27(templateDir, ".claude", "skills", "README.md");
|
|
4867
5322
|
if (await pathExists(skillsReadmeSrc)) {
|
|
4868
5323
|
await copyFile(
|
|
4869
5324
|
skillsReadmeSrc,
|
|
4870
|
-
|
|
5325
|
+
join27(targetDir, ".claude", "skills", "README.md")
|
|
4871
5326
|
);
|
|
4872
5327
|
}
|
|
4873
5328
|
printStatus(".claude/skills/README.md");
|
|
4874
5329
|
await copyFile(
|
|
4875
|
-
|
|
4876
|
-
|
|
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
|
-
|
|
4881
|
-
|
|
5335
|
+
join27(templateDir, "AGENTS.md"),
|
|
5336
|
+
join27(targetDir, "AGENTS.md")
|
|
4882
5337
|
);
|
|
4883
5338
|
printStatus("AGENTS.md");
|
|
4884
|
-
const envExampleSrc =
|
|
5339
|
+
const envExampleSrc = join27(templateDir, ".env.example");
|
|
4885
5340
|
if (await pathExists(envExampleSrc)) {
|
|
4886
|
-
await copyFile(envExampleSrc,
|
|
5341
|
+
await copyFile(envExampleSrc, join27(targetDir, ".env.example"));
|
|
4887
5342
|
printStatus(".env.example");
|
|
4888
5343
|
}
|
|
4889
|
-
const knowledgeTemplatesDir =
|
|
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
|
|
5351
|
+
await mkdir15(knowledgeTemplatesDir, { recursive: true });
|
|
4897
5352
|
}
|
|
4898
5353
|
for (const tmpl of ["decision.md", "feature.md", "note.md"]) {
|
|
4899
|
-
const src =
|
|
4900
|
-
const dest =
|
|
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
|
-
|
|
4928
|
-
|
|
5382
|
+
join27(templateDir, ".flydocs", "version"),
|
|
5383
|
+
join27(targetDir, ".flydocs", "version")
|
|
4929
5384
|
);
|
|
4930
5385
|
printStatus(`.flydocs/version \u2192 ${version}`);
|
|
4931
|
-
const clSrc =
|
|
5386
|
+
const clSrc = join27(templateDir, "CHANGELOG.md");
|
|
4932
5387
|
if (await pathExists(clSrc)) {
|
|
4933
|
-
await copyFile(clSrc,
|
|
5388
|
+
await copyFile(clSrc, join27(targetDir, ".flydocs", "CHANGELOG.md"));
|
|
4934
5389
|
printStatus(".flydocs/CHANGELOG.md");
|
|
4935
5390
|
}
|
|
4936
|
-
const mfSrc =
|
|
5391
|
+
const mfSrc = join27(templateDir, "manifest.json");
|
|
4937
5392
|
if (await pathExists(mfSrc)) {
|
|
4938
|
-
await copyFile(mfSrc,
|
|
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
|
|
5001
|
-
import { resolve as
|
|
5002
|
-
import { readdir as
|
|
5003
|
-
import { confirm as confirm5, select as
|
|
5004
|
-
import
|
|
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 =
|
|
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
|
|
5467
|
+
const entries = await readdir9(skillsDir);
|
|
5013
5468
|
for (const entry of entries) {
|
|
5014
5469
|
if (entry.startsWith(OWNED_SKILL_PREFIX)) {
|
|
5015
|
-
await
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
5507
|
+
const fullPath = join28(targetDir, dir);
|
|
5053
5508
|
if (await pathExists(fullPath) && await isEmptyDir(fullPath)) {
|
|
5054
|
-
await
|
|
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 =
|
|
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 =
|
|
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 =
|
|
5131
|
-
const hasFlydocs = await pathExists(
|
|
5132
|
-
const hasAgentsMd = await pathExists(
|
|
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(
|
|
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
|
|
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 (
|
|
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(
|
|
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(` ${
|
|
5637
|
+
console.log(` ${pc12.dim(path)}`);
|
|
5183
5638
|
}
|
|
5184
|
-
console.log(` ${
|
|
5185
|
-
console.log(` ${
|
|
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: ${
|
|
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: ${
|
|
5649
|
+
console.log(` User content: ${pc12.red("flydocs/ (deleted)")}`);
|
|
5195
5650
|
} else {
|
|
5196
5651
|
console.log();
|
|
5197
|
-
console.log(` User content: ${
|
|
5652
|
+
console.log(` User content: ${pc12.green("flydocs/ (preserved)")}`);
|
|
5198
5653
|
}
|
|
5199
5654
|
}
|
|
5200
5655
|
console.log();
|
|
5201
|
-
console.log(
|
|
5656
|
+
console.log(pc12.bold("Preserved:"));
|
|
5202
5657
|
console.log(
|
|
5203
|
-
` ${
|
|
5658
|
+
` ${pc12.dim(".claude/skills/ (non-flydocs community skills)")}`
|
|
5204
5659
|
);
|
|
5205
|
-
console.log(` ${
|
|
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 (
|
|
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 =
|
|
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
|
|
5689
|
+
await rm8(fullPath, { recursive: true, force: true });
|
|
5235
5690
|
} else {
|
|
5236
|
-
await
|
|
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 =
|
|
5700
|
+
const flydocsPath = join28(targetDir, "flydocs");
|
|
5246
5701
|
if (contentAction === "archive") {
|
|
5247
|
-
const archivePath =
|
|
5702
|
+
const archivePath = join28(targetDir, "flydocs-archive");
|
|
5248
5703
|
if (await pathExists(archivePath)) {
|
|
5249
|
-
await
|
|
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
|
|
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(
|
|
5728
|
+
console.log(pc12.bold("Uninstall Summary"));
|
|
5274
5729
|
console.log();
|
|
5275
5730
|
if (result.removed.length > 0) {
|
|
5276
|
-
console.log(` ${
|
|
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(` ${
|
|
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
|
-
` ${
|
|
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
|
-
` ${
|
|
5755
|
+
` ${pc12.dim("Skipped")} (${result.skipped.length} \u2014 not found):`
|
|
5301
5756
|
);
|
|
5302
5757
|
for (const item of result.skipped) {
|
|
5303
|
-
console.log(` ${
|
|
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: ${
|
|
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
|
|
5322
|
-
import
|
|
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 =
|
|
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(` ${
|
|
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
|
-
` ${
|
|
5794
|
+
` ${pc13.cyan("Claude Code:")} Type ${pc13.bold("/flydocs-setup")} in chat`
|
|
5340
5795
|
);
|
|
5341
5796
|
console.log(
|
|
5342
|
-
` ${
|
|
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
|
|
5359
|
-
import
|
|
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 =
|
|
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(
|
|
5836
|
+
console.log(pc14.bold("Platform"));
|
|
5382
5837
|
for (const skill of result.platform) {
|
|
5383
5838
|
console.log(
|
|
5384
|
-
` ${skill.name} ${
|
|
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(
|
|
5845
|
+
console.log(pc14.bold("Community"));
|
|
5391
5846
|
for (const skill of result.community) {
|
|
5392
5847
|
console.log(
|
|
5393
|
-
` ${skill.name} ${
|
|
5848
|
+
` ${skill.name} ${pc14.dim(`(${skill.triggers} triggers)`)}`
|
|
5394
5849
|
);
|
|
5395
5850
|
}
|
|
5396
5851
|
}
|
|
5397
5852
|
console.log();
|
|
5398
5853
|
}
|
|
5399
5854
|
});
|
|
5400
|
-
search =
|
|
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: ${
|
|
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(` ${
|
|
5878
|
+
console.log(` ${pc14.bold(skill.name)}`);
|
|
5424
5879
|
console.log(` ${skill.description}`);
|
|
5425
|
-
console.log(` ${
|
|
5880
|
+
console.log(` ${pc14.dim(skill.repo)}`);
|
|
5426
5881
|
if (skill.tags.length > 0) {
|
|
5427
|
-
console.log(` ${
|
|
5882
|
+
console.log(` ${pc14.dim(skill.tags.join(", "))}`);
|
|
5428
5883
|
}
|
|
5429
5884
|
console.log();
|
|
5430
5885
|
}
|
|
5431
5886
|
}
|
|
5432
5887
|
});
|
|
5433
|
-
add =
|
|
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 =
|
|
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 =
|
|
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
|
|
5486
|
-
import { text as text4, confirm as confirm6, isCancel as
|
|
5487
|
-
import
|
|
5488
|
-
import { join as
|
|
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 =
|
|
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 =
|
|
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 ${
|
|
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 (
|
|
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(` ${
|
|
5999
|
+
console.log(` ${pc15.bold("Connect to FlyDocs Cloud")}`);
|
|
5545
6000
|
console.log();
|
|
5546
6001
|
console.log(
|
|
5547
|
-
` ${
|
|
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 (
|
|
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 ${
|
|
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 ${
|
|
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 ${
|
|
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 ${
|
|
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
|
-
` ${
|
|
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 ${
|
|
6087
|
+
` 1. Run ${pc15.cyan("/flydocs-setup")} in your IDE to configure your project`
|
|
5633
6088
|
);
|
|
5634
|
-
console.log(` 2. Run ${
|
|
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
|
|
5647
|
-
import { text as text5, confirm as confirm7, isCancel as
|
|
5648
|
-
import
|
|
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 =
|
|
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(` ${
|
|
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: ${
|
|
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 (
|
|
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
|
-
` ${
|
|
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 (
|
|
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 ${
|
|
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 ${
|
|
6194
|
+
printStatus(`Key stored at ${pc16.dim(credentialsPath())}`);
|
|
5740
6195
|
await checkCredentialPermissions();
|
|
5741
6196
|
console.log();
|
|
5742
|
-
console.log(` ${
|
|
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, {
|