@flydocs/cli 0.6.0-alpha.32 → 0.6.0-alpha.34
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 +696 -453
- 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.34";
|
|
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
|
}
|
|
@@ -1328,6 +1328,11 @@ async function scanDeprecated(targetDir) {
|
|
|
1328
1328
|
found.push(item);
|
|
1329
1329
|
}
|
|
1330
1330
|
}
|
|
1331
|
+
for (const file of DEPRECATED_CONTEXT_FILES) {
|
|
1332
|
+
if (await pathExists(join10(targetDir, file))) {
|
|
1333
|
+
found.push(file);
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1331
1336
|
for (const skill of DEPRECATED_SKILLS) {
|
|
1332
1337
|
const p = join10(targetDir, ".claude", "skills", skill);
|
|
1333
1338
|
if (await pathExists(p)) {
|
|
@@ -1436,7 +1441,7 @@ async function promptCleanup(targetDir, paths) {
|
|
|
1436
1441
|
printStatus(`Deleted: ${p}`);
|
|
1437
1442
|
}
|
|
1438
1443
|
}
|
|
1439
|
-
var DEPRECATED_DIRS, DEPRECATED_FILES, DEPRECATED_SKILLS, DEPRECATED_RULES_DIR, DEPRECATED_FLYDOCS_DIRS, DEPRECATED_HOOKS, DEPRECATED_CURSOR_RULES, DEPRECATED_CURSOR_RULE_DIRS, DEPRECATED_COMMANDS;
|
|
1444
|
+
var DEPRECATED_DIRS, DEPRECATED_FILES, DEPRECATED_CONTEXT_FILES, DEPRECATED_SKILLS, DEPRECATED_RULES_DIR, DEPRECATED_FLYDOCS_DIRS, DEPRECATED_HOOKS, DEPRECATED_CURSOR_RULES, DEPRECATED_CURSOR_RULE_DIRS, DEPRECATED_COMMANDS;
|
|
1440
1445
|
var init_deprecated = __esm({
|
|
1441
1446
|
"src/lib/deprecated.ts"() {
|
|
1442
1447
|
"use strict";
|
|
@@ -1444,6 +1449,11 @@ var init_deprecated = __esm({
|
|
|
1444
1449
|
init_ui();
|
|
1445
1450
|
DEPRECATED_DIRS = [".docflow", "docflow"];
|
|
1446
1451
|
DEPRECATED_FILES = ["AGENTS.md.bak", ".cursor/mcp.json"];
|
|
1452
|
+
DEPRECATED_CONTEXT_FILES = [
|
|
1453
|
+
"flydocs/context/overview.md",
|
|
1454
|
+
"flydocs/context/stack.md",
|
|
1455
|
+
"flydocs/context/standards.md"
|
|
1456
|
+
];
|
|
1447
1457
|
DEPRECATED_SKILLS = [
|
|
1448
1458
|
"linear-workflow",
|
|
1449
1459
|
"session-workflow",
|
|
@@ -3027,11 +3037,11 @@ async function fetchTemplates(apiKey, sinceVersion, workspaceId) {
|
|
|
3027
3037
|
}
|
|
3028
3038
|
return await response.json();
|
|
3029
3039
|
}
|
|
3030
|
-
async function fetchArtifacts(apiKey, sinceVersion) {
|
|
3040
|
+
async function fetchArtifacts(apiKey, sinceVersion, workspaceId) {
|
|
3031
3041
|
const baseUrl = resolveRelayUrl();
|
|
3032
3042
|
const response = await fetch(`${baseUrl}/artifacts?since=${sinceVersion}`, {
|
|
3033
3043
|
method: "GET",
|
|
3034
|
-
headers: headers(apiKey),
|
|
3044
|
+
headers: headers(apiKey, workspaceId),
|
|
3035
3045
|
signal: AbortSignal.timeout(3e4)
|
|
3036
3046
|
});
|
|
3037
3047
|
if (!response.ok) {
|
|
@@ -3044,23 +3054,6 @@ async function fetchArtifacts(apiKey, sinceVersion) {
|
|
|
3044
3054
|
}
|
|
3045
3055
|
return await response.json();
|
|
3046
3056
|
}
|
|
3047
|
-
async function fetchAgentConfigs(apiKey, workspaceId) {
|
|
3048
|
-
const baseUrl = resolveRelayUrl();
|
|
3049
|
-
const response = await fetch(`${baseUrl}/artifacts/agent-configs`, {
|
|
3050
|
-
method: "GET",
|
|
3051
|
-
headers: headers(apiKey, workspaceId),
|
|
3052
|
-
signal: AbortSignal.timeout(15e3)
|
|
3053
|
-
});
|
|
3054
|
-
if (!response.ok) {
|
|
3055
|
-
const body = await response.text().catch(() => "");
|
|
3056
|
-
throw new RelayError(
|
|
3057
|
-
`agent-configs fetch failed (${response.status})`,
|
|
3058
|
-
response.status,
|
|
3059
|
-
body
|
|
3060
|
-
);
|
|
3061
|
-
}
|
|
3062
|
-
return await response.json();
|
|
3063
|
-
}
|
|
3064
3057
|
async function triggerScan(apiKey, repoName, options) {
|
|
3065
3058
|
const baseUrl = resolveRelayUrl();
|
|
3066
3059
|
const body = {
|
|
@@ -3102,78 +3095,156 @@ var init_relay_client = __esm({
|
|
|
3102
3095
|
}
|
|
3103
3096
|
});
|
|
3104
3097
|
|
|
3098
|
+
// src/lib/managed-paths.ts
|
|
3099
|
+
import { join as join18 } from "path";
|
|
3100
|
+
import { readdir as readdir4, rm as rm4, unlink } from "fs/promises";
|
|
3101
|
+
function isSkipped(path, skipPaths) {
|
|
3102
|
+
return skipPaths.some((skip) => path === skip || path.startsWith(skip));
|
|
3103
|
+
}
|
|
3104
|
+
async function wipeManagedPaths(targetDir, skipPaths = []) {
|
|
3105
|
+
let deleted = 0;
|
|
3106
|
+
let skipped = 0;
|
|
3107
|
+
for (const dir of MANAGED_DIRECTORIES) {
|
|
3108
|
+
const fullPath = join18(targetDir, dir);
|
|
3109
|
+
if (isSkipped(dir + "/", skipPaths) || isSkipped(dir, skipPaths)) {
|
|
3110
|
+
if (await pathExists(fullPath)) {
|
|
3111
|
+
skipped++;
|
|
3112
|
+
}
|
|
3113
|
+
continue;
|
|
3114
|
+
}
|
|
3115
|
+
if (await pathExists(fullPath)) {
|
|
3116
|
+
await rm4(fullPath, { recursive: true, force: true });
|
|
3117
|
+
deleted++;
|
|
3118
|
+
}
|
|
3119
|
+
}
|
|
3120
|
+
for (const file of MANAGED_FILES) {
|
|
3121
|
+
if (isSkipped(file, skipPaths)) {
|
|
3122
|
+
skipped++;
|
|
3123
|
+
continue;
|
|
3124
|
+
}
|
|
3125
|
+
const fullPath = join18(targetDir, file);
|
|
3126
|
+
if (await pathExists(fullPath)) {
|
|
3127
|
+
await unlink(fullPath);
|
|
3128
|
+
deleted++;
|
|
3129
|
+
}
|
|
3130
|
+
}
|
|
3131
|
+
const skillsDir = join18(targetDir, ".claude", "skills");
|
|
3132
|
+
if (await pathExists(skillsDir)) {
|
|
3133
|
+
const entries = await readdir4(skillsDir, { withFileTypes: true });
|
|
3134
|
+
for (const entry of entries) {
|
|
3135
|
+
if (!entry.isDirectory()) continue;
|
|
3136
|
+
if (!entry.name.startsWith(CORE_SKILL_PREFIX)) continue;
|
|
3137
|
+
const skillPath = `.claude/skills/${entry.name}/`;
|
|
3138
|
+
if (isSkipped(skillPath, skipPaths)) {
|
|
3139
|
+
skipped++;
|
|
3140
|
+
continue;
|
|
3141
|
+
}
|
|
3142
|
+
await rm4(join18(skillsDir, entry.name), { recursive: true, force: true });
|
|
3143
|
+
deleted++;
|
|
3144
|
+
}
|
|
3145
|
+
}
|
|
3146
|
+
if (deleted > 0) {
|
|
3147
|
+
printStatus(`Wiped ${deleted} managed path(s)`);
|
|
3148
|
+
}
|
|
3149
|
+
if (skipped > 0) {
|
|
3150
|
+
printInfo(`Preserved ${skipped} path(s) via skipPaths override`);
|
|
3151
|
+
}
|
|
3152
|
+
return { deleted, skipped };
|
|
3153
|
+
}
|
|
3154
|
+
var MANAGED_DIRECTORIES, MANAGED_FILES, CORE_SKILL_PREFIX;
|
|
3155
|
+
var init_managed_paths = __esm({
|
|
3156
|
+
"src/lib/managed-paths.ts"() {
|
|
3157
|
+
"use strict";
|
|
3158
|
+
init_fs_ops();
|
|
3159
|
+
init_ui();
|
|
3160
|
+
MANAGED_DIRECTORIES = [
|
|
3161
|
+
".claude/hooks",
|
|
3162
|
+
".claude/commands",
|
|
3163
|
+
".claude/agents",
|
|
3164
|
+
".cursor/rules",
|
|
3165
|
+
".cursor/commands",
|
|
3166
|
+
".cursor/agents"
|
|
3167
|
+
];
|
|
3168
|
+
MANAGED_FILES = [
|
|
3169
|
+
".claude/settings.json",
|
|
3170
|
+
".claude/CLAUDE.md",
|
|
3171
|
+
".cursor/hooks.json",
|
|
3172
|
+
"AGENTS.md"
|
|
3173
|
+
];
|
|
3174
|
+
CORE_SKILL_PREFIX = "flydocs-";
|
|
3175
|
+
}
|
|
3176
|
+
});
|
|
3177
|
+
|
|
3105
3178
|
// src/lib/artifacts.ts
|
|
3106
3179
|
import { mkdir as mkdir9, writeFile as writeFile11 } from "fs/promises";
|
|
3107
|
-
import { join as
|
|
3108
|
-
|
|
3109
|
-
|
|
3180
|
+
import { join as join19, dirname as dirname3 } from "path";
|
|
3181
|
+
function isPathSkipped(artifactPath, skipPaths) {
|
|
3182
|
+
return skipPaths.some(
|
|
3183
|
+
(skip) => artifactPath === skip || artifactPath.startsWith(skip)
|
|
3184
|
+
);
|
|
3185
|
+
}
|
|
3186
|
+
async function syncArtifacts(targetDir, apiKey, workspaceId, currentVersion, skipPaths = []) {
|
|
3187
|
+
const response = await fetchArtifacts(apiKey, currentVersion, workspaceId);
|
|
3110
3188
|
if (response.artifacts.length === 0) {
|
|
3111
|
-
return { written: 0, version: currentVersion };
|
|
3189
|
+
return { written: 0, skipped: 0, version: currentVersion };
|
|
3112
3190
|
}
|
|
3113
3191
|
let written = 0;
|
|
3192
|
+
let skipped = 0;
|
|
3114
3193
|
for (const artifact of response.artifacts) {
|
|
3194
|
+
if (skipPaths.length > 0 && isPathSkipped(artifact.path, skipPaths)) {
|
|
3195
|
+
skipped++;
|
|
3196
|
+
continue;
|
|
3197
|
+
}
|
|
3115
3198
|
await writeArtifact(targetDir, artifact);
|
|
3116
3199
|
written++;
|
|
3117
3200
|
}
|
|
3118
3201
|
printStatus(
|
|
3119
3202
|
`Synced ${written} artifact(s) (v${currentVersion} \u2192 v${response.version})`
|
|
3120
3203
|
);
|
|
3121
|
-
|
|
3122
|
-
}
|
|
3123
|
-
async function syncAgentConfigs(targetDir, apiKey, workspaceId) {
|
|
3124
|
-
const response = await fetchAgentConfigs(apiKey, workspaceId);
|
|
3125
|
-
let written = 0;
|
|
3126
|
-
for (const file of response.files) {
|
|
3127
|
-
const filePath = join18(targetDir, file.path);
|
|
3128
|
-
await mkdir9(dirname3(filePath), { recursive: true });
|
|
3129
|
-
await writeFile11(filePath, file.content, "utf-8");
|
|
3130
|
-
written++;
|
|
3204
|
+
if (skipped > 0) {
|
|
3205
|
+
printInfo(`Skipped ${skipped} artifact(s) via artifactOverrides.skipPaths`);
|
|
3131
3206
|
}
|
|
3132
|
-
|
|
3133
|
-
printStatus(`Wrote ${written} agent config(s) (CLAUDE.md, AGENTS.md)`);
|
|
3134
|
-
}
|
|
3135
|
-
return written;
|
|
3207
|
+
return { written, skipped, version: response.version };
|
|
3136
3208
|
}
|
|
3137
3209
|
async function writeArtifact(targetDir, artifact) {
|
|
3138
|
-
const filePath =
|
|
3210
|
+
const filePath = join19(targetDir, artifact.path);
|
|
3139
3211
|
await mkdir9(dirname3(filePath), { recursive: true });
|
|
3140
3212
|
await writeFile11(filePath, artifact.content, "utf-8");
|
|
3141
3213
|
}
|
|
3142
|
-
async function syncAllArtifacts(targetDir, apiKey, workspaceId, currentArtifactVersion) {
|
|
3214
|
+
async function syncAllArtifacts(targetDir, apiKey, workspaceId, currentArtifactVersion, skipPaths = []) {
|
|
3143
3215
|
const changes = [];
|
|
3144
3216
|
let artifactVersion = currentArtifactVersion;
|
|
3217
|
+
const { deleted, skipped } = await wipeManagedPaths(targetDir, skipPaths);
|
|
3218
|
+
if (deleted > 0) {
|
|
3219
|
+
changes.push(`Wiped ${deleted} managed path(s)`);
|
|
3220
|
+
}
|
|
3221
|
+
if (skipped > 0) {
|
|
3222
|
+
changes.push(`Preserved ${skipped} path(s) (skipPaths override)`);
|
|
3223
|
+
}
|
|
3145
3224
|
try {
|
|
3146
3225
|
const result = await syncArtifacts(
|
|
3147
3226
|
targetDir,
|
|
3148
3227
|
apiKey,
|
|
3149
3228
|
workspaceId,
|
|
3150
|
-
currentArtifactVersion
|
|
3229
|
+
currentArtifactVersion,
|
|
3230
|
+
skipPaths
|
|
3151
3231
|
);
|
|
3152
3232
|
if (result.written > 0) {
|
|
3153
3233
|
changes.push(`Synced ${result.written} artifact(s)`);
|
|
3154
3234
|
artifactVersion = result.version;
|
|
3155
3235
|
}
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
`Could not fetch artifacts (${err.status}). Will retry on next sync.`
|
|
3236
|
+
if (result.skipped > 0) {
|
|
3237
|
+
changes.push(
|
|
3238
|
+
`Skipped ${result.skipped} artifact(s) (skipPaths override)`
|
|
3160
3239
|
);
|
|
3161
|
-
} else {
|
|
3162
|
-
printWarning("Artifact sync failed. Will retry on next sync.");
|
|
3163
|
-
}
|
|
3164
|
-
}
|
|
3165
|
-
try {
|
|
3166
|
-
const configCount = await syncAgentConfigs(targetDir, apiKey, workspaceId);
|
|
3167
|
-
if (configCount > 0) {
|
|
3168
|
-
changes.push(`Wrote ${configCount} agent config(s)`);
|
|
3169
3240
|
}
|
|
3170
3241
|
} catch (err) {
|
|
3171
3242
|
if (err instanceof RelayError) {
|
|
3172
3243
|
printWarning(
|
|
3173
|
-
`Could not fetch
|
|
3244
|
+
`Could not fetch artifacts (${err.status}). Will retry on next sync.`
|
|
3174
3245
|
);
|
|
3175
3246
|
} else {
|
|
3176
|
-
printWarning("
|
|
3247
|
+
printWarning("Artifact sync failed. Will retry on next sync.");
|
|
3177
3248
|
}
|
|
3178
3249
|
}
|
|
3179
3250
|
return { artifactVersion, changes };
|
|
@@ -3183,6 +3254,7 @@ var init_artifacts = __esm({
|
|
|
3183
3254
|
"use strict";
|
|
3184
3255
|
init_ui();
|
|
3185
3256
|
init_relay_client();
|
|
3257
|
+
init_managed_paths();
|
|
3186
3258
|
}
|
|
3187
3259
|
});
|
|
3188
3260
|
|
|
@@ -3195,11 +3267,11 @@ __export(cleanup_exports, {
|
|
|
3195
3267
|
});
|
|
3196
3268
|
import { defineCommand as defineCommand2 } from "citty";
|
|
3197
3269
|
import pc7 from "picocolors";
|
|
3198
|
-
import { join as
|
|
3199
|
-
import { readFile as readFile13, writeFile as writeFile12, rm as
|
|
3270
|
+
import { join as join20 } from "path";
|
|
3271
|
+
import { readFile as readFile13, writeFile as writeFile12, rm as rm5 } from "fs/promises";
|
|
3200
3272
|
async function scanArtifacts(targetDir) {
|
|
3201
3273
|
const actions = [];
|
|
3202
|
-
const localMePath =
|
|
3274
|
+
const localMePath = join20(targetDir, ".flydocs", "me.json");
|
|
3203
3275
|
if (await pathExists(localMePath) && await pathExists(globalMePath())) {
|
|
3204
3276
|
actions.push({
|
|
3205
3277
|
description: "Remove .flydocs/me.json (migrated to ~/.flydocs/me.json)",
|
|
@@ -3207,7 +3279,7 @@ async function scanArtifacts(targetDir) {
|
|
|
3207
3279
|
type: "file"
|
|
3208
3280
|
});
|
|
3209
3281
|
}
|
|
3210
|
-
const validationCachePath =
|
|
3282
|
+
const validationCachePath = join20(
|
|
3211
3283
|
targetDir,
|
|
3212
3284
|
".flydocs",
|
|
3213
3285
|
"validation-cache.json"
|
|
@@ -3221,7 +3293,7 @@ async function scanArtifacts(targetDir) {
|
|
|
3221
3293
|
}
|
|
3222
3294
|
const hasGlobalCreds = await pathExists(credentialsPath());
|
|
3223
3295
|
for (const envFile of [".env", ".env.local"]) {
|
|
3224
|
-
const envPath =
|
|
3296
|
+
const envPath = join20(targetDir, envFile);
|
|
3225
3297
|
if (!await pathExists(envPath)) continue;
|
|
3226
3298
|
const content = await readFile13(envPath, "utf-8");
|
|
3227
3299
|
const lines = content.split("\n");
|
|
@@ -3246,7 +3318,7 @@ async function scanArtifacts(targetDir) {
|
|
|
3246
3318
|
try {
|
|
3247
3319
|
const config = await readAnyConfig(targetDir);
|
|
3248
3320
|
const rawContent = await readFile13(
|
|
3249
|
-
|
|
3321
|
+
join20(targetDir, ".flydocs", "config.json"),
|
|
3250
3322
|
"utf-8"
|
|
3251
3323
|
);
|
|
3252
3324
|
const raw = JSON.parse(rawContent);
|
|
@@ -3255,7 +3327,7 @@ async function scanArtifacts(targetDir) {
|
|
|
3255
3327
|
if (field in raw) {
|
|
3256
3328
|
actions.push({
|
|
3257
3329
|
description: `Remove ghost field "${field}" from config.json`,
|
|
3258
|
-
path:
|
|
3330
|
+
path: join20(targetDir, ".flydocs", "config.json"),
|
|
3259
3331
|
type: "field"
|
|
3260
3332
|
});
|
|
3261
3333
|
}
|
|
@@ -3274,7 +3346,7 @@ async function scanArtifacts(targetDir) {
|
|
|
3274
3346
|
if (field in raw) {
|
|
3275
3347
|
actions.push({
|
|
3276
3348
|
description: `Remove v1 field "${field}" from config.json (server-owned in v2)`,
|
|
3277
|
-
path:
|
|
3349
|
+
path: join20(targetDir, ".flydocs", "config.json"),
|
|
3278
3350
|
type: "field"
|
|
3279
3351
|
});
|
|
3280
3352
|
}
|
|
@@ -3289,7 +3361,7 @@ async function executeCleanup(targetDir, actions) {
|
|
|
3289
3361
|
const lineRemovals = actions.filter((a) => a.type === "line");
|
|
3290
3362
|
const fieldRemovals = actions.filter((a) => a.type === "field");
|
|
3291
3363
|
for (const action of fileRemovals) {
|
|
3292
|
-
await
|
|
3364
|
+
await rm5(action.path, { force: true });
|
|
3293
3365
|
}
|
|
3294
3366
|
const envFiles = /* @__PURE__ */ new Map();
|
|
3295
3367
|
for (const action of lineRemovals) {
|
|
@@ -3307,13 +3379,13 @@ async function executeCleanup(targetDir, actions) {
|
|
|
3307
3379
|
(l) => l.trim().length > 0 && !l.trim().startsWith("#")
|
|
3308
3380
|
);
|
|
3309
3381
|
if (!hasContent) {
|
|
3310
|
-
await
|
|
3382
|
+
await rm5(envPath, { force: true });
|
|
3311
3383
|
} else {
|
|
3312
3384
|
await writeFile12(envPath, filtered.join("\n"), "utf-8");
|
|
3313
3385
|
}
|
|
3314
3386
|
}
|
|
3315
3387
|
if (fieldRemovals.length > 0) {
|
|
3316
|
-
const configPath =
|
|
3388
|
+
const configPath = join20(targetDir, ".flydocs", "config.json");
|
|
3317
3389
|
const content = await readFile13(configPath, "utf-8");
|
|
3318
3390
|
const config = JSON.parse(content);
|
|
3319
3391
|
for (const action of fieldRemovals) {
|
|
@@ -3360,7 +3432,7 @@ var init_cleanup = __esm({
|
|
|
3360
3432
|
console.log(` ${pc7.bold("FlyDocs Cleanup")}`);
|
|
3361
3433
|
console.log();
|
|
3362
3434
|
const hasConfig = await pathExists(
|
|
3363
|
-
|
|
3435
|
+
join20(targetDir, ".flydocs", "config.json")
|
|
3364
3436
|
);
|
|
3365
3437
|
if (!hasConfig) {
|
|
3366
3438
|
printError("No .flydocs/config.json found. Run flydocs init first.");
|
|
@@ -3404,16 +3476,16 @@ var init_cleanup = __esm({
|
|
|
3404
3476
|
});
|
|
3405
3477
|
|
|
3406
3478
|
// src/lib/ide-archive.ts
|
|
3407
|
-
import { readFile as readFile14, writeFile as writeFile13, mkdir as mkdir10, readdir as
|
|
3408
|
-
import { join as
|
|
3479
|
+
import { readFile as readFile14, writeFile as writeFile13, mkdir as mkdir10, readdir as readdir5 } from "fs/promises";
|
|
3480
|
+
import { join as join21, basename } from "path";
|
|
3409
3481
|
async function archiveIdeConfigs(targetDir) {
|
|
3410
3482
|
const archived = [];
|
|
3411
3483
|
for (const cfg of SINGLE_FILE_CONFIGS) {
|
|
3412
|
-
const absSource =
|
|
3484
|
+
const absSource = join21(targetDir, cfg.source);
|
|
3413
3485
|
if (!await pathExists(absSource)) continue;
|
|
3414
3486
|
const content = await readFile14(absSource, "utf-8");
|
|
3415
|
-
const absDest =
|
|
3416
|
-
await mkdir10(
|
|
3487
|
+
const absDest = join21(targetDir, cfg.archive);
|
|
3488
|
+
await mkdir10(join21(absDest, ".."), { recursive: true });
|
|
3417
3489
|
await writeFile13(absDest, content, "utf-8");
|
|
3418
3490
|
archived.push({
|
|
3419
3491
|
sourcePath: cfg.source,
|
|
@@ -3422,17 +3494,17 @@ async function archiveIdeConfigs(targetDir) {
|
|
|
3422
3494
|
});
|
|
3423
3495
|
printStatus(`Archived ${cfg.source}`);
|
|
3424
3496
|
}
|
|
3425
|
-
const cursorRulesDir =
|
|
3497
|
+
const cursorRulesDir = join21(targetDir, ".cursor", "rules");
|
|
3426
3498
|
if (await pathExists(cursorRulesDir)) {
|
|
3427
3499
|
let entries;
|
|
3428
3500
|
try {
|
|
3429
|
-
entries = await
|
|
3501
|
+
entries = await readdir5(cursorRulesDir);
|
|
3430
3502
|
} catch {
|
|
3431
3503
|
entries = [];
|
|
3432
3504
|
}
|
|
3433
3505
|
const mdFiles = entries.filter((f) => f.endsWith(".md"));
|
|
3434
3506
|
if (mdFiles.length > 0) {
|
|
3435
|
-
const archiveSubdir =
|
|
3507
|
+
const archiveSubdir = join21(
|
|
3436
3508
|
targetDir,
|
|
3437
3509
|
"flydocs",
|
|
3438
3510
|
"knowledge",
|
|
@@ -3441,10 +3513,10 @@ async function archiveIdeConfigs(targetDir) {
|
|
|
3441
3513
|
);
|
|
3442
3514
|
await mkdir10(archiveSubdir, { recursive: true });
|
|
3443
3515
|
for (const file of mdFiles) {
|
|
3444
|
-
const absSource =
|
|
3516
|
+
const absSource = join21(cursorRulesDir, file);
|
|
3445
3517
|
const content = await readFile14(absSource, "utf-8");
|
|
3446
3518
|
const archivePath = `flydocs/knowledge/archived/cursor-rules/${basename(file)}`;
|
|
3447
|
-
const absDest =
|
|
3519
|
+
const absDest = join21(targetDir, archivePath);
|
|
3448
3520
|
await writeFile13(absDest, content, "utf-8");
|
|
3449
3521
|
archived.push({
|
|
3450
3522
|
sourcePath: `.cursor/rules/${file}`,
|
|
@@ -3477,10 +3549,10 @@ var init_ide_archive = __esm({
|
|
|
3477
3549
|
});
|
|
3478
3550
|
|
|
3479
3551
|
// src/lib/workspace.ts
|
|
3480
|
-
import { readFile as readFile15, writeFile as writeFile14, readdir as
|
|
3481
|
-
import { join as
|
|
3552
|
+
import { readFile as readFile15, writeFile as writeFile14, readdir as readdir6, stat as stat2 } from "fs/promises";
|
|
3553
|
+
import { join as join22, dirname as dirname4, relative, resolve as resolve3 } from "path";
|
|
3482
3554
|
async function readWorkspaceFile(dir) {
|
|
3483
|
-
const filePath =
|
|
3555
|
+
const filePath = join22(dir, WORKSPACE_FILENAME);
|
|
3484
3556
|
if (!await pathExists(filePath)) return null;
|
|
3485
3557
|
const content = await readFile15(filePath, "utf-8");
|
|
3486
3558
|
const parsed = JSON.parse(content);
|
|
@@ -3488,21 +3560,21 @@ async function readWorkspaceFile(dir) {
|
|
|
3488
3560
|
return parsed;
|
|
3489
3561
|
}
|
|
3490
3562
|
async function writeWorkspaceFile(dir, workspace) {
|
|
3491
|
-
const filePath =
|
|
3563
|
+
const filePath = join22(dir, WORKSPACE_FILENAME);
|
|
3492
3564
|
const content = JSON.stringify(workspace, null, 2) + "\n";
|
|
3493
3565
|
await writeFile14(filePath, content, "utf-8");
|
|
3494
3566
|
}
|
|
3495
3567
|
async function detectSiblingRepos(parentDir) {
|
|
3496
3568
|
const repos = {};
|
|
3497
|
-
const entries = await
|
|
3569
|
+
const entries = await readdir6(parentDir);
|
|
3498
3570
|
for (const entry of entries) {
|
|
3499
3571
|
if (entry.startsWith(".")) continue;
|
|
3500
|
-
const entryPath =
|
|
3572
|
+
const entryPath = join22(parentDir, entry);
|
|
3501
3573
|
const entryStat = await stat2(entryPath).catch(() => null);
|
|
3502
3574
|
if (!entryStat?.isDirectory()) continue;
|
|
3503
|
-
const hasGit = await pathExists(
|
|
3575
|
+
const hasGit = await pathExists(join22(entryPath, ".git"));
|
|
3504
3576
|
const hasFlydocs = await pathExists(
|
|
3505
|
-
|
|
3577
|
+
join22(entryPath, ".flydocs", "config.json")
|
|
3506
3578
|
);
|
|
3507
3579
|
if (hasGit || hasFlydocs) {
|
|
3508
3580
|
repos[entry] = { path: `./${entry}` };
|
|
@@ -3517,7 +3589,7 @@ async function readSiblingDescriptors(workspaceDir, repos) {
|
|
|
3517
3589
|
const descriptors = [];
|
|
3518
3590
|
for (const [name, entry] of Object.entries(repos)) {
|
|
3519
3591
|
const repoDir = resolve3(workspaceDir, entry.path);
|
|
3520
|
-
const serviceJsonPath =
|
|
3592
|
+
const serviceJsonPath = join22(repoDir, "flydocs", "context", "service.json");
|
|
3521
3593
|
if (!await pathExists(serviceJsonPath)) continue;
|
|
3522
3594
|
try {
|
|
3523
3595
|
const content = await readFile15(serviceJsonPath, "utf-8");
|
|
@@ -3632,7 +3704,7 @@ __export(scan_exports, {
|
|
|
3632
3704
|
import { defineCommand as defineCommand3 } from "citty";
|
|
3633
3705
|
import { spinner } from "@clack/prompts";
|
|
3634
3706
|
import pc8 from "picocolors";
|
|
3635
|
-
import { join as
|
|
3707
|
+
import { join as join23 } from "path";
|
|
3636
3708
|
import { mkdir as mkdir11, writeFile as writeFile15 } from "fs/promises";
|
|
3637
3709
|
async function resolveRepoName(targetDir, repoArg) {
|
|
3638
3710
|
if (repoArg) return repoArg;
|
|
@@ -3661,15 +3733,15 @@ async function resolveRepoName(targetDir, repoArg) {
|
|
|
3661
3733
|
}
|
|
3662
3734
|
async function writeScanResults(targetDir, response) {
|
|
3663
3735
|
const written = [];
|
|
3664
|
-
const contextDir =
|
|
3736
|
+
const contextDir = join23(targetDir, "flydocs", "context");
|
|
3665
3737
|
await mkdir11(contextDir, { recursive: true });
|
|
3666
3738
|
if (response.projectMd) {
|
|
3667
|
-
const projectMdPath =
|
|
3739
|
+
const projectMdPath = join23(contextDir, "project.md");
|
|
3668
3740
|
await writeFile15(projectMdPath, response.projectMd, "utf-8");
|
|
3669
3741
|
written.push("flydocs/context/project.md");
|
|
3670
3742
|
}
|
|
3671
3743
|
if (response.serviceJson) {
|
|
3672
|
-
const serviceJsonPath =
|
|
3744
|
+
const serviceJsonPath = join23(contextDir, "service.json");
|
|
3673
3745
|
await writeFile15(
|
|
3674
3746
|
serviceJsonPath,
|
|
3675
3747
|
JSON.stringify(response.serviceJson, null, 2) + "\n",
|
|
@@ -3825,7 +3897,7 @@ __export(init_exports, {
|
|
|
3825
3897
|
import { defineCommand as defineCommand4 } from "citty";
|
|
3826
3898
|
import { text as text2, confirm as confirm3, select as select2, isCancel as isCancel4, cancel as cancel3 } from "@clack/prompts";
|
|
3827
3899
|
import pc9 from "picocolors";
|
|
3828
|
-
import { join as
|
|
3900
|
+
import { join as join24 } from "path";
|
|
3829
3901
|
import { mkdir as mkdir12, writeFile as writeFile16 } from "fs/promises";
|
|
3830
3902
|
import { execFile } from "child_process";
|
|
3831
3903
|
import { promisify } from "util";
|
|
@@ -3906,7 +3978,7 @@ async function resolveAndValidateKey(keyArg, targetDir) {
|
|
|
3906
3978
|
}
|
|
3907
3979
|
async function pullServerConfig(apiKey, targetDir, workspaceId, forceIncludeContext = false) {
|
|
3908
3980
|
printInfo("Pulling config from server...");
|
|
3909
|
-
const isFirstInit = forceIncludeContext || !await pathExists(
|
|
3981
|
+
const isFirstInit = forceIncludeContext || !await pathExists(join24(targetDir, ".flydocs", "config.json"));
|
|
3910
3982
|
try {
|
|
3911
3983
|
const response = await fetchConfigV2(apiKey, {
|
|
3912
3984
|
includeContext: isFirstInit,
|
|
@@ -3935,7 +4007,7 @@ async function initSingleRepo(targetDir, apiKey, serverResponse, options = {}) {
|
|
|
3935
4007
|
const actions = [];
|
|
3936
4008
|
const skipped = [];
|
|
3937
4009
|
const { childRepoMode = false } = options;
|
|
3938
|
-
await mkdir12(
|
|
4010
|
+
await mkdir12(join24(targetDir, ".flydocs"), { recursive: true });
|
|
3939
4011
|
const configWithHash = applyConfigHash(serverResponse.config);
|
|
3940
4012
|
await writeConfig(targetDir, configWithHash);
|
|
3941
4013
|
actions.push("Wrote .flydocs/config.json (from server)");
|
|
@@ -3948,16 +4020,16 @@ async function initSingleRepo(targetDir, apiKey, serverResponse, options = {}) {
|
|
|
3948
4020
|
actions.push("Wrote ~/.flydocs/me.json");
|
|
3949
4021
|
}
|
|
3950
4022
|
if (serverResponse.context) {
|
|
3951
|
-
const contextDir =
|
|
4023
|
+
const contextDir = join24(targetDir, "flydocs", "context");
|
|
3952
4024
|
await mkdir12(contextDir, { recursive: true });
|
|
3953
|
-
const projectMdPath =
|
|
4025
|
+
const projectMdPath = join24(contextDir, "project.md");
|
|
3954
4026
|
if (!await pathExists(projectMdPath)) {
|
|
3955
4027
|
await writeFile16(projectMdPath, serverResponse.context.projectMd, "utf-8");
|
|
3956
4028
|
actions.push("Wrote flydocs/context/project.md");
|
|
3957
4029
|
} else {
|
|
3958
4030
|
skipped.push("flydocs/context/project.md (already exists)");
|
|
3959
4031
|
}
|
|
3960
|
-
const serviceJsonPath =
|
|
4032
|
+
const serviceJsonPath = join24(contextDir, "service.json");
|
|
3961
4033
|
if (serverResponse.context.serviceJson && !await pathExists(serviceJsonPath)) {
|
|
3962
4034
|
await writeFile16(
|
|
3963
4035
|
serviceJsonPath,
|
|
@@ -4004,26 +4076,26 @@ async function initSingleRepo(targetDir, apiKey, serverResponse, options = {}) {
|
|
|
4004
4076
|
};
|
|
4005
4077
|
}
|
|
4006
4078
|
async function cleanServerManagedFiles(targetDir) {
|
|
4007
|
-
const { rm:
|
|
4079
|
+
const { rm: rm9 } = await import("fs/promises");
|
|
4008
4080
|
let cleaned = 0;
|
|
4009
4081
|
for (const dir of SERVER_MANAGED_DIRS) {
|
|
4010
|
-
const fullPath =
|
|
4082
|
+
const fullPath = join24(targetDir, dir);
|
|
4011
4083
|
if (await pathExists(fullPath)) {
|
|
4012
|
-
await
|
|
4084
|
+
await rm9(fullPath, { recursive: true, force: true });
|
|
4013
4085
|
cleaned++;
|
|
4014
4086
|
}
|
|
4015
4087
|
}
|
|
4016
4088
|
for (const file of SERVER_MANAGED_FILES) {
|
|
4017
|
-
const fullPath =
|
|
4089
|
+
const fullPath = join24(targetDir, file);
|
|
4018
4090
|
if (await pathExists(fullPath)) {
|
|
4019
|
-
await
|
|
4091
|
+
await rm9(fullPath, { force: true });
|
|
4020
4092
|
cleaned++;
|
|
4021
4093
|
}
|
|
4022
4094
|
}
|
|
4023
4095
|
return cleaned;
|
|
4024
4096
|
}
|
|
4025
4097
|
async function checkGitFreshness(repoDir) {
|
|
4026
|
-
const hasGit = await pathExists(
|
|
4098
|
+
const hasGit = await pathExists(join24(repoDir, ".git"));
|
|
4027
4099
|
if (!hasGit) return;
|
|
4028
4100
|
try {
|
|
4029
4101
|
await execFileAsync("git", ["-C", repoDir, "fetch", "--quiet"], {
|
|
@@ -4052,7 +4124,7 @@ async function checkGitFreshness(repoDir) {
|
|
|
4052
4124
|
}
|
|
4053
4125
|
}
|
|
4054
4126
|
async function isEmptyOrNonRepo(dir) {
|
|
4055
|
-
const hasGit = await pathExists(
|
|
4127
|
+
const hasGit = await pathExists(join24(dir, ".git"));
|
|
4056
4128
|
if (hasGit) return false;
|
|
4057
4129
|
const siblings = await detectSiblingRepos(dir);
|
|
4058
4130
|
if (Object.keys(siblings).length >= 2) return false;
|
|
@@ -4122,9 +4194,9 @@ async function runCloneAndInit(targetDir, keyArg, repos, apiKey, workspaceId) {
|
|
|
4122
4194
|
for (let i = 0; i < repos.length; i++) {
|
|
4123
4195
|
const repo = repos[i];
|
|
4124
4196
|
const shortName = repoNames[i];
|
|
4125
|
-
const cloneDir =
|
|
4197
|
+
const cloneDir = join24(targetDir, shortName);
|
|
4126
4198
|
console.log();
|
|
4127
|
-
if (await pathExists(
|
|
4199
|
+
if (await pathExists(join24(cloneDir, ".git"))) {
|
|
4128
4200
|
printInfo(`${pc9.bold(shortName)} already cloned, initializing...`);
|
|
4129
4201
|
await checkGitFreshness(cloneDir);
|
|
4130
4202
|
} else {
|
|
@@ -4167,8 +4239,8 @@ async function runCloneAndInit(targetDir, keyArg, repos, apiKey, workspaceId) {
|
|
|
4167
4239
|
);
|
|
4168
4240
|
await writeWorkspaceFile(targetDir, workspaceFile);
|
|
4169
4241
|
allActions.push(`.flydocs-workspace.json (${repos.length} repos)`);
|
|
4170
|
-
const contextDir =
|
|
4171
|
-
const workspaceMdPath =
|
|
4242
|
+
const contextDir = join24(targetDir, "flydocs", "context");
|
|
4243
|
+
const workspaceMdPath = join24(contextDir, "workspace.md");
|
|
4172
4244
|
if (!await pathExists(workspaceMdPath)) {
|
|
4173
4245
|
await mkdir12(contextDir, { recursive: true });
|
|
4174
4246
|
const content = firstResponse.context?.workspaceMd ?? await generateWorkspaceMd(targetDir, workspaceFile);
|
|
@@ -4187,7 +4259,7 @@ async function runCloneAndInit(targetDir, keyArg, repos, apiKey, workspaceId) {
|
|
|
4187
4259
|
}
|
|
4188
4260
|
}
|
|
4189
4261
|
async function isParentDirectory(dir) {
|
|
4190
|
-
const hasGit = await pathExists(
|
|
4262
|
+
const hasGit = await pathExists(join24(dir, ".git"));
|
|
4191
4263
|
if (hasGit) return false;
|
|
4192
4264
|
const repos = await detectSiblingRepos(dir);
|
|
4193
4265
|
return Object.keys(repos).length >= 2;
|
|
@@ -4207,7 +4279,7 @@ async function runMultiRepoInit(parentDir, keyArg) {
|
|
|
4207
4279
|
cancel3("Init cancelled.");
|
|
4208
4280
|
process.exit(0);
|
|
4209
4281
|
}
|
|
4210
|
-
const firstRepoDir =
|
|
4282
|
+
const firstRepoDir = join24(parentDir, repoNames[0]);
|
|
4211
4283
|
const { apiKey, workspaceId } = await resolveAndValidateKey(
|
|
4212
4284
|
keyArg,
|
|
4213
4285
|
firstRepoDir
|
|
@@ -4240,7 +4312,7 @@ async function runMultiRepoInit(parentDir, keyArg) {
|
|
|
4240
4312
|
await ensureGitignore(parentDir);
|
|
4241
4313
|
allActions.push("Updated workspace root .gitignore");
|
|
4242
4314
|
for (const repoName of repoNames) {
|
|
4243
|
-
const repoDir =
|
|
4315
|
+
const repoDir = join24(parentDir, repoName);
|
|
4244
4316
|
console.log();
|
|
4245
4317
|
printInfo(`Initializing ${pc9.bold(repoName)}...`);
|
|
4246
4318
|
await checkGitFreshness(repoDir);
|
|
@@ -4272,8 +4344,8 @@ async function runMultiRepoInit(parentDir, keyArg) {
|
|
|
4272
4344
|
await writeWorkspaceFile(parentDir, workspaceFile);
|
|
4273
4345
|
allActions.push(`.flydocs-workspace.json (${repoNames.length} repos)`);
|
|
4274
4346
|
}
|
|
4275
|
-
const contextDir =
|
|
4276
|
-
const workspaceMdPath =
|
|
4347
|
+
const contextDir = join24(parentDir, "flydocs", "context");
|
|
4348
|
+
const workspaceMdPath = join24(contextDir, "workspace.md");
|
|
4277
4349
|
if (await pathExists(workspaceMdPath)) {
|
|
4278
4350
|
allSkipped.push("flydocs/context/workspace.md (already exists)");
|
|
4279
4351
|
} else {
|
|
@@ -4426,7 +4498,7 @@ var init_init = __esm({
|
|
|
4426
4498
|
actions.unshift("Stored credential globally (~/.flydocs/credentials)");
|
|
4427
4499
|
const topology = serverResponse.config.topology;
|
|
4428
4500
|
if (topology?.type === 4 && topology.label === "sibling-repos") {
|
|
4429
|
-
const parentDir =
|
|
4501
|
+
const parentDir = join24(targetDir, "..");
|
|
4430
4502
|
const existing = await readWorkspaceFile(parentDir);
|
|
4431
4503
|
if (existing) {
|
|
4432
4504
|
skipped.push(".flydocs-workspace.json (already exists)");
|
|
@@ -4547,16 +4619,320 @@ var init_init = __esm({
|
|
|
4547
4619
|
}
|
|
4548
4620
|
});
|
|
4549
4621
|
|
|
4622
|
+
// src/lib/skill-conflicts.ts
|
|
4623
|
+
import { join as join25 } from "path";
|
|
4624
|
+
import { readdir as readdir7, rm as rm6, cp as cp2, mkdir as mkdir13 } from "fs/promises";
|
|
4625
|
+
import { select as select3, isCancel as isCancel5 } from "@clack/prompts";
|
|
4626
|
+
async function resolveSkillConflicts(targetDir, keptPaths = []) {
|
|
4627
|
+
const result = {
|
|
4628
|
+
newKeptPaths: [],
|
|
4629
|
+
archived: 0,
|
|
4630
|
+
deleted: 0
|
|
4631
|
+
};
|
|
4632
|
+
const skillsDir = join25(targetDir, ".claude", "skills");
|
|
4633
|
+
if (!await pathExists(skillsDir)) return result;
|
|
4634
|
+
const entries = await readdir7(skillsDir, { withFileTypes: true });
|
|
4635
|
+
for (const entry of entries) {
|
|
4636
|
+
if (!entry.isDirectory()) continue;
|
|
4637
|
+
if (entry.name.startsWith(CORE_SKILL_PREFIX2)) continue;
|
|
4638
|
+
const relPath = `.claude/skills/${entry.name}`;
|
|
4639
|
+
if (keptPaths.includes(relPath) || keptPaths.includes(relPath + "/")) {
|
|
4640
|
+
continue;
|
|
4641
|
+
}
|
|
4642
|
+
await promptConflict(targetDir, skillsDir, entry.name, relPath, result);
|
|
4643
|
+
}
|
|
4644
|
+
if (result.archived > 0 || result.deleted > 0 || result.newKeptPaths.length > 0) {
|
|
4645
|
+
const parts = [];
|
|
4646
|
+
if (result.archived > 0) parts.push(`${result.archived} archived`);
|
|
4647
|
+
if (result.deleted > 0) parts.push(`${result.deleted} deleted`);
|
|
4648
|
+
if (result.newKeptPaths.length > 0)
|
|
4649
|
+
parts.push(`${result.newKeptPaths.length} kept`);
|
|
4650
|
+
printInfo(`Non-core skills: ${parts.join(", ")}`);
|
|
4651
|
+
}
|
|
4652
|
+
return result;
|
|
4653
|
+
}
|
|
4654
|
+
async function promptConflict(targetDir, skillsDir, name, relPath, result) {
|
|
4655
|
+
const choice = await select3({
|
|
4656
|
+
message: `Found non-managed skill: ${name}. What should we do?`,
|
|
4657
|
+
options: [
|
|
4658
|
+
{
|
|
4659
|
+
value: "keep",
|
|
4660
|
+
label: "Keep \u2014 leave in place, don't ask again"
|
|
4661
|
+
},
|
|
4662
|
+
{
|
|
4663
|
+
value: "archive",
|
|
4664
|
+
label: "Archive \u2014 move to flydocs/knowledge/archived/skills/"
|
|
4665
|
+
},
|
|
4666
|
+
{
|
|
4667
|
+
value: "delete",
|
|
4668
|
+
label: "Delete \u2014 remove permanently"
|
|
4669
|
+
}
|
|
4670
|
+
]
|
|
4671
|
+
});
|
|
4672
|
+
if (isCancel5(choice)) {
|
|
4673
|
+
result.newKeptPaths.push(relPath);
|
|
4674
|
+
return;
|
|
4675
|
+
}
|
|
4676
|
+
const fullPath = join25(skillsDir, name);
|
|
4677
|
+
switch (choice) {
|
|
4678
|
+
case "keep":
|
|
4679
|
+
result.newKeptPaths.push(relPath);
|
|
4680
|
+
printInfo(`Keeping ${name} (won't ask again)`);
|
|
4681
|
+
break;
|
|
4682
|
+
case "archive": {
|
|
4683
|
+
const archiveDir = join25(
|
|
4684
|
+
targetDir,
|
|
4685
|
+
"flydocs",
|
|
4686
|
+
"knowledge",
|
|
4687
|
+
"archived",
|
|
4688
|
+
"skills"
|
|
4689
|
+
);
|
|
4690
|
+
await mkdir13(archiveDir, { recursive: true });
|
|
4691
|
+
const archiveDest = join25(archiveDir, name);
|
|
4692
|
+
if (await pathExists(archiveDest)) {
|
|
4693
|
+
await rm6(archiveDest, { recursive: true, force: true });
|
|
4694
|
+
}
|
|
4695
|
+
await cp2(fullPath, archiveDest, { recursive: true });
|
|
4696
|
+
await rm6(fullPath, { recursive: true, force: true });
|
|
4697
|
+
result.archived++;
|
|
4698
|
+
printStatus(`Archived ${name} \u2192 flydocs/knowledge/archived/skills/`);
|
|
4699
|
+
break;
|
|
4700
|
+
}
|
|
4701
|
+
case "delete":
|
|
4702
|
+
await rm6(fullPath, { recursive: true, force: true });
|
|
4703
|
+
result.deleted++;
|
|
4704
|
+
printStatus(`Deleted ${name}`);
|
|
4705
|
+
break;
|
|
4706
|
+
}
|
|
4707
|
+
}
|
|
4708
|
+
var CORE_SKILL_PREFIX2;
|
|
4709
|
+
var init_skill_conflicts = __esm({
|
|
4710
|
+
"src/lib/skill-conflicts.ts"() {
|
|
4711
|
+
"use strict";
|
|
4712
|
+
init_fs_ops();
|
|
4713
|
+
init_ui();
|
|
4714
|
+
CORE_SKILL_PREFIX2 = "flydocs-";
|
|
4715
|
+
}
|
|
4716
|
+
});
|
|
4717
|
+
|
|
4718
|
+
// src/commands/sync.ts
|
|
4719
|
+
var sync_exports = {};
|
|
4720
|
+
__export(sync_exports, {
|
|
4721
|
+
default: () => sync_default,
|
|
4722
|
+
runSync: () => runSync
|
|
4723
|
+
});
|
|
4724
|
+
import { defineCommand as defineCommand5 } from "citty";
|
|
4725
|
+
import pc10 from "picocolors";
|
|
4726
|
+
import { join as join26, resolve as resolve4 } from "path";
|
|
4727
|
+
import { mkdir as mkdir14, writeFile as writeFile17 } from "fs/promises";
|
|
4728
|
+
async function runSync(targetDir) {
|
|
4729
|
+
const changes = [];
|
|
4730
|
+
printInfo("Syncing with server...");
|
|
4731
|
+
const resolved = await resolveApiKey(void 0, targetDir);
|
|
4732
|
+
if (!resolved) {
|
|
4733
|
+
printError("No API key found. Run `flydocs auth` or `flydocs init` first.");
|
|
4734
|
+
process.exit(1);
|
|
4735
|
+
}
|
|
4736
|
+
const apiKey = resolved.key;
|
|
4737
|
+
const cred = await readGlobalCredential();
|
|
4738
|
+
const workspaceId = cred?.workspaceId;
|
|
4739
|
+
if (!workspaceId) {
|
|
4740
|
+
printError(
|
|
4741
|
+
"No workspace ID found. Run `flydocs init` to set up your workspace."
|
|
4742
|
+
);
|
|
4743
|
+
process.exit(1);
|
|
4744
|
+
}
|
|
4745
|
+
let currentTemplateVersion = 0;
|
|
4746
|
+
let currentArtifactVersion = 0;
|
|
4747
|
+
let localOverrides;
|
|
4748
|
+
try {
|
|
4749
|
+
const currentConfig = await readAnyConfig(targetDir);
|
|
4750
|
+
if (isConfigV2(currentConfig)) {
|
|
4751
|
+
currentTemplateVersion = currentConfig.configVersion ?? 0;
|
|
4752
|
+
currentArtifactVersion = currentConfig.artifactVersion ?? 0;
|
|
4753
|
+
localOverrides = currentConfig.artifactOverrides;
|
|
4754
|
+
}
|
|
4755
|
+
} catch {
|
|
4756
|
+
}
|
|
4757
|
+
let serverResponse;
|
|
4758
|
+
try {
|
|
4759
|
+
serverResponse = await fetchConfigV2(apiKey, { workspaceId });
|
|
4760
|
+
} catch (err) {
|
|
4761
|
+
if (err instanceof RelayError) {
|
|
4762
|
+
printWarning(`Server unavailable (${err.status}), using cached config.`);
|
|
4763
|
+
} else {
|
|
4764
|
+
printWarning("Server unreachable, using cached config.");
|
|
4765
|
+
}
|
|
4766
|
+
console.log(` ${pc10.dim("Config may be stale. Retry when connected.")}`);
|
|
4767
|
+
return changes;
|
|
4768
|
+
}
|
|
4769
|
+
if (!serverResponse.valid) {
|
|
4770
|
+
printWarning("Server returned invalid config. Keeping current config.");
|
|
4771
|
+
return changes;
|
|
4772
|
+
}
|
|
4773
|
+
await mkdir14(join26(targetDir, ".flydocs"), { recursive: true });
|
|
4774
|
+
const serverConfig = serverResponse.config;
|
|
4775
|
+
if (localOverrides) {
|
|
4776
|
+
serverConfig.artifactOverrides = localOverrides;
|
|
4777
|
+
}
|
|
4778
|
+
const configWithHash = applyConfigHash(serverConfig);
|
|
4779
|
+
await writeConfig(targetDir, configWithHash);
|
|
4780
|
+
changes.push("Updated .flydocs/config.json");
|
|
4781
|
+
const serverTemplateVersion = serverResponse.templates.version;
|
|
4782
|
+
if (serverTemplateVersion > currentTemplateVersion) {
|
|
4783
|
+
try {
|
|
4784
|
+
const templatesResponse = await fetchTemplates(
|
|
4785
|
+
apiKey,
|
|
4786
|
+
currentTemplateVersion,
|
|
4787
|
+
workspaceId
|
|
4788
|
+
);
|
|
4789
|
+
if (templatesResponse.templates.length > 0) {
|
|
4790
|
+
const templatesDir = join26(
|
|
4791
|
+
targetDir,
|
|
4792
|
+
".claude",
|
|
4793
|
+
"skills",
|
|
4794
|
+
"flydocs-workflow",
|
|
4795
|
+
"templates"
|
|
4796
|
+
);
|
|
4797
|
+
await mkdir14(templatesDir, { recursive: true });
|
|
4798
|
+
for (const template of templatesResponse.templates) {
|
|
4799
|
+
const filename = `${template.type}.md`;
|
|
4800
|
+
const subdir = template.category === "issue" ? "issues" : template.category === "pr" ? "pr" : template.category === "comment" ? "." : ".";
|
|
4801
|
+
const templateDir = join26(templatesDir, subdir);
|
|
4802
|
+
await mkdir14(templateDir, { recursive: true });
|
|
4803
|
+
await writeFile17(
|
|
4804
|
+
join26(templateDir, filename),
|
|
4805
|
+
template.content,
|
|
4806
|
+
"utf-8"
|
|
4807
|
+
);
|
|
4808
|
+
}
|
|
4809
|
+
changes.push(
|
|
4810
|
+
`Updated ${templatesResponse.templates.length} templates (v${currentTemplateVersion} \u2192 v${serverTemplateVersion})`
|
|
4811
|
+
);
|
|
4812
|
+
}
|
|
4813
|
+
} catch (err) {
|
|
4814
|
+
if (err instanceof RelayError) {
|
|
4815
|
+
printWarning("Could not fetch templates. Will retry on next sync.");
|
|
4816
|
+
} else {
|
|
4817
|
+
printWarning("Template sync failed. Will retry on next sync.");
|
|
4818
|
+
}
|
|
4819
|
+
}
|
|
4820
|
+
}
|
|
4821
|
+
const serverArtifactVersion = serverResponse.artifactVersion ?? 0;
|
|
4822
|
+
const skipPaths = localOverrides?.skipPaths ?? [];
|
|
4823
|
+
if (serverArtifactVersion > currentArtifactVersion) {
|
|
4824
|
+
const artifactWriteRoot = await resolveArtifactWriteRoot(
|
|
4825
|
+
targetDir,
|
|
4826
|
+
serverResponse.config
|
|
4827
|
+
);
|
|
4828
|
+
const { changes: artifactChanges } = await syncAllArtifacts(
|
|
4829
|
+
artifactWriteRoot,
|
|
4830
|
+
apiKey,
|
|
4831
|
+
workspaceId,
|
|
4832
|
+
currentArtifactVersion,
|
|
4833
|
+
skipPaths
|
|
4834
|
+
);
|
|
4835
|
+
changes.push(...artifactChanges);
|
|
4836
|
+
if (artifactWriteRoot !== targetDir) {
|
|
4837
|
+
changes.push(`Artifacts written to workspace root`);
|
|
4838
|
+
}
|
|
4839
|
+
const keptPaths = localOverrides?.keptPaths ?? [];
|
|
4840
|
+
const conflicts = await resolveSkillConflicts(artifactWriteRoot, keptPaths);
|
|
4841
|
+
if (conflicts.newKeptPaths.length > 0) {
|
|
4842
|
+
try {
|
|
4843
|
+
const updatedConfig = await readAnyConfig(targetDir);
|
|
4844
|
+
if (isConfigV2(updatedConfig)) {
|
|
4845
|
+
const existingKept = updatedConfig.artifactOverrides?.keptPaths ?? [];
|
|
4846
|
+
const mergedKept = [
|
|
4847
|
+
.../* @__PURE__ */ new Set([...existingKept, ...conflicts.newKeptPaths])
|
|
4848
|
+
];
|
|
4849
|
+
updatedConfig.artifactOverrides = {
|
|
4850
|
+
...updatedConfig.artifactOverrides,
|
|
4851
|
+
skipPaths: updatedConfig.artifactOverrides?.skipPaths ?? [],
|
|
4852
|
+
keptPaths: mergedKept
|
|
4853
|
+
};
|
|
4854
|
+
const hashed = applyConfigHash(updatedConfig);
|
|
4855
|
+
await writeConfig(targetDir, hashed);
|
|
4856
|
+
changes.push(
|
|
4857
|
+
`Persisted ${conflicts.newKeptPaths.length} kept path(s) to config`
|
|
4858
|
+
);
|
|
4859
|
+
}
|
|
4860
|
+
} catch {
|
|
4861
|
+
}
|
|
4862
|
+
}
|
|
4863
|
+
if (conflicts.archived > 0) {
|
|
4864
|
+
changes.push(`Archived ${conflicts.archived} non-core skill(s)`);
|
|
4865
|
+
}
|
|
4866
|
+
if (conflicts.deleted > 0) {
|
|
4867
|
+
changes.push(`Deleted ${conflicts.deleted} non-core skill(s)`);
|
|
4868
|
+
}
|
|
4869
|
+
}
|
|
4870
|
+
await migrateGitignore(targetDir);
|
|
4871
|
+
return changes;
|
|
4872
|
+
}
|
|
4873
|
+
async function resolveArtifactWriteRoot(targetDir, config) {
|
|
4874
|
+
const topology = config.topology;
|
|
4875
|
+
if (topology && topology.type === 4 && topology.label === "sibling-repos") {
|
|
4876
|
+
const parentDir = join26(targetDir, "..");
|
|
4877
|
+
const workspaceFile = await readWorkspaceFile(parentDir);
|
|
4878
|
+
if (workspaceFile) {
|
|
4879
|
+
return resolve4(parentDir);
|
|
4880
|
+
}
|
|
4881
|
+
}
|
|
4882
|
+
return targetDir;
|
|
4883
|
+
}
|
|
4884
|
+
var sync_default;
|
|
4885
|
+
var init_sync = __esm({
|
|
4886
|
+
"src/commands/sync.ts"() {
|
|
4887
|
+
"use strict";
|
|
4888
|
+
init_ui();
|
|
4889
|
+
init_global_config();
|
|
4890
|
+
init_config();
|
|
4891
|
+
init_config_integrity();
|
|
4892
|
+
init_types();
|
|
4893
|
+
init_gitignore();
|
|
4894
|
+
init_artifacts();
|
|
4895
|
+
init_workspace();
|
|
4896
|
+
init_relay_client();
|
|
4897
|
+
init_skill_conflicts();
|
|
4898
|
+
sync_default = defineCommand5({
|
|
4899
|
+
meta: {
|
|
4900
|
+
name: "sync",
|
|
4901
|
+
description: "Pull latest config and templates from server"
|
|
4902
|
+
},
|
|
4903
|
+
args: {
|
|
4904
|
+
path: {
|
|
4905
|
+
type: "string",
|
|
4906
|
+
description: "Path to project directory"
|
|
4907
|
+
}
|
|
4908
|
+
},
|
|
4909
|
+
async run({ args }) {
|
|
4910
|
+
const targetDir = args.path ?? process.cwd();
|
|
4911
|
+
console.log();
|
|
4912
|
+
const changes = await runSync(targetDir);
|
|
4913
|
+
if (changes.length === 0) {
|
|
4914
|
+
printStatus("Already up to date.");
|
|
4915
|
+
} else {
|
|
4916
|
+
for (const change of changes) {
|
|
4917
|
+
printStatus(change);
|
|
4918
|
+
}
|
|
4919
|
+
}
|
|
4920
|
+
console.log();
|
|
4921
|
+
}
|
|
4922
|
+
});
|
|
4923
|
+
}
|
|
4924
|
+
});
|
|
4925
|
+
|
|
4550
4926
|
// src/commands/update.ts
|
|
4551
4927
|
var update_exports = {};
|
|
4552
4928
|
__export(update_exports, {
|
|
4553
4929
|
default: () => update_default
|
|
4554
4930
|
});
|
|
4555
|
-
import { defineCommand as
|
|
4556
|
-
import { resolve as
|
|
4557
|
-
import { mkdir as
|
|
4558
|
-
import { select as
|
|
4559
|
-
import
|
|
4931
|
+
import { defineCommand as defineCommand6 } from "citty";
|
|
4932
|
+
import { resolve as resolve5, join as join27 } from "path";
|
|
4933
|
+
import { mkdir as mkdir15, cp as cp3, readFile as readFile16, readdir as readdir8, rm as rm7 } from "fs/promises";
|
|
4934
|
+
import { select as select4, text as text3, confirm as confirm4, isCancel as isCancel6, cancel as cancel4 } from "@clack/prompts";
|
|
4935
|
+
import pc11 from "picocolors";
|
|
4560
4936
|
var update_default;
|
|
4561
4937
|
var init_update = __esm({
|
|
4562
4938
|
"src/commands/update.ts"() {
|
|
@@ -4575,7 +4951,11 @@ var init_update = __esm({
|
|
|
4575
4951
|
init_update_check();
|
|
4576
4952
|
init_telemetry();
|
|
4577
4953
|
init_integrity();
|
|
4578
|
-
|
|
4954
|
+
init_config();
|
|
4955
|
+
init_types();
|
|
4956
|
+
init_managed_paths();
|
|
4957
|
+
init_sync();
|
|
4958
|
+
update_default = defineCommand6({
|
|
4579
4959
|
meta: {
|
|
4580
4960
|
name: "update",
|
|
4581
4961
|
description: "Update an existing FlyDocs installation"
|
|
@@ -4620,11 +5000,11 @@ var init_update = __esm({
|
|
|
4620
5000
|
await capture("update_started", { template_version: version });
|
|
4621
5001
|
let targetDir;
|
|
4622
5002
|
if (args.path) {
|
|
4623
|
-
targetDir =
|
|
5003
|
+
targetDir = resolve5(args.path.replace(/^~/, process.env.HOME ?? "~"));
|
|
4624
5004
|
} else if (args.here) {
|
|
4625
5005
|
targetDir = process.cwd();
|
|
4626
5006
|
} else {
|
|
4627
|
-
const choice = await
|
|
5007
|
+
const choice = await select4({
|
|
4628
5008
|
message: "Which project would you like to update?",
|
|
4629
5009
|
options: [
|
|
4630
5010
|
{
|
|
@@ -4637,7 +5017,7 @@ var init_update = __esm({
|
|
|
4637
5017
|
}
|
|
4638
5018
|
]
|
|
4639
5019
|
});
|
|
4640
|
-
if (
|
|
5020
|
+
if (isCancel6(choice)) {
|
|
4641
5021
|
cancel4("Update cancelled.");
|
|
4642
5022
|
process.exit(0);
|
|
4643
5023
|
}
|
|
@@ -4647,11 +5027,11 @@ var init_update = __esm({
|
|
|
4647
5027
|
const enteredPath = await text3({
|
|
4648
5028
|
message: "Enter project path:"
|
|
4649
5029
|
});
|
|
4650
|
-
if (
|
|
5030
|
+
if (isCancel6(enteredPath)) {
|
|
4651
5031
|
cancel4("Update cancelled.");
|
|
4652
5032
|
process.exit(0);
|
|
4653
5033
|
}
|
|
4654
|
-
targetDir =
|
|
5034
|
+
targetDir = resolve5(
|
|
4655
5035
|
enteredPath.replace(/^~/, process.env.HOME ?? "~")
|
|
4656
5036
|
);
|
|
4657
5037
|
}
|
|
@@ -4660,11 +5040,11 @@ var init_update = __esm({
|
|
|
4660
5040
|
printError(`Directory does not exist: ${targetDir}`);
|
|
4661
5041
|
process.exit(1);
|
|
4662
5042
|
}
|
|
4663
|
-
targetDir =
|
|
5043
|
+
targetDir = resolve5(targetDir);
|
|
4664
5044
|
process.chdir(targetDir);
|
|
4665
|
-
const hasVersion = await pathExists(
|
|
5045
|
+
const hasVersion = await pathExists(join27(targetDir, ".flydocs", "version"));
|
|
4666
5046
|
const hasConfig = await pathExists(
|
|
4667
|
-
|
|
5047
|
+
join27(targetDir, ".flydocs", "config.json")
|
|
4668
5048
|
);
|
|
4669
5049
|
if (!hasVersion && !hasConfig) {
|
|
4670
5050
|
printError(`Not a FlyDocs project: ${targetDir}`);
|
|
@@ -4676,7 +5056,7 @@ var init_update = __esm({
|
|
|
4676
5056
|
let currentVersion = "0.1.0";
|
|
4677
5057
|
if (hasVersion) {
|
|
4678
5058
|
const vContent = await readFile16(
|
|
4679
|
-
|
|
5059
|
+
join27(targetDir, ".flydocs", "version"),
|
|
4680
5060
|
"utf-8"
|
|
4681
5061
|
);
|
|
4682
5062
|
currentVersion = vContent.trim();
|
|
@@ -4698,7 +5078,7 @@ var init_update = __esm({
|
|
|
4698
5078
|
const shouldContinue = await confirm4({
|
|
4699
5079
|
message: "Continue anyway?"
|
|
4700
5080
|
});
|
|
4701
|
-
if (
|
|
5081
|
+
if (isCancel6(shouldContinue) || !shouldContinue) {
|
|
4702
5082
|
process.exit(0);
|
|
4703
5083
|
}
|
|
4704
5084
|
}
|
|
@@ -4710,35 +5090,65 @@ var init_update = __esm({
|
|
|
4710
5090
|
});
|
|
4711
5091
|
console.log(`Updating: v${currentVersion} \u2192 v${version}`);
|
|
4712
5092
|
console.log();
|
|
4713
|
-
const changelogPath =
|
|
5093
|
+
const changelogPath = join27(templateDir, "CHANGELOG.md");
|
|
4714
5094
|
const whatsNew = await getWhatsNew(changelogPath, currentVersion, version);
|
|
4715
5095
|
if (whatsNew.length > 0) {
|
|
4716
|
-
console.log(
|
|
5096
|
+
console.log(pc11.cyan("What's new:"));
|
|
4717
5097
|
console.log();
|
|
4718
5098
|
for (const entry of whatsNew) {
|
|
4719
5099
|
console.log(` ${entry}`);
|
|
4720
5100
|
}
|
|
4721
5101
|
console.log();
|
|
4722
5102
|
}
|
|
5103
|
+
if (hasConfig) {
|
|
5104
|
+
try {
|
|
5105
|
+
const existingConfig = await readAnyConfig(targetDir);
|
|
5106
|
+
if (isConfigV2(existingConfig)) {
|
|
5107
|
+
printInfo(
|
|
5108
|
+
"Cloud project detected \u2014 running sync flow (wipe-and-replace)"
|
|
5109
|
+
);
|
|
5110
|
+
console.log();
|
|
5111
|
+
const syncChanges = await runSync(targetDir);
|
|
5112
|
+
if (syncChanges.length > 0) {
|
|
5113
|
+
for (const change of syncChanges) {
|
|
5114
|
+
printStatus(change);
|
|
5115
|
+
}
|
|
5116
|
+
}
|
|
5117
|
+
console.log();
|
|
5118
|
+
console.log(
|
|
5119
|
+
` ${pc11.dim("Tip: use")} ${pc11.cyan("flydocs sync")} ${pc11.dim("for file-only refresh (no CLI update).")}`
|
|
5120
|
+
);
|
|
5121
|
+
await capture("update_completed", {
|
|
5122
|
+
current_version: currentVersion,
|
|
5123
|
+
version,
|
|
5124
|
+
tier: "cloud",
|
|
5125
|
+
mode: "sync-delegate"
|
|
5126
|
+
});
|
|
5127
|
+
await flush();
|
|
5128
|
+
return;
|
|
5129
|
+
}
|
|
5130
|
+
} catch {
|
|
5131
|
+
}
|
|
5132
|
+
}
|
|
4723
5133
|
const now = /* @__PURE__ */ new Date();
|
|
4724
5134
|
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
|
|
5135
|
+
const backupDir = join27(targetDir, ".flydocs", `backup-${ts}`);
|
|
5136
|
+
await mkdir15(backupDir, { recursive: true });
|
|
4727
5137
|
if (hasConfig) {
|
|
4728
|
-
await
|
|
4729
|
-
|
|
4730
|
-
|
|
5138
|
+
await cp3(
|
|
5139
|
+
join27(targetDir, ".flydocs", "config.json"),
|
|
5140
|
+
join27(backupDir, "config.json")
|
|
4731
5141
|
);
|
|
4732
5142
|
printStatus(`Config backed up to .flydocs/backup-${ts}/`);
|
|
4733
5143
|
}
|
|
4734
5144
|
try {
|
|
4735
|
-
const flydocsDir =
|
|
4736
|
-
const entries = await
|
|
5145
|
+
const flydocsDir = join27(targetDir, ".flydocs");
|
|
5146
|
+
const entries = await readdir8(flydocsDir);
|
|
4737
5147
|
const backups = entries.filter((e) => e.startsWith("backup-")).sort();
|
|
4738
5148
|
if (backups.length > 3) {
|
|
4739
5149
|
const toRemove = backups.slice(0, backups.length - 3);
|
|
4740
5150
|
for (const old of toRemove) {
|
|
4741
|
-
await
|
|
5151
|
+
await rm7(join27(flydocsDir, old), { recursive: true, force: true });
|
|
4742
5152
|
}
|
|
4743
5153
|
}
|
|
4744
5154
|
} catch {
|
|
@@ -4775,19 +5185,21 @@ var init_update = __esm({
|
|
|
4775
5185
|
effectiveTier = preserved.tier;
|
|
4776
5186
|
}
|
|
4777
5187
|
await ensureDirectories(targetDir, effectiveTier);
|
|
5188
|
+
console.log("Wiping server-managed paths...");
|
|
5189
|
+
await wipeManagedPaths(targetDir);
|
|
4778
5190
|
console.log("Replacing framework directories...");
|
|
4779
5191
|
await replaceDirectory(
|
|
4780
|
-
|
|
4781
|
-
|
|
5192
|
+
join27(templateDir, ".flydocs", "templates"),
|
|
5193
|
+
join27(targetDir, ".flydocs", "templates")
|
|
4782
5194
|
);
|
|
4783
5195
|
printStatus(".flydocs/templates");
|
|
4784
5196
|
await replaceDirectory(
|
|
4785
|
-
|
|
4786
|
-
|
|
5197
|
+
join27(templateDir, ".claude", "hooks"),
|
|
5198
|
+
join27(targetDir, ".claude", "hooks")
|
|
4787
5199
|
);
|
|
4788
5200
|
printStatus(".claude/hooks");
|
|
4789
5201
|
const hasExistingAgents = await pathExists(
|
|
4790
|
-
|
|
5202
|
+
join27(targetDir, ".claude", "agents")
|
|
4791
5203
|
);
|
|
4792
5204
|
let installAgents;
|
|
4793
5205
|
if (args.yes) {
|
|
@@ -4796,7 +5208,7 @@ var init_update = __esm({
|
|
|
4796
5208
|
installAgents = true;
|
|
4797
5209
|
} else {
|
|
4798
5210
|
console.log();
|
|
4799
|
-
console.log(` ${
|
|
5211
|
+
console.log(` ${pc11.bold(pc11.yellow("Sub-Agents (Recommended)"))}`);
|
|
4800
5212
|
console.log();
|
|
4801
5213
|
console.log(
|
|
4802
5214
|
" Sub-agents are specialized roles (PM, implementation, review,"
|
|
@@ -4812,27 +5224,27 @@ var init_update = __esm({
|
|
|
4812
5224
|
message: "Install sub-agents?",
|
|
4813
5225
|
initialValue: true
|
|
4814
5226
|
});
|
|
4815
|
-
if (
|
|
5227
|
+
if (isCancel6(agentConfirm)) {
|
|
4816
5228
|
installAgents = false;
|
|
4817
5229
|
} else {
|
|
4818
5230
|
installAgents = agentConfirm;
|
|
4819
5231
|
}
|
|
4820
5232
|
}
|
|
4821
5233
|
if (installAgents) {
|
|
4822
|
-
const claudeAgentsSrc =
|
|
5234
|
+
const claudeAgentsSrc = join27(templateDir, ".claude", "agents");
|
|
4823
5235
|
if (await pathExists(claudeAgentsSrc)) {
|
|
4824
|
-
await
|
|
5236
|
+
await mkdir15(join27(targetDir, ".claude", "agents"), { recursive: true });
|
|
4825
5237
|
await copyDirectoryContents(
|
|
4826
5238
|
claudeAgentsSrc,
|
|
4827
|
-
|
|
5239
|
+
join27(targetDir, ".claude", "agents")
|
|
4828
5240
|
);
|
|
4829
5241
|
}
|
|
4830
|
-
const cursorAgentsSrc =
|
|
5242
|
+
const cursorAgentsSrc = join27(templateDir, ".cursor", "agents");
|
|
4831
5243
|
if (await pathExists(cursorAgentsSrc)) {
|
|
4832
|
-
await
|
|
5244
|
+
await mkdir15(join27(targetDir, ".cursor", "agents"), { recursive: true });
|
|
4833
5245
|
await copyDirectoryContents(
|
|
4834
5246
|
cursorAgentsSrc,
|
|
4835
|
-
|
|
5247
|
+
join27(targetDir, ".cursor", "agents")
|
|
4836
5248
|
);
|
|
4837
5249
|
}
|
|
4838
5250
|
printStatus(
|
|
@@ -4846,58 +5258,58 @@ var init_update = __esm({
|
|
|
4846
5258
|
console.log();
|
|
4847
5259
|
console.log("Replacing framework files...");
|
|
4848
5260
|
await copyFile(
|
|
4849
|
-
|
|
4850
|
-
|
|
5261
|
+
join27(templateDir, ".claude", "CLAUDE.md"),
|
|
5262
|
+
join27(targetDir, ".claude", "CLAUDE.md")
|
|
4851
5263
|
);
|
|
4852
5264
|
await copyFile(
|
|
4853
|
-
|
|
4854
|
-
|
|
5265
|
+
join27(templateDir, ".claude", "settings.json"),
|
|
5266
|
+
join27(targetDir, ".claude", "settings.json")
|
|
4855
5267
|
);
|
|
4856
5268
|
printStatus(".claude/CLAUDE.md, settings.json");
|
|
4857
5269
|
await copyDirectoryContents(
|
|
4858
|
-
|
|
4859
|
-
|
|
5270
|
+
join27(templateDir, ".claude", "commands"),
|
|
5271
|
+
join27(targetDir, ".claude", "commands")
|
|
4860
5272
|
);
|
|
4861
5273
|
await copyDirectoryContents(
|
|
4862
|
-
|
|
4863
|
-
|
|
5274
|
+
join27(templateDir, ".claude", "commands"),
|
|
5275
|
+
join27(targetDir, ".cursor", "commands")
|
|
4864
5276
|
);
|
|
4865
5277
|
printStatus(".claude/commands, .cursor/commands");
|
|
4866
|
-
const skillsReadmeSrc =
|
|
5278
|
+
const skillsReadmeSrc = join27(templateDir, ".claude", "skills", "README.md");
|
|
4867
5279
|
if (await pathExists(skillsReadmeSrc)) {
|
|
4868
5280
|
await copyFile(
|
|
4869
5281
|
skillsReadmeSrc,
|
|
4870
|
-
|
|
5282
|
+
join27(targetDir, ".claude", "skills", "README.md")
|
|
4871
5283
|
);
|
|
4872
5284
|
}
|
|
4873
5285
|
printStatus(".claude/skills/README.md");
|
|
4874
5286
|
await copyFile(
|
|
4875
|
-
|
|
4876
|
-
|
|
5287
|
+
join27(templateDir, ".cursor", "hooks.json"),
|
|
5288
|
+
join27(targetDir, ".cursor", "hooks.json")
|
|
4877
5289
|
);
|
|
4878
5290
|
printStatus(".cursor/hooks.json");
|
|
4879
5291
|
await copyFile(
|
|
4880
|
-
|
|
4881
|
-
|
|
5292
|
+
join27(templateDir, "AGENTS.md"),
|
|
5293
|
+
join27(targetDir, "AGENTS.md")
|
|
4882
5294
|
);
|
|
4883
5295
|
printStatus("AGENTS.md");
|
|
4884
|
-
const envExampleSrc =
|
|
5296
|
+
const envExampleSrc = join27(templateDir, ".env.example");
|
|
4885
5297
|
if (await pathExists(envExampleSrc)) {
|
|
4886
|
-
await copyFile(envExampleSrc,
|
|
5298
|
+
await copyFile(envExampleSrc, join27(targetDir, ".env.example"));
|
|
4887
5299
|
printStatus(".env.example");
|
|
4888
5300
|
}
|
|
4889
|
-
const knowledgeTemplatesDir =
|
|
5301
|
+
const knowledgeTemplatesDir = join27(
|
|
4890
5302
|
targetDir,
|
|
4891
5303
|
"flydocs",
|
|
4892
5304
|
"knowledge",
|
|
4893
5305
|
"templates"
|
|
4894
5306
|
);
|
|
4895
5307
|
if (!await pathExists(knowledgeTemplatesDir)) {
|
|
4896
|
-
await
|
|
5308
|
+
await mkdir15(knowledgeTemplatesDir, { recursive: true });
|
|
4897
5309
|
}
|
|
4898
5310
|
for (const tmpl of ["decision.md", "feature.md", "note.md"]) {
|
|
4899
|
-
const src =
|
|
4900
|
-
const dest =
|
|
5311
|
+
const src = join27(templateDir, "flydocs", "knowledge", "templates", tmpl);
|
|
5312
|
+
const dest = join27(knowledgeTemplatesDir, tmpl);
|
|
4901
5313
|
if (await pathExists(src) && !await pathExists(dest)) {
|
|
4902
5314
|
await copyFile(src, dest);
|
|
4903
5315
|
}
|
|
@@ -4924,18 +5336,18 @@ var init_update = __esm({
|
|
|
4924
5336
|
printWarning("Config merge failed \u2014 config.json preserved as-is");
|
|
4925
5337
|
}
|
|
4926
5338
|
await copyFile(
|
|
4927
|
-
|
|
4928
|
-
|
|
5339
|
+
join27(templateDir, ".flydocs", "version"),
|
|
5340
|
+
join27(targetDir, ".flydocs", "version")
|
|
4929
5341
|
);
|
|
4930
5342
|
printStatus(`.flydocs/version \u2192 ${version}`);
|
|
4931
|
-
const clSrc =
|
|
5343
|
+
const clSrc = join27(templateDir, "CHANGELOG.md");
|
|
4932
5344
|
if (await pathExists(clSrc)) {
|
|
4933
|
-
await copyFile(clSrc,
|
|
5345
|
+
await copyFile(clSrc, join27(targetDir, ".flydocs", "CHANGELOG.md"));
|
|
4934
5346
|
printStatus(".flydocs/CHANGELOG.md");
|
|
4935
5347
|
}
|
|
4936
|
-
const mfSrc =
|
|
5348
|
+
const mfSrc = join27(templateDir, "manifest.json");
|
|
4937
5349
|
if (await pathExists(mfSrc)) {
|
|
4938
|
-
await copyFile(mfSrc,
|
|
5350
|
+
await copyFile(mfSrc, join27(targetDir, ".flydocs", "manifest.json"));
|
|
4939
5351
|
printStatus(".flydocs/manifest.json");
|
|
4940
5352
|
}
|
|
4941
5353
|
await generateIntegrity(targetDir, version);
|
|
@@ -4997,22 +5409,22 @@ var uninstall_exports = {};
|
|
|
4997
5409
|
__export(uninstall_exports, {
|
|
4998
5410
|
default: () => uninstall_default
|
|
4999
5411
|
});
|
|
5000
|
-
import { defineCommand as
|
|
5001
|
-
import { resolve as
|
|
5002
|
-
import { readdir as
|
|
5003
|
-
import { confirm as confirm5, select as
|
|
5004
|
-
import
|
|
5412
|
+
import { defineCommand as defineCommand7 } from "citty";
|
|
5413
|
+
import { resolve as resolve6, join as join28 } from "path";
|
|
5414
|
+
import { readdir as readdir9, rm as rm8, rename as rename2 } from "fs/promises";
|
|
5415
|
+
import { confirm as confirm5, select as select5, isCancel as isCancel7, cancel as cancel5 } from "@clack/prompts";
|
|
5416
|
+
import pc12 from "picocolors";
|
|
5005
5417
|
async function removeOwnedSkills(targetDir) {
|
|
5006
|
-
const skillsDir =
|
|
5418
|
+
const skillsDir = join28(targetDir, ".claude", "skills");
|
|
5007
5419
|
const removed = [];
|
|
5008
5420
|
if (!await pathExists(skillsDir)) {
|
|
5009
5421
|
return removed;
|
|
5010
5422
|
}
|
|
5011
5423
|
try {
|
|
5012
|
-
const entries = await
|
|
5424
|
+
const entries = await readdir9(skillsDir);
|
|
5013
5425
|
for (const entry of entries) {
|
|
5014
5426
|
if (entry.startsWith(OWNED_SKILL_PREFIX)) {
|
|
5015
|
-
await
|
|
5427
|
+
await rm8(join28(skillsDir, entry), { recursive: true, force: true });
|
|
5016
5428
|
removed.push(`.claude/skills/${entry}`);
|
|
5017
5429
|
}
|
|
5018
5430
|
}
|
|
@@ -5021,16 +5433,16 @@ async function removeOwnedSkills(targetDir) {
|
|
|
5021
5433
|
return removed;
|
|
5022
5434
|
}
|
|
5023
5435
|
async function removeOwnedCursorRules(targetDir) {
|
|
5024
|
-
const rulesDir =
|
|
5436
|
+
const rulesDir = join28(targetDir, ".cursor", "rules");
|
|
5025
5437
|
const removed = [];
|
|
5026
5438
|
if (!await pathExists(rulesDir)) {
|
|
5027
5439
|
return removed;
|
|
5028
5440
|
}
|
|
5029
5441
|
try {
|
|
5030
|
-
const entries = await
|
|
5442
|
+
const entries = await readdir9(rulesDir);
|
|
5031
5443
|
for (const entry of entries) {
|
|
5032
5444
|
if (entry.startsWith(OWNED_RULE_PREFIX) && entry.endsWith(".mdc")) {
|
|
5033
|
-
await
|
|
5445
|
+
await rm8(join28(rulesDir, entry), { force: true });
|
|
5034
5446
|
removed.push(`.cursor/rules/${entry}`);
|
|
5035
5447
|
}
|
|
5036
5448
|
}
|
|
@@ -5040,7 +5452,7 @@ async function removeOwnedCursorRules(targetDir) {
|
|
|
5040
5452
|
}
|
|
5041
5453
|
async function isEmptyDir(dirPath) {
|
|
5042
5454
|
try {
|
|
5043
|
-
const entries = await
|
|
5455
|
+
const entries = await readdir9(dirPath);
|
|
5044
5456
|
return entries.length === 0;
|
|
5045
5457
|
} catch {
|
|
5046
5458
|
return false;
|
|
@@ -5049,9 +5461,9 @@ async function isEmptyDir(dirPath) {
|
|
|
5049
5461
|
async function cleanupEmptyParents(targetDir, dirs) {
|
|
5050
5462
|
const cleaned = [];
|
|
5051
5463
|
for (const dir of dirs) {
|
|
5052
|
-
const fullPath =
|
|
5464
|
+
const fullPath = join28(targetDir, dir);
|
|
5053
5465
|
if (await pathExists(fullPath) && await isEmptyDir(fullPath)) {
|
|
5054
|
-
await
|
|
5466
|
+
await rm8(fullPath, { recursive: true, force: true });
|
|
5055
5467
|
cleaned.push(dir);
|
|
5056
5468
|
}
|
|
5057
5469
|
}
|
|
@@ -5081,7 +5493,7 @@ var init_uninstall = __esm({
|
|
|
5081
5493
|
];
|
|
5082
5494
|
OWNED_SKILL_PREFIX = "flydocs-";
|
|
5083
5495
|
OWNED_RULE_PREFIX = "flydocs-";
|
|
5084
|
-
uninstall_default =
|
|
5496
|
+
uninstall_default = defineCommand7({
|
|
5085
5497
|
meta: {
|
|
5086
5498
|
name: "uninstall",
|
|
5087
5499
|
description: "Remove FlyDocs from a project directory"
|
|
@@ -5117,7 +5529,7 @@ var init_uninstall = __esm({
|
|
|
5117
5529
|
printBanner(CLI_VERSION);
|
|
5118
5530
|
let targetDir;
|
|
5119
5531
|
if (args.path) {
|
|
5120
|
-
targetDir =
|
|
5532
|
+
targetDir = resolve6(args.path.replace(/^~/, process.env.HOME ?? "~"));
|
|
5121
5533
|
} else if (args.here) {
|
|
5122
5534
|
targetDir = process.cwd();
|
|
5123
5535
|
} else {
|
|
@@ -5127,9 +5539,9 @@ var init_uninstall = __esm({
|
|
|
5127
5539
|
printError(`Directory does not exist: ${targetDir}`);
|
|
5128
5540
|
process.exit(1);
|
|
5129
5541
|
}
|
|
5130
|
-
targetDir =
|
|
5131
|
-
const hasFlydocs = await pathExists(
|
|
5132
|
-
const hasAgentsMd = await pathExists(
|
|
5542
|
+
targetDir = resolve6(targetDir);
|
|
5543
|
+
const hasFlydocs = await pathExists(join28(targetDir, ".flydocs"));
|
|
5544
|
+
const hasAgentsMd = await pathExists(join28(targetDir, "AGENTS.md"));
|
|
5133
5545
|
if (!hasFlydocs && !hasAgentsMd) {
|
|
5134
5546
|
printError(`Not a FlyDocs project: ${targetDir}`);
|
|
5135
5547
|
printInfo("No .flydocs/ directory or AGENTS.md found.");
|
|
@@ -5141,12 +5553,12 @@ var init_uninstall = __esm({
|
|
|
5141
5553
|
const removeAll = forceAll || args.all;
|
|
5142
5554
|
const skipPrompts = forceAll || args.yes;
|
|
5143
5555
|
let contentAction = "preserve";
|
|
5144
|
-
const hasUserContent = await pathExists(
|
|
5556
|
+
const hasUserContent = await pathExists(join28(targetDir, "flydocs"));
|
|
5145
5557
|
if (hasUserContent) {
|
|
5146
5558
|
if (removeAll) {
|
|
5147
5559
|
contentAction = "remove";
|
|
5148
5560
|
} else if (!skipPrompts) {
|
|
5149
|
-
const choice = await
|
|
5561
|
+
const choice = await select5({
|
|
5150
5562
|
message: "What should happen to your flydocs/ content (project docs, knowledge base)?",
|
|
5151
5563
|
options: [
|
|
5152
5564
|
{
|
|
@@ -5166,7 +5578,7 @@ var init_uninstall = __esm({
|
|
|
5166
5578
|
}
|
|
5167
5579
|
]
|
|
5168
5580
|
});
|
|
5169
|
-
if (
|
|
5581
|
+
if (isCancel7(choice)) {
|
|
5170
5582
|
cancel5("Uninstall cancelled.");
|
|
5171
5583
|
process.exit(0);
|
|
5172
5584
|
}
|
|
@@ -5175,39 +5587,39 @@ var init_uninstall = __esm({
|
|
|
5175
5587
|
}
|
|
5176
5588
|
if (!skipPrompts) {
|
|
5177
5589
|
console.log();
|
|
5178
|
-
console.log(
|
|
5590
|
+
console.log(pc12.bold("The following will be removed:"));
|
|
5179
5591
|
console.log();
|
|
5180
5592
|
console.log(" Framework files:");
|
|
5181
5593
|
for (const [path] of ALWAYS_REMOVED) {
|
|
5182
|
-
console.log(` ${
|
|
5594
|
+
console.log(` ${pc12.dim(path)}`);
|
|
5183
5595
|
}
|
|
5184
|
-
console.log(` ${
|
|
5185
|
-
console.log(` ${
|
|
5596
|
+
console.log(` ${pc12.dim(".claude/skills/flydocs-*")}`);
|
|
5597
|
+
console.log(` ${pc12.dim(".cursor/rules/flydocs-*.mdc")}`);
|
|
5186
5598
|
if (hasUserContent) {
|
|
5187
5599
|
if (contentAction === "archive") {
|
|
5188
5600
|
console.log();
|
|
5189
5601
|
console.log(
|
|
5190
|
-
` User content: ${
|
|
5602
|
+
` User content: ${pc12.yellow("flydocs/ -> flydocs-archive/")}`
|
|
5191
5603
|
);
|
|
5192
5604
|
} else if (contentAction === "remove") {
|
|
5193
5605
|
console.log();
|
|
5194
|
-
console.log(` User content: ${
|
|
5606
|
+
console.log(` User content: ${pc12.red("flydocs/ (deleted)")}`);
|
|
5195
5607
|
} else {
|
|
5196
5608
|
console.log();
|
|
5197
|
-
console.log(` User content: ${
|
|
5609
|
+
console.log(` User content: ${pc12.green("flydocs/ (preserved)")}`);
|
|
5198
5610
|
}
|
|
5199
5611
|
}
|
|
5200
5612
|
console.log();
|
|
5201
|
-
console.log(
|
|
5613
|
+
console.log(pc12.bold("Preserved:"));
|
|
5202
5614
|
console.log(
|
|
5203
|
-
` ${
|
|
5615
|
+
` ${pc12.dim(".claude/skills/ (non-flydocs community skills)")}`
|
|
5204
5616
|
);
|
|
5205
|
-
console.log(` ${
|
|
5617
|
+
console.log(` ${pc12.dim(".env, .env.local")}`);
|
|
5206
5618
|
console.log();
|
|
5207
5619
|
const shouldContinue = await confirm5({
|
|
5208
5620
|
message: "Proceed with uninstall?"
|
|
5209
5621
|
});
|
|
5210
|
-
if (
|
|
5622
|
+
if (isCancel7(shouldContinue) || !shouldContinue) {
|
|
5211
5623
|
cancel5("Uninstall cancelled.");
|
|
5212
5624
|
process.exit(0);
|
|
5213
5625
|
}
|
|
@@ -5224,16 +5636,16 @@ var init_uninstall = __esm({
|
|
|
5224
5636
|
const removedRules = await removeOwnedCursorRules(targetDir);
|
|
5225
5637
|
result.removed.push(...removedRules);
|
|
5226
5638
|
for (const [relativePath, type] of ALWAYS_REMOVED) {
|
|
5227
|
-
const fullPath =
|
|
5639
|
+
const fullPath = join28(targetDir, relativePath);
|
|
5228
5640
|
if (!await pathExists(fullPath)) {
|
|
5229
5641
|
result.skipped.push(relativePath);
|
|
5230
5642
|
continue;
|
|
5231
5643
|
}
|
|
5232
5644
|
try {
|
|
5233
5645
|
if (type === "dir") {
|
|
5234
|
-
await
|
|
5646
|
+
await rm8(fullPath, { recursive: true, force: true });
|
|
5235
5647
|
} else {
|
|
5236
|
-
await
|
|
5648
|
+
await rm8(fullPath, { force: true });
|
|
5237
5649
|
}
|
|
5238
5650
|
result.removed.push(relativePath);
|
|
5239
5651
|
} catch {
|
|
@@ -5242,16 +5654,16 @@ var init_uninstall = __esm({
|
|
|
5242
5654
|
}
|
|
5243
5655
|
}
|
|
5244
5656
|
if (hasUserContent) {
|
|
5245
|
-
const flydocsPath =
|
|
5657
|
+
const flydocsPath = join28(targetDir, "flydocs");
|
|
5246
5658
|
if (contentAction === "archive") {
|
|
5247
|
-
const archivePath =
|
|
5659
|
+
const archivePath = join28(targetDir, "flydocs-archive");
|
|
5248
5660
|
if (await pathExists(archivePath)) {
|
|
5249
|
-
await
|
|
5661
|
+
await rm8(archivePath, { recursive: true, force: true });
|
|
5250
5662
|
}
|
|
5251
5663
|
await rename2(flydocsPath, archivePath);
|
|
5252
5664
|
result.archived.push("flydocs/ -> flydocs-archive/");
|
|
5253
5665
|
} else if (contentAction === "remove") {
|
|
5254
|
-
await
|
|
5666
|
+
await rm8(flydocsPath, { recursive: true, force: true });
|
|
5255
5667
|
result.removed.push("flydocs/");
|
|
5256
5668
|
}
|
|
5257
5669
|
}
|
|
@@ -5270,17 +5682,17 @@ var init_uninstall = __esm({
|
|
|
5270
5682
|
result.restored = originals.map((f) => f.relativePath);
|
|
5271
5683
|
}
|
|
5272
5684
|
console.log();
|
|
5273
|
-
console.log(
|
|
5685
|
+
console.log(pc12.bold("Uninstall Summary"));
|
|
5274
5686
|
console.log();
|
|
5275
5687
|
if (result.removed.length > 0) {
|
|
5276
|
-
console.log(` ${
|
|
5688
|
+
console.log(` ${pc12.green("Removed")} (${result.removed.length}):`);
|
|
5277
5689
|
for (const item of result.removed) {
|
|
5278
5690
|
printStatus(item);
|
|
5279
5691
|
}
|
|
5280
5692
|
}
|
|
5281
5693
|
if (result.archived.length > 0) {
|
|
5282
5694
|
console.log();
|
|
5283
|
-
console.log(` ${
|
|
5695
|
+
console.log(` ${pc12.yellow("Archived")} (${result.archived.length}):`);
|
|
5284
5696
|
for (const item of result.archived) {
|
|
5285
5697
|
printInfo(item);
|
|
5286
5698
|
}
|
|
@@ -5288,7 +5700,7 @@ var init_uninstall = __esm({
|
|
|
5288
5700
|
if (result.restored.length > 0) {
|
|
5289
5701
|
console.log();
|
|
5290
5702
|
console.log(
|
|
5291
|
-
` ${
|
|
5703
|
+
` ${pc12.green("Restored")} (${result.restored.length} pre-FlyDocs original(s)):`
|
|
5292
5704
|
);
|
|
5293
5705
|
for (const item of result.restored) {
|
|
5294
5706
|
printInfo(item);
|
|
@@ -5297,16 +5709,16 @@ var init_uninstall = __esm({
|
|
|
5297
5709
|
if (result.skipped.length > 0) {
|
|
5298
5710
|
console.log();
|
|
5299
5711
|
console.log(
|
|
5300
|
-
` ${
|
|
5712
|
+
` ${pc12.dim("Skipped")} (${result.skipped.length} \u2014 not found):`
|
|
5301
5713
|
);
|
|
5302
5714
|
for (const item of result.skipped) {
|
|
5303
|
-
console.log(` ${
|
|
5715
|
+
console.log(` ${pc12.dim(item)}`);
|
|
5304
5716
|
}
|
|
5305
5717
|
}
|
|
5306
5718
|
console.log();
|
|
5307
5719
|
printStatus("FlyDocs has been removed from this project.");
|
|
5308
5720
|
console.log();
|
|
5309
|
-
printInfo(`To reinstall: ${
|
|
5721
|
+
printInfo(`To reinstall: ${pc12.cyan("npx @flydocs/cli install --here")}`);
|
|
5310
5722
|
console.log();
|
|
5311
5723
|
}
|
|
5312
5724
|
});
|
|
@@ -5318,28 +5730,28 @@ var setup_exports = {};
|
|
|
5318
5730
|
__export(setup_exports, {
|
|
5319
5731
|
default: () => setup_default
|
|
5320
5732
|
});
|
|
5321
|
-
import { defineCommand as
|
|
5322
|
-
import
|
|
5733
|
+
import { defineCommand as defineCommand8 } from "citty";
|
|
5734
|
+
import pc13 from "picocolors";
|
|
5323
5735
|
var setup_default;
|
|
5324
5736
|
var init_setup = __esm({
|
|
5325
5737
|
"src/commands/setup.ts"() {
|
|
5326
5738
|
"use strict";
|
|
5327
|
-
setup_default =
|
|
5739
|
+
setup_default = defineCommand8({
|
|
5328
5740
|
meta: {
|
|
5329
5741
|
name: "setup",
|
|
5330
5742
|
description: "Configure FlyDocs settings for this project"
|
|
5331
5743
|
},
|
|
5332
5744
|
run() {
|
|
5333
5745
|
console.log();
|
|
5334
|
-
console.log(` ${
|
|
5746
|
+
console.log(` ${pc13.bold("FlyDocs Setup")}`);
|
|
5335
5747
|
console.log();
|
|
5336
5748
|
console.log(` Setup runs inside your IDE as an interactive AI command.`);
|
|
5337
5749
|
console.log();
|
|
5338
5750
|
console.log(
|
|
5339
|
-
` ${
|
|
5751
|
+
` ${pc13.cyan("Claude Code:")} Type ${pc13.bold("/flydocs-setup")} in chat`
|
|
5340
5752
|
);
|
|
5341
5753
|
console.log(
|
|
5342
|
-
` ${
|
|
5754
|
+
` ${pc13.cyan("Cursor:")} Type ${pc13.bold("/flydocs-setup")} in chat`
|
|
5343
5755
|
);
|
|
5344
5756
|
console.log();
|
|
5345
5757
|
console.log(` This configures your project context, detects your stack,`);
|
|
@@ -5355,14 +5767,14 @@ var skills_exports = {};
|
|
|
5355
5767
|
__export(skills_exports, {
|
|
5356
5768
|
default: () => skills_default
|
|
5357
5769
|
});
|
|
5358
|
-
import { defineCommand as
|
|
5359
|
-
import
|
|
5770
|
+
import { defineCommand as defineCommand9 } from "citty";
|
|
5771
|
+
import pc14 from "picocolors";
|
|
5360
5772
|
var list, search, add, remove, skills_default;
|
|
5361
5773
|
var init_skills2 = __esm({
|
|
5362
5774
|
"src/commands/skills.ts"() {
|
|
5363
5775
|
"use strict";
|
|
5364
5776
|
init_skill_manager();
|
|
5365
|
-
list =
|
|
5777
|
+
list = defineCommand9({
|
|
5366
5778
|
meta: {
|
|
5367
5779
|
name: "list",
|
|
5368
5780
|
description: "List installed skills"
|
|
@@ -5378,26 +5790,26 @@ var init_skills2 = __esm({
|
|
|
5378
5790
|
console.log(`${total} skill(s) installed:`);
|
|
5379
5791
|
if (result.platform.length > 0) {
|
|
5380
5792
|
console.log();
|
|
5381
|
-
console.log(
|
|
5793
|
+
console.log(pc14.bold("Platform"));
|
|
5382
5794
|
for (const skill of result.platform) {
|
|
5383
5795
|
console.log(
|
|
5384
|
-
` ${skill.name} ${
|
|
5796
|
+
` ${skill.name} ${pc14.dim(`(${skill.triggers} triggers)`)}`
|
|
5385
5797
|
);
|
|
5386
5798
|
}
|
|
5387
5799
|
}
|
|
5388
5800
|
if (result.community.length > 0) {
|
|
5389
5801
|
console.log();
|
|
5390
|
-
console.log(
|
|
5802
|
+
console.log(pc14.bold("Community"));
|
|
5391
5803
|
for (const skill of result.community) {
|
|
5392
5804
|
console.log(
|
|
5393
|
-
` ${skill.name} ${
|
|
5805
|
+
` ${skill.name} ${pc14.dim(`(${skill.triggers} triggers)`)}`
|
|
5394
5806
|
);
|
|
5395
5807
|
}
|
|
5396
5808
|
}
|
|
5397
5809
|
console.log();
|
|
5398
5810
|
}
|
|
5399
5811
|
});
|
|
5400
|
-
search =
|
|
5812
|
+
search = defineCommand9({
|
|
5401
5813
|
meta: {
|
|
5402
5814
|
name: "search",
|
|
5403
5815
|
description: "Search community skills"
|
|
@@ -5413,24 +5825,24 @@ var init_skills2 = __esm({
|
|
|
5413
5825
|
const results = await searchCatalog(args.keyword);
|
|
5414
5826
|
if (results.length === 0) {
|
|
5415
5827
|
console.log(`No skills found for "${args.keyword}".`);
|
|
5416
|
-
console.log(` Browse the catalog at: ${
|
|
5828
|
+
console.log(` Browse the catalog at: ${pc14.cyan("https://skills.sh/")}`);
|
|
5417
5829
|
return;
|
|
5418
5830
|
}
|
|
5419
5831
|
console.log();
|
|
5420
5832
|
console.log(`${results.length} skill(s) matching "${args.keyword}":`);
|
|
5421
5833
|
console.log();
|
|
5422
5834
|
for (const skill of results) {
|
|
5423
|
-
console.log(` ${
|
|
5835
|
+
console.log(` ${pc14.bold(skill.name)}`);
|
|
5424
5836
|
console.log(` ${skill.description}`);
|
|
5425
|
-
console.log(` ${
|
|
5837
|
+
console.log(` ${pc14.dim(skill.repo)}`);
|
|
5426
5838
|
if (skill.tags.length > 0) {
|
|
5427
|
-
console.log(` ${
|
|
5839
|
+
console.log(` ${pc14.dim(skill.tags.join(", "))}`);
|
|
5428
5840
|
}
|
|
5429
5841
|
console.log();
|
|
5430
5842
|
}
|
|
5431
5843
|
}
|
|
5432
5844
|
});
|
|
5433
|
-
add =
|
|
5845
|
+
add = defineCommand9({
|
|
5434
5846
|
meta: {
|
|
5435
5847
|
name: "add",
|
|
5436
5848
|
description: "Install a community skill"
|
|
@@ -5446,7 +5858,7 @@ var init_skills2 = __esm({
|
|
|
5446
5858
|
await addSkill(process.cwd(), args.source);
|
|
5447
5859
|
}
|
|
5448
5860
|
});
|
|
5449
|
-
remove =
|
|
5861
|
+
remove = defineCommand9({
|
|
5450
5862
|
meta: {
|
|
5451
5863
|
name: "remove",
|
|
5452
5864
|
description: "Remove an installed community skill"
|
|
@@ -5462,7 +5874,7 @@ var init_skills2 = __esm({
|
|
|
5462
5874
|
await removeSkill(process.cwd(), args.name);
|
|
5463
5875
|
}
|
|
5464
5876
|
});
|
|
5465
|
-
skills_default =
|
|
5877
|
+
skills_default = defineCommand9({
|
|
5466
5878
|
meta: {
|
|
5467
5879
|
name: "skills",
|
|
5468
5880
|
description: "Manage FlyDocs skills (list, search, add, remove)"
|
|
@@ -5482,10 +5894,10 @@ var connect_exports = {};
|
|
|
5482
5894
|
__export(connect_exports, {
|
|
5483
5895
|
default: () => connect_default
|
|
5484
5896
|
});
|
|
5485
|
-
import { defineCommand as
|
|
5486
|
-
import { text as text4, confirm as confirm6, isCancel as
|
|
5487
|
-
import
|
|
5488
|
-
import { join as
|
|
5897
|
+
import { defineCommand as defineCommand10 } from "citty";
|
|
5898
|
+
import { text as text4, confirm as confirm6, isCancel as isCancel8, cancel as cancel6 } from "@clack/prompts";
|
|
5899
|
+
import pc15 from "picocolors";
|
|
5900
|
+
import { join as join29 } from "path";
|
|
5489
5901
|
var connect_default;
|
|
5490
5902
|
var init_connect = __esm({
|
|
5491
5903
|
"src/commands/connect.ts"() {
|
|
@@ -5495,7 +5907,7 @@ var init_connect = __esm({
|
|
|
5495
5907
|
init_template();
|
|
5496
5908
|
init_ui();
|
|
5497
5909
|
init_api_key();
|
|
5498
|
-
connect_default =
|
|
5910
|
+
connect_default = defineCommand10({
|
|
5499
5911
|
meta: {
|
|
5500
5912
|
name: "connect",
|
|
5501
5913
|
description: "Connect FlyDocs to a cloud provider"
|
|
@@ -5520,11 +5932,11 @@ var init_connect = __esm({
|
|
|
5520
5932
|
},
|
|
5521
5933
|
async run({ args }) {
|
|
5522
5934
|
const targetDir = args.path ?? process.cwd();
|
|
5523
|
-
const configPath =
|
|
5935
|
+
const configPath = join29(targetDir, ".flydocs", "config.json");
|
|
5524
5936
|
if (!await pathExists(configPath)) {
|
|
5525
5937
|
printError("Not a FlyDocs project (.flydocs/config.json not found).");
|
|
5526
5938
|
console.log(
|
|
5527
|
-
` Run ${
|
|
5939
|
+
` Run ${pc15.cyan("flydocs")} first to install FlyDocs in this project.`
|
|
5528
5940
|
);
|
|
5529
5941
|
process.exit(1);
|
|
5530
5942
|
}
|
|
@@ -5535,16 +5947,16 @@ var init_connect = __esm({
|
|
|
5535
5947
|
const reconnect = await confirm6({
|
|
5536
5948
|
message: "Want to update your API key?"
|
|
5537
5949
|
});
|
|
5538
|
-
if (
|
|
5950
|
+
if (isCancel8(reconnect) || !reconnect) {
|
|
5539
5951
|
console.log(` No changes made.`);
|
|
5540
5952
|
return;
|
|
5541
5953
|
}
|
|
5542
5954
|
}
|
|
5543
5955
|
console.log();
|
|
5544
|
-
console.log(` ${
|
|
5956
|
+
console.log(` ${pc15.bold("Connect to FlyDocs Cloud")}`);
|
|
5545
5957
|
console.log();
|
|
5546
5958
|
console.log(
|
|
5547
|
-
` ${
|
|
5959
|
+
` ${pc15.dim("Get your API key (fdk_...) from your FlyDocs dashboard")}`
|
|
5548
5960
|
);
|
|
5549
5961
|
console.log();
|
|
5550
5962
|
let apiKey = args.key ?? "";
|
|
@@ -5560,7 +5972,7 @@ var init_connect = __esm({
|
|
|
5560
5972
|
return void 0;
|
|
5561
5973
|
}
|
|
5562
5974
|
});
|
|
5563
|
-
if (
|
|
5975
|
+
if (isCancel8(keyInput)) {
|
|
5564
5976
|
cancel6("Connection cancelled.");
|
|
5565
5977
|
process.exit(0);
|
|
5566
5978
|
}
|
|
@@ -5582,7 +5994,7 @@ var init_connect = __esm({
|
|
|
5582
5994
|
console.log(` Check your key and try again.`);
|
|
5583
5995
|
process.exit(1);
|
|
5584
5996
|
}
|
|
5585
|
-
printStatus(`Connected to ${
|
|
5997
|
+
printStatus(`Connected to ${pc15.bold(result.org)}`);
|
|
5586
5998
|
} catch {
|
|
5587
5999
|
printError(
|
|
5588
6000
|
"Could not reach relay API. Check your network and try again."
|
|
@@ -5590,7 +6002,7 @@ var init_connect = __esm({
|
|
|
5590
6002
|
process.exit(1);
|
|
5591
6003
|
}
|
|
5592
6004
|
const envFile = await storeEnvKey(targetDir, "FLYDOCS_API_KEY", apiKey);
|
|
5593
|
-
printStatus(`API key stored in ${
|
|
6005
|
+
printStatus(`API key stored in ${pc15.dim(envFile)}`);
|
|
5594
6006
|
} else {
|
|
5595
6007
|
try {
|
|
5596
6008
|
const result = await validateLinearKey(apiKey);
|
|
@@ -5600,7 +6012,7 @@ var init_connect = __esm({
|
|
|
5600
6012
|
process.exit(1);
|
|
5601
6013
|
}
|
|
5602
6014
|
printStatus(
|
|
5603
|
-
`Authenticated as ${
|
|
6015
|
+
`Authenticated as ${pc15.bold(result.name)} (${result.email})`
|
|
5604
6016
|
);
|
|
5605
6017
|
} catch {
|
|
5606
6018
|
printError("Invalid API key or network error.");
|
|
@@ -5608,7 +6020,7 @@ var init_connect = __esm({
|
|
|
5608
6020
|
process.exit(1);
|
|
5609
6021
|
}
|
|
5610
6022
|
const envFile = await storeEnvKey(targetDir, "LINEAR_API_KEY", apiKey);
|
|
5611
|
-
printStatus(`API key stored in ${
|
|
6023
|
+
printStatus(`API key stored in ${pc15.dim(envFile)}`);
|
|
5612
6024
|
}
|
|
5613
6025
|
const wasLocal = config.tier === "local";
|
|
5614
6026
|
config.tier = "cloud";
|
|
@@ -5624,14 +6036,14 @@ var init_connect = __esm({
|
|
|
5624
6036
|
}
|
|
5625
6037
|
console.log();
|
|
5626
6038
|
console.log(
|
|
5627
|
-
` ${
|
|
6039
|
+
` ${pc15.bold("Connected!")} Your project is now on the cloud tier.`
|
|
5628
6040
|
);
|
|
5629
6041
|
console.log();
|
|
5630
6042
|
console.log(` Next steps:`);
|
|
5631
6043
|
console.log(
|
|
5632
|
-
` 1. Run ${
|
|
6044
|
+
` 1. Run ${pc15.cyan("/flydocs-setup")} in your IDE to configure your project`
|
|
5633
6045
|
);
|
|
5634
|
-
console.log(` 2. Run ${
|
|
6046
|
+
console.log(` 2. Run ${pc15.cyan("/start-session")} to begin working`);
|
|
5635
6047
|
console.log();
|
|
5636
6048
|
}
|
|
5637
6049
|
});
|
|
@@ -5643,9 +6055,9 @@ var auth_exports = {};
|
|
|
5643
6055
|
__export(auth_exports, {
|
|
5644
6056
|
default: () => auth_default
|
|
5645
6057
|
});
|
|
5646
|
-
import { defineCommand as
|
|
5647
|
-
import { text as text5, confirm as confirm7, isCancel as
|
|
5648
|
-
import
|
|
6058
|
+
import { defineCommand as defineCommand11 } from "citty";
|
|
6059
|
+
import { text as text5, confirm as confirm7, isCancel as isCancel9, cancel as cancel7 } from "@clack/prompts";
|
|
6060
|
+
import pc16 from "picocolors";
|
|
5649
6061
|
var auth_default;
|
|
5650
6062
|
var init_auth = __esm({
|
|
5651
6063
|
"src/commands/auth.ts"() {
|
|
@@ -5653,7 +6065,7 @@ var init_auth = __esm({
|
|
|
5653
6065
|
init_ui();
|
|
5654
6066
|
init_api_key();
|
|
5655
6067
|
init_global_config();
|
|
5656
|
-
auth_default =
|
|
6068
|
+
auth_default = defineCommand11({
|
|
5657
6069
|
meta: {
|
|
5658
6070
|
name: "auth",
|
|
5659
6071
|
description: "Store API key globally (~/.flydocs/credentials)"
|
|
@@ -5667,25 +6079,25 @@ var init_auth = __esm({
|
|
|
5667
6079
|
},
|
|
5668
6080
|
async run({ args }) {
|
|
5669
6081
|
console.log();
|
|
5670
|
-
console.log(` ${
|
|
6082
|
+
console.log(` ${pc16.bold("FlyDocs Authentication")}`);
|
|
5671
6083
|
console.log();
|
|
5672
6084
|
let apiKey = args.key ?? "";
|
|
5673
6085
|
const existing = await readGlobalCredential();
|
|
5674
6086
|
if (existing?.apiKey && !apiKey) {
|
|
5675
6087
|
printInfo(
|
|
5676
|
-
`Existing key found: ${
|
|
6088
|
+
`Existing key found: ${pc16.dim(existing.apiKey.slice(0, 8) + "...")}`
|
|
5677
6089
|
);
|
|
5678
6090
|
const replace = await confirm7({
|
|
5679
6091
|
message: "Replace with a new key?"
|
|
5680
6092
|
});
|
|
5681
|
-
if (
|
|
6093
|
+
if (isCancel9(replace) || !replace) {
|
|
5682
6094
|
console.log(` No changes made.`);
|
|
5683
6095
|
return;
|
|
5684
6096
|
}
|
|
5685
6097
|
}
|
|
5686
6098
|
if (!apiKey) {
|
|
5687
6099
|
console.log(
|
|
5688
|
-
` ${
|
|
6100
|
+
` ${pc16.dim("Get your API key (fdk_...) from your FlyDocs dashboard")}`
|
|
5689
6101
|
);
|
|
5690
6102
|
console.log();
|
|
5691
6103
|
const keyInput = await text5({
|
|
@@ -5699,7 +6111,7 @@ var init_auth = __esm({
|
|
|
5699
6111
|
return void 0;
|
|
5700
6112
|
}
|
|
5701
6113
|
});
|
|
5702
|
-
if (
|
|
6114
|
+
if (isCancel9(keyInput)) {
|
|
5703
6115
|
cancel7("Authentication cancelled.");
|
|
5704
6116
|
process.exit(0);
|
|
5705
6117
|
}
|
|
@@ -5721,7 +6133,7 @@ var init_auth = __esm({
|
|
|
5721
6133
|
printError("Invalid API key. Check your key and try again.");
|
|
5722
6134
|
process.exit(1);
|
|
5723
6135
|
}
|
|
5724
|
-
printStatus(`Authenticated with ${
|
|
6136
|
+
printStatus(`Authenticated with ${pc16.bold(result.org)}`);
|
|
5725
6137
|
} catch {
|
|
5726
6138
|
printError(
|
|
5727
6139
|
"Could not reach FlyDocs API. Check your network and try again."
|
|
@@ -5736,10 +6148,10 @@ var init_auth = __esm({
|
|
|
5736
6148
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5737
6149
|
lastValidated: (/* @__PURE__ */ new Date()).toISOString()
|
|
5738
6150
|
});
|
|
5739
|
-
printStatus(`Key stored at ${
|
|
6151
|
+
printStatus(`Key stored at ${pc16.dim(credentialsPath())}`);
|
|
5740
6152
|
await checkCredentialPermissions();
|
|
5741
6153
|
console.log();
|
|
5742
|
-
console.log(` ${
|
|
6154
|
+
console.log(` ${pc16.bold("Authenticated!")} Key stored globally.`);
|
|
5743
6155
|
console.log(` All FlyDocs projects on this machine will use this key.`);
|
|
5744
6156
|
console.log();
|
|
5745
6157
|
}
|
|
@@ -5747,175 +6159,6 @@ var init_auth = __esm({
|
|
|
5747
6159
|
}
|
|
5748
6160
|
});
|
|
5749
6161
|
|
|
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
6162
|
// src/commands/upgrade.ts
|
|
5920
6163
|
var upgrade_exports = {};
|
|
5921
6164
|
__export(upgrade_exports, {
|