@flydocs/cli 0.6.0-alpha.27 → 0.6.0-alpha.28
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 +470 -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.28";
|
|
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,44 @@ 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
|
+
}
|
|
3295
3548
|
async function isParentDirectory(dir) {
|
|
3296
|
-
const hasGit = await pathExists(
|
|
3549
|
+
const hasGit = await pathExists(join20(dir, ".git"));
|
|
3297
3550
|
if (hasGit) return false;
|
|
3298
3551
|
const repos = await detectSiblingRepos(dir);
|
|
3299
3552
|
return Object.keys(repos).length >= 2;
|
|
@@ -3303,7 +3556,7 @@ async function runMultiRepoInit(parentDir, keyArg) {
|
|
|
3303
3556
|
const repoNames = Object.keys(repos).sort();
|
|
3304
3557
|
printInfo(`Detected ${repoNames.length} repos:`);
|
|
3305
3558
|
for (const name of repoNames) {
|
|
3306
|
-
console.log(` ${
|
|
3559
|
+
console.log(` ${pc8.cyan(name)}`);
|
|
3307
3560
|
}
|
|
3308
3561
|
console.log();
|
|
3309
3562
|
const shouldContinue = await confirm3({
|
|
@@ -3313,7 +3566,7 @@ async function runMultiRepoInit(parentDir, keyArg) {
|
|
|
3313
3566
|
cancel3("Init cancelled.");
|
|
3314
3567
|
process.exit(0);
|
|
3315
3568
|
}
|
|
3316
|
-
const firstRepoDir =
|
|
3569
|
+
const firstRepoDir = join20(parentDir, repoNames[0]);
|
|
3317
3570
|
const { apiKey, workspaceId } = await resolveAndValidateKey(
|
|
3318
3571
|
keyArg,
|
|
3319
3572
|
firstRepoDir
|
|
@@ -3325,9 +3578,10 @@ async function runMultiRepoInit(parentDir, keyArg) {
|
|
|
3325
3578
|
let allWarnings = [];
|
|
3326
3579
|
let firstResponse;
|
|
3327
3580
|
for (const repoName of repoNames) {
|
|
3328
|
-
const repoDir =
|
|
3581
|
+
const repoDir = join20(parentDir, repoName);
|
|
3329
3582
|
console.log();
|
|
3330
|
-
printInfo(`Initializing ${
|
|
3583
|
+
printInfo(`Initializing ${pc8.bold(repoName)}...`);
|
|
3584
|
+
await checkGitFreshness(repoDir);
|
|
3331
3585
|
const serverResponse = await pullServerConfig(apiKey, repoDir, workspaceId);
|
|
3332
3586
|
if (!firstResponse) firstResponse = serverResponse;
|
|
3333
3587
|
const { actions, skipped } = await initSingleRepo(
|
|
@@ -3356,47 +3610,60 @@ async function runMultiRepoInit(parentDir, keyArg) {
|
|
|
3356
3610
|
await writeWorkspaceFile(parentDir, workspaceFile);
|
|
3357
3611
|
allActions.push(`.flydocs-workspace.json (${repoNames.length} repos)`);
|
|
3358
3612
|
}
|
|
3359
|
-
const contextDir =
|
|
3360
|
-
const workspaceMdPath =
|
|
3613
|
+
const contextDir = join20(parentDir, "flydocs", "context");
|
|
3614
|
+
const workspaceMdPath = join20(contextDir, "workspace.md");
|
|
3361
3615
|
if (await pathExists(workspaceMdPath)) {
|
|
3362
3616
|
allSkipped.push("flydocs/context/workspace.md (already exists)");
|
|
3363
3617
|
} else {
|
|
3364
3618
|
await mkdir9(contextDir, { recursive: true });
|
|
3365
3619
|
const workspaceJson = await readWorkspaceFile(parentDir) ?? buildWorkspaceFile(firstResponse.workspaceId, repos);
|
|
3366
3620
|
const content = firstResponse.context?.workspaceMd ?? await generateWorkspaceMd(parentDir, workspaceJson);
|
|
3367
|
-
await
|
|
3621
|
+
await writeFile13(workspaceMdPath, content, "utf-8");
|
|
3368
3622
|
const source = firstResponse.context?.workspaceMd ? "from server" : "generated locally";
|
|
3369
3623
|
allActions.push(`Wrote flydocs/context/workspace.md (${source})`);
|
|
3370
3624
|
}
|
|
3371
3625
|
}
|
|
3372
3626
|
console.log();
|
|
3373
|
-
printInitReport(
|
|
3627
|
+
printInitReport(
|
|
3628
|
+
allActions,
|
|
3629
|
+
allSkipped,
|
|
3630
|
+
allWarnings,
|
|
3631
|
+
!!firstResponse?.context
|
|
3632
|
+
);
|
|
3374
3633
|
}
|
|
3375
|
-
function printInitReport(actions, skipped, warnings) {
|
|
3634
|
+
function printInitReport(actions, skipped, warnings, hasContext) {
|
|
3376
3635
|
console.log();
|
|
3377
3636
|
const lines = [];
|
|
3378
3637
|
for (const action of actions) {
|
|
3379
|
-
lines.push(`${
|
|
3638
|
+
lines.push(`${pc8.green("+")} ${action}`);
|
|
3380
3639
|
}
|
|
3381
3640
|
for (const skip of skipped) {
|
|
3382
|
-
lines.push(`${
|
|
3641
|
+
lines.push(`${pc8.dim("-")} ${skip}`);
|
|
3642
|
+
}
|
|
3643
|
+
if (!hasContext) {
|
|
3644
|
+
lines.push("");
|
|
3645
|
+
lines.push(
|
|
3646
|
+
`${pc8.yellow("!")} No generated context yet. An admin can generate it from the portal.`
|
|
3647
|
+
);
|
|
3383
3648
|
}
|
|
3384
3649
|
if (warnings.length > 0) {
|
|
3385
3650
|
lines.push("");
|
|
3386
3651
|
for (const warning of warnings) {
|
|
3387
|
-
lines.push(`${
|
|
3652
|
+
lines.push(`${pc8.yellow("!")} ${warning}`);
|
|
3388
3653
|
}
|
|
3389
3654
|
}
|
|
3390
3655
|
printCompletionBox("FlyDocs Initialized", lines);
|
|
3391
3656
|
console.log();
|
|
3392
3657
|
console.log(` Next steps:`);
|
|
3393
3658
|
console.log(
|
|
3394
|
-
` ${
|
|
3659
|
+
` ${pc8.cyan("flydocs sync")} Pull latest config and templates`
|
|
3660
|
+
);
|
|
3661
|
+
console.log(
|
|
3662
|
+
` ${pc8.cyan("cursor .")} ${pc8.dim("or")} ${pc8.cyan("code .")} Open your IDE, then use ${pc8.bold("/start-session")}`
|
|
3395
3663
|
);
|
|
3396
|
-
console.log(` ${pc7.cyan("/start-session")} \u2014 begin working`);
|
|
3397
3664
|
console.log();
|
|
3398
3665
|
}
|
|
3399
|
-
var init_default;
|
|
3666
|
+
var execFileAsync, init_default;
|
|
3400
3667
|
var init_init = __esm({
|
|
3401
3668
|
"src/commands/init.ts"() {
|
|
3402
3669
|
"use strict";
|
|
@@ -3408,8 +3675,10 @@ var init_init = __esm({
|
|
|
3408
3675
|
init_gitignore();
|
|
3409
3676
|
init_fs_ops();
|
|
3410
3677
|
init_relay_client();
|
|
3678
|
+
init_cleanup();
|
|
3411
3679
|
init_workspace();
|
|
3412
|
-
|
|
3680
|
+
execFileAsync = promisify(execFile);
|
|
3681
|
+
init_default = defineCommand3({
|
|
3413
3682
|
meta: {
|
|
3414
3683
|
name: "init",
|
|
3415
3684
|
description: "Initialize FlyDocs in this project (unified setup)"
|
|
@@ -3427,12 +3696,13 @@ var init_init = __esm({
|
|
|
3427
3696
|
async run({ args }) {
|
|
3428
3697
|
const targetDir = args.path ?? process.cwd();
|
|
3429
3698
|
console.log();
|
|
3430
|
-
console.log(` ${
|
|
3699
|
+
console.log(` ${pc8.bold("FlyDocs Init")}`);
|
|
3431
3700
|
console.log();
|
|
3432
3701
|
if (await isParentDirectory(targetDir)) {
|
|
3433
3702
|
await runMultiRepoInit(targetDir, args.key);
|
|
3434
3703
|
return;
|
|
3435
3704
|
}
|
|
3705
|
+
await checkGitFreshness(targetDir);
|
|
3436
3706
|
const { apiKey, workspaceId } = await resolveAndValidateKey(
|
|
3437
3707
|
args.key,
|
|
3438
3708
|
targetDir
|
|
@@ -3450,7 +3720,7 @@ var init_init = __esm({
|
|
|
3450
3720
|
actions.unshift("Stored credential globally (~/.flydocs/credentials)");
|
|
3451
3721
|
const topology = serverResponse.config.topology;
|
|
3452
3722
|
if (topology?.type === 4 && topology.label === "sibling-repos") {
|
|
3453
|
-
const parentDir =
|
|
3723
|
+
const parentDir = join20(targetDir, "..");
|
|
3454
3724
|
const existing = await readWorkspaceFile(parentDir);
|
|
3455
3725
|
if (existing) {
|
|
3456
3726
|
skipped.push(".flydocs-workspace.json (already exists)");
|
|
@@ -3468,7 +3738,12 @@ var init_init = __esm({
|
|
|
3468
3738
|
}
|
|
3469
3739
|
}
|
|
3470
3740
|
}
|
|
3471
|
-
printInitReport(
|
|
3741
|
+
printInitReport(
|
|
3742
|
+
actions,
|
|
3743
|
+
skipped,
|
|
3744
|
+
serverResponse.warnings,
|
|
3745
|
+
!!serverResponse.context
|
|
3746
|
+
);
|
|
3472
3747
|
}
|
|
3473
3748
|
});
|
|
3474
3749
|
}
|
|
@@ -3479,11 +3754,11 @@ var update_exports = {};
|
|
|
3479
3754
|
__export(update_exports, {
|
|
3480
3755
|
default: () => update_default
|
|
3481
3756
|
});
|
|
3482
|
-
import { defineCommand as
|
|
3483
|
-
import { resolve as resolve4, join as
|
|
3484
|
-
import { mkdir as mkdir10, cp as cp2, readFile as
|
|
3757
|
+
import { defineCommand as defineCommand4 } from "citty";
|
|
3758
|
+
import { resolve as resolve4, join as join21 } from "path";
|
|
3759
|
+
import { mkdir as mkdir10, cp as cp2, readFile as readFile15, readdir as readdir5, rm as rm5 } from "fs/promises";
|
|
3485
3760
|
import { select as select3, text as text3, confirm as confirm4, isCancel as isCancel5, cancel as cancel4 } from "@clack/prompts";
|
|
3486
|
-
import
|
|
3761
|
+
import pc9 from "picocolors";
|
|
3487
3762
|
var update_default;
|
|
3488
3763
|
var init_update = __esm({
|
|
3489
3764
|
"src/commands/update.ts"() {
|
|
@@ -3502,7 +3777,7 @@ var init_update = __esm({
|
|
|
3502
3777
|
init_update_check();
|
|
3503
3778
|
init_telemetry();
|
|
3504
3779
|
init_integrity();
|
|
3505
|
-
update_default =
|
|
3780
|
+
update_default = defineCommand4({
|
|
3506
3781
|
meta: {
|
|
3507
3782
|
name: "update",
|
|
3508
3783
|
description: "Update an existing FlyDocs installation"
|
|
@@ -3589,9 +3864,9 @@ var init_update = __esm({
|
|
|
3589
3864
|
}
|
|
3590
3865
|
targetDir = resolve4(targetDir);
|
|
3591
3866
|
process.chdir(targetDir);
|
|
3592
|
-
const hasVersion = await pathExists(
|
|
3867
|
+
const hasVersion = await pathExists(join21(targetDir, ".flydocs", "version"));
|
|
3593
3868
|
const hasConfig = await pathExists(
|
|
3594
|
-
|
|
3869
|
+
join21(targetDir, ".flydocs", "config.json")
|
|
3595
3870
|
);
|
|
3596
3871
|
if (!hasVersion && !hasConfig) {
|
|
3597
3872
|
printError(`Not a FlyDocs project: ${targetDir}`);
|
|
@@ -3602,8 +3877,8 @@ var init_update = __esm({
|
|
|
3602
3877
|
console.log();
|
|
3603
3878
|
let currentVersion = "0.1.0";
|
|
3604
3879
|
if (hasVersion) {
|
|
3605
|
-
const vContent = await
|
|
3606
|
-
|
|
3880
|
+
const vContent = await readFile15(
|
|
3881
|
+
join21(targetDir, ".flydocs", "version"),
|
|
3607
3882
|
"utf-8"
|
|
3608
3883
|
);
|
|
3609
3884
|
currentVersion = vContent.trim();
|
|
@@ -3637,10 +3912,10 @@ var init_update = __esm({
|
|
|
3637
3912
|
});
|
|
3638
3913
|
console.log(`Updating: v${currentVersion} \u2192 v${version}`);
|
|
3639
3914
|
console.log();
|
|
3640
|
-
const changelogPath =
|
|
3915
|
+
const changelogPath = join21(templateDir, "CHANGELOG.md");
|
|
3641
3916
|
const whatsNew = await getWhatsNew(changelogPath, currentVersion, version);
|
|
3642
3917
|
if (whatsNew.length > 0) {
|
|
3643
|
-
console.log(
|
|
3918
|
+
console.log(pc9.cyan("What's new:"));
|
|
3644
3919
|
console.log();
|
|
3645
3920
|
for (const entry of whatsNew) {
|
|
3646
3921
|
console.log(` ${entry}`);
|
|
@@ -3649,23 +3924,23 @@ var init_update = __esm({
|
|
|
3649
3924
|
}
|
|
3650
3925
|
const now = /* @__PURE__ */ new Date();
|
|
3651
3926
|
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 =
|
|
3927
|
+
const backupDir = join21(targetDir, ".flydocs", `backup-${ts}`);
|
|
3653
3928
|
await mkdir10(backupDir, { recursive: true });
|
|
3654
3929
|
if (hasConfig) {
|
|
3655
3930
|
await cp2(
|
|
3656
|
-
|
|
3657
|
-
|
|
3931
|
+
join21(targetDir, ".flydocs", "config.json"),
|
|
3932
|
+
join21(backupDir, "config.json")
|
|
3658
3933
|
);
|
|
3659
3934
|
printStatus(`Config backed up to .flydocs/backup-${ts}/`);
|
|
3660
3935
|
}
|
|
3661
3936
|
try {
|
|
3662
|
-
const flydocsDir =
|
|
3937
|
+
const flydocsDir = join21(targetDir, ".flydocs");
|
|
3663
3938
|
const entries = await readdir5(flydocsDir);
|
|
3664
3939
|
const backups = entries.filter((e) => e.startsWith("backup-")).sort();
|
|
3665
3940
|
if (backups.length > 3) {
|
|
3666
3941
|
const toRemove = backups.slice(0, backups.length - 3);
|
|
3667
3942
|
for (const old of toRemove) {
|
|
3668
|
-
await
|
|
3943
|
+
await rm5(join21(flydocsDir, old), { recursive: true, force: true });
|
|
3669
3944
|
}
|
|
3670
3945
|
}
|
|
3671
3946
|
} catch {
|
|
@@ -3704,17 +3979,17 @@ var init_update = __esm({
|
|
|
3704
3979
|
await ensureDirectories(targetDir, effectiveTier);
|
|
3705
3980
|
console.log("Replacing framework directories...");
|
|
3706
3981
|
await replaceDirectory(
|
|
3707
|
-
|
|
3708
|
-
|
|
3982
|
+
join21(templateDir, ".flydocs", "templates"),
|
|
3983
|
+
join21(targetDir, ".flydocs", "templates")
|
|
3709
3984
|
);
|
|
3710
3985
|
printStatus(".flydocs/templates");
|
|
3711
3986
|
await replaceDirectory(
|
|
3712
|
-
|
|
3713
|
-
|
|
3987
|
+
join21(templateDir, ".claude", "hooks"),
|
|
3988
|
+
join21(targetDir, ".claude", "hooks")
|
|
3714
3989
|
);
|
|
3715
3990
|
printStatus(".claude/hooks");
|
|
3716
3991
|
const hasExistingAgents = await pathExists(
|
|
3717
|
-
|
|
3992
|
+
join21(targetDir, ".claude", "agents")
|
|
3718
3993
|
);
|
|
3719
3994
|
let installAgents;
|
|
3720
3995
|
if (args.yes) {
|
|
@@ -3723,7 +3998,7 @@ var init_update = __esm({
|
|
|
3723
3998
|
installAgents = true;
|
|
3724
3999
|
} else {
|
|
3725
4000
|
console.log();
|
|
3726
|
-
console.log(` ${
|
|
4001
|
+
console.log(` ${pc9.bold(pc9.yellow("Sub-Agents (Recommended)"))}`);
|
|
3727
4002
|
console.log();
|
|
3728
4003
|
console.log(
|
|
3729
4004
|
" Sub-agents are specialized roles (PM, implementation, review,"
|
|
@@ -3746,20 +4021,20 @@ var init_update = __esm({
|
|
|
3746
4021
|
}
|
|
3747
4022
|
}
|
|
3748
4023
|
if (installAgents) {
|
|
3749
|
-
const claudeAgentsSrc =
|
|
4024
|
+
const claudeAgentsSrc = join21(templateDir, ".claude", "agents");
|
|
3750
4025
|
if (await pathExists(claudeAgentsSrc)) {
|
|
3751
|
-
await mkdir10(
|
|
4026
|
+
await mkdir10(join21(targetDir, ".claude", "agents"), { recursive: true });
|
|
3752
4027
|
await copyDirectoryContents(
|
|
3753
4028
|
claudeAgentsSrc,
|
|
3754
|
-
|
|
4029
|
+
join21(targetDir, ".claude", "agents")
|
|
3755
4030
|
);
|
|
3756
4031
|
}
|
|
3757
|
-
const cursorAgentsSrc =
|
|
4032
|
+
const cursorAgentsSrc = join21(templateDir, ".cursor", "agents");
|
|
3758
4033
|
if (await pathExists(cursorAgentsSrc)) {
|
|
3759
|
-
await mkdir10(
|
|
4034
|
+
await mkdir10(join21(targetDir, ".cursor", "agents"), { recursive: true });
|
|
3760
4035
|
await copyDirectoryContents(
|
|
3761
4036
|
cursorAgentsSrc,
|
|
3762
|
-
|
|
4037
|
+
join21(targetDir, ".cursor", "agents")
|
|
3763
4038
|
);
|
|
3764
4039
|
}
|
|
3765
4040
|
printStatus(
|
|
@@ -3773,47 +4048,47 @@ var init_update = __esm({
|
|
|
3773
4048
|
console.log();
|
|
3774
4049
|
console.log("Replacing framework files...");
|
|
3775
4050
|
await copyFile(
|
|
3776
|
-
|
|
3777
|
-
|
|
4051
|
+
join21(templateDir, ".claude", "CLAUDE.md"),
|
|
4052
|
+
join21(targetDir, ".claude", "CLAUDE.md")
|
|
3778
4053
|
);
|
|
3779
4054
|
await copyFile(
|
|
3780
|
-
|
|
3781
|
-
|
|
4055
|
+
join21(templateDir, ".claude", "settings.json"),
|
|
4056
|
+
join21(targetDir, ".claude", "settings.json")
|
|
3782
4057
|
);
|
|
3783
4058
|
printStatus(".claude/CLAUDE.md, settings.json");
|
|
3784
4059
|
await copyDirectoryContents(
|
|
3785
|
-
|
|
3786
|
-
|
|
4060
|
+
join21(templateDir, ".claude", "commands"),
|
|
4061
|
+
join21(targetDir, ".claude", "commands")
|
|
3787
4062
|
);
|
|
3788
4063
|
await copyDirectoryContents(
|
|
3789
|
-
|
|
3790
|
-
|
|
4064
|
+
join21(templateDir, ".claude", "commands"),
|
|
4065
|
+
join21(targetDir, ".cursor", "commands")
|
|
3791
4066
|
);
|
|
3792
4067
|
printStatus(".claude/commands, .cursor/commands");
|
|
3793
|
-
const skillsReadmeSrc =
|
|
4068
|
+
const skillsReadmeSrc = join21(templateDir, ".claude", "skills", "README.md");
|
|
3794
4069
|
if (await pathExists(skillsReadmeSrc)) {
|
|
3795
4070
|
await copyFile(
|
|
3796
4071
|
skillsReadmeSrc,
|
|
3797
|
-
|
|
4072
|
+
join21(targetDir, ".claude", "skills", "README.md")
|
|
3798
4073
|
);
|
|
3799
4074
|
}
|
|
3800
4075
|
printStatus(".claude/skills/README.md");
|
|
3801
4076
|
await copyFile(
|
|
3802
|
-
|
|
3803
|
-
|
|
4077
|
+
join21(templateDir, ".cursor", "hooks.json"),
|
|
4078
|
+
join21(targetDir, ".cursor", "hooks.json")
|
|
3804
4079
|
);
|
|
3805
4080
|
printStatus(".cursor/hooks.json");
|
|
3806
4081
|
await copyFile(
|
|
3807
|
-
|
|
3808
|
-
|
|
4082
|
+
join21(templateDir, "AGENTS.md"),
|
|
4083
|
+
join21(targetDir, "AGENTS.md")
|
|
3809
4084
|
);
|
|
3810
4085
|
printStatus("AGENTS.md");
|
|
3811
|
-
const envExampleSrc =
|
|
4086
|
+
const envExampleSrc = join21(templateDir, ".env.example");
|
|
3812
4087
|
if (await pathExists(envExampleSrc)) {
|
|
3813
|
-
await copyFile(envExampleSrc,
|
|
4088
|
+
await copyFile(envExampleSrc, join21(targetDir, ".env.example"));
|
|
3814
4089
|
printStatus(".env.example");
|
|
3815
4090
|
}
|
|
3816
|
-
const knowledgeTemplatesDir =
|
|
4091
|
+
const knowledgeTemplatesDir = join21(
|
|
3817
4092
|
targetDir,
|
|
3818
4093
|
"flydocs",
|
|
3819
4094
|
"knowledge",
|
|
@@ -3823,8 +4098,8 @@ var init_update = __esm({
|
|
|
3823
4098
|
await mkdir10(knowledgeTemplatesDir, { recursive: true });
|
|
3824
4099
|
}
|
|
3825
4100
|
for (const tmpl of ["decision.md", "feature.md", "note.md"]) {
|
|
3826
|
-
const src =
|
|
3827
|
-
const dest =
|
|
4101
|
+
const src = join21(templateDir, "flydocs", "knowledge", "templates", tmpl);
|
|
4102
|
+
const dest = join21(knowledgeTemplatesDir, tmpl);
|
|
3828
4103
|
if (await pathExists(src) && !await pathExists(dest)) {
|
|
3829
4104
|
await copyFile(src, dest);
|
|
3830
4105
|
}
|
|
@@ -3851,18 +4126,18 @@ var init_update = __esm({
|
|
|
3851
4126
|
printWarning("Config merge failed \u2014 config.json preserved as-is");
|
|
3852
4127
|
}
|
|
3853
4128
|
await copyFile(
|
|
3854
|
-
|
|
3855
|
-
|
|
4129
|
+
join21(templateDir, ".flydocs", "version"),
|
|
4130
|
+
join21(targetDir, ".flydocs", "version")
|
|
3856
4131
|
);
|
|
3857
4132
|
printStatus(`.flydocs/version \u2192 ${version}`);
|
|
3858
|
-
const clSrc =
|
|
4133
|
+
const clSrc = join21(templateDir, "CHANGELOG.md");
|
|
3859
4134
|
if (await pathExists(clSrc)) {
|
|
3860
|
-
await copyFile(clSrc,
|
|
4135
|
+
await copyFile(clSrc, join21(targetDir, ".flydocs", "CHANGELOG.md"));
|
|
3861
4136
|
printStatus(".flydocs/CHANGELOG.md");
|
|
3862
4137
|
}
|
|
3863
|
-
const mfSrc =
|
|
4138
|
+
const mfSrc = join21(templateDir, "manifest.json");
|
|
3864
4139
|
if (await pathExists(mfSrc)) {
|
|
3865
|
-
await copyFile(mfSrc,
|
|
4140
|
+
await copyFile(mfSrc, join21(targetDir, ".flydocs", "manifest.json"));
|
|
3866
4141
|
printStatus(".flydocs/manifest.json");
|
|
3867
4142
|
}
|
|
3868
4143
|
await generateIntegrity(targetDir, version);
|
|
@@ -3924,13 +4199,13 @@ var uninstall_exports = {};
|
|
|
3924
4199
|
__export(uninstall_exports, {
|
|
3925
4200
|
default: () => uninstall_default
|
|
3926
4201
|
});
|
|
3927
|
-
import { defineCommand as
|
|
3928
|
-
import { resolve as resolve5, join as
|
|
3929
|
-
import { readdir as readdir6, rm as
|
|
4202
|
+
import { defineCommand as defineCommand5 } from "citty";
|
|
4203
|
+
import { resolve as resolve5, join as join22 } from "path";
|
|
4204
|
+
import { readdir as readdir6, rm as rm6, rename as rename2 } from "fs/promises";
|
|
3930
4205
|
import { confirm as confirm5, select as select4, isCancel as isCancel6, cancel as cancel5 } from "@clack/prompts";
|
|
3931
|
-
import
|
|
4206
|
+
import pc10 from "picocolors";
|
|
3932
4207
|
async function removeOwnedSkills(targetDir) {
|
|
3933
|
-
const skillsDir =
|
|
4208
|
+
const skillsDir = join22(targetDir, ".claude", "skills");
|
|
3934
4209
|
const removed = [];
|
|
3935
4210
|
if (!await pathExists(skillsDir)) {
|
|
3936
4211
|
return removed;
|
|
@@ -3939,7 +4214,7 @@ async function removeOwnedSkills(targetDir) {
|
|
|
3939
4214
|
const entries = await readdir6(skillsDir);
|
|
3940
4215
|
for (const entry of entries) {
|
|
3941
4216
|
if (entry.startsWith(OWNED_SKILL_PREFIX)) {
|
|
3942
|
-
await
|
|
4217
|
+
await rm6(join22(skillsDir, entry), { recursive: true, force: true });
|
|
3943
4218
|
removed.push(`.claude/skills/${entry}`);
|
|
3944
4219
|
}
|
|
3945
4220
|
}
|
|
@@ -3948,7 +4223,7 @@ async function removeOwnedSkills(targetDir) {
|
|
|
3948
4223
|
return removed;
|
|
3949
4224
|
}
|
|
3950
4225
|
async function removeOwnedCursorRules(targetDir) {
|
|
3951
|
-
const rulesDir =
|
|
4226
|
+
const rulesDir = join22(targetDir, ".cursor", "rules");
|
|
3952
4227
|
const removed = [];
|
|
3953
4228
|
if (!await pathExists(rulesDir)) {
|
|
3954
4229
|
return removed;
|
|
@@ -3957,7 +4232,7 @@ async function removeOwnedCursorRules(targetDir) {
|
|
|
3957
4232
|
const entries = await readdir6(rulesDir);
|
|
3958
4233
|
for (const entry of entries) {
|
|
3959
4234
|
if (entry.startsWith(OWNED_RULE_PREFIX) && entry.endsWith(".mdc")) {
|
|
3960
|
-
await
|
|
4235
|
+
await rm6(join22(rulesDir, entry), { force: true });
|
|
3961
4236
|
removed.push(`.cursor/rules/${entry}`);
|
|
3962
4237
|
}
|
|
3963
4238
|
}
|
|
@@ -3976,9 +4251,9 @@ async function isEmptyDir(dirPath) {
|
|
|
3976
4251
|
async function cleanupEmptyParents(targetDir, dirs) {
|
|
3977
4252
|
const cleaned = [];
|
|
3978
4253
|
for (const dir of dirs) {
|
|
3979
|
-
const fullPath =
|
|
4254
|
+
const fullPath = join22(targetDir, dir);
|
|
3980
4255
|
if (await pathExists(fullPath) && await isEmptyDir(fullPath)) {
|
|
3981
|
-
await
|
|
4256
|
+
await rm6(fullPath, { recursive: true, force: true });
|
|
3982
4257
|
cleaned.push(dir);
|
|
3983
4258
|
}
|
|
3984
4259
|
}
|
|
@@ -4008,7 +4283,7 @@ var init_uninstall = __esm({
|
|
|
4008
4283
|
];
|
|
4009
4284
|
OWNED_SKILL_PREFIX = "flydocs-";
|
|
4010
4285
|
OWNED_RULE_PREFIX = "flydocs-";
|
|
4011
|
-
uninstall_default =
|
|
4286
|
+
uninstall_default = defineCommand5({
|
|
4012
4287
|
meta: {
|
|
4013
4288
|
name: "uninstall",
|
|
4014
4289
|
description: "Remove FlyDocs from a project directory"
|
|
@@ -4055,8 +4330,8 @@ var init_uninstall = __esm({
|
|
|
4055
4330
|
process.exit(1);
|
|
4056
4331
|
}
|
|
4057
4332
|
targetDir = resolve5(targetDir);
|
|
4058
|
-
const hasFlydocs = await pathExists(
|
|
4059
|
-
const hasAgentsMd = await pathExists(
|
|
4333
|
+
const hasFlydocs = await pathExists(join22(targetDir, ".flydocs"));
|
|
4334
|
+
const hasAgentsMd = await pathExists(join22(targetDir, "AGENTS.md"));
|
|
4060
4335
|
if (!hasFlydocs && !hasAgentsMd) {
|
|
4061
4336
|
printError(`Not a FlyDocs project: ${targetDir}`);
|
|
4062
4337
|
printInfo("No .flydocs/ directory or AGENTS.md found.");
|
|
@@ -4068,7 +4343,7 @@ var init_uninstall = __esm({
|
|
|
4068
4343
|
const removeAll = forceAll || args.all;
|
|
4069
4344
|
const skipPrompts = forceAll || args.yes;
|
|
4070
4345
|
let contentAction = "preserve";
|
|
4071
|
-
const hasUserContent = await pathExists(
|
|
4346
|
+
const hasUserContent = await pathExists(join22(targetDir, "flydocs"));
|
|
4072
4347
|
if (hasUserContent) {
|
|
4073
4348
|
if (removeAll) {
|
|
4074
4349
|
contentAction = "remove";
|
|
@@ -4102,34 +4377,34 @@ var init_uninstall = __esm({
|
|
|
4102
4377
|
}
|
|
4103
4378
|
if (!skipPrompts) {
|
|
4104
4379
|
console.log();
|
|
4105
|
-
console.log(
|
|
4380
|
+
console.log(pc10.bold("The following will be removed:"));
|
|
4106
4381
|
console.log();
|
|
4107
4382
|
console.log(" Framework files:");
|
|
4108
4383
|
for (const [path] of ALWAYS_REMOVED) {
|
|
4109
|
-
console.log(` ${
|
|
4384
|
+
console.log(` ${pc10.dim(path)}`);
|
|
4110
4385
|
}
|
|
4111
|
-
console.log(` ${
|
|
4112
|
-
console.log(` ${
|
|
4386
|
+
console.log(` ${pc10.dim(".claude/skills/flydocs-*")}`);
|
|
4387
|
+
console.log(` ${pc10.dim(".cursor/rules/flydocs-*.mdc")}`);
|
|
4113
4388
|
if (hasUserContent) {
|
|
4114
4389
|
if (contentAction === "archive") {
|
|
4115
4390
|
console.log();
|
|
4116
4391
|
console.log(
|
|
4117
|
-
` User content: ${
|
|
4392
|
+
` User content: ${pc10.yellow("flydocs/ -> flydocs-archive/")}`
|
|
4118
4393
|
);
|
|
4119
4394
|
} else if (contentAction === "remove") {
|
|
4120
4395
|
console.log();
|
|
4121
|
-
console.log(` User content: ${
|
|
4396
|
+
console.log(` User content: ${pc10.red("flydocs/ (deleted)")}`);
|
|
4122
4397
|
} else {
|
|
4123
4398
|
console.log();
|
|
4124
|
-
console.log(` User content: ${
|
|
4399
|
+
console.log(` User content: ${pc10.green("flydocs/ (preserved)")}`);
|
|
4125
4400
|
}
|
|
4126
4401
|
}
|
|
4127
4402
|
console.log();
|
|
4128
|
-
console.log(
|
|
4403
|
+
console.log(pc10.bold("Preserved:"));
|
|
4129
4404
|
console.log(
|
|
4130
|
-
` ${
|
|
4405
|
+
` ${pc10.dim(".claude/skills/ (non-flydocs community skills)")}`
|
|
4131
4406
|
);
|
|
4132
|
-
console.log(` ${
|
|
4407
|
+
console.log(` ${pc10.dim(".env, .env.local")}`);
|
|
4133
4408
|
console.log();
|
|
4134
4409
|
const shouldContinue = await confirm5({
|
|
4135
4410
|
message: "Proceed with uninstall?"
|
|
@@ -4151,16 +4426,16 @@ var init_uninstall = __esm({
|
|
|
4151
4426
|
const removedRules = await removeOwnedCursorRules(targetDir);
|
|
4152
4427
|
result.removed.push(...removedRules);
|
|
4153
4428
|
for (const [relativePath, type] of ALWAYS_REMOVED) {
|
|
4154
|
-
const fullPath =
|
|
4429
|
+
const fullPath = join22(targetDir, relativePath);
|
|
4155
4430
|
if (!await pathExists(fullPath)) {
|
|
4156
4431
|
result.skipped.push(relativePath);
|
|
4157
4432
|
continue;
|
|
4158
4433
|
}
|
|
4159
4434
|
try {
|
|
4160
4435
|
if (type === "dir") {
|
|
4161
|
-
await
|
|
4436
|
+
await rm6(fullPath, { recursive: true, force: true });
|
|
4162
4437
|
} else {
|
|
4163
|
-
await
|
|
4438
|
+
await rm6(fullPath, { force: true });
|
|
4164
4439
|
}
|
|
4165
4440
|
result.removed.push(relativePath);
|
|
4166
4441
|
} catch {
|
|
@@ -4169,16 +4444,16 @@ var init_uninstall = __esm({
|
|
|
4169
4444
|
}
|
|
4170
4445
|
}
|
|
4171
4446
|
if (hasUserContent) {
|
|
4172
|
-
const flydocsPath =
|
|
4447
|
+
const flydocsPath = join22(targetDir, "flydocs");
|
|
4173
4448
|
if (contentAction === "archive") {
|
|
4174
|
-
const archivePath =
|
|
4449
|
+
const archivePath = join22(targetDir, "flydocs-archive");
|
|
4175
4450
|
if (await pathExists(archivePath)) {
|
|
4176
|
-
await
|
|
4451
|
+
await rm6(archivePath, { recursive: true, force: true });
|
|
4177
4452
|
}
|
|
4178
4453
|
await rename2(flydocsPath, archivePath);
|
|
4179
4454
|
result.archived.push("flydocs/ -> flydocs-archive/");
|
|
4180
4455
|
} else if (contentAction === "remove") {
|
|
4181
|
-
await
|
|
4456
|
+
await rm6(flydocsPath, { recursive: true, force: true });
|
|
4182
4457
|
result.removed.push("flydocs/");
|
|
4183
4458
|
}
|
|
4184
4459
|
}
|
|
@@ -4197,17 +4472,17 @@ var init_uninstall = __esm({
|
|
|
4197
4472
|
result.restored = originals.map((f) => f.relativePath);
|
|
4198
4473
|
}
|
|
4199
4474
|
console.log();
|
|
4200
|
-
console.log(
|
|
4475
|
+
console.log(pc10.bold("Uninstall Summary"));
|
|
4201
4476
|
console.log();
|
|
4202
4477
|
if (result.removed.length > 0) {
|
|
4203
|
-
console.log(` ${
|
|
4478
|
+
console.log(` ${pc10.green("Removed")} (${result.removed.length}):`);
|
|
4204
4479
|
for (const item of result.removed) {
|
|
4205
4480
|
printStatus(item);
|
|
4206
4481
|
}
|
|
4207
4482
|
}
|
|
4208
4483
|
if (result.archived.length > 0) {
|
|
4209
4484
|
console.log();
|
|
4210
|
-
console.log(` ${
|
|
4485
|
+
console.log(` ${pc10.yellow("Archived")} (${result.archived.length}):`);
|
|
4211
4486
|
for (const item of result.archived) {
|
|
4212
4487
|
printInfo(item);
|
|
4213
4488
|
}
|
|
@@ -4215,7 +4490,7 @@ var init_uninstall = __esm({
|
|
|
4215
4490
|
if (result.restored.length > 0) {
|
|
4216
4491
|
console.log();
|
|
4217
4492
|
console.log(
|
|
4218
|
-
` ${
|
|
4493
|
+
` ${pc10.green("Restored")} (${result.restored.length} pre-FlyDocs original(s)):`
|
|
4219
4494
|
);
|
|
4220
4495
|
for (const item of result.restored) {
|
|
4221
4496
|
printInfo(item);
|
|
@@ -4224,16 +4499,16 @@ var init_uninstall = __esm({
|
|
|
4224
4499
|
if (result.skipped.length > 0) {
|
|
4225
4500
|
console.log();
|
|
4226
4501
|
console.log(
|
|
4227
|
-
` ${
|
|
4502
|
+
` ${pc10.dim("Skipped")} (${result.skipped.length} \u2014 not found):`
|
|
4228
4503
|
);
|
|
4229
4504
|
for (const item of result.skipped) {
|
|
4230
|
-
console.log(` ${
|
|
4505
|
+
console.log(` ${pc10.dim(item)}`);
|
|
4231
4506
|
}
|
|
4232
4507
|
}
|
|
4233
4508
|
console.log();
|
|
4234
4509
|
printStatus("FlyDocs has been removed from this project.");
|
|
4235
4510
|
console.log();
|
|
4236
|
-
printInfo(`To reinstall: ${
|
|
4511
|
+
printInfo(`To reinstall: ${pc10.cyan("npx @flydocs/cli install --here")}`);
|
|
4237
4512
|
console.log();
|
|
4238
4513
|
}
|
|
4239
4514
|
});
|
|
@@ -4245,28 +4520,28 @@ var setup_exports = {};
|
|
|
4245
4520
|
__export(setup_exports, {
|
|
4246
4521
|
default: () => setup_default
|
|
4247
4522
|
});
|
|
4248
|
-
import { defineCommand as
|
|
4249
|
-
import
|
|
4523
|
+
import { defineCommand as defineCommand6 } from "citty";
|
|
4524
|
+
import pc11 from "picocolors";
|
|
4250
4525
|
var setup_default;
|
|
4251
4526
|
var init_setup = __esm({
|
|
4252
4527
|
"src/commands/setup.ts"() {
|
|
4253
4528
|
"use strict";
|
|
4254
|
-
setup_default =
|
|
4529
|
+
setup_default = defineCommand6({
|
|
4255
4530
|
meta: {
|
|
4256
4531
|
name: "setup",
|
|
4257
4532
|
description: "Configure FlyDocs settings for this project"
|
|
4258
4533
|
},
|
|
4259
4534
|
run() {
|
|
4260
4535
|
console.log();
|
|
4261
|
-
console.log(` ${
|
|
4536
|
+
console.log(` ${pc11.bold("FlyDocs Setup")}`);
|
|
4262
4537
|
console.log();
|
|
4263
4538
|
console.log(` Setup runs inside your IDE as an interactive AI command.`);
|
|
4264
4539
|
console.log();
|
|
4265
4540
|
console.log(
|
|
4266
|
-
` ${
|
|
4541
|
+
` ${pc11.cyan("Claude Code:")} Type ${pc11.bold("/flydocs-setup")} in chat`
|
|
4267
4542
|
);
|
|
4268
4543
|
console.log(
|
|
4269
|
-
` ${
|
|
4544
|
+
` ${pc11.cyan("Cursor:")} Type ${pc11.bold("/flydocs-setup")} in chat`
|
|
4270
4545
|
);
|
|
4271
4546
|
console.log();
|
|
4272
4547
|
console.log(` This configures your project context, detects your stack,`);
|
|
@@ -4282,14 +4557,14 @@ var skills_exports = {};
|
|
|
4282
4557
|
__export(skills_exports, {
|
|
4283
4558
|
default: () => skills_default
|
|
4284
4559
|
});
|
|
4285
|
-
import { defineCommand as
|
|
4286
|
-
import
|
|
4560
|
+
import { defineCommand as defineCommand7 } from "citty";
|
|
4561
|
+
import pc12 from "picocolors";
|
|
4287
4562
|
var list, search, add, remove, skills_default;
|
|
4288
4563
|
var init_skills2 = __esm({
|
|
4289
4564
|
"src/commands/skills.ts"() {
|
|
4290
4565
|
"use strict";
|
|
4291
4566
|
init_skill_manager();
|
|
4292
|
-
list =
|
|
4567
|
+
list = defineCommand7({
|
|
4293
4568
|
meta: {
|
|
4294
4569
|
name: "list",
|
|
4295
4570
|
description: "List installed skills"
|
|
@@ -4305,26 +4580,26 @@ var init_skills2 = __esm({
|
|
|
4305
4580
|
console.log(`${total} skill(s) installed:`);
|
|
4306
4581
|
if (result.platform.length > 0) {
|
|
4307
4582
|
console.log();
|
|
4308
|
-
console.log(
|
|
4583
|
+
console.log(pc12.bold("Platform"));
|
|
4309
4584
|
for (const skill of result.platform) {
|
|
4310
4585
|
console.log(
|
|
4311
|
-
` ${skill.name} ${
|
|
4586
|
+
` ${skill.name} ${pc12.dim(`(${skill.triggers} triggers)`)}`
|
|
4312
4587
|
);
|
|
4313
4588
|
}
|
|
4314
4589
|
}
|
|
4315
4590
|
if (result.community.length > 0) {
|
|
4316
4591
|
console.log();
|
|
4317
|
-
console.log(
|
|
4592
|
+
console.log(pc12.bold("Community"));
|
|
4318
4593
|
for (const skill of result.community) {
|
|
4319
4594
|
console.log(
|
|
4320
|
-
` ${skill.name} ${
|
|
4595
|
+
` ${skill.name} ${pc12.dim(`(${skill.triggers} triggers)`)}`
|
|
4321
4596
|
);
|
|
4322
4597
|
}
|
|
4323
4598
|
}
|
|
4324
4599
|
console.log();
|
|
4325
4600
|
}
|
|
4326
4601
|
});
|
|
4327
|
-
search =
|
|
4602
|
+
search = defineCommand7({
|
|
4328
4603
|
meta: {
|
|
4329
4604
|
name: "search",
|
|
4330
4605
|
description: "Search community skills"
|
|
@@ -4340,24 +4615,24 @@ var init_skills2 = __esm({
|
|
|
4340
4615
|
const results = await searchCatalog(args.keyword);
|
|
4341
4616
|
if (results.length === 0) {
|
|
4342
4617
|
console.log(`No skills found for "${args.keyword}".`);
|
|
4343
|
-
console.log(` Browse the catalog at: ${
|
|
4618
|
+
console.log(` Browse the catalog at: ${pc12.cyan("https://skills.sh/")}`);
|
|
4344
4619
|
return;
|
|
4345
4620
|
}
|
|
4346
4621
|
console.log();
|
|
4347
4622
|
console.log(`${results.length} skill(s) matching "${args.keyword}":`);
|
|
4348
4623
|
console.log();
|
|
4349
4624
|
for (const skill of results) {
|
|
4350
|
-
console.log(` ${
|
|
4625
|
+
console.log(` ${pc12.bold(skill.name)}`);
|
|
4351
4626
|
console.log(` ${skill.description}`);
|
|
4352
|
-
console.log(` ${
|
|
4627
|
+
console.log(` ${pc12.dim(skill.repo)}`);
|
|
4353
4628
|
if (skill.tags.length > 0) {
|
|
4354
|
-
console.log(` ${
|
|
4629
|
+
console.log(` ${pc12.dim(skill.tags.join(", "))}`);
|
|
4355
4630
|
}
|
|
4356
4631
|
console.log();
|
|
4357
4632
|
}
|
|
4358
4633
|
}
|
|
4359
4634
|
});
|
|
4360
|
-
add =
|
|
4635
|
+
add = defineCommand7({
|
|
4361
4636
|
meta: {
|
|
4362
4637
|
name: "add",
|
|
4363
4638
|
description: "Install a community skill"
|
|
@@ -4373,7 +4648,7 @@ var init_skills2 = __esm({
|
|
|
4373
4648
|
await addSkill(process.cwd(), args.source);
|
|
4374
4649
|
}
|
|
4375
4650
|
});
|
|
4376
|
-
remove =
|
|
4651
|
+
remove = defineCommand7({
|
|
4377
4652
|
meta: {
|
|
4378
4653
|
name: "remove",
|
|
4379
4654
|
description: "Remove an installed community skill"
|
|
@@ -4389,7 +4664,7 @@ var init_skills2 = __esm({
|
|
|
4389
4664
|
await removeSkill(process.cwd(), args.name);
|
|
4390
4665
|
}
|
|
4391
4666
|
});
|
|
4392
|
-
skills_default =
|
|
4667
|
+
skills_default = defineCommand7({
|
|
4393
4668
|
meta: {
|
|
4394
4669
|
name: "skills",
|
|
4395
4670
|
description: "Manage FlyDocs skills (list, search, add, remove)"
|
|
@@ -4409,10 +4684,10 @@ var connect_exports = {};
|
|
|
4409
4684
|
__export(connect_exports, {
|
|
4410
4685
|
default: () => connect_default
|
|
4411
4686
|
});
|
|
4412
|
-
import { defineCommand as
|
|
4687
|
+
import { defineCommand as defineCommand8 } from "citty";
|
|
4413
4688
|
import { text as text4, confirm as confirm6, isCancel as isCancel7, cancel as cancel6 } from "@clack/prompts";
|
|
4414
|
-
import
|
|
4415
|
-
import { join as
|
|
4689
|
+
import pc13 from "picocolors";
|
|
4690
|
+
import { join as join23 } from "path";
|
|
4416
4691
|
var connect_default;
|
|
4417
4692
|
var init_connect = __esm({
|
|
4418
4693
|
"src/commands/connect.ts"() {
|
|
@@ -4422,7 +4697,7 @@ var init_connect = __esm({
|
|
|
4422
4697
|
init_template();
|
|
4423
4698
|
init_ui();
|
|
4424
4699
|
init_api_key();
|
|
4425
|
-
connect_default =
|
|
4700
|
+
connect_default = defineCommand8({
|
|
4426
4701
|
meta: {
|
|
4427
4702
|
name: "connect",
|
|
4428
4703
|
description: "Connect FlyDocs to a cloud provider"
|
|
@@ -4447,11 +4722,11 @@ var init_connect = __esm({
|
|
|
4447
4722
|
},
|
|
4448
4723
|
async run({ args }) {
|
|
4449
4724
|
const targetDir = args.path ?? process.cwd();
|
|
4450
|
-
const configPath =
|
|
4725
|
+
const configPath = join23(targetDir, ".flydocs", "config.json");
|
|
4451
4726
|
if (!await pathExists(configPath)) {
|
|
4452
4727
|
printError("Not a FlyDocs project (.flydocs/config.json not found).");
|
|
4453
4728
|
console.log(
|
|
4454
|
-
` Run ${
|
|
4729
|
+
` Run ${pc13.cyan("flydocs")} first to install FlyDocs in this project.`
|
|
4455
4730
|
);
|
|
4456
4731
|
process.exit(1);
|
|
4457
4732
|
}
|
|
@@ -4468,10 +4743,10 @@ var init_connect = __esm({
|
|
|
4468
4743
|
}
|
|
4469
4744
|
}
|
|
4470
4745
|
console.log();
|
|
4471
|
-
console.log(` ${
|
|
4746
|
+
console.log(` ${pc13.bold("Connect to FlyDocs Cloud")}`);
|
|
4472
4747
|
console.log();
|
|
4473
4748
|
console.log(
|
|
4474
|
-
` ${
|
|
4749
|
+
` ${pc13.dim("Get your API key (fdk_...) from your FlyDocs dashboard")}`
|
|
4475
4750
|
);
|
|
4476
4751
|
console.log();
|
|
4477
4752
|
let apiKey = args.key ?? "";
|
|
@@ -4509,7 +4784,7 @@ var init_connect = __esm({
|
|
|
4509
4784
|
console.log(` Check your key and try again.`);
|
|
4510
4785
|
process.exit(1);
|
|
4511
4786
|
}
|
|
4512
|
-
printStatus(`Connected to ${
|
|
4787
|
+
printStatus(`Connected to ${pc13.bold(result.org)}`);
|
|
4513
4788
|
} catch {
|
|
4514
4789
|
printError(
|
|
4515
4790
|
"Could not reach relay API. Check your network and try again."
|
|
@@ -4517,7 +4792,7 @@ var init_connect = __esm({
|
|
|
4517
4792
|
process.exit(1);
|
|
4518
4793
|
}
|
|
4519
4794
|
const envFile = await storeEnvKey(targetDir, "FLYDOCS_API_KEY", apiKey);
|
|
4520
|
-
printStatus(`API key stored in ${
|
|
4795
|
+
printStatus(`API key stored in ${pc13.dim(envFile)}`);
|
|
4521
4796
|
} else {
|
|
4522
4797
|
try {
|
|
4523
4798
|
const result = await validateLinearKey(apiKey);
|
|
@@ -4527,7 +4802,7 @@ var init_connect = __esm({
|
|
|
4527
4802
|
process.exit(1);
|
|
4528
4803
|
}
|
|
4529
4804
|
printStatus(
|
|
4530
|
-
`Authenticated as ${
|
|
4805
|
+
`Authenticated as ${pc13.bold(result.name)} (${result.email})`
|
|
4531
4806
|
);
|
|
4532
4807
|
} catch {
|
|
4533
4808
|
printError("Invalid API key or network error.");
|
|
@@ -4535,7 +4810,7 @@ var init_connect = __esm({
|
|
|
4535
4810
|
process.exit(1);
|
|
4536
4811
|
}
|
|
4537
4812
|
const envFile = await storeEnvKey(targetDir, "LINEAR_API_KEY", apiKey);
|
|
4538
|
-
printStatus(`API key stored in ${
|
|
4813
|
+
printStatus(`API key stored in ${pc13.dim(envFile)}`);
|
|
4539
4814
|
}
|
|
4540
4815
|
const wasLocal = config.tier === "local";
|
|
4541
4816
|
config.tier = "cloud";
|
|
@@ -4551,14 +4826,14 @@ var init_connect = __esm({
|
|
|
4551
4826
|
}
|
|
4552
4827
|
console.log();
|
|
4553
4828
|
console.log(
|
|
4554
|
-
` ${
|
|
4829
|
+
` ${pc13.bold("Connected!")} Your project is now on the cloud tier.`
|
|
4555
4830
|
);
|
|
4556
4831
|
console.log();
|
|
4557
4832
|
console.log(` Next steps:`);
|
|
4558
4833
|
console.log(
|
|
4559
|
-
` 1. Run ${
|
|
4834
|
+
` 1. Run ${pc13.cyan("/flydocs-setup")} in your IDE to configure your project`
|
|
4560
4835
|
);
|
|
4561
|
-
console.log(` 2. Run ${
|
|
4836
|
+
console.log(` 2. Run ${pc13.cyan("/start-session")} to begin working`);
|
|
4562
4837
|
console.log();
|
|
4563
4838
|
}
|
|
4564
4839
|
});
|
|
@@ -4570,9 +4845,9 @@ var auth_exports = {};
|
|
|
4570
4845
|
__export(auth_exports, {
|
|
4571
4846
|
default: () => auth_default
|
|
4572
4847
|
});
|
|
4573
|
-
import { defineCommand as
|
|
4848
|
+
import { defineCommand as defineCommand9 } from "citty";
|
|
4574
4849
|
import { text as text5, confirm as confirm7, isCancel as isCancel8, cancel as cancel7 } from "@clack/prompts";
|
|
4575
|
-
import
|
|
4850
|
+
import pc14 from "picocolors";
|
|
4576
4851
|
var auth_default;
|
|
4577
4852
|
var init_auth = __esm({
|
|
4578
4853
|
"src/commands/auth.ts"() {
|
|
@@ -4580,7 +4855,7 @@ var init_auth = __esm({
|
|
|
4580
4855
|
init_ui();
|
|
4581
4856
|
init_api_key();
|
|
4582
4857
|
init_global_config();
|
|
4583
|
-
auth_default =
|
|
4858
|
+
auth_default = defineCommand9({
|
|
4584
4859
|
meta: {
|
|
4585
4860
|
name: "auth",
|
|
4586
4861
|
description: "Store API key globally (~/.flydocs/credentials)"
|
|
@@ -4594,13 +4869,13 @@ var init_auth = __esm({
|
|
|
4594
4869
|
},
|
|
4595
4870
|
async run({ args }) {
|
|
4596
4871
|
console.log();
|
|
4597
|
-
console.log(` ${
|
|
4872
|
+
console.log(` ${pc14.bold("FlyDocs Authentication")}`);
|
|
4598
4873
|
console.log();
|
|
4599
4874
|
let apiKey = args.key ?? "";
|
|
4600
4875
|
const existing = await readGlobalCredential();
|
|
4601
4876
|
if (existing?.apiKey && !apiKey) {
|
|
4602
4877
|
printInfo(
|
|
4603
|
-
`Existing key found: ${
|
|
4878
|
+
`Existing key found: ${pc14.dim(existing.apiKey.slice(0, 8) + "...")}`
|
|
4604
4879
|
);
|
|
4605
4880
|
const replace = await confirm7({
|
|
4606
4881
|
message: "Replace with a new key?"
|
|
@@ -4612,7 +4887,7 @@ var init_auth = __esm({
|
|
|
4612
4887
|
}
|
|
4613
4888
|
if (!apiKey) {
|
|
4614
4889
|
console.log(
|
|
4615
|
-
` ${
|
|
4890
|
+
` ${pc14.dim("Get your API key (fdk_...) from your FlyDocs dashboard")}`
|
|
4616
4891
|
);
|
|
4617
4892
|
console.log();
|
|
4618
4893
|
const keyInput = await text5({
|
|
@@ -4648,7 +4923,7 @@ var init_auth = __esm({
|
|
|
4648
4923
|
printError("Invalid API key. Check your key and try again.");
|
|
4649
4924
|
process.exit(1);
|
|
4650
4925
|
}
|
|
4651
|
-
printStatus(`Authenticated with ${
|
|
4926
|
+
printStatus(`Authenticated with ${pc14.bold(result.org)}`);
|
|
4652
4927
|
} catch {
|
|
4653
4928
|
printError(
|
|
4654
4929
|
"Could not reach FlyDocs API. Check your network and try again."
|
|
@@ -4663,10 +4938,10 @@ var init_auth = __esm({
|
|
|
4663
4938
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4664
4939
|
lastValidated: (/* @__PURE__ */ new Date()).toISOString()
|
|
4665
4940
|
});
|
|
4666
|
-
printStatus(`Key stored at ${
|
|
4941
|
+
printStatus(`Key stored at ${pc14.dim(credentialsPath())}`);
|
|
4667
4942
|
await checkCredentialPermissions();
|
|
4668
4943
|
console.log();
|
|
4669
|
-
console.log(` ${
|
|
4944
|
+
console.log(` ${pc14.bold("Authenticated!")} Key stored globally.`);
|
|
4670
4945
|
console.log(` All FlyDocs projects on this machine will use this key.`);
|
|
4671
4946
|
console.log();
|
|
4672
4947
|
}
|
|
@@ -4679,10 +4954,10 @@ var sync_exports = {};
|
|
|
4679
4954
|
__export(sync_exports, {
|
|
4680
4955
|
default: () => sync_default
|
|
4681
4956
|
});
|
|
4682
|
-
import { defineCommand as
|
|
4683
|
-
import
|
|
4684
|
-
import { join as
|
|
4685
|
-
import { mkdir as mkdir11, writeFile as
|
|
4957
|
+
import { defineCommand as defineCommand10 } from "citty";
|
|
4958
|
+
import pc15 from "picocolors";
|
|
4959
|
+
import { join as join24 } from "path";
|
|
4960
|
+
import { mkdir as mkdir11, writeFile as writeFile14 } from "fs/promises";
|
|
4686
4961
|
var sync_default;
|
|
4687
4962
|
var init_sync = __esm({
|
|
4688
4963
|
"src/commands/sync.ts"() {
|
|
@@ -4694,7 +4969,7 @@ var init_sync = __esm({
|
|
|
4694
4969
|
init_fs_ops();
|
|
4695
4970
|
init_types();
|
|
4696
4971
|
init_relay_client();
|
|
4697
|
-
sync_default =
|
|
4972
|
+
sync_default = defineCommand10({
|
|
4698
4973
|
meta: {
|
|
4699
4974
|
name: "sync",
|
|
4700
4975
|
description: "Pull latest config and templates from server"
|
|
@@ -4745,14 +5020,14 @@ var init_sync = __esm({
|
|
|
4745
5020
|
} else {
|
|
4746
5021
|
printWarning("Server unreachable, using cached config.");
|
|
4747
5022
|
}
|
|
4748
|
-
console.log(` ${
|
|
5023
|
+
console.log(` ${pc15.dim("Config may be stale. Retry when connected.")}`);
|
|
4749
5024
|
return;
|
|
4750
5025
|
}
|
|
4751
5026
|
if (!serverResponse.valid) {
|
|
4752
5027
|
printWarning("Server returned invalid config. Keeping current config.");
|
|
4753
5028
|
return;
|
|
4754
5029
|
}
|
|
4755
|
-
await mkdir11(
|
|
5030
|
+
await mkdir11(join24(targetDir, ".flydocs"), { recursive: true });
|
|
4756
5031
|
const configWithHash = applyConfigHash(serverResponse.config);
|
|
4757
5032
|
await writeConfig(targetDir, configWithHash);
|
|
4758
5033
|
changes.push("Updated .flydocs/config.json");
|
|
@@ -4765,7 +5040,7 @@ var init_sync = __esm({
|
|
|
4765
5040
|
workspaceId
|
|
4766
5041
|
);
|
|
4767
5042
|
if (templatesResponse.templates.length > 0) {
|
|
4768
|
-
const templatesDir =
|
|
5043
|
+
const templatesDir = join24(
|
|
4769
5044
|
targetDir,
|
|
4770
5045
|
".claude",
|
|
4771
5046
|
"skills",
|
|
@@ -4776,10 +5051,10 @@ var init_sync = __esm({
|
|
|
4776
5051
|
for (const template of templatesResponse.templates) {
|
|
4777
5052
|
const filename = `${template.type}.md`;
|
|
4778
5053
|
const subdir = template.category === "issue" ? "issues" : template.category === "pr" ? "pr" : template.category === "comment" ? "." : ".";
|
|
4779
|
-
const templateDir =
|
|
5054
|
+
const templateDir = join24(templatesDir, subdir);
|
|
4780
5055
|
await mkdir11(templateDir, { recursive: true });
|
|
4781
|
-
await
|
|
4782
|
-
|
|
5056
|
+
await writeFile14(
|
|
5057
|
+
join24(templateDir, filename),
|
|
4783
5058
|
template.content,
|
|
4784
5059
|
"utf-8"
|
|
4785
5060
|
);
|
|
@@ -4809,221 +5084,6 @@ var init_sync = __esm({
|
|
|
4809
5084
|
}
|
|
4810
5085
|
});
|
|
4811
5086
|
|
|
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
5087
|
// src/commands/upgrade.ts
|
|
5028
5088
|
var upgrade_exports = {};
|
|
5029
5089
|
__export(upgrade_exports, {
|