@flydocs/cli 0.6.0-alpha.27 → 0.6.0-alpha.29
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 +622 -410
- package/package.json +1 -1
- package/template/.flydocs/config.json +1 -1
- package/template/.flydocs/version +1 -1
- 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.29";
|
|
19
19
|
CLI_NAME = "flydocs";
|
|
20
20
|
PACKAGE_NAME = "@flydocs/cli";
|
|
21
21
|
POSTHOG_API_KEY = "phc_v1MSJTQDFkMS90CBh3mxIz3v8bYCCnKU6v1ir6bz0Xn";
|
|
@@ -2989,33 +2989,250 @@ var init_relay_client = __esm({
|
|
|
2989
2989
|
}
|
|
2990
2990
|
});
|
|
2991
2991
|
|
|
2992
|
+
// src/commands/cleanup.ts
|
|
2993
|
+
var cleanup_exports = {};
|
|
2994
|
+
__export(cleanup_exports, {
|
|
2995
|
+
default: () => cleanup_default,
|
|
2996
|
+
executeCleanup: () => executeCleanup,
|
|
2997
|
+
scanArtifacts: () => scanArtifacts
|
|
2998
|
+
});
|
|
2999
|
+
import { defineCommand as defineCommand2 } from "citty";
|
|
3000
|
+
import pc7 from "picocolors";
|
|
3001
|
+
import { join as join18 } from "path";
|
|
3002
|
+
import { readFile as readFile13, writeFile as writeFile11, rm as rm4 } from "fs/promises";
|
|
3003
|
+
async function scanArtifacts(targetDir) {
|
|
3004
|
+
const actions = [];
|
|
3005
|
+
const localMePath = join18(targetDir, ".flydocs", "me.json");
|
|
3006
|
+
if (await pathExists(localMePath) && await pathExists(globalMePath())) {
|
|
3007
|
+
actions.push({
|
|
3008
|
+
description: "Remove .flydocs/me.json (migrated to ~/.flydocs/me.json)",
|
|
3009
|
+
path: localMePath,
|
|
3010
|
+
type: "file"
|
|
3011
|
+
});
|
|
3012
|
+
}
|
|
3013
|
+
const validationCachePath = join18(
|
|
3014
|
+
targetDir,
|
|
3015
|
+
".flydocs",
|
|
3016
|
+
"validation-cache.json"
|
|
3017
|
+
);
|
|
3018
|
+
if (await pathExists(validationCachePath)) {
|
|
3019
|
+
actions.push({
|
|
3020
|
+
description: "Remove .flydocs/validation-cache.json (replaced by configVersion)",
|
|
3021
|
+
path: validationCachePath,
|
|
3022
|
+
type: "file"
|
|
3023
|
+
});
|
|
3024
|
+
}
|
|
3025
|
+
const hasGlobalCreds = await pathExists(credentialsPath());
|
|
3026
|
+
for (const envFile of [".env", ".env.local"]) {
|
|
3027
|
+
const envPath = join18(targetDir, envFile);
|
|
3028
|
+
if (!await pathExists(envPath)) continue;
|
|
3029
|
+
const content = await readFile13(envPath, "utf-8");
|
|
3030
|
+
const lines = content.split("\n");
|
|
3031
|
+
for (const line of lines) {
|
|
3032
|
+
const trimmed = line.trim();
|
|
3033
|
+
if (hasGlobalCreds && trimmed.startsWith("FLYDOCS_API_KEY=")) {
|
|
3034
|
+
actions.push({
|
|
3035
|
+
description: `Remove FLYDOCS_API_KEY from ${envFile} (migrated to ~/.flydocs/credentials)`,
|
|
3036
|
+
path: envPath,
|
|
3037
|
+
type: "line"
|
|
3038
|
+
});
|
|
3039
|
+
}
|
|
3040
|
+
if (trimmed.startsWith("FLYDOCS_RELAY_URL=")) {
|
|
3041
|
+
actions.push({
|
|
3042
|
+
description: `Remove FLYDOCS_RELAY_URL from ${envFile}`,
|
|
3043
|
+
path: envPath,
|
|
3044
|
+
type: "line"
|
|
3045
|
+
});
|
|
3046
|
+
}
|
|
3047
|
+
}
|
|
3048
|
+
}
|
|
3049
|
+
try {
|
|
3050
|
+
const config = await readAnyConfig(targetDir);
|
|
3051
|
+
const rawContent = await readFile13(
|
|
3052
|
+
join18(targetDir, ".flydocs", "config.json"),
|
|
3053
|
+
"utf-8"
|
|
3054
|
+
);
|
|
3055
|
+
const raw = JSON.parse(rawContent);
|
|
3056
|
+
const ghostFields = ["provider", "statusMapping"];
|
|
3057
|
+
for (const field of ghostFields) {
|
|
3058
|
+
if (field in raw) {
|
|
3059
|
+
actions.push({
|
|
3060
|
+
description: `Remove ghost field "${field}" from config.json`,
|
|
3061
|
+
path: join18(targetDir, ".flydocs", "config.json"),
|
|
3062
|
+
type: "field"
|
|
3063
|
+
});
|
|
3064
|
+
}
|
|
3065
|
+
}
|
|
3066
|
+
if (isConfigV2(config)) {
|
|
3067
|
+
const v1OnlyFields = [
|
|
3068
|
+
"workspaceId",
|
|
3069
|
+
"issueLabels",
|
|
3070
|
+
"workspace",
|
|
3071
|
+
"onboardComplete",
|
|
3072
|
+
"sourceRepo",
|
|
3073
|
+
"designSystem",
|
|
3074
|
+
"aiLabor"
|
|
3075
|
+
];
|
|
3076
|
+
for (const field of v1OnlyFields) {
|
|
3077
|
+
if (field in raw) {
|
|
3078
|
+
actions.push({
|
|
3079
|
+
description: `Remove v1 field "${field}" from config.json (server-owned in v2)`,
|
|
3080
|
+
path: join18(targetDir, ".flydocs", "config.json"),
|
|
3081
|
+
type: "field"
|
|
3082
|
+
});
|
|
3083
|
+
}
|
|
3084
|
+
}
|
|
3085
|
+
}
|
|
3086
|
+
} catch {
|
|
3087
|
+
}
|
|
3088
|
+
return actions;
|
|
3089
|
+
}
|
|
3090
|
+
async function executeCleanup(targetDir, actions) {
|
|
3091
|
+
const fileRemovals = actions.filter((a) => a.type === "file");
|
|
3092
|
+
const lineRemovals = actions.filter((a) => a.type === "line");
|
|
3093
|
+
const fieldRemovals = actions.filter((a) => a.type === "field");
|
|
3094
|
+
for (const action of fileRemovals) {
|
|
3095
|
+
await rm4(action.path, { force: true });
|
|
3096
|
+
}
|
|
3097
|
+
const envFiles = /* @__PURE__ */ new Map();
|
|
3098
|
+
for (const action of lineRemovals) {
|
|
3099
|
+
if (!envFiles.has(action.path)) {
|
|
3100
|
+
const content = await readFile13(action.path, "utf-8");
|
|
3101
|
+
envFiles.set(action.path, content.split("\n"));
|
|
3102
|
+
}
|
|
3103
|
+
}
|
|
3104
|
+
for (const [envPath, lines] of envFiles) {
|
|
3105
|
+
const filtered = lines.filter((line) => {
|
|
3106
|
+
const trimmed = line.trim();
|
|
3107
|
+
return !trimmed.startsWith("FLYDOCS_API_KEY=") && !trimmed.startsWith("FLYDOCS_RELAY_URL=");
|
|
3108
|
+
});
|
|
3109
|
+
const hasContent = filtered.some(
|
|
3110
|
+
(l) => l.trim().length > 0 && !l.trim().startsWith("#")
|
|
3111
|
+
);
|
|
3112
|
+
if (!hasContent) {
|
|
3113
|
+
await rm4(envPath, { force: true });
|
|
3114
|
+
} else {
|
|
3115
|
+
await writeFile11(envPath, filtered.join("\n"), "utf-8");
|
|
3116
|
+
}
|
|
3117
|
+
}
|
|
3118
|
+
if (fieldRemovals.length > 0) {
|
|
3119
|
+
const configPath = join18(targetDir, ".flydocs", "config.json");
|
|
3120
|
+
const content = await readFile13(configPath, "utf-8");
|
|
3121
|
+
const config = JSON.parse(content);
|
|
3122
|
+
for (const action of fieldRemovals) {
|
|
3123
|
+
const match = action.description.match(/"(\w+)"/);
|
|
3124
|
+
if (match) {
|
|
3125
|
+
delete config[match[1]];
|
|
3126
|
+
}
|
|
3127
|
+
}
|
|
3128
|
+
await writeFile11(
|
|
3129
|
+
configPath,
|
|
3130
|
+
JSON.stringify(config, null, 2) + "\n",
|
|
3131
|
+
"utf-8"
|
|
3132
|
+
);
|
|
3133
|
+
}
|
|
3134
|
+
}
|
|
3135
|
+
var cleanup_default;
|
|
3136
|
+
var init_cleanup = __esm({
|
|
3137
|
+
"src/commands/cleanup.ts"() {
|
|
3138
|
+
"use strict";
|
|
3139
|
+
init_ui();
|
|
3140
|
+
init_fs_ops();
|
|
3141
|
+
init_config();
|
|
3142
|
+
init_types();
|
|
3143
|
+
init_global_config();
|
|
3144
|
+
cleanup_default = defineCommand2({
|
|
3145
|
+
meta: {
|
|
3146
|
+
name: "cleanup",
|
|
3147
|
+
description: "Remove legacy v1 artifacts after migration (dry-run by default)"
|
|
3148
|
+
},
|
|
3149
|
+
args: {
|
|
3150
|
+
confirm: {
|
|
3151
|
+
type: "boolean",
|
|
3152
|
+
description: "Actually remove artifacts (default: dry-run only)",
|
|
3153
|
+
default: false
|
|
3154
|
+
},
|
|
3155
|
+
path: {
|
|
3156
|
+
type: "string",
|
|
3157
|
+
description: "Path to project directory"
|
|
3158
|
+
}
|
|
3159
|
+
},
|
|
3160
|
+
async run({ args }) {
|
|
3161
|
+
const targetDir = args.path ?? process.cwd();
|
|
3162
|
+
console.log();
|
|
3163
|
+
console.log(` ${pc7.bold("FlyDocs Cleanup")}`);
|
|
3164
|
+
console.log();
|
|
3165
|
+
const hasConfig = await pathExists(
|
|
3166
|
+
join18(targetDir, ".flydocs", "config.json")
|
|
3167
|
+
);
|
|
3168
|
+
if (!hasConfig) {
|
|
3169
|
+
printError("No .flydocs/config.json found. Run flydocs init first.");
|
|
3170
|
+
process.exit(1);
|
|
3171
|
+
}
|
|
3172
|
+
const hasGlobalCreds = await pathExists(credentialsPath());
|
|
3173
|
+
if (!hasGlobalCreds) {
|
|
3174
|
+
printWarning(
|
|
3175
|
+
"No global credentials found. Run flydocs init to set up credentials before cleanup."
|
|
3176
|
+
);
|
|
3177
|
+
}
|
|
3178
|
+
const actions = await scanArtifacts(targetDir);
|
|
3179
|
+
if (actions.length === 0) {
|
|
3180
|
+
printStatus("No legacy artifacts found. Already clean.");
|
|
3181
|
+
console.log();
|
|
3182
|
+
return;
|
|
3183
|
+
}
|
|
3184
|
+
const mode = args.confirm ? "Removing" : "Would remove";
|
|
3185
|
+
printInfo(`${mode} ${actions.length} legacy artifact(s):`);
|
|
3186
|
+
console.log();
|
|
3187
|
+
for (const action of actions) {
|
|
3188
|
+
const icon = args.confirm ? pc7.red("-") : pc7.yellow("?");
|
|
3189
|
+
console.log(` ${icon} ${action.description}`);
|
|
3190
|
+
}
|
|
3191
|
+
console.log();
|
|
3192
|
+
if (!args.confirm) {
|
|
3193
|
+
printInfo(
|
|
3194
|
+
`Dry-run complete. Run ${pc7.cyan("flydocs cleanup --confirm")} to remove.`
|
|
3195
|
+
);
|
|
3196
|
+
console.log();
|
|
3197
|
+
return;
|
|
3198
|
+
}
|
|
3199
|
+
await executeCleanup(targetDir, actions);
|
|
3200
|
+
printCompletionBox("Cleanup Complete", [
|
|
3201
|
+
`${pc7.green("+")} Removed ${actions.length} legacy artifact(s)`
|
|
3202
|
+
]);
|
|
3203
|
+
console.log();
|
|
3204
|
+
}
|
|
3205
|
+
});
|
|
3206
|
+
}
|
|
3207
|
+
});
|
|
3208
|
+
|
|
2992
3209
|
// src/lib/workspace.ts
|
|
2993
|
-
import { readFile as
|
|
2994
|
-
import { join as
|
|
3210
|
+
import { readFile as readFile14, writeFile as writeFile12, readdir as readdir4, stat as stat2 } from "fs/promises";
|
|
3211
|
+
import { join as join19, dirname as dirname3, relative, resolve as resolve3 } from "path";
|
|
2995
3212
|
async function readWorkspaceFile(dir) {
|
|
2996
|
-
const filePath =
|
|
3213
|
+
const filePath = join19(dir, WORKSPACE_FILENAME);
|
|
2997
3214
|
if (!await pathExists(filePath)) return null;
|
|
2998
|
-
const content = await
|
|
3215
|
+
const content = await readFile14(filePath, "utf-8");
|
|
2999
3216
|
const parsed = JSON.parse(content);
|
|
3000
3217
|
validateWorkspaceFile(parsed);
|
|
3001
3218
|
return parsed;
|
|
3002
3219
|
}
|
|
3003
3220
|
async function writeWorkspaceFile(dir, workspace) {
|
|
3004
|
-
const filePath =
|
|
3221
|
+
const filePath = join19(dir, WORKSPACE_FILENAME);
|
|
3005
3222
|
const content = JSON.stringify(workspace, null, 2) + "\n";
|
|
3006
|
-
await
|
|
3223
|
+
await writeFile12(filePath, content, "utf-8");
|
|
3007
3224
|
}
|
|
3008
3225
|
async function detectSiblingRepos(parentDir) {
|
|
3009
3226
|
const repos = {};
|
|
3010
3227
|
const entries = await readdir4(parentDir);
|
|
3011
3228
|
for (const entry of entries) {
|
|
3012
3229
|
if (entry.startsWith(".")) continue;
|
|
3013
|
-
const entryPath =
|
|
3230
|
+
const entryPath = join19(parentDir, entry);
|
|
3014
3231
|
const entryStat = await stat2(entryPath).catch(() => null);
|
|
3015
3232
|
if (!entryStat?.isDirectory()) continue;
|
|
3016
|
-
const hasGit = await pathExists(
|
|
3233
|
+
const hasGit = await pathExists(join19(entryPath, ".git"));
|
|
3017
3234
|
const hasFlydocs = await pathExists(
|
|
3018
|
-
|
|
3235
|
+
join19(entryPath, ".flydocs", "config.json")
|
|
3019
3236
|
);
|
|
3020
3237
|
if (hasGit || hasFlydocs) {
|
|
3021
3238
|
repos[entry] = { path: `./${entry}` };
|
|
@@ -3030,10 +3247,10 @@ async function readSiblingDescriptors(workspaceDir, repos) {
|
|
|
3030
3247
|
const descriptors = [];
|
|
3031
3248
|
for (const [name, entry] of Object.entries(repos)) {
|
|
3032
3249
|
const repoDir = resolve3(workspaceDir, entry.path);
|
|
3033
|
-
const serviceJsonPath =
|
|
3250
|
+
const serviceJsonPath = join19(repoDir, "flydocs", "context", "service.json");
|
|
3034
3251
|
if (!await pathExists(serviceJsonPath)) continue;
|
|
3035
3252
|
try {
|
|
3036
|
-
const content = await
|
|
3253
|
+
const content = await readFile14(serviceJsonPath, "utf-8");
|
|
3037
3254
|
const descriptor = JSON.parse(content);
|
|
3038
3255
|
descriptors.push({ name, path: entry.path, descriptor });
|
|
3039
3256
|
} catch {
|
|
@@ -3141,16 +3358,18 @@ var init_exports = {};
|
|
|
3141
3358
|
__export(init_exports, {
|
|
3142
3359
|
default: () => init_default
|
|
3143
3360
|
});
|
|
3144
|
-
import { defineCommand as
|
|
3361
|
+
import { defineCommand as defineCommand3 } from "citty";
|
|
3145
3362
|
import { text as text2, confirm as confirm3, select as select2, isCancel as isCancel4, cancel as cancel3 } from "@clack/prompts";
|
|
3146
|
-
import
|
|
3147
|
-
import { join as
|
|
3148
|
-
import { mkdir as mkdir9, writeFile as
|
|
3363
|
+
import pc8 from "picocolors";
|
|
3364
|
+
import { join as join20 } from "path";
|
|
3365
|
+
import { mkdir as mkdir9, writeFile as writeFile13 } from "fs/promises";
|
|
3366
|
+
import { execFile } from "child_process";
|
|
3367
|
+
import { promisify } from "util";
|
|
3149
3368
|
async function resolveAndValidateKey(keyArg, targetDir) {
|
|
3150
3369
|
let resolved = await resolveApiKey(keyArg, targetDir);
|
|
3151
3370
|
if (!resolved) {
|
|
3152
3371
|
console.log(
|
|
3153
|
-
` ${
|
|
3372
|
+
` ${pc8.dim("Get your API key (fdk_...) from your FlyDocs dashboard")}`
|
|
3154
3373
|
);
|
|
3155
3374
|
console.log();
|
|
3156
3375
|
const keyInput = await text2({
|
|
@@ -3180,13 +3399,13 @@ async function resolveAndValidateKey(keyArg, targetDir) {
|
|
|
3180
3399
|
printError("Invalid API key. Check your key and try again.");
|
|
3181
3400
|
process.exit(1);
|
|
3182
3401
|
}
|
|
3183
|
-
printStatus(`Authenticated with ${
|
|
3402
|
+
printStatus(`Authenticated with ${pc8.bold(result.org)}`);
|
|
3184
3403
|
} catch {
|
|
3185
3404
|
printError(
|
|
3186
3405
|
"Could not reach FlyDocs API. Check your network and try again."
|
|
3187
3406
|
);
|
|
3188
3407
|
console.log(
|
|
3189
|
-
` ${
|
|
3408
|
+
` ${pc8.dim("flydocs init requires server access. For offline use, run flydocs install instead.")}`
|
|
3190
3409
|
);
|
|
3191
3410
|
process.exit(1);
|
|
3192
3411
|
}
|
|
@@ -3197,7 +3416,7 @@ async function resolveAndValidateKey(keyArg, targetDir) {
|
|
|
3197
3416
|
process.exit(1);
|
|
3198
3417
|
} else if (workspaces.length === 1) {
|
|
3199
3418
|
workspaceId = workspaces[0].id;
|
|
3200
|
-
printStatus(`Workspace: ${
|
|
3419
|
+
printStatus(`Workspace: ${pc8.bold(workspaces[0].name)}`);
|
|
3201
3420
|
} else {
|
|
3202
3421
|
const choice = await select2({
|
|
3203
3422
|
message: "Select workspace",
|
|
@@ -3224,7 +3443,7 @@ async function resolveAndValidateKey(keyArg, targetDir) {
|
|
|
3224
3443
|
async function pullServerConfig(apiKey, targetDir, workspaceId) {
|
|
3225
3444
|
printInfo("Pulling config from server...");
|
|
3226
3445
|
const isFirstInit = !await pathExists(
|
|
3227
|
-
|
|
3446
|
+
join20(targetDir, ".flydocs", "config.json")
|
|
3228
3447
|
);
|
|
3229
3448
|
try {
|
|
3230
3449
|
const response = await fetchConfigV2(apiKey, {
|
|
@@ -3241,7 +3460,7 @@ async function pullServerConfig(apiKey, targetDir, workspaceId) {
|
|
|
3241
3460
|
printError(`Server error: ${err.message}`);
|
|
3242
3461
|
if (err.status === 401) {
|
|
3243
3462
|
console.log(
|
|
3244
|
-
` ${
|
|
3463
|
+
` ${pc8.dim("Your API key may be revoked. Run flydocs auth with a new key.")}`
|
|
3245
3464
|
);
|
|
3246
3465
|
}
|
|
3247
3466
|
} else {
|
|
@@ -3253,7 +3472,7 @@ async function pullServerConfig(apiKey, targetDir, workspaceId) {
|
|
|
3253
3472
|
async function initSingleRepo(targetDir, apiKey, serverResponse) {
|
|
3254
3473
|
const actions = [];
|
|
3255
3474
|
const skipped = [];
|
|
3256
|
-
await mkdir9(
|
|
3475
|
+
await mkdir9(join20(targetDir, ".flydocs"), { recursive: true });
|
|
3257
3476
|
const configWithHash = applyConfigHash(serverResponse.config);
|
|
3258
3477
|
await writeConfig(targetDir, configWithHash);
|
|
3259
3478
|
actions.push("Wrote .flydocs/config.json (from server)");
|
|
@@ -3266,18 +3485,18 @@ async function initSingleRepo(targetDir, apiKey, serverResponse) {
|
|
|
3266
3485
|
actions.push("Wrote ~/.flydocs/me.json");
|
|
3267
3486
|
}
|
|
3268
3487
|
if (serverResponse.context) {
|
|
3269
|
-
const contextDir =
|
|
3488
|
+
const contextDir = join20(targetDir, "flydocs", "context");
|
|
3270
3489
|
await mkdir9(contextDir, { recursive: true });
|
|
3271
|
-
const projectMdPath =
|
|
3490
|
+
const projectMdPath = join20(contextDir, "project.md");
|
|
3272
3491
|
if (!await pathExists(projectMdPath)) {
|
|
3273
|
-
await
|
|
3492
|
+
await writeFile13(projectMdPath, serverResponse.context.projectMd, "utf-8");
|
|
3274
3493
|
actions.push("Wrote flydocs/context/project.md");
|
|
3275
3494
|
} else {
|
|
3276
3495
|
skipped.push("flydocs/context/project.md (already exists)");
|
|
3277
3496
|
}
|
|
3278
|
-
const serviceJsonPath =
|
|
3497
|
+
const serviceJsonPath = join20(contextDir, "service.json");
|
|
3279
3498
|
if (serverResponse.context.serviceJson && !await pathExists(serviceJsonPath)) {
|
|
3280
|
-
await
|
|
3499
|
+
await writeFile13(
|
|
3281
3500
|
serviceJsonPath,
|
|
3282
3501
|
JSON.stringify(serverResponse.context.serviceJson, null, 2) + "\n",
|
|
3283
3502
|
"utf-8"
|
|
@@ -3290,10 +3509,175 @@ async function initSingleRepo(targetDir, apiKey, serverResponse) {
|
|
|
3290
3509
|
await ensureGitignore(targetDir);
|
|
3291
3510
|
await ensurePlatformIgnores(targetDir);
|
|
3292
3511
|
actions.push("Updated ignore files");
|
|
3512
|
+
const artifacts = await scanArtifacts(targetDir);
|
|
3513
|
+
if (artifacts.length > 0) {
|
|
3514
|
+
await executeCleanup(targetDir, artifacts);
|
|
3515
|
+
actions.push(`Cleaned ${artifacts.length} legacy artifact(s)`);
|
|
3516
|
+
}
|
|
3293
3517
|
return { actions, skipped };
|
|
3294
3518
|
}
|
|
3519
|
+
async function checkGitFreshness(repoDir) {
|
|
3520
|
+
const hasGit = await pathExists(join20(repoDir, ".git"));
|
|
3521
|
+
if (!hasGit) return;
|
|
3522
|
+
try {
|
|
3523
|
+
await execFileAsync("git", ["-C", repoDir, "fetch", "--quiet"], {
|
|
3524
|
+
timeout: 15e3
|
|
3525
|
+
});
|
|
3526
|
+
const { stdout } = await execFileAsync(
|
|
3527
|
+
"git",
|
|
3528
|
+
["-C", repoDir, "rev-list", "--count", "HEAD..@{upstream}"],
|
|
3529
|
+
{ timeout: 5e3 }
|
|
3530
|
+
);
|
|
3531
|
+
const behind = parseInt(stdout.trim(), 10);
|
|
3532
|
+
if (behind <= 0) return;
|
|
3533
|
+
printWarning(`Repo is ${behind} commit(s) behind remote.`);
|
|
3534
|
+
const shouldPull = await confirm3({
|
|
3535
|
+
message: "Pull latest before init?"
|
|
3536
|
+
});
|
|
3537
|
+
if (isCancel4(shouldPull) || !shouldPull) {
|
|
3538
|
+
printInfo("Continuing without pulling.");
|
|
3539
|
+
return;
|
|
3540
|
+
}
|
|
3541
|
+
await execFileAsync("git", ["-C", repoDir, "pull", "--ff-only"], {
|
|
3542
|
+
timeout: 3e4
|
|
3543
|
+
});
|
|
3544
|
+
printStatus("Pulled latest from remote.");
|
|
3545
|
+
} catch {
|
|
3546
|
+
}
|
|
3547
|
+
}
|
|
3548
|
+
async function isEmptyOrNonRepo(dir) {
|
|
3549
|
+
const hasGit = await pathExists(join20(dir, ".git"));
|
|
3550
|
+
if (hasGit) return false;
|
|
3551
|
+
const siblings = await detectSiblingRepos(dir);
|
|
3552
|
+
if (Object.keys(siblings).length >= 2) return false;
|
|
3553
|
+
return true;
|
|
3554
|
+
}
|
|
3555
|
+
function repoShortName(fullName) {
|
|
3556
|
+
return fullName.includes("/") ? fullName.split("/").pop() : fullName;
|
|
3557
|
+
}
|
|
3558
|
+
async function runCloneAndInit(targetDir, keyArg, repos, apiKey, workspaceId) {
|
|
3559
|
+
if (repos.length === 1) {
|
|
3560
|
+
const repo = repos[0];
|
|
3561
|
+
const shortName = repoShortName(repo.name);
|
|
3562
|
+
printInfo(`Workspace has 1 repo: ${pc8.bold(shortName)}`);
|
|
3563
|
+
const shouldClone = await confirm3({
|
|
3564
|
+
message: `Clone ${shortName} and initialize?`
|
|
3565
|
+
});
|
|
3566
|
+
if (isCancel4(shouldClone) || !shouldClone) {
|
|
3567
|
+
cancel3("Init cancelled.");
|
|
3568
|
+
process.exit(0);
|
|
3569
|
+
}
|
|
3570
|
+
const cloneDir = join20(targetDir, shortName);
|
|
3571
|
+
printInfo(`Cloning ${shortName}...`);
|
|
3572
|
+
await execFileAsync("git", ["clone", repo.cloneUrl, cloneDir], {
|
|
3573
|
+
timeout: 6e4
|
|
3574
|
+
});
|
|
3575
|
+
printStatus(`Cloned ${shortName}`);
|
|
3576
|
+
const serverResponse = await pullServerConfig(
|
|
3577
|
+
apiKey,
|
|
3578
|
+
cloneDir,
|
|
3579
|
+
workspaceId
|
|
3580
|
+
);
|
|
3581
|
+
const { actions, skipped } = await initSingleRepo(
|
|
3582
|
+
cloneDir,
|
|
3583
|
+
apiKey,
|
|
3584
|
+
serverResponse
|
|
3585
|
+
);
|
|
3586
|
+
actions.unshift("Stored credential globally (~/.flydocs/credentials)");
|
|
3587
|
+
actions.unshift(`Cloned ${shortName}`);
|
|
3588
|
+
printInitReport(
|
|
3589
|
+
actions,
|
|
3590
|
+
skipped,
|
|
3591
|
+
serverResponse.warnings,
|
|
3592
|
+
!!serverResponse.context
|
|
3593
|
+
);
|
|
3594
|
+
} else {
|
|
3595
|
+
const repoNames = repos.map((r) => repoShortName(r.name));
|
|
3596
|
+
printInfo(`Workspace has ${repos.length} repos:`);
|
|
3597
|
+
for (const name of repoNames) {
|
|
3598
|
+
console.log(` ${pc8.cyan(name)}`);
|
|
3599
|
+
}
|
|
3600
|
+
console.log();
|
|
3601
|
+
const shouldClone = await confirm3({
|
|
3602
|
+
message: `Clone and initialize all ${repos.length} repos?`
|
|
3603
|
+
});
|
|
3604
|
+
if (isCancel4(shouldClone) || !shouldClone) {
|
|
3605
|
+
cancel3("Init cancelled.");
|
|
3606
|
+
process.exit(0);
|
|
3607
|
+
}
|
|
3608
|
+
const allActions = [
|
|
3609
|
+
"Stored credential globally (~/.flydocs/credentials)"
|
|
3610
|
+
];
|
|
3611
|
+
const allSkipped = [];
|
|
3612
|
+
let allWarnings = [];
|
|
3613
|
+
let firstResponse;
|
|
3614
|
+
for (let i = 0; i < repos.length; i++) {
|
|
3615
|
+
const repo = repos[i];
|
|
3616
|
+
const shortName = repoNames[i];
|
|
3617
|
+
const cloneDir = join20(targetDir, shortName);
|
|
3618
|
+
console.log();
|
|
3619
|
+
if (await pathExists(join20(cloneDir, ".git"))) {
|
|
3620
|
+
printInfo(`${pc8.bold(shortName)} already cloned, initializing...`);
|
|
3621
|
+
await checkGitFreshness(cloneDir);
|
|
3622
|
+
} else {
|
|
3623
|
+
printInfo(`Cloning ${pc8.bold(shortName)}...`);
|
|
3624
|
+
await execFileAsync("git", ["clone", repo.cloneUrl, cloneDir], {
|
|
3625
|
+
timeout: 6e4
|
|
3626
|
+
});
|
|
3627
|
+
allActions.push(`Cloned ${shortName}`);
|
|
3628
|
+
}
|
|
3629
|
+
const serverResponse = await pullServerConfig(
|
|
3630
|
+
apiKey,
|
|
3631
|
+
cloneDir,
|
|
3632
|
+
workspaceId
|
|
3633
|
+
);
|
|
3634
|
+
if (!firstResponse) firstResponse = serverResponse;
|
|
3635
|
+
const { actions, skipped } = await initSingleRepo(
|
|
3636
|
+
cloneDir,
|
|
3637
|
+
apiKey,
|
|
3638
|
+
serverResponse
|
|
3639
|
+
);
|
|
3640
|
+
for (const action of actions) {
|
|
3641
|
+
allActions.push(`[${shortName}] ${action}`);
|
|
3642
|
+
}
|
|
3643
|
+
for (const skip of skipped) {
|
|
3644
|
+
allSkipped.push(`[${shortName}] ${skip}`);
|
|
3645
|
+
}
|
|
3646
|
+
allWarnings = [...allWarnings, ...serverResponse.warnings];
|
|
3647
|
+
printStatus(`${shortName} initialized`);
|
|
3648
|
+
}
|
|
3649
|
+
if (firstResponse) {
|
|
3650
|
+
const repoEntries = {};
|
|
3651
|
+
for (const name of repoNames) {
|
|
3652
|
+
repoEntries[name] = { path: `./${name}` };
|
|
3653
|
+
}
|
|
3654
|
+
const workspaceFile = buildWorkspaceFile(
|
|
3655
|
+
firstResponse.workspaceId,
|
|
3656
|
+
repoEntries
|
|
3657
|
+
);
|
|
3658
|
+
await writeWorkspaceFile(targetDir, workspaceFile);
|
|
3659
|
+
allActions.push(`.flydocs-workspace.json (${repos.length} repos)`);
|
|
3660
|
+
const contextDir = join20(targetDir, "flydocs", "context");
|
|
3661
|
+
const workspaceMdPath = join20(contextDir, "workspace.md");
|
|
3662
|
+
if (!await pathExists(workspaceMdPath)) {
|
|
3663
|
+
await mkdir9(contextDir, { recursive: true });
|
|
3664
|
+
const content = firstResponse.context?.workspaceMd ?? await generateWorkspaceMd(targetDir, workspaceFile);
|
|
3665
|
+
await writeFile13(workspaceMdPath, content, "utf-8");
|
|
3666
|
+
const source = firstResponse.context?.workspaceMd ? "from server" : "generated locally";
|
|
3667
|
+
allActions.push(`Wrote flydocs/context/workspace.md (${source})`);
|
|
3668
|
+
}
|
|
3669
|
+
}
|
|
3670
|
+
console.log();
|
|
3671
|
+
printInitReport(
|
|
3672
|
+
allActions,
|
|
3673
|
+
allSkipped,
|
|
3674
|
+
allWarnings,
|
|
3675
|
+
!!firstResponse?.context
|
|
3676
|
+
);
|
|
3677
|
+
}
|
|
3678
|
+
}
|
|
3295
3679
|
async function isParentDirectory(dir) {
|
|
3296
|
-
const hasGit = await pathExists(
|
|
3680
|
+
const hasGit = await pathExists(join20(dir, ".git"));
|
|
3297
3681
|
if (hasGit) return false;
|
|
3298
3682
|
const repos = await detectSiblingRepos(dir);
|
|
3299
3683
|
return Object.keys(repos).length >= 2;
|
|
@@ -3303,7 +3687,7 @@ async function runMultiRepoInit(parentDir, keyArg) {
|
|
|
3303
3687
|
const repoNames = Object.keys(repos).sort();
|
|
3304
3688
|
printInfo(`Detected ${repoNames.length} repos:`);
|
|
3305
3689
|
for (const name of repoNames) {
|
|
3306
|
-
console.log(` ${
|
|
3690
|
+
console.log(` ${pc8.cyan(name)}`);
|
|
3307
3691
|
}
|
|
3308
3692
|
console.log();
|
|
3309
3693
|
const shouldContinue = await confirm3({
|
|
@@ -3313,7 +3697,7 @@ async function runMultiRepoInit(parentDir, keyArg) {
|
|
|
3313
3697
|
cancel3("Init cancelled.");
|
|
3314
3698
|
process.exit(0);
|
|
3315
3699
|
}
|
|
3316
|
-
const firstRepoDir =
|
|
3700
|
+
const firstRepoDir = join20(parentDir, repoNames[0]);
|
|
3317
3701
|
const { apiKey, workspaceId } = await resolveAndValidateKey(
|
|
3318
3702
|
keyArg,
|
|
3319
3703
|
firstRepoDir
|
|
@@ -3325,9 +3709,10 @@ async function runMultiRepoInit(parentDir, keyArg) {
|
|
|
3325
3709
|
let allWarnings = [];
|
|
3326
3710
|
let firstResponse;
|
|
3327
3711
|
for (const repoName of repoNames) {
|
|
3328
|
-
const repoDir =
|
|
3712
|
+
const repoDir = join20(parentDir, repoName);
|
|
3329
3713
|
console.log();
|
|
3330
|
-
printInfo(`Initializing ${
|
|
3714
|
+
printInfo(`Initializing ${pc8.bold(repoName)}...`);
|
|
3715
|
+
await checkGitFreshness(repoDir);
|
|
3331
3716
|
const serverResponse = await pullServerConfig(apiKey, repoDir, workspaceId);
|
|
3332
3717
|
if (!firstResponse) firstResponse = serverResponse;
|
|
3333
3718
|
const { actions, skipped } = await initSingleRepo(
|
|
@@ -3356,47 +3741,60 @@ async function runMultiRepoInit(parentDir, keyArg) {
|
|
|
3356
3741
|
await writeWorkspaceFile(parentDir, workspaceFile);
|
|
3357
3742
|
allActions.push(`.flydocs-workspace.json (${repoNames.length} repos)`);
|
|
3358
3743
|
}
|
|
3359
|
-
const contextDir =
|
|
3360
|
-
const workspaceMdPath =
|
|
3744
|
+
const contextDir = join20(parentDir, "flydocs", "context");
|
|
3745
|
+
const workspaceMdPath = join20(contextDir, "workspace.md");
|
|
3361
3746
|
if (await pathExists(workspaceMdPath)) {
|
|
3362
3747
|
allSkipped.push("flydocs/context/workspace.md (already exists)");
|
|
3363
3748
|
} else {
|
|
3364
3749
|
await mkdir9(contextDir, { recursive: true });
|
|
3365
3750
|
const workspaceJson = await readWorkspaceFile(parentDir) ?? buildWorkspaceFile(firstResponse.workspaceId, repos);
|
|
3366
3751
|
const content = firstResponse.context?.workspaceMd ?? await generateWorkspaceMd(parentDir, workspaceJson);
|
|
3367
|
-
await
|
|
3752
|
+
await writeFile13(workspaceMdPath, content, "utf-8");
|
|
3368
3753
|
const source = firstResponse.context?.workspaceMd ? "from server" : "generated locally";
|
|
3369
3754
|
allActions.push(`Wrote flydocs/context/workspace.md (${source})`);
|
|
3370
3755
|
}
|
|
3371
3756
|
}
|
|
3372
3757
|
console.log();
|
|
3373
|
-
printInitReport(
|
|
3758
|
+
printInitReport(
|
|
3759
|
+
allActions,
|
|
3760
|
+
allSkipped,
|
|
3761
|
+
allWarnings,
|
|
3762
|
+
!!firstResponse?.context
|
|
3763
|
+
);
|
|
3374
3764
|
}
|
|
3375
|
-
function printInitReport(actions, skipped, warnings) {
|
|
3765
|
+
function printInitReport(actions, skipped, warnings, hasContext) {
|
|
3376
3766
|
console.log();
|
|
3377
3767
|
const lines = [];
|
|
3378
3768
|
for (const action of actions) {
|
|
3379
|
-
lines.push(`${
|
|
3769
|
+
lines.push(`${pc8.green("+")} ${action}`);
|
|
3380
3770
|
}
|
|
3381
3771
|
for (const skip of skipped) {
|
|
3382
|
-
lines.push(`${
|
|
3772
|
+
lines.push(`${pc8.dim("-")} ${skip}`);
|
|
3773
|
+
}
|
|
3774
|
+
if (!hasContext) {
|
|
3775
|
+
lines.push("");
|
|
3776
|
+
lines.push(
|
|
3777
|
+
`${pc8.yellow("!")} No generated context yet. An admin can generate it from the portal.`
|
|
3778
|
+
);
|
|
3383
3779
|
}
|
|
3384
3780
|
if (warnings.length > 0) {
|
|
3385
3781
|
lines.push("");
|
|
3386
3782
|
for (const warning of warnings) {
|
|
3387
|
-
lines.push(`${
|
|
3783
|
+
lines.push(`${pc8.yellow("!")} ${warning}`);
|
|
3388
3784
|
}
|
|
3389
3785
|
}
|
|
3390
3786
|
printCompletionBox("FlyDocs Initialized", lines);
|
|
3391
3787
|
console.log();
|
|
3392
3788
|
console.log(` Next steps:`);
|
|
3393
3789
|
console.log(
|
|
3394
|
-
` ${
|
|
3790
|
+
` ${pc8.cyan("flydocs sync")} Pull latest config and templates`
|
|
3791
|
+
);
|
|
3792
|
+
console.log(
|
|
3793
|
+
` ${pc8.cyan("cursor .")} ${pc8.dim("or")} ${pc8.cyan("code .")} Open your IDE, then use ${pc8.bold("/start-session")}`
|
|
3395
3794
|
);
|
|
3396
|
-
console.log(` ${pc7.cyan("/start-session")} \u2014 begin working`);
|
|
3397
3795
|
console.log();
|
|
3398
3796
|
}
|
|
3399
|
-
var init_default;
|
|
3797
|
+
var execFileAsync, init_default;
|
|
3400
3798
|
var init_init = __esm({
|
|
3401
3799
|
"src/commands/init.ts"() {
|
|
3402
3800
|
"use strict";
|
|
@@ -3408,8 +3806,10 @@ var init_init = __esm({
|
|
|
3408
3806
|
init_gitignore();
|
|
3409
3807
|
init_fs_ops();
|
|
3410
3808
|
init_relay_client();
|
|
3809
|
+
init_cleanup();
|
|
3411
3810
|
init_workspace();
|
|
3412
|
-
|
|
3811
|
+
execFileAsync = promisify(execFile);
|
|
3812
|
+
init_default = defineCommand3({
|
|
3413
3813
|
meta: {
|
|
3414
3814
|
name: "init",
|
|
3415
3815
|
description: "Initialize FlyDocs in this project (unified setup)"
|
|
@@ -3427,12 +3827,34 @@ var init_init = __esm({
|
|
|
3427
3827
|
async run({ args }) {
|
|
3428
3828
|
const targetDir = args.path ?? process.cwd();
|
|
3429
3829
|
console.log();
|
|
3430
|
-
console.log(` ${
|
|
3830
|
+
console.log(` ${pc8.bold("FlyDocs Init")}`);
|
|
3431
3831
|
console.log();
|
|
3432
3832
|
if (await isParentDirectory(targetDir)) {
|
|
3433
3833
|
await runMultiRepoInit(targetDir, args.key);
|
|
3434
3834
|
return;
|
|
3435
3835
|
}
|
|
3836
|
+
if (await isEmptyOrNonRepo(targetDir)) {
|
|
3837
|
+
const { apiKey: apiKey2, workspaceId: workspaceId2 } = await resolveAndValidateKey(
|
|
3838
|
+
args.key,
|
|
3839
|
+
targetDir
|
|
3840
|
+
);
|
|
3841
|
+
const preflightResponse = await pullServerConfig(
|
|
3842
|
+
apiKey2,
|
|
3843
|
+
targetDir,
|
|
3844
|
+
workspaceId2
|
|
3845
|
+
);
|
|
3846
|
+
if (preflightResponse.repos && preflightResponse.repos.length > 0) {
|
|
3847
|
+
await runCloneAndInit(
|
|
3848
|
+
targetDir,
|
|
3849
|
+
args.key,
|
|
3850
|
+
preflightResponse.repos,
|
|
3851
|
+
apiKey2,
|
|
3852
|
+
workspaceId2
|
|
3853
|
+
);
|
|
3854
|
+
return;
|
|
3855
|
+
}
|
|
3856
|
+
}
|
|
3857
|
+
await checkGitFreshness(targetDir);
|
|
3436
3858
|
const { apiKey, workspaceId } = await resolveAndValidateKey(
|
|
3437
3859
|
args.key,
|
|
3438
3860
|
targetDir
|
|
@@ -3450,7 +3872,7 @@ var init_init = __esm({
|
|
|
3450
3872
|
actions.unshift("Stored credential globally (~/.flydocs/credentials)");
|
|
3451
3873
|
const topology = serverResponse.config.topology;
|
|
3452
3874
|
if (topology?.type === 4 && topology.label === "sibling-repos") {
|
|
3453
|
-
const parentDir =
|
|
3875
|
+
const parentDir = join20(targetDir, "..");
|
|
3454
3876
|
const existing = await readWorkspaceFile(parentDir);
|
|
3455
3877
|
if (existing) {
|
|
3456
3878
|
skipped.push(".flydocs-workspace.json (already exists)");
|
|
@@ -3468,7 +3890,12 @@ var init_init = __esm({
|
|
|
3468
3890
|
}
|
|
3469
3891
|
}
|
|
3470
3892
|
}
|
|
3471
|
-
printInitReport(
|
|
3893
|
+
printInitReport(
|
|
3894
|
+
actions,
|
|
3895
|
+
skipped,
|
|
3896
|
+
serverResponse.warnings,
|
|
3897
|
+
!!serverResponse.context
|
|
3898
|
+
);
|
|
3472
3899
|
}
|
|
3473
3900
|
});
|
|
3474
3901
|
}
|
|
@@ -3479,11 +3906,11 @@ var update_exports = {};
|
|
|
3479
3906
|
__export(update_exports, {
|
|
3480
3907
|
default: () => update_default
|
|
3481
3908
|
});
|
|
3482
|
-
import { defineCommand as
|
|
3483
|
-
import { resolve as resolve4, join as
|
|
3484
|
-
import { mkdir as mkdir10, cp as cp2, readFile as
|
|
3909
|
+
import { defineCommand as defineCommand4 } from "citty";
|
|
3910
|
+
import { resolve as resolve4, join as join21 } from "path";
|
|
3911
|
+
import { mkdir as mkdir10, cp as cp2, readFile as readFile15, readdir as readdir5, rm as rm5 } from "fs/promises";
|
|
3485
3912
|
import { select as select3, text as text3, confirm as confirm4, isCancel as isCancel5, cancel as cancel4 } from "@clack/prompts";
|
|
3486
|
-
import
|
|
3913
|
+
import pc9 from "picocolors";
|
|
3487
3914
|
var update_default;
|
|
3488
3915
|
var init_update = __esm({
|
|
3489
3916
|
"src/commands/update.ts"() {
|
|
@@ -3502,7 +3929,7 @@ var init_update = __esm({
|
|
|
3502
3929
|
init_update_check();
|
|
3503
3930
|
init_telemetry();
|
|
3504
3931
|
init_integrity();
|
|
3505
|
-
update_default =
|
|
3932
|
+
update_default = defineCommand4({
|
|
3506
3933
|
meta: {
|
|
3507
3934
|
name: "update",
|
|
3508
3935
|
description: "Update an existing FlyDocs installation"
|
|
@@ -3589,9 +4016,9 @@ var init_update = __esm({
|
|
|
3589
4016
|
}
|
|
3590
4017
|
targetDir = resolve4(targetDir);
|
|
3591
4018
|
process.chdir(targetDir);
|
|
3592
|
-
const hasVersion = await pathExists(
|
|
4019
|
+
const hasVersion = await pathExists(join21(targetDir, ".flydocs", "version"));
|
|
3593
4020
|
const hasConfig = await pathExists(
|
|
3594
|
-
|
|
4021
|
+
join21(targetDir, ".flydocs", "config.json")
|
|
3595
4022
|
);
|
|
3596
4023
|
if (!hasVersion && !hasConfig) {
|
|
3597
4024
|
printError(`Not a FlyDocs project: ${targetDir}`);
|
|
@@ -3602,8 +4029,8 @@ var init_update = __esm({
|
|
|
3602
4029
|
console.log();
|
|
3603
4030
|
let currentVersion = "0.1.0";
|
|
3604
4031
|
if (hasVersion) {
|
|
3605
|
-
const vContent = await
|
|
3606
|
-
|
|
4032
|
+
const vContent = await readFile15(
|
|
4033
|
+
join21(targetDir, ".flydocs", "version"),
|
|
3607
4034
|
"utf-8"
|
|
3608
4035
|
);
|
|
3609
4036
|
currentVersion = vContent.trim();
|
|
@@ -3637,10 +4064,10 @@ var init_update = __esm({
|
|
|
3637
4064
|
});
|
|
3638
4065
|
console.log(`Updating: v${currentVersion} \u2192 v${version}`);
|
|
3639
4066
|
console.log();
|
|
3640
|
-
const changelogPath =
|
|
4067
|
+
const changelogPath = join21(templateDir, "CHANGELOG.md");
|
|
3641
4068
|
const whatsNew = await getWhatsNew(changelogPath, currentVersion, version);
|
|
3642
4069
|
if (whatsNew.length > 0) {
|
|
3643
|
-
console.log(
|
|
4070
|
+
console.log(pc9.cyan("What's new:"));
|
|
3644
4071
|
console.log();
|
|
3645
4072
|
for (const entry of whatsNew) {
|
|
3646
4073
|
console.log(` ${entry}`);
|
|
@@ -3649,23 +4076,23 @@ var init_update = __esm({
|
|
|
3649
4076
|
}
|
|
3650
4077
|
const now = /* @__PURE__ */ new Date();
|
|
3651
4078
|
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")}`;
|
|
3652
|
-
const backupDir =
|
|
4079
|
+
const backupDir = join21(targetDir, ".flydocs", `backup-${ts}`);
|
|
3653
4080
|
await mkdir10(backupDir, { recursive: true });
|
|
3654
4081
|
if (hasConfig) {
|
|
3655
4082
|
await cp2(
|
|
3656
|
-
|
|
3657
|
-
|
|
4083
|
+
join21(targetDir, ".flydocs", "config.json"),
|
|
4084
|
+
join21(backupDir, "config.json")
|
|
3658
4085
|
);
|
|
3659
4086
|
printStatus(`Config backed up to .flydocs/backup-${ts}/`);
|
|
3660
4087
|
}
|
|
3661
4088
|
try {
|
|
3662
|
-
const flydocsDir =
|
|
4089
|
+
const flydocsDir = join21(targetDir, ".flydocs");
|
|
3663
4090
|
const entries = await readdir5(flydocsDir);
|
|
3664
4091
|
const backups = entries.filter((e) => e.startsWith("backup-")).sort();
|
|
3665
4092
|
if (backups.length > 3) {
|
|
3666
4093
|
const toRemove = backups.slice(0, backups.length - 3);
|
|
3667
4094
|
for (const old of toRemove) {
|
|
3668
|
-
await
|
|
4095
|
+
await rm5(join21(flydocsDir, old), { recursive: true, force: true });
|
|
3669
4096
|
}
|
|
3670
4097
|
}
|
|
3671
4098
|
} catch {
|
|
@@ -3704,17 +4131,17 @@ var init_update = __esm({
|
|
|
3704
4131
|
await ensureDirectories(targetDir, effectiveTier);
|
|
3705
4132
|
console.log("Replacing framework directories...");
|
|
3706
4133
|
await replaceDirectory(
|
|
3707
|
-
|
|
3708
|
-
|
|
4134
|
+
join21(templateDir, ".flydocs", "templates"),
|
|
4135
|
+
join21(targetDir, ".flydocs", "templates")
|
|
3709
4136
|
);
|
|
3710
4137
|
printStatus(".flydocs/templates");
|
|
3711
4138
|
await replaceDirectory(
|
|
3712
|
-
|
|
3713
|
-
|
|
4139
|
+
join21(templateDir, ".claude", "hooks"),
|
|
4140
|
+
join21(targetDir, ".claude", "hooks")
|
|
3714
4141
|
);
|
|
3715
4142
|
printStatus(".claude/hooks");
|
|
3716
4143
|
const hasExistingAgents = await pathExists(
|
|
3717
|
-
|
|
4144
|
+
join21(targetDir, ".claude", "agents")
|
|
3718
4145
|
);
|
|
3719
4146
|
let installAgents;
|
|
3720
4147
|
if (args.yes) {
|
|
@@ -3723,7 +4150,7 @@ var init_update = __esm({
|
|
|
3723
4150
|
installAgents = true;
|
|
3724
4151
|
} else {
|
|
3725
4152
|
console.log();
|
|
3726
|
-
console.log(` ${
|
|
4153
|
+
console.log(` ${pc9.bold(pc9.yellow("Sub-Agents (Recommended)"))}`);
|
|
3727
4154
|
console.log();
|
|
3728
4155
|
console.log(
|
|
3729
4156
|
" Sub-agents are specialized roles (PM, implementation, review,"
|
|
@@ -3746,20 +4173,20 @@ var init_update = __esm({
|
|
|
3746
4173
|
}
|
|
3747
4174
|
}
|
|
3748
4175
|
if (installAgents) {
|
|
3749
|
-
const claudeAgentsSrc =
|
|
4176
|
+
const claudeAgentsSrc = join21(templateDir, ".claude", "agents");
|
|
3750
4177
|
if (await pathExists(claudeAgentsSrc)) {
|
|
3751
|
-
await mkdir10(
|
|
4178
|
+
await mkdir10(join21(targetDir, ".claude", "agents"), { recursive: true });
|
|
3752
4179
|
await copyDirectoryContents(
|
|
3753
4180
|
claudeAgentsSrc,
|
|
3754
|
-
|
|
4181
|
+
join21(targetDir, ".claude", "agents")
|
|
3755
4182
|
);
|
|
3756
4183
|
}
|
|
3757
|
-
const cursorAgentsSrc =
|
|
4184
|
+
const cursorAgentsSrc = join21(templateDir, ".cursor", "agents");
|
|
3758
4185
|
if (await pathExists(cursorAgentsSrc)) {
|
|
3759
|
-
await mkdir10(
|
|
4186
|
+
await mkdir10(join21(targetDir, ".cursor", "agents"), { recursive: true });
|
|
3760
4187
|
await copyDirectoryContents(
|
|
3761
4188
|
cursorAgentsSrc,
|
|
3762
|
-
|
|
4189
|
+
join21(targetDir, ".cursor", "agents")
|
|
3763
4190
|
);
|
|
3764
4191
|
}
|
|
3765
4192
|
printStatus(
|
|
@@ -3773,47 +4200,47 @@ var init_update = __esm({
|
|
|
3773
4200
|
console.log();
|
|
3774
4201
|
console.log("Replacing framework files...");
|
|
3775
4202
|
await copyFile(
|
|
3776
|
-
|
|
3777
|
-
|
|
4203
|
+
join21(templateDir, ".claude", "CLAUDE.md"),
|
|
4204
|
+
join21(targetDir, ".claude", "CLAUDE.md")
|
|
3778
4205
|
);
|
|
3779
4206
|
await copyFile(
|
|
3780
|
-
|
|
3781
|
-
|
|
4207
|
+
join21(templateDir, ".claude", "settings.json"),
|
|
4208
|
+
join21(targetDir, ".claude", "settings.json")
|
|
3782
4209
|
);
|
|
3783
4210
|
printStatus(".claude/CLAUDE.md, settings.json");
|
|
3784
4211
|
await copyDirectoryContents(
|
|
3785
|
-
|
|
3786
|
-
|
|
4212
|
+
join21(templateDir, ".claude", "commands"),
|
|
4213
|
+
join21(targetDir, ".claude", "commands")
|
|
3787
4214
|
);
|
|
3788
4215
|
await copyDirectoryContents(
|
|
3789
|
-
|
|
3790
|
-
|
|
4216
|
+
join21(templateDir, ".claude", "commands"),
|
|
4217
|
+
join21(targetDir, ".cursor", "commands")
|
|
3791
4218
|
);
|
|
3792
4219
|
printStatus(".claude/commands, .cursor/commands");
|
|
3793
|
-
const skillsReadmeSrc =
|
|
4220
|
+
const skillsReadmeSrc = join21(templateDir, ".claude", "skills", "README.md");
|
|
3794
4221
|
if (await pathExists(skillsReadmeSrc)) {
|
|
3795
4222
|
await copyFile(
|
|
3796
4223
|
skillsReadmeSrc,
|
|
3797
|
-
|
|
4224
|
+
join21(targetDir, ".claude", "skills", "README.md")
|
|
3798
4225
|
);
|
|
3799
4226
|
}
|
|
3800
4227
|
printStatus(".claude/skills/README.md");
|
|
3801
4228
|
await copyFile(
|
|
3802
|
-
|
|
3803
|
-
|
|
4229
|
+
join21(templateDir, ".cursor", "hooks.json"),
|
|
4230
|
+
join21(targetDir, ".cursor", "hooks.json")
|
|
3804
4231
|
);
|
|
3805
4232
|
printStatus(".cursor/hooks.json");
|
|
3806
4233
|
await copyFile(
|
|
3807
|
-
|
|
3808
|
-
|
|
4234
|
+
join21(templateDir, "AGENTS.md"),
|
|
4235
|
+
join21(targetDir, "AGENTS.md")
|
|
3809
4236
|
);
|
|
3810
4237
|
printStatus("AGENTS.md");
|
|
3811
|
-
const envExampleSrc =
|
|
4238
|
+
const envExampleSrc = join21(templateDir, ".env.example");
|
|
3812
4239
|
if (await pathExists(envExampleSrc)) {
|
|
3813
|
-
await copyFile(envExampleSrc,
|
|
4240
|
+
await copyFile(envExampleSrc, join21(targetDir, ".env.example"));
|
|
3814
4241
|
printStatus(".env.example");
|
|
3815
4242
|
}
|
|
3816
|
-
const knowledgeTemplatesDir =
|
|
4243
|
+
const knowledgeTemplatesDir = join21(
|
|
3817
4244
|
targetDir,
|
|
3818
4245
|
"flydocs",
|
|
3819
4246
|
"knowledge",
|
|
@@ -3823,8 +4250,8 @@ var init_update = __esm({
|
|
|
3823
4250
|
await mkdir10(knowledgeTemplatesDir, { recursive: true });
|
|
3824
4251
|
}
|
|
3825
4252
|
for (const tmpl of ["decision.md", "feature.md", "note.md"]) {
|
|
3826
|
-
const src =
|
|
3827
|
-
const dest =
|
|
4253
|
+
const src = join21(templateDir, "flydocs", "knowledge", "templates", tmpl);
|
|
4254
|
+
const dest = join21(knowledgeTemplatesDir, tmpl);
|
|
3828
4255
|
if (await pathExists(src) && !await pathExists(dest)) {
|
|
3829
4256
|
await copyFile(src, dest);
|
|
3830
4257
|
}
|
|
@@ -3851,18 +4278,18 @@ var init_update = __esm({
|
|
|
3851
4278
|
printWarning("Config merge failed \u2014 config.json preserved as-is");
|
|
3852
4279
|
}
|
|
3853
4280
|
await copyFile(
|
|
3854
|
-
|
|
3855
|
-
|
|
4281
|
+
join21(templateDir, ".flydocs", "version"),
|
|
4282
|
+
join21(targetDir, ".flydocs", "version")
|
|
3856
4283
|
);
|
|
3857
4284
|
printStatus(`.flydocs/version \u2192 ${version}`);
|
|
3858
|
-
const clSrc =
|
|
4285
|
+
const clSrc = join21(templateDir, "CHANGELOG.md");
|
|
3859
4286
|
if (await pathExists(clSrc)) {
|
|
3860
|
-
await copyFile(clSrc,
|
|
4287
|
+
await copyFile(clSrc, join21(targetDir, ".flydocs", "CHANGELOG.md"));
|
|
3861
4288
|
printStatus(".flydocs/CHANGELOG.md");
|
|
3862
4289
|
}
|
|
3863
|
-
const mfSrc =
|
|
4290
|
+
const mfSrc = join21(templateDir, "manifest.json");
|
|
3864
4291
|
if (await pathExists(mfSrc)) {
|
|
3865
|
-
await copyFile(mfSrc,
|
|
4292
|
+
await copyFile(mfSrc, join21(targetDir, ".flydocs", "manifest.json"));
|
|
3866
4293
|
printStatus(".flydocs/manifest.json");
|
|
3867
4294
|
}
|
|
3868
4295
|
await generateIntegrity(targetDir, version);
|
|
@@ -3924,13 +4351,13 @@ var uninstall_exports = {};
|
|
|
3924
4351
|
__export(uninstall_exports, {
|
|
3925
4352
|
default: () => uninstall_default
|
|
3926
4353
|
});
|
|
3927
|
-
import { defineCommand as
|
|
3928
|
-
import { resolve as resolve5, join as
|
|
3929
|
-
import { readdir as readdir6, rm as
|
|
4354
|
+
import { defineCommand as defineCommand5 } from "citty";
|
|
4355
|
+
import { resolve as resolve5, join as join22 } from "path";
|
|
4356
|
+
import { readdir as readdir6, rm as rm6, rename as rename2 } from "fs/promises";
|
|
3930
4357
|
import { confirm as confirm5, select as select4, isCancel as isCancel6, cancel as cancel5 } from "@clack/prompts";
|
|
3931
|
-
import
|
|
4358
|
+
import pc10 from "picocolors";
|
|
3932
4359
|
async function removeOwnedSkills(targetDir) {
|
|
3933
|
-
const skillsDir =
|
|
4360
|
+
const skillsDir = join22(targetDir, ".claude", "skills");
|
|
3934
4361
|
const removed = [];
|
|
3935
4362
|
if (!await pathExists(skillsDir)) {
|
|
3936
4363
|
return removed;
|
|
@@ -3939,7 +4366,7 @@ async function removeOwnedSkills(targetDir) {
|
|
|
3939
4366
|
const entries = await readdir6(skillsDir);
|
|
3940
4367
|
for (const entry of entries) {
|
|
3941
4368
|
if (entry.startsWith(OWNED_SKILL_PREFIX)) {
|
|
3942
|
-
await
|
|
4369
|
+
await rm6(join22(skillsDir, entry), { recursive: true, force: true });
|
|
3943
4370
|
removed.push(`.claude/skills/${entry}`);
|
|
3944
4371
|
}
|
|
3945
4372
|
}
|
|
@@ -3948,7 +4375,7 @@ async function removeOwnedSkills(targetDir) {
|
|
|
3948
4375
|
return removed;
|
|
3949
4376
|
}
|
|
3950
4377
|
async function removeOwnedCursorRules(targetDir) {
|
|
3951
|
-
const rulesDir =
|
|
4378
|
+
const rulesDir = join22(targetDir, ".cursor", "rules");
|
|
3952
4379
|
const removed = [];
|
|
3953
4380
|
if (!await pathExists(rulesDir)) {
|
|
3954
4381
|
return removed;
|
|
@@ -3957,7 +4384,7 @@ async function removeOwnedCursorRules(targetDir) {
|
|
|
3957
4384
|
const entries = await readdir6(rulesDir);
|
|
3958
4385
|
for (const entry of entries) {
|
|
3959
4386
|
if (entry.startsWith(OWNED_RULE_PREFIX) && entry.endsWith(".mdc")) {
|
|
3960
|
-
await
|
|
4387
|
+
await rm6(join22(rulesDir, entry), { force: true });
|
|
3961
4388
|
removed.push(`.cursor/rules/${entry}`);
|
|
3962
4389
|
}
|
|
3963
4390
|
}
|
|
@@ -3976,9 +4403,9 @@ async function isEmptyDir(dirPath) {
|
|
|
3976
4403
|
async function cleanupEmptyParents(targetDir, dirs) {
|
|
3977
4404
|
const cleaned = [];
|
|
3978
4405
|
for (const dir of dirs) {
|
|
3979
|
-
const fullPath =
|
|
4406
|
+
const fullPath = join22(targetDir, dir);
|
|
3980
4407
|
if (await pathExists(fullPath) && await isEmptyDir(fullPath)) {
|
|
3981
|
-
await
|
|
4408
|
+
await rm6(fullPath, { recursive: true, force: true });
|
|
3982
4409
|
cleaned.push(dir);
|
|
3983
4410
|
}
|
|
3984
4411
|
}
|
|
@@ -4008,7 +4435,7 @@ var init_uninstall = __esm({
|
|
|
4008
4435
|
];
|
|
4009
4436
|
OWNED_SKILL_PREFIX = "flydocs-";
|
|
4010
4437
|
OWNED_RULE_PREFIX = "flydocs-";
|
|
4011
|
-
uninstall_default =
|
|
4438
|
+
uninstall_default = defineCommand5({
|
|
4012
4439
|
meta: {
|
|
4013
4440
|
name: "uninstall",
|
|
4014
4441
|
description: "Remove FlyDocs from a project directory"
|
|
@@ -4055,8 +4482,8 @@ var init_uninstall = __esm({
|
|
|
4055
4482
|
process.exit(1);
|
|
4056
4483
|
}
|
|
4057
4484
|
targetDir = resolve5(targetDir);
|
|
4058
|
-
const hasFlydocs = await pathExists(
|
|
4059
|
-
const hasAgentsMd = await pathExists(
|
|
4485
|
+
const hasFlydocs = await pathExists(join22(targetDir, ".flydocs"));
|
|
4486
|
+
const hasAgentsMd = await pathExists(join22(targetDir, "AGENTS.md"));
|
|
4060
4487
|
if (!hasFlydocs && !hasAgentsMd) {
|
|
4061
4488
|
printError(`Not a FlyDocs project: ${targetDir}`);
|
|
4062
4489
|
printInfo("No .flydocs/ directory or AGENTS.md found.");
|
|
@@ -4068,7 +4495,7 @@ var init_uninstall = __esm({
|
|
|
4068
4495
|
const removeAll = forceAll || args.all;
|
|
4069
4496
|
const skipPrompts = forceAll || args.yes;
|
|
4070
4497
|
let contentAction = "preserve";
|
|
4071
|
-
const hasUserContent = await pathExists(
|
|
4498
|
+
const hasUserContent = await pathExists(join22(targetDir, "flydocs"));
|
|
4072
4499
|
if (hasUserContent) {
|
|
4073
4500
|
if (removeAll) {
|
|
4074
4501
|
contentAction = "remove";
|
|
@@ -4102,34 +4529,34 @@ var init_uninstall = __esm({
|
|
|
4102
4529
|
}
|
|
4103
4530
|
if (!skipPrompts) {
|
|
4104
4531
|
console.log();
|
|
4105
|
-
console.log(
|
|
4532
|
+
console.log(pc10.bold("The following will be removed:"));
|
|
4106
4533
|
console.log();
|
|
4107
4534
|
console.log(" Framework files:");
|
|
4108
4535
|
for (const [path] of ALWAYS_REMOVED) {
|
|
4109
|
-
console.log(` ${
|
|
4536
|
+
console.log(` ${pc10.dim(path)}`);
|
|
4110
4537
|
}
|
|
4111
|
-
console.log(` ${
|
|
4112
|
-
console.log(` ${
|
|
4538
|
+
console.log(` ${pc10.dim(".claude/skills/flydocs-*")}`);
|
|
4539
|
+
console.log(` ${pc10.dim(".cursor/rules/flydocs-*.mdc")}`);
|
|
4113
4540
|
if (hasUserContent) {
|
|
4114
4541
|
if (contentAction === "archive") {
|
|
4115
4542
|
console.log();
|
|
4116
4543
|
console.log(
|
|
4117
|
-
` User content: ${
|
|
4544
|
+
` User content: ${pc10.yellow("flydocs/ -> flydocs-archive/")}`
|
|
4118
4545
|
);
|
|
4119
4546
|
} else if (contentAction === "remove") {
|
|
4120
4547
|
console.log();
|
|
4121
|
-
console.log(` User content: ${
|
|
4548
|
+
console.log(` User content: ${pc10.red("flydocs/ (deleted)")}`);
|
|
4122
4549
|
} else {
|
|
4123
4550
|
console.log();
|
|
4124
|
-
console.log(` User content: ${
|
|
4551
|
+
console.log(` User content: ${pc10.green("flydocs/ (preserved)")}`);
|
|
4125
4552
|
}
|
|
4126
4553
|
}
|
|
4127
4554
|
console.log();
|
|
4128
|
-
console.log(
|
|
4555
|
+
console.log(pc10.bold("Preserved:"));
|
|
4129
4556
|
console.log(
|
|
4130
|
-
` ${
|
|
4557
|
+
` ${pc10.dim(".claude/skills/ (non-flydocs community skills)")}`
|
|
4131
4558
|
);
|
|
4132
|
-
console.log(` ${
|
|
4559
|
+
console.log(` ${pc10.dim(".env, .env.local")}`);
|
|
4133
4560
|
console.log();
|
|
4134
4561
|
const shouldContinue = await confirm5({
|
|
4135
4562
|
message: "Proceed with uninstall?"
|
|
@@ -4151,16 +4578,16 @@ var init_uninstall = __esm({
|
|
|
4151
4578
|
const removedRules = await removeOwnedCursorRules(targetDir);
|
|
4152
4579
|
result.removed.push(...removedRules);
|
|
4153
4580
|
for (const [relativePath, type] of ALWAYS_REMOVED) {
|
|
4154
|
-
const fullPath =
|
|
4581
|
+
const fullPath = join22(targetDir, relativePath);
|
|
4155
4582
|
if (!await pathExists(fullPath)) {
|
|
4156
4583
|
result.skipped.push(relativePath);
|
|
4157
4584
|
continue;
|
|
4158
4585
|
}
|
|
4159
4586
|
try {
|
|
4160
4587
|
if (type === "dir") {
|
|
4161
|
-
await
|
|
4588
|
+
await rm6(fullPath, { recursive: true, force: true });
|
|
4162
4589
|
} else {
|
|
4163
|
-
await
|
|
4590
|
+
await rm6(fullPath, { force: true });
|
|
4164
4591
|
}
|
|
4165
4592
|
result.removed.push(relativePath);
|
|
4166
4593
|
} catch {
|
|
@@ -4169,16 +4596,16 @@ var init_uninstall = __esm({
|
|
|
4169
4596
|
}
|
|
4170
4597
|
}
|
|
4171
4598
|
if (hasUserContent) {
|
|
4172
|
-
const flydocsPath =
|
|
4599
|
+
const flydocsPath = join22(targetDir, "flydocs");
|
|
4173
4600
|
if (contentAction === "archive") {
|
|
4174
|
-
const archivePath =
|
|
4601
|
+
const archivePath = join22(targetDir, "flydocs-archive");
|
|
4175
4602
|
if (await pathExists(archivePath)) {
|
|
4176
|
-
await
|
|
4603
|
+
await rm6(archivePath, { recursive: true, force: true });
|
|
4177
4604
|
}
|
|
4178
4605
|
await rename2(flydocsPath, archivePath);
|
|
4179
4606
|
result.archived.push("flydocs/ -> flydocs-archive/");
|
|
4180
4607
|
} else if (contentAction === "remove") {
|
|
4181
|
-
await
|
|
4608
|
+
await rm6(flydocsPath, { recursive: true, force: true });
|
|
4182
4609
|
result.removed.push("flydocs/");
|
|
4183
4610
|
}
|
|
4184
4611
|
}
|
|
@@ -4197,17 +4624,17 @@ var init_uninstall = __esm({
|
|
|
4197
4624
|
result.restored = originals.map((f) => f.relativePath);
|
|
4198
4625
|
}
|
|
4199
4626
|
console.log();
|
|
4200
|
-
console.log(
|
|
4627
|
+
console.log(pc10.bold("Uninstall Summary"));
|
|
4201
4628
|
console.log();
|
|
4202
4629
|
if (result.removed.length > 0) {
|
|
4203
|
-
console.log(` ${
|
|
4630
|
+
console.log(` ${pc10.green("Removed")} (${result.removed.length}):`);
|
|
4204
4631
|
for (const item of result.removed) {
|
|
4205
4632
|
printStatus(item);
|
|
4206
4633
|
}
|
|
4207
4634
|
}
|
|
4208
4635
|
if (result.archived.length > 0) {
|
|
4209
4636
|
console.log();
|
|
4210
|
-
console.log(` ${
|
|
4637
|
+
console.log(` ${pc10.yellow("Archived")} (${result.archived.length}):`);
|
|
4211
4638
|
for (const item of result.archived) {
|
|
4212
4639
|
printInfo(item);
|
|
4213
4640
|
}
|
|
@@ -4215,7 +4642,7 @@ var init_uninstall = __esm({
|
|
|
4215
4642
|
if (result.restored.length > 0) {
|
|
4216
4643
|
console.log();
|
|
4217
4644
|
console.log(
|
|
4218
|
-
` ${
|
|
4645
|
+
` ${pc10.green("Restored")} (${result.restored.length} pre-FlyDocs original(s)):`
|
|
4219
4646
|
);
|
|
4220
4647
|
for (const item of result.restored) {
|
|
4221
4648
|
printInfo(item);
|
|
@@ -4224,16 +4651,16 @@ var init_uninstall = __esm({
|
|
|
4224
4651
|
if (result.skipped.length > 0) {
|
|
4225
4652
|
console.log();
|
|
4226
4653
|
console.log(
|
|
4227
|
-
` ${
|
|
4654
|
+
` ${pc10.dim("Skipped")} (${result.skipped.length} \u2014 not found):`
|
|
4228
4655
|
);
|
|
4229
4656
|
for (const item of result.skipped) {
|
|
4230
|
-
console.log(` ${
|
|
4657
|
+
console.log(` ${pc10.dim(item)}`);
|
|
4231
4658
|
}
|
|
4232
4659
|
}
|
|
4233
4660
|
console.log();
|
|
4234
4661
|
printStatus("FlyDocs has been removed from this project.");
|
|
4235
4662
|
console.log();
|
|
4236
|
-
printInfo(`To reinstall: ${
|
|
4663
|
+
printInfo(`To reinstall: ${pc10.cyan("npx @flydocs/cli install --here")}`);
|
|
4237
4664
|
console.log();
|
|
4238
4665
|
}
|
|
4239
4666
|
});
|
|
@@ -4245,28 +4672,28 @@ var setup_exports = {};
|
|
|
4245
4672
|
__export(setup_exports, {
|
|
4246
4673
|
default: () => setup_default
|
|
4247
4674
|
});
|
|
4248
|
-
import { defineCommand as
|
|
4249
|
-
import
|
|
4675
|
+
import { defineCommand as defineCommand6 } from "citty";
|
|
4676
|
+
import pc11 from "picocolors";
|
|
4250
4677
|
var setup_default;
|
|
4251
4678
|
var init_setup = __esm({
|
|
4252
4679
|
"src/commands/setup.ts"() {
|
|
4253
4680
|
"use strict";
|
|
4254
|
-
setup_default =
|
|
4681
|
+
setup_default = defineCommand6({
|
|
4255
4682
|
meta: {
|
|
4256
4683
|
name: "setup",
|
|
4257
4684
|
description: "Configure FlyDocs settings for this project"
|
|
4258
4685
|
},
|
|
4259
4686
|
run() {
|
|
4260
4687
|
console.log();
|
|
4261
|
-
console.log(` ${
|
|
4688
|
+
console.log(` ${pc11.bold("FlyDocs Setup")}`);
|
|
4262
4689
|
console.log();
|
|
4263
4690
|
console.log(` Setup runs inside your IDE as an interactive AI command.`);
|
|
4264
4691
|
console.log();
|
|
4265
4692
|
console.log(
|
|
4266
|
-
` ${
|
|
4693
|
+
` ${pc11.cyan("Claude Code:")} Type ${pc11.bold("/flydocs-setup")} in chat`
|
|
4267
4694
|
);
|
|
4268
4695
|
console.log(
|
|
4269
|
-
` ${
|
|
4696
|
+
` ${pc11.cyan("Cursor:")} Type ${pc11.bold("/flydocs-setup")} in chat`
|
|
4270
4697
|
);
|
|
4271
4698
|
console.log();
|
|
4272
4699
|
console.log(` This configures your project context, detects your stack,`);
|
|
@@ -4282,14 +4709,14 @@ var skills_exports = {};
|
|
|
4282
4709
|
__export(skills_exports, {
|
|
4283
4710
|
default: () => skills_default
|
|
4284
4711
|
});
|
|
4285
|
-
import { defineCommand as
|
|
4286
|
-
import
|
|
4712
|
+
import { defineCommand as defineCommand7 } from "citty";
|
|
4713
|
+
import pc12 from "picocolors";
|
|
4287
4714
|
var list, search, add, remove, skills_default;
|
|
4288
4715
|
var init_skills2 = __esm({
|
|
4289
4716
|
"src/commands/skills.ts"() {
|
|
4290
4717
|
"use strict";
|
|
4291
4718
|
init_skill_manager();
|
|
4292
|
-
list =
|
|
4719
|
+
list = defineCommand7({
|
|
4293
4720
|
meta: {
|
|
4294
4721
|
name: "list",
|
|
4295
4722
|
description: "List installed skills"
|
|
@@ -4305,26 +4732,26 @@ var init_skills2 = __esm({
|
|
|
4305
4732
|
console.log(`${total} skill(s) installed:`);
|
|
4306
4733
|
if (result.platform.length > 0) {
|
|
4307
4734
|
console.log();
|
|
4308
|
-
console.log(
|
|
4735
|
+
console.log(pc12.bold("Platform"));
|
|
4309
4736
|
for (const skill of result.platform) {
|
|
4310
4737
|
console.log(
|
|
4311
|
-
` ${skill.name} ${
|
|
4738
|
+
` ${skill.name} ${pc12.dim(`(${skill.triggers} triggers)`)}`
|
|
4312
4739
|
);
|
|
4313
4740
|
}
|
|
4314
4741
|
}
|
|
4315
4742
|
if (result.community.length > 0) {
|
|
4316
4743
|
console.log();
|
|
4317
|
-
console.log(
|
|
4744
|
+
console.log(pc12.bold("Community"));
|
|
4318
4745
|
for (const skill of result.community) {
|
|
4319
4746
|
console.log(
|
|
4320
|
-
` ${skill.name} ${
|
|
4747
|
+
` ${skill.name} ${pc12.dim(`(${skill.triggers} triggers)`)}`
|
|
4321
4748
|
);
|
|
4322
4749
|
}
|
|
4323
4750
|
}
|
|
4324
4751
|
console.log();
|
|
4325
4752
|
}
|
|
4326
4753
|
});
|
|
4327
|
-
search =
|
|
4754
|
+
search = defineCommand7({
|
|
4328
4755
|
meta: {
|
|
4329
4756
|
name: "search",
|
|
4330
4757
|
description: "Search community skills"
|
|
@@ -4340,24 +4767,24 @@ var init_skills2 = __esm({
|
|
|
4340
4767
|
const results = await searchCatalog(args.keyword);
|
|
4341
4768
|
if (results.length === 0) {
|
|
4342
4769
|
console.log(`No skills found for "${args.keyword}".`);
|
|
4343
|
-
console.log(` Browse the catalog at: ${
|
|
4770
|
+
console.log(` Browse the catalog at: ${pc12.cyan("https://skills.sh/")}`);
|
|
4344
4771
|
return;
|
|
4345
4772
|
}
|
|
4346
4773
|
console.log();
|
|
4347
4774
|
console.log(`${results.length} skill(s) matching "${args.keyword}":`);
|
|
4348
4775
|
console.log();
|
|
4349
4776
|
for (const skill of results) {
|
|
4350
|
-
console.log(` ${
|
|
4777
|
+
console.log(` ${pc12.bold(skill.name)}`);
|
|
4351
4778
|
console.log(` ${skill.description}`);
|
|
4352
|
-
console.log(` ${
|
|
4779
|
+
console.log(` ${pc12.dim(skill.repo)}`);
|
|
4353
4780
|
if (skill.tags.length > 0) {
|
|
4354
|
-
console.log(` ${
|
|
4781
|
+
console.log(` ${pc12.dim(skill.tags.join(", "))}`);
|
|
4355
4782
|
}
|
|
4356
4783
|
console.log();
|
|
4357
4784
|
}
|
|
4358
4785
|
}
|
|
4359
4786
|
});
|
|
4360
|
-
add =
|
|
4787
|
+
add = defineCommand7({
|
|
4361
4788
|
meta: {
|
|
4362
4789
|
name: "add",
|
|
4363
4790
|
description: "Install a community skill"
|
|
@@ -4373,7 +4800,7 @@ var init_skills2 = __esm({
|
|
|
4373
4800
|
await addSkill(process.cwd(), args.source);
|
|
4374
4801
|
}
|
|
4375
4802
|
});
|
|
4376
|
-
remove =
|
|
4803
|
+
remove = defineCommand7({
|
|
4377
4804
|
meta: {
|
|
4378
4805
|
name: "remove",
|
|
4379
4806
|
description: "Remove an installed community skill"
|
|
@@ -4389,7 +4816,7 @@ var init_skills2 = __esm({
|
|
|
4389
4816
|
await removeSkill(process.cwd(), args.name);
|
|
4390
4817
|
}
|
|
4391
4818
|
});
|
|
4392
|
-
skills_default =
|
|
4819
|
+
skills_default = defineCommand7({
|
|
4393
4820
|
meta: {
|
|
4394
4821
|
name: "skills",
|
|
4395
4822
|
description: "Manage FlyDocs skills (list, search, add, remove)"
|
|
@@ -4409,10 +4836,10 @@ var connect_exports = {};
|
|
|
4409
4836
|
__export(connect_exports, {
|
|
4410
4837
|
default: () => connect_default
|
|
4411
4838
|
});
|
|
4412
|
-
import { defineCommand as
|
|
4839
|
+
import { defineCommand as defineCommand8 } from "citty";
|
|
4413
4840
|
import { text as text4, confirm as confirm6, isCancel as isCancel7, cancel as cancel6 } from "@clack/prompts";
|
|
4414
|
-
import
|
|
4415
|
-
import { join as
|
|
4841
|
+
import pc13 from "picocolors";
|
|
4842
|
+
import { join as join23 } from "path";
|
|
4416
4843
|
var connect_default;
|
|
4417
4844
|
var init_connect = __esm({
|
|
4418
4845
|
"src/commands/connect.ts"() {
|
|
@@ -4422,7 +4849,7 @@ var init_connect = __esm({
|
|
|
4422
4849
|
init_template();
|
|
4423
4850
|
init_ui();
|
|
4424
4851
|
init_api_key();
|
|
4425
|
-
connect_default =
|
|
4852
|
+
connect_default = defineCommand8({
|
|
4426
4853
|
meta: {
|
|
4427
4854
|
name: "connect",
|
|
4428
4855
|
description: "Connect FlyDocs to a cloud provider"
|
|
@@ -4447,11 +4874,11 @@ var init_connect = __esm({
|
|
|
4447
4874
|
},
|
|
4448
4875
|
async run({ args }) {
|
|
4449
4876
|
const targetDir = args.path ?? process.cwd();
|
|
4450
|
-
const configPath =
|
|
4877
|
+
const configPath = join23(targetDir, ".flydocs", "config.json");
|
|
4451
4878
|
if (!await pathExists(configPath)) {
|
|
4452
4879
|
printError("Not a FlyDocs project (.flydocs/config.json not found).");
|
|
4453
4880
|
console.log(
|
|
4454
|
-
` Run ${
|
|
4881
|
+
` Run ${pc13.cyan("flydocs")} first to install FlyDocs in this project.`
|
|
4455
4882
|
);
|
|
4456
4883
|
process.exit(1);
|
|
4457
4884
|
}
|
|
@@ -4468,10 +4895,10 @@ var init_connect = __esm({
|
|
|
4468
4895
|
}
|
|
4469
4896
|
}
|
|
4470
4897
|
console.log();
|
|
4471
|
-
console.log(` ${
|
|
4898
|
+
console.log(` ${pc13.bold("Connect to FlyDocs Cloud")}`);
|
|
4472
4899
|
console.log();
|
|
4473
4900
|
console.log(
|
|
4474
|
-
` ${
|
|
4901
|
+
` ${pc13.dim("Get your API key (fdk_...) from your FlyDocs dashboard")}`
|
|
4475
4902
|
);
|
|
4476
4903
|
console.log();
|
|
4477
4904
|
let apiKey = args.key ?? "";
|
|
@@ -4509,7 +4936,7 @@ var init_connect = __esm({
|
|
|
4509
4936
|
console.log(` Check your key and try again.`);
|
|
4510
4937
|
process.exit(1);
|
|
4511
4938
|
}
|
|
4512
|
-
printStatus(`Connected to ${
|
|
4939
|
+
printStatus(`Connected to ${pc13.bold(result.org)}`);
|
|
4513
4940
|
} catch {
|
|
4514
4941
|
printError(
|
|
4515
4942
|
"Could not reach relay API. Check your network and try again."
|
|
@@ -4517,7 +4944,7 @@ var init_connect = __esm({
|
|
|
4517
4944
|
process.exit(1);
|
|
4518
4945
|
}
|
|
4519
4946
|
const envFile = await storeEnvKey(targetDir, "FLYDOCS_API_KEY", apiKey);
|
|
4520
|
-
printStatus(`API key stored in ${
|
|
4947
|
+
printStatus(`API key stored in ${pc13.dim(envFile)}`);
|
|
4521
4948
|
} else {
|
|
4522
4949
|
try {
|
|
4523
4950
|
const result = await validateLinearKey(apiKey);
|
|
@@ -4527,7 +4954,7 @@ var init_connect = __esm({
|
|
|
4527
4954
|
process.exit(1);
|
|
4528
4955
|
}
|
|
4529
4956
|
printStatus(
|
|
4530
|
-
`Authenticated as ${
|
|
4957
|
+
`Authenticated as ${pc13.bold(result.name)} (${result.email})`
|
|
4531
4958
|
);
|
|
4532
4959
|
} catch {
|
|
4533
4960
|
printError("Invalid API key or network error.");
|
|
@@ -4535,7 +4962,7 @@ var init_connect = __esm({
|
|
|
4535
4962
|
process.exit(1);
|
|
4536
4963
|
}
|
|
4537
4964
|
const envFile = await storeEnvKey(targetDir, "LINEAR_API_KEY", apiKey);
|
|
4538
|
-
printStatus(`API key stored in ${
|
|
4965
|
+
printStatus(`API key stored in ${pc13.dim(envFile)}`);
|
|
4539
4966
|
}
|
|
4540
4967
|
const wasLocal = config.tier === "local";
|
|
4541
4968
|
config.tier = "cloud";
|
|
@@ -4551,14 +4978,14 @@ var init_connect = __esm({
|
|
|
4551
4978
|
}
|
|
4552
4979
|
console.log();
|
|
4553
4980
|
console.log(
|
|
4554
|
-
` ${
|
|
4981
|
+
` ${pc13.bold("Connected!")} Your project is now on the cloud tier.`
|
|
4555
4982
|
);
|
|
4556
4983
|
console.log();
|
|
4557
4984
|
console.log(` Next steps:`);
|
|
4558
4985
|
console.log(
|
|
4559
|
-
` 1. Run ${
|
|
4986
|
+
` 1. Run ${pc13.cyan("/flydocs-setup")} in your IDE to configure your project`
|
|
4560
4987
|
);
|
|
4561
|
-
console.log(` 2. Run ${
|
|
4988
|
+
console.log(` 2. Run ${pc13.cyan("/start-session")} to begin working`);
|
|
4562
4989
|
console.log();
|
|
4563
4990
|
}
|
|
4564
4991
|
});
|
|
@@ -4570,9 +4997,9 @@ var auth_exports = {};
|
|
|
4570
4997
|
__export(auth_exports, {
|
|
4571
4998
|
default: () => auth_default
|
|
4572
4999
|
});
|
|
4573
|
-
import { defineCommand as
|
|
5000
|
+
import { defineCommand as defineCommand9 } from "citty";
|
|
4574
5001
|
import { text as text5, confirm as confirm7, isCancel as isCancel8, cancel as cancel7 } from "@clack/prompts";
|
|
4575
|
-
import
|
|
5002
|
+
import pc14 from "picocolors";
|
|
4576
5003
|
var auth_default;
|
|
4577
5004
|
var init_auth = __esm({
|
|
4578
5005
|
"src/commands/auth.ts"() {
|
|
@@ -4580,7 +5007,7 @@ var init_auth = __esm({
|
|
|
4580
5007
|
init_ui();
|
|
4581
5008
|
init_api_key();
|
|
4582
5009
|
init_global_config();
|
|
4583
|
-
auth_default =
|
|
5010
|
+
auth_default = defineCommand9({
|
|
4584
5011
|
meta: {
|
|
4585
5012
|
name: "auth",
|
|
4586
5013
|
description: "Store API key globally (~/.flydocs/credentials)"
|
|
@@ -4594,13 +5021,13 @@ var init_auth = __esm({
|
|
|
4594
5021
|
},
|
|
4595
5022
|
async run({ args }) {
|
|
4596
5023
|
console.log();
|
|
4597
|
-
console.log(` ${
|
|
5024
|
+
console.log(` ${pc14.bold("FlyDocs Authentication")}`);
|
|
4598
5025
|
console.log();
|
|
4599
5026
|
let apiKey = args.key ?? "";
|
|
4600
5027
|
const existing = await readGlobalCredential();
|
|
4601
5028
|
if (existing?.apiKey && !apiKey) {
|
|
4602
5029
|
printInfo(
|
|
4603
|
-
`Existing key found: ${
|
|
5030
|
+
`Existing key found: ${pc14.dim(existing.apiKey.slice(0, 8) + "...")}`
|
|
4604
5031
|
);
|
|
4605
5032
|
const replace = await confirm7({
|
|
4606
5033
|
message: "Replace with a new key?"
|
|
@@ -4612,7 +5039,7 @@ var init_auth = __esm({
|
|
|
4612
5039
|
}
|
|
4613
5040
|
if (!apiKey) {
|
|
4614
5041
|
console.log(
|
|
4615
|
-
` ${
|
|
5042
|
+
` ${pc14.dim("Get your API key (fdk_...) from your FlyDocs dashboard")}`
|
|
4616
5043
|
);
|
|
4617
5044
|
console.log();
|
|
4618
5045
|
const keyInput = await text5({
|
|
@@ -4648,7 +5075,7 @@ var init_auth = __esm({
|
|
|
4648
5075
|
printError("Invalid API key. Check your key and try again.");
|
|
4649
5076
|
process.exit(1);
|
|
4650
5077
|
}
|
|
4651
|
-
printStatus(`Authenticated with ${
|
|
5078
|
+
printStatus(`Authenticated with ${pc14.bold(result.org)}`);
|
|
4652
5079
|
} catch {
|
|
4653
5080
|
printError(
|
|
4654
5081
|
"Could not reach FlyDocs API. Check your network and try again."
|
|
@@ -4663,10 +5090,10 @@ var init_auth = __esm({
|
|
|
4663
5090
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4664
5091
|
lastValidated: (/* @__PURE__ */ new Date()).toISOString()
|
|
4665
5092
|
});
|
|
4666
|
-
printStatus(`Key stored at ${
|
|
5093
|
+
printStatus(`Key stored at ${pc14.dim(credentialsPath())}`);
|
|
4667
5094
|
await checkCredentialPermissions();
|
|
4668
5095
|
console.log();
|
|
4669
|
-
console.log(` ${
|
|
5096
|
+
console.log(` ${pc14.bold("Authenticated!")} Key stored globally.`);
|
|
4670
5097
|
console.log(` All FlyDocs projects on this machine will use this key.`);
|
|
4671
5098
|
console.log();
|
|
4672
5099
|
}
|
|
@@ -4679,10 +5106,10 @@ var sync_exports = {};
|
|
|
4679
5106
|
__export(sync_exports, {
|
|
4680
5107
|
default: () => sync_default
|
|
4681
5108
|
});
|
|
4682
|
-
import { defineCommand as
|
|
4683
|
-
import
|
|
4684
|
-
import { join as
|
|
4685
|
-
import { mkdir as mkdir11, writeFile as
|
|
5109
|
+
import { defineCommand as defineCommand10 } from "citty";
|
|
5110
|
+
import pc15 from "picocolors";
|
|
5111
|
+
import { join as join24 } from "path";
|
|
5112
|
+
import { mkdir as mkdir11, writeFile as writeFile14 } from "fs/promises";
|
|
4686
5113
|
var sync_default;
|
|
4687
5114
|
var init_sync = __esm({
|
|
4688
5115
|
"src/commands/sync.ts"() {
|
|
@@ -4694,7 +5121,7 @@ var init_sync = __esm({
|
|
|
4694
5121
|
init_fs_ops();
|
|
4695
5122
|
init_types();
|
|
4696
5123
|
init_relay_client();
|
|
4697
|
-
sync_default =
|
|
5124
|
+
sync_default = defineCommand10({
|
|
4698
5125
|
meta: {
|
|
4699
5126
|
name: "sync",
|
|
4700
5127
|
description: "Pull latest config and templates from server"
|
|
@@ -4745,14 +5172,14 @@ var init_sync = __esm({
|
|
|
4745
5172
|
} else {
|
|
4746
5173
|
printWarning("Server unreachable, using cached config.");
|
|
4747
5174
|
}
|
|
4748
|
-
console.log(` ${
|
|
5175
|
+
console.log(` ${pc15.dim("Config may be stale. Retry when connected.")}`);
|
|
4749
5176
|
return;
|
|
4750
5177
|
}
|
|
4751
5178
|
if (!serverResponse.valid) {
|
|
4752
5179
|
printWarning("Server returned invalid config. Keeping current config.");
|
|
4753
5180
|
return;
|
|
4754
5181
|
}
|
|
4755
|
-
await mkdir11(
|
|
5182
|
+
await mkdir11(join24(targetDir, ".flydocs"), { recursive: true });
|
|
4756
5183
|
const configWithHash = applyConfigHash(serverResponse.config);
|
|
4757
5184
|
await writeConfig(targetDir, configWithHash);
|
|
4758
5185
|
changes.push("Updated .flydocs/config.json");
|
|
@@ -4765,7 +5192,7 @@ var init_sync = __esm({
|
|
|
4765
5192
|
workspaceId
|
|
4766
5193
|
);
|
|
4767
5194
|
if (templatesResponse.templates.length > 0) {
|
|
4768
|
-
const templatesDir =
|
|
5195
|
+
const templatesDir = join24(
|
|
4769
5196
|
targetDir,
|
|
4770
5197
|
".claude",
|
|
4771
5198
|
"skills",
|
|
@@ -4776,10 +5203,10 @@ var init_sync = __esm({
|
|
|
4776
5203
|
for (const template of templatesResponse.templates) {
|
|
4777
5204
|
const filename = `${template.type}.md`;
|
|
4778
5205
|
const subdir = template.category === "issue" ? "issues" : template.category === "pr" ? "pr" : template.category === "comment" ? "." : ".";
|
|
4779
|
-
const templateDir =
|
|
5206
|
+
const templateDir = join24(templatesDir, subdir);
|
|
4780
5207
|
await mkdir11(templateDir, { recursive: true });
|
|
4781
|
-
await
|
|
4782
|
-
|
|
5208
|
+
await writeFile14(
|
|
5209
|
+
join24(templateDir, filename),
|
|
4783
5210
|
template.content,
|
|
4784
5211
|
"utf-8"
|
|
4785
5212
|
);
|
|
@@ -4809,221 +5236,6 @@ var init_sync = __esm({
|
|
|
4809
5236
|
}
|
|
4810
5237
|
});
|
|
4811
5238
|
|
|
4812
|
-
// src/commands/cleanup.ts
|
|
4813
|
-
var cleanup_exports = {};
|
|
4814
|
-
__export(cleanup_exports, {
|
|
4815
|
-
default: () => cleanup_default
|
|
4816
|
-
});
|
|
4817
|
-
import { defineCommand as defineCommand10 } from "citty";
|
|
4818
|
-
import pc15 from "picocolors";
|
|
4819
|
-
import { join as join24 } from "path";
|
|
4820
|
-
import { readFile as readFile15, writeFile as writeFile14, rm as rm6 } from "fs/promises";
|
|
4821
|
-
async function scanArtifacts(targetDir) {
|
|
4822
|
-
const actions = [];
|
|
4823
|
-
const localMePath = join24(targetDir, ".flydocs", "me.json");
|
|
4824
|
-
if (await pathExists(localMePath) && await pathExists(globalMePath())) {
|
|
4825
|
-
actions.push({
|
|
4826
|
-
description: "Remove .flydocs/me.json (migrated to ~/.flydocs/me.json)",
|
|
4827
|
-
path: localMePath,
|
|
4828
|
-
type: "file"
|
|
4829
|
-
});
|
|
4830
|
-
}
|
|
4831
|
-
const validationCachePath = join24(
|
|
4832
|
-
targetDir,
|
|
4833
|
-
".flydocs",
|
|
4834
|
-
"validation-cache.json"
|
|
4835
|
-
);
|
|
4836
|
-
if (await pathExists(validationCachePath)) {
|
|
4837
|
-
actions.push({
|
|
4838
|
-
description: "Remove .flydocs/validation-cache.json (replaced by configVersion)",
|
|
4839
|
-
path: validationCachePath,
|
|
4840
|
-
type: "file"
|
|
4841
|
-
});
|
|
4842
|
-
}
|
|
4843
|
-
const hasGlobalCreds = await pathExists(credentialsPath());
|
|
4844
|
-
for (const envFile of [".env", ".env.local"]) {
|
|
4845
|
-
const envPath = join24(targetDir, envFile);
|
|
4846
|
-
if (!await pathExists(envPath)) continue;
|
|
4847
|
-
const content = await readFile15(envPath, "utf-8");
|
|
4848
|
-
const lines = content.split("\n");
|
|
4849
|
-
for (const line of lines) {
|
|
4850
|
-
const trimmed = line.trim();
|
|
4851
|
-
if (hasGlobalCreds && trimmed.startsWith("FLYDOCS_API_KEY=")) {
|
|
4852
|
-
actions.push({
|
|
4853
|
-
description: `Remove FLYDOCS_API_KEY from ${envFile} (migrated to ~/.flydocs/credentials)`,
|
|
4854
|
-
path: envPath,
|
|
4855
|
-
type: "line"
|
|
4856
|
-
});
|
|
4857
|
-
}
|
|
4858
|
-
if (trimmed.startsWith("FLYDOCS_RELAY_URL=")) {
|
|
4859
|
-
actions.push({
|
|
4860
|
-
description: `Remove FLYDOCS_RELAY_URL from ${envFile}`,
|
|
4861
|
-
path: envPath,
|
|
4862
|
-
type: "line"
|
|
4863
|
-
});
|
|
4864
|
-
}
|
|
4865
|
-
}
|
|
4866
|
-
}
|
|
4867
|
-
try {
|
|
4868
|
-
const config = await readAnyConfig(targetDir);
|
|
4869
|
-
const rawContent = await readFile15(
|
|
4870
|
-
join24(targetDir, ".flydocs", "config.json"),
|
|
4871
|
-
"utf-8"
|
|
4872
|
-
);
|
|
4873
|
-
const raw = JSON.parse(rawContent);
|
|
4874
|
-
const ghostFields = ["provider", "statusMapping"];
|
|
4875
|
-
for (const field of ghostFields) {
|
|
4876
|
-
if (field in raw) {
|
|
4877
|
-
actions.push({
|
|
4878
|
-
description: `Remove ghost field "${field}" from config.json`,
|
|
4879
|
-
path: join24(targetDir, ".flydocs", "config.json"),
|
|
4880
|
-
type: "field"
|
|
4881
|
-
});
|
|
4882
|
-
}
|
|
4883
|
-
}
|
|
4884
|
-
if (isConfigV2(config)) {
|
|
4885
|
-
const v1OnlyFields = [
|
|
4886
|
-
"workspaceId",
|
|
4887
|
-
"issueLabels",
|
|
4888
|
-
"workspace",
|
|
4889
|
-
"onboardComplete",
|
|
4890
|
-
"sourceRepo",
|
|
4891
|
-
"designSystem",
|
|
4892
|
-
"aiLabor"
|
|
4893
|
-
];
|
|
4894
|
-
for (const field of v1OnlyFields) {
|
|
4895
|
-
if (field in raw) {
|
|
4896
|
-
actions.push({
|
|
4897
|
-
description: `Remove v1 field "${field}" from config.json (server-owned in v2)`,
|
|
4898
|
-
path: join24(targetDir, ".flydocs", "config.json"),
|
|
4899
|
-
type: "field"
|
|
4900
|
-
});
|
|
4901
|
-
}
|
|
4902
|
-
}
|
|
4903
|
-
}
|
|
4904
|
-
} catch {
|
|
4905
|
-
}
|
|
4906
|
-
return actions;
|
|
4907
|
-
}
|
|
4908
|
-
async function executeCleanup(targetDir, actions) {
|
|
4909
|
-
const fileRemovals = actions.filter((a) => a.type === "file");
|
|
4910
|
-
const lineRemovals = actions.filter((a) => a.type === "line");
|
|
4911
|
-
const fieldRemovals = actions.filter((a) => a.type === "field");
|
|
4912
|
-
for (const action of fileRemovals) {
|
|
4913
|
-
await rm6(action.path, { force: true });
|
|
4914
|
-
}
|
|
4915
|
-
const envFiles = /* @__PURE__ */ new Map();
|
|
4916
|
-
for (const action of lineRemovals) {
|
|
4917
|
-
if (!envFiles.has(action.path)) {
|
|
4918
|
-
const content = await readFile15(action.path, "utf-8");
|
|
4919
|
-
envFiles.set(action.path, content.split("\n"));
|
|
4920
|
-
}
|
|
4921
|
-
}
|
|
4922
|
-
for (const [envPath, lines] of envFiles) {
|
|
4923
|
-
const filtered = lines.filter((line) => {
|
|
4924
|
-
const trimmed = line.trim();
|
|
4925
|
-
return !trimmed.startsWith("FLYDOCS_API_KEY=") && !trimmed.startsWith("FLYDOCS_RELAY_URL=");
|
|
4926
|
-
});
|
|
4927
|
-
const hasContent = filtered.some(
|
|
4928
|
-
(l) => l.trim().length > 0 && !l.trim().startsWith("#")
|
|
4929
|
-
);
|
|
4930
|
-
if (!hasContent) {
|
|
4931
|
-
await rm6(envPath, { force: true });
|
|
4932
|
-
} else {
|
|
4933
|
-
await writeFile14(envPath, filtered.join("\n"), "utf-8");
|
|
4934
|
-
}
|
|
4935
|
-
}
|
|
4936
|
-
if (fieldRemovals.length > 0) {
|
|
4937
|
-
const configPath = join24(targetDir, ".flydocs", "config.json");
|
|
4938
|
-
const content = await readFile15(configPath, "utf-8");
|
|
4939
|
-
const config = JSON.parse(content);
|
|
4940
|
-
for (const action of fieldRemovals) {
|
|
4941
|
-
const match = action.description.match(/"(\w+)"/);
|
|
4942
|
-
if (match) {
|
|
4943
|
-
delete config[match[1]];
|
|
4944
|
-
}
|
|
4945
|
-
}
|
|
4946
|
-
await writeFile14(
|
|
4947
|
-
configPath,
|
|
4948
|
-
JSON.stringify(config, null, 2) + "\n",
|
|
4949
|
-
"utf-8"
|
|
4950
|
-
);
|
|
4951
|
-
}
|
|
4952
|
-
}
|
|
4953
|
-
var cleanup_default;
|
|
4954
|
-
var init_cleanup = __esm({
|
|
4955
|
-
"src/commands/cleanup.ts"() {
|
|
4956
|
-
"use strict";
|
|
4957
|
-
init_ui();
|
|
4958
|
-
init_fs_ops();
|
|
4959
|
-
init_config();
|
|
4960
|
-
init_types();
|
|
4961
|
-
init_global_config();
|
|
4962
|
-
cleanup_default = defineCommand10({
|
|
4963
|
-
meta: {
|
|
4964
|
-
name: "cleanup",
|
|
4965
|
-
description: "Remove legacy v1 artifacts after migration (dry-run by default)"
|
|
4966
|
-
},
|
|
4967
|
-
args: {
|
|
4968
|
-
confirm: {
|
|
4969
|
-
type: "boolean",
|
|
4970
|
-
description: "Actually remove artifacts (default: dry-run only)",
|
|
4971
|
-
default: false
|
|
4972
|
-
},
|
|
4973
|
-
path: {
|
|
4974
|
-
type: "string",
|
|
4975
|
-
description: "Path to project directory"
|
|
4976
|
-
}
|
|
4977
|
-
},
|
|
4978
|
-
async run({ args }) {
|
|
4979
|
-
const targetDir = args.path ?? process.cwd();
|
|
4980
|
-
console.log();
|
|
4981
|
-
console.log(` ${pc15.bold("FlyDocs Cleanup")}`);
|
|
4982
|
-
console.log();
|
|
4983
|
-
const hasConfig = await pathExists(
|
|
4984
|
-
join24(targetDir, ".flydocs", "config.json")
|
|
4985
|
-
);
|
|
4986
|
-
if (!hasConfig) {
|
|
4987
|
-
printError("No .flydocs/config.json found. Run flydocs init first.");
|
|
4988
|
-
process.exit(1);
|
|
4989
|
-
}
|
|
4990
|
-
const hasGlobalCreds = await pathExists(credentialsPath());
|
|
4991
|
-
if (!hasGlobalCreds) {
|
|
4992
|
-
printWarning(
|
|
4993
|
-
"No global credentials found. Run flydocs init to set up credentials before cleanup."
|
|
4994
|
-
);
|
|
4995
|
-
}
|
|
4996
|
-
const actions = await scanArtifacts(targetDir);
|
|
4997
|
-
if (actions.length === 0) {
|
|
4998
|
-
printStatus("No legacy artifacts found. Already clean.");
|
|
4999
|
-
console.log();
|
|
5000
|
-
return;
|
|
5001
|
-
}
|
|
5002
|
-
const mode = args.confirm ? "Removing" : "Would remove";
|
|
5003
|
-
printInfo(`${mode} ${actions.length} legacy artifact(s):`);
|
|
5004
|
-
console.log();
|
|
5005
|
-
for (const action of actions) {
|
|
5006
|
-
const icon = args.confirm ? pc15.red("-") : pc15.yellow("?");
|
|
5007
|
-
console.log(` ${icon} ${action.description}`);
|
|
5008
|
-
}
|
|
5009
|
-
console.log();
|
|
5010
|
-
if (!args.confirm) {
|
|
5011
|
-
printInfo(
|
|
5012
|
-
`Dry-run complete. Run ${pc15.cyan("flydocs cleanup --confirm")} to remove.`
|
|
5013
|
-
);
|
|
5014
|
-
console.log();
|
|
5015
|
-
return;
|
|
5016
|
-
}
|
|
5017
|
-
await executeCleanup(targetDir, actions);
|
|
5018
|
-
printCompletionBox("Cleanup Complete", [
|
|
5019
|
-
`${pc15.green("+")} Removed ${actions.length} legacy artifact(s)`
|
|
5020
|
-
]);
|
|
5021
|
-
console.log();
|
|
5022
|
-
}
|
|
5023
|
-
});
|
|
5024
|
-
}
|
|
5025
|
-
});
|
|
5026
|
-
|
|
5027
5239
|
// src/commands/upgrade.ts
|
|
5028
5240
|
var upgrade_exports = {};
|
|
5029
5241
|
__export(upgrade_exports, {
|