@flydocs/cli 0.6.0-alpha.24 → 0.6.0-alpha.26
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 +1342 -205
- package/package.json +1 -1
- package/template/.claude/hooks/session-start.py +117 -1
- package/template/.claude/skills/flydocs-workflow/reference/service-descriptor-schema.md +13 -4
- package/template/.claude/skills/flydocs-workflow/scripts/graph_build.py +2 -2
- 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.26";
|
|
19
19
|
CLI_NAME = "flydocs";
|
|
20
20
|
PACKAGE_NAME = "@flydocs/cli";
|
|
21
21
|
POSTHOG_API_KEY = "phc_v1MSJTQDFkMS90CBh3mxIz3v8bYCCnKU6v1ir6bz0Xn";
|
|
@@ -136,8 +136,8 @@ var init_template = __esm({
|
|
|
136
136
|
|
|
137
137
|
// src/lib/ui.ts
|
|
138
138
|
import pc2 from "picocolors";
|
|
139
|
-
function shadow(
|
|
140
|
-
return `\x1B[38;2;55;45;70m${
|
|
139
|
+
function shadow(text6) {
|
|
140
|
+
return `\x1B[38;2;55;45;70m${text6}\x1B[0m`;
|
|
141
141
|
}
|
|
142
142
|
function renderBannerBlock() {
|
|
143
143
|
const height = BANNER_ROWS.length;
|
|
@@ -268,12 +268,70 @@ var init_ui = __esm({
|
|
|
268
268
|
}
|
|
269
269
|
});
|
|
270
270
|
|
|
271
|
+
// src/lib/types.ts
|
|
272
|
+
function isConfigV2(config) {
|
|
273
|
+
return config.configFormat === 2;
|
|
274
|
+
}
|
|
275
|
+
var init_types = __esm({
|
|
276
|
+
"src/lib/types.ts"() {
|
|
277
|
+
"use strict";
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
// src/lib/config-integrity.ts
|
|
282
|
+
import { createHash } from "crypto";
|
|
283
|
+
function computeConfigHash(config) {
|
|
284
|
+
const { configHash: _, ...rest } = config;
|
|
285
|
+
const serialized = JSON.stringify(rest, Object.keys(rest).sort());
|
|
286
|
+
return `sha256:${createHash("sha256").update(serialized, "utf-8").digest("hex")}`;
|
|
287
|
+
}
|
|
288
|
+
function validateConfigIntegrity(config) {
|
|
289
|
+
if (!config.configHash) return false;
|
|
290
|
+
const computed = computeConfigHash(config);
|
|
291
|
+
return computed === config.configHash;
|
|
292
|
+
}
|
|
293
|
+
function checkConfigIntegrity(config) {
|
|
294
|
+
if (!config.configHash) {
|
|
295
|
+
return true;
|
|
296
|
+
}
|
|
297
|
+
const valid = validateConfigIntegrity(config);
|
|
298
|
+
if (!valid) {
|
|
299
|
+
printWarning(
|
|
300
|
+
"Config modified locally \u2014 will restore from server on next sync."
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
return valid;
|
|
304
|
+
}
|
|
305
|
+
function applyConfigHash(config) {
|
|
306
|
+
const hash = computeConfigHash(config);
|
|
307
|
+
return { ...config, configHash: hash };
|
|
308
|
+
}
|
|
309
|
+
var init_config_integrity = __esm({
|
|
310
|
+
"src/lib/config-integrity.ts"() {
|
|
311
|
+
"use strict";
|
|
312
|
+
init_ui();
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
|
|
271
316
|
// src/lib/config.ts
|
|
272
317
|
import { readFile as readFile2, writeFile } from "fs/promises";
|
|
273
318
|
import { join as join3 } from "path";
|
|
274
|
-
async function
|
|
319
|
+
async function readAnyConfig(dir) {
|
|
275
320
|
const content = await readFile2(join3(dir, ".flydocs", "config.json"), "utf-8");
|
|
276
|
-
|
|
321
|
+
const config = JSON.parse(content);
|
|
322
|
+
if (isConfigV2(config)) {
|
|
323
|
+
checkConfigIntegrity(config);
|
|
324
|
+
}
|
|
325
|
+
return config;
|
|
326
|
+
}
|
|
327
|
+
async function readConfig(dir) {
|
|
328
|
+
const config = await readAnyConfig(dir);
|
|
329
|
+
if (isConfigV2(config)) {
|
|
330
|
+
throw new Error(
|
|
331
|
+
"This command requires v1 config format. Run `flydocs sync` to use v2 commands."
|
|
332
|
+
);
|
|
333
|
+
}
|
|
334
|
+
return config;
|
|
277
335
|
}
|
|
278
336
|
async function writeConfig(dir, config) {
|
|
279
337
|
const content = JSON.stringify(config, null, 2) + "\n";
|
|
@@ -343,6 +401,8 @@ async function mergeConfig(templateDir, version, tierFlag, preserved) {
|
|
|
343
401
|
var init_config = __esm({
|
|
344
402
|
"src/lib/config.ts"() {
|
|
345
403
|
"use strict";
|
|
404
|
+
init_types();
|
|
405
|
+
init_config_integrity();
|
|
346
406
|
}
|
|
347
407
|
});
|
|
348
408
|
|
|
@@ -363,7 +423,7 @@ async function installOwnedSkills(templateDir, targetDir, _tier) {
|
|
|
363
423
|
async function replaceOwnedSkills(templateDir, targetDir, _tier) {
|
|
364
424
|
const skillsDir = join4(targetDir, ".claude", "skills");
|
|
365
425
|
const templateSkillsDir = join4(templateDir, ".claude", "skills");
|
|
366
|
-
const { rm:
|
|
426
|
+
const { rm: rm7 } = await import("fs/promises");
|
|
367
427
|
await replaceDirectory(
|
|
368
428
|
join4(templateSkillsDir, OWNED_SKILL),
|
|
369
429
|
join4(skillsDir, OWNED_SKILL)
|
|
@@ -371,7 +431,7 @@ async function replaceOwnedSkills(templateDir, targetDir, _tier) {
|
|
|
371
431
|
for (const legacy of LEGACY_SKILLS) {
|
|
372
432
|
const legacyPath = join4(skillsDir, legacy);
|
|
373
433
|
if (await pathExists(legacyPath)) {
|
|
374
|
-
await
|
|
434
|
+
await rm7(legacyPath, { recursive: true, force: true });
|
|
375
435
|
}
|
|
376
436
|
}
|
|
377
437
|
const readmeSrc = join4(templateSkillsDir, "README.md");
|
|
@@ -380,9 +440,9 @@ async function replaceOwnedSkills(templateDir, targetDir, _tier) {
|
|
|
380
440
|
}
|
|
381
441
|
}
|
|
382
442
|
async function copyCursorRules(targetDir) {
|
|
383
|
-
const { mkdir:
|
|
443
|
+
const { mkdir: mkdir12 } = await import("fs/promises");
|
|
384
444
|
const rulesDir = join4(targetDir, ".cursor", "rules");
|
|
385
|
-
await
|
|
445
|
+
await mkdir12(rulesDir, { recursive: true });
|
|
386
446
|
const workflowRule = join4(
|
|
387
447
|
targetDir,
|
|
388
448
|
".claude",
|
|
@@ -393,11 +453,11 @@ async function copyCursorRules(targetDir) {
|
|
|
393
453
|
if (await pathExists(workflowRule)) {
|
|
394
454
|
await copyFile(workflowRule, join4(rulesDir, "flydocs-workflow.mdc"));
|
|
395
455
|
}
|
|
396
|
-
const { rm:
|
|
456
|
+
const { rm: rm7 } = await import("fs/promises");
|
|
397
457
|
for (const legacy of ["flydocs-mechanism.mdc", "flydocs-context7.mdc"]) {
|
|
398
458
|
const legacyRule = join4(rulesDir, legacy);
|
|
399
459
|
if (await pathExists(legacyRule)) {
|
|
400
|
-
await
|
|
460
|
+
await rm7(legacyRule, { force: true });
|
|
401
461
|
}
|
|
402
462
|
}
|
|
403
463
|
}
|
|
@@ -715,8 +775,8 @@ function flushFrontmatterValue(mode, lines) {
|
|
|
715
775
|
return lines.join("\n").trim();
|
|
716
776
|
}
|
|
717
777
|
}
|
|
718
|
-
function parseFrontmatter(
|
|
719
|
-
const match =
|
|
778
|
+
function parseFrontmatter(text6) {
|
|
779
|
+
const match = text6.match(/^---\s*\n([\s\S]*?)\n---/);
|
|
720
780
|
if (!match) return null;
|
|
721
781
|
const block = match[1];
|
|
722
782
|
const result = {};
|
|
@@ -1481,7 +1541,7 @@ async function ensurePlatformIgnores(targetDir) {
|
|
|
1481
1541
|
if (!await pathExists(filePath)) continue;
|
|
1482
1542
|
const content = await readFile6(filePath, "utf-8");
|
|
1483
1543
|
if (content.includes("# FlyDocs")) continue;
|
|
1484
|
-
const section = "\n# FlyDocs \u2014
|
|
1544
|
+
const section = "\n# FlyDocs \u2014 managed by flydocs-cli, do not edit this section\n" + FLYDOCS_DEPLOY_EXCLUSIONS.join("\n") + "\n";
|
|
1485
1545
|
await appendFile(filePath, section, "utf-8");
|
|
1486
1546
|
printStatus(`Added FlyDocs exclusions to ${filename}`);
|
|
1487
1547
|
}
|
|
@@ -1496,14 +1556,19 @@ var init_gitignore = __esm({
|
|
|
1496
1556
|
".gcloudignore",
|
|
1497
1557
|
".dockerignore",
|
|
1498
1558
|
".vercelignore",
|
|
1499
|
-
".npmignore"
|
|
1559
|
+
".npmignore",
|
|
1560
|
+
".cfignore",
|
|
1561
|
+
".ebignore",
|
|
1562
|
+
".funcignore"
|
|
1500
1563
|
];
|
|
1501
1564
|
FLYDOCS_DEPLOY_EXCLUSIONS = [
|
|
1502
1565
|
".flydocs/",
|
|
1503
1566
|
".claude/",
|
|
1504
1567
|
".cursor/",
|
|
1505
1568
|
"flydocs/",
|
|
1506
|
-
"
|
|
1569
|
+
".flydocs-workspace.json",
|
|
1570
|
+
"AGENTS.md",
|
|
1571
|
+
".cursorrules"
|
|
1507
1572
|
];
|
|
1508
1573
|
FLYDOCS_GITIGNORE_ENTRIES = [
|
|
1509
1574
|
".env",
|
|
@@ -2759,16 +2824,630 @@ var init_install = __esm({
|
|
|
2759
2824
|
}
|
|
2760
2825
|
});
|
|
2761
2826
|
|
|
2827
|
+
// src/lib/global-config.ts
|
|
2828
|
+
import { readFile as readFile12, writeFile as writeFile10, mkdir as mkdir8, stat, chmod } from "fs/promises";
|
|
2829
|
+
import { join as join17 } from "path";
|
|
2830
|
+
import { homedir as homedir3 } from "os";
|
|
2831
|
+
function globalDir() {
|
|
2832
|
+
return join17(homedir3(), ".flydocs");
|
|
2833
|
+
}
|
|
2834
|
+
function credentialsPath() {
|
|
2835
|
+
return join17(globalDir(), "credentials");
|
|
2836
|
+
}
|
|
2837
|
+
function globalMePath() {
|
|
2838
|
+
return join17(globalDir(), "me.json");
|
|
2839
|
+
}
|
|
2840
|
+
async function ensureGlobalDir() {
|
|
2841
|
+
const dir = globalDir();
|
|
2842
|
+
if (!await pathExists(dir)) {
|
|
2843
|
+
await mkdir8(dir, { recursive: true, mode: 448 });
|
|
2844
|
+
}
|
|
2845
|
+
return dir;
|
|
2846
|
+
}
|
|
2847
|
+
async function readGlobalCredential() {
|
|
2848
|
+
const path = credentialsPath();
|
|
2849
|
+
if (!await pathExists(path)) return null;
|
|
2850
|
+
try {
|
|
2851
|
+
const content = await readFile12(path, "utf-8");
|
|
2852
|
+
return JSON.parse(content);
|
|
2853
|
+
} catch {
|
|
2854
|
+
return null;
|
|
2855
|
+
}
|
|
2856
|
+
}
|
|
2857
|
+
async function writeGlobalCredential(credential) {
|
|
2858
|
+
await ensureGlobalDir();
|
|
2859
|
+
const path = credentialsPath();
|
|
2860
|
+
await writeFile10(path, JSON.stringify(credential, null, 2) + "\n", {
|
|
2861
|
+
encoding: "utf-8",
|
|
2862
|
+
mode: 384
|
|
2863
|
+
});
|
|
2864
|
+
await chmod(path, 384);
|
|
2865
|
+
}
|
|
2866
|
+
async function checkCredentialPermissions() {
|
|
2867
|
+
const path = credentialsPath();
|
|
2868
|
+
if (!await pathExists(path)) return;
|
|
2869
|
+
try {
|
|
2870
|
+
const stats = await stat(path);
|
|
2871
|
+
const mode = stats.mode & 511;
|
|
2872
|
+
if (mode !== 384) {
|
|
2873
|
+
printWarning(
|
|
2874
|
+
`Credential file permissions are too open (${mode.toString(8)}). Expected 0600. Run: chmod 600 ${path}`
|
|
2875
|
+
);
|
|
2876
|
+
}
|
|
2877
|
+
} catch {
|
|
2878
|
+
}
|
|
2879
|
+
}
|
|
2880
|
+
async function writeGlobalIdentity(identity) {
|
|
2881
|
+
await ensureGlobalDir();
|
|
2882
|
+
const path = globalMePath();
|
|
2883
|
+
await writeFile10(path, JSON.stringify(identity, null, 2) + "\n", "utf-8");
|
|
2884
|
+
}
|
|
2885
|
+
async function resolveApiKey(explicitKey, projectDir) {
|
|
2886
|
+
if (explicitKey) {
|
|
2887
|
+
return { key: explicitKey, source: "--key flag" };
|
|
2888
|
+
}
|
|
2889
|
+
const envKey = process.env.FLYDOCS_API_KEY;
|
|
2890
|
+
if (envKey) {
|
|
2891
|
+
return { key: envKey, source: "FLYDOCS_API_KEY env var" };
|
|
2892
|
+
}
|
|
2893
|
+
const globalCred = await readGlobalCredential();
|
|
2894
|
+
if (globalCred?.apiKey) {
|
|
2895
|
+
return { key: globalCred.apiKey, source: "~/.flydocs/credentials" };
|
|
2896
|
+
}
|
|
2897
|
+
if (projectDir) {
|
|
2898
|
+
const envLocalKey = await readEnvKey(projectDir, "FLYDOCS_API_KEY");
|
|
2899
|
+
if (envLocalKey) {
|
|
2900
|
+
return { key: envLocalKey, source: ".env.local (legacy)" };
|
|
2901
|
+
}
|
|
2902
|
+
}
|
|
2903
|
+
return null;
|
|
2904
|
+
}
|
|
2905
|
+
async function readEnvKey(dir, varName) {
|
|
2906
|
+
for (const filename of [".env.local", ".env"]) {
|
|
2907
|
+
const filePath = join17(dir, filename);
|
|
2908
|
+
if (!await pathExists(filePath)) continue;
|
|
2909
|
+
try {
|
|
2910
|
+
const content = await readFile12(filePath, "utf-8");
|
|
2911
|
+
const match = content.match(new RegExp(`^${varName}=(.+)$`, "m"));
|
|
2912
|
+
if (match) return match[1].trim();
|
|
2913
|
+
} catch {
|
|
2914
|
+
continue;
|
|
2915
|
+
}
|
|
2916
|
+
}
|
|
2917
|
+
return null;
|
|
2918
|
+
}
|
|
2919
|
+
var init_global_config = __esm({
|
|
2920
|
+
"src/lib/global-config.ts"() {
|
|
2921
|
+
"use strict";
|
|
2922
|
+
init_fs_ops();
|
|
2923
|
+
init_ui();
|
|
2924
|
+
}
|
|
2925
|
+
});
|
|
2926
|
+
|
|
2927
|
+
// src/lib/relay-client.ts
|
|
2928
|
+
function resolveRelayUrl() {
|
|
2929
|
+
return process.env.FLYDOCS_RELAY_URL?.replace(/\/$/, "") ?? DEFAULT_RELAY_URL;
|
|
2930
|
+
}
|
|
2931
|
+
function headers(apiKey) {
|
|
2932
|
+
return {
|
|
2933
|
+
Authorization: `Bearer ${apiKey}`,
|
|
2934
|
+
"Content-Type": "application/json",
|
|
2935
|
+
Accept: "application/json"
|
|
2936
|
+
};
|
|
2937
|
+
}
|
|
2938
|
+
async function fetchConfigV2(apiKey, options = {}) {
|
|
2939
|
+
const baseUrl = resolveRelayUrl();
|
|
2940
|
+
const params = new URLSearchParams({ format: "2" });
|
|
2941
|
+
if (options.includeContext) params.set("includeContext", "true");
|
|
2942
|
+
const response = await fetch(`${baseUrl}/config/generate?${params}`, {
|
|
2943
|
+
method: "GET",
|
|
2944
|
+
headers: headers(apiKey),
|
|
2945
|
+
signal: AbortSignal.timeout(3e4)
|
|
2946
|
+
});
|
|
2947
|
+
if (!response.ok) {
|
|
2948
|
+
const body = await response.text().catch(() => "");
|
|
2949
|
+
throw new RelayError(
|
|
2950
|
+
`config/generate failed (${response.status})`,
|
|
2951
|
+
response.status,
|
|
2952
|
+
body
|
|
2953
|
+
);
|
|
2954
|
+
}
|
|
2955
|
+
return await response.json();
|
|
2956
|
+
}
|
|
2957
|
+
async function fetchTemplates(apiKey, sinceVersion) {
|
|
2958
|
+
const baseUrl = resolveRelayUrl();
|
|
2959
|
+
const response = await fetch(`${baseUrl}/templates?since=${sinceVersion}`, {
|
|
2960
|
+
method: "GET",
|
|
2961
|
+
headers: headers(apiKey),
|
|
2962
|
+
signal: AbortSignal.timeout(15e3)
|
|
2963
|
+
});
|
|
2964
|
+
if (!response.ok) {
|
|
2965
|
+
const body = await response.text().catch(() => "");
|
|
2966
|
+
throw new RelayError(
|
|
2967
|
+
`templates fetch failed (${response.status})`,
|
|
2968
|
+
response.status,
|
|
2969
|
+
body
|
|
2970
|
+
);
|
|
2971
|
+
}
|
|
2972
|
+
return await response.json();
|
|
2973
|
+
}
|
|
2974
|
+
var DEFAULT_RELAY_URL, RelayError;
|
|
2975
|
+
var init_relay_client = __esm({
|
|
2976
|
+
"src/lib/relay-client.ts"() {
|
|
2977
|
+
"use strict";
|
|
2978
|
+
DEFAULT_RELAY_URL = "https://app.flydocs.ai/api/relay";
|
|
2979
|
+
RelayError = class extends Error {
|
|
2980
|
+
constructor(message, status2, body) {
|
|
2981
|
+
super(message);
|
|
2982
|
+
this.status = status2;
|
|
2983
|
+
this.body = body;
|
|
2984
|
+
this.name = "RelayError";
|
|
2985
|
+
}
|
|
2986
|
+
};
|
|
2987
|
+
}
|
|
2988
|
+
});
|
|
2989
|
+
|
|
2990
|
+
// src/lib/workspace.ts
|
|
2991
|
+
import { readFile as readFile13, writeFile as writeFile11, readdir as readdir4, stat as stat2 } from "fs/promises";
|
|
2992
|
+
import { join as join18, dirname as dirname3, relative, resolve as resolve3 } from "path";
|
|
2993
|
+
async function readWorkspaceFile(dir) {
|
|
2994
|
+
const filePath = join18(dir, WORKSPACE_FILENAME);
|
|
2995
|
+
if (!await pathExists(filePath)) return null;
|
|
2996
|
+
const content = await readFile13(filePath, "utf-8");
|
|
2997
|
+
const parsed = JSON.parse(content);
|
|
2998
|
+
validateWorkspaceFile(parsed);
|
|
2999
|
+
return parsed;
|
|
3000
|
+
}
|
|
3001
|
+
async function writeWorkspaceFile(dir, workspace) {
|
|
3002
|
+
const filePath = join18(dir, WORKSPACE_FILENAME);
|
|
3003
|
+
const content = JSON.stringify(workspace, null, 2) + "\n";
|
|
3004
|
+
await writeFile11(filePath, content, "utf-8");
|
|
3005
|
+
}
|
|
3006
|
+
async function detectSiblingRepos(parentDir) {
|
|
3007
|
+
const repos = {};
|
|
3008
|
+
const entries = await readdir4(parentDir);
|
|
3009
|
+
for (const entry of entries) {
|
|
3010
|
+
if (entry.startsWith(".")) continue;
|
|
3011
|
+
const entryPath = join18(parentDir, entry);
|
|
3012
|
+
const entryStat = await stat2(entryPath).catch(() => null);
|
|
3013
|
+
if (!entryStat?.isDirectory()) continue;
|
|
3014
|
+
const hasGit = await pathExists(join18(entryPath, ".git"));
|
|
3015
|
+
const hasFlydocs = await pathExists(
|
|
3016
|
+
join18(entryPath, ".flydocs", "config.json")
|
|
3017
|
+
);
|
|
3018
|
+
if (hasGit || hasFlydocs) {
|
|
3019
|
+
repos[entry] = { path: `./${entry}` };
|
|
3020
|
+
}
|
|
3021
|
+
}
|
|
3022
|
+
return repos;
|
|
3023
|
+
}
|
|
3024
|
+
function buildWorkspaceFile(workspaceId, repos) {
|
|
3025
|
+
return { workspaceId, repos };
|
|
3026
|
+
}
|
|
3027
|
+
async function readSiblingDescriptors(workspaceDir, repos) {
|
|
3028
|
+
const descriptors = [];
|
|
3029
|
+
for (const [name, entry] of Object.entries(repos)) {
|
|
3030
|
+
const repoDir = resolve3(workspaceDir, entry.path);
|
|
3031
|
+
const serviceJsonPath = join18(repoDir, "flydocs", "context", "service.json");
|
|
3032
|
+
if (!await pathExists(serviceJsonPath)) continue;
|
|
3033
|
+
try {
|
|
3034
|
+
const content = await readFile13(serviceJsonPath, "utf-8");
|
|
3035
|
+
const descriptor = JSON.parse(content);
|
|
3036
|
+
descriptors.push({ name, path: entry.path, descriptor });
|
|
3037
|
+
} catch {
|
|
3038
|
+
}
|
|
3039
|
+
}
|
|
3040
|
+
return descriptors;
|
|
3041
|
+
}
|
|
3042
|
+
async function generateWorkspaceMd(workspaceDir, workspace, productName) {
|
|
3043
|
+
const descriptors = await readSiblingDescriptors(
|
|
3044
|
+
workspaceDir,
|
|
3045
|
+
workspace.repos
|
|
3046
|
+
);
|
|
3047
|
+
const repoCount = Object.keys(workspace.repos).length;
|
|
3048
|
+
const lines = [];
|
|
3049
|
+
const title = productName ?? "Workspace";
|
|
3050
|
+
lines.push(`# Product: ${title}`);
|
|
3051
|
+
lines.push("");
|
|
3052
|
+
lines.push("## Overview");
|
|
3053
|
+
lines.push("");
|
|
3054
|
+
if (descriptors.length > 0) {
|
|
3055
|
+
const purposes = descriptors.map((d) => d.descriptor.purpose).filter(Boolean);
|
|
3056
|
+
if (purposes.length > 0) {
|
|
3057
|
+
lines.push(purposes.join(". ") + ".");
|
|
3058
|
+
} else {
|
|
3059
|
+
lines.push(`Multi-repo workspace with ${repoCount} repositories.`);
|
|
3060
|
+
}
|
|
3061
|
+
} else {
|
|
3062
|
+
lines.push(`Multi-repo workspace with ${repoCount} repositories.`);
|
|
3063
|
+
}
|
|
3064
|
+
lines.push("");
|
|
3065
|
+
lines.push("## Architecture");
|
|
3066
|
+
lines.push("");
|
|
3067
|
+
lines.push(`${repoCount}-repo sibling topology.`);
|
|
3068
|
+
lines.push("");
|
|
3069
|
+
lines.push("## Repos");
|
|
3070
|
+
lines.push("");
|
|
3071
|
+
for (const [name, entry] of Object.entries(workspace.repos)) {
|
|
3072
|
+
const desc = descriptors.find((d) => d.name === name);
|
|
3073
|
+
const purpose = desc?.descriptor.purpose ?? "";
|
|
3074
|
+
const stack = desc?.descriptor.stack?.join(", ") ?? "";
|
|
3075
|
+
const detail = [purpose, stack].filter(Boolean).join(". ");
|
|
3076
|
+
const projectMdLink = `${entry.path}/flydocs/context/project.md`;
|
|
3077
|
+
lines.push(
|
|
3078
|
+
`- **${name}** \u2014 ${detail || "No description"}. [Details](${projectMdLink})`
|
|
3079
|
+
);
|
|
3080
|
+
}
|
|
3081
|
+
lines.push("");
|
|
3082
|
+
const edges = [];
|
|
3083
|
+
for (const desc of descriptors) {
|
|
3084
|
+
for (const dep of desc.descriptor.dependencies ?? []) {
|
|
3085
|
+
const target = dep.service;
|
|
3086
|
+
const iface = dep.interface;
|
|
3087
|
+
edges.push(`- ${desc.name} \u2192 ${target} (${iface})`);
|
|
3088
|
+
}
|
|
3089
|
+
}
|
|
3090
|
+
lines.push("## Cross-Repo Dependencies");
|
|
3091
|
+
lines.push("");
|
|
3092
|
+
if (edges.length > 0) {
|
|
3093
|
+
lines.push(...edges);
|
|
3094
|
+
} else {
|
|
3095
|
+
lines.push("No cross-repo dependencies detected.");
|
|
3096
|
+
}
|
|
3097
|
+
lines.push("");
|
|
3098
|
+
return lines.join("\n");
|
|
3099
|
+
}
|
|
3100
|
+
function validateWorkspaceFile(value) {
|
|
3101
|
+
if (typeof value !== "object" || value === null) {
|
|
3102
|
+
throw new Error("Invalid workspace file: expected an object");
|
|
3103
|
+
}
|
|
3104
|
+
const obj = value;
|
|
3105
|
+
if (typeof obj.workspaceId !== "string" || obj.workspaceId.length === 0) {
|
|
3106
|
+
throw new Error(
|
|
3107
|
+
"Invalid workspace file: workspaceId must be a non-empty string"
|
|
3108
|
+
);
|
|
3109
|
+
}
|
|
3110
|
+
if (typeof obj.repos !== "object" || obj.repos === null) {
|
|
3111
|
+
throw new Error("Invalid workspace file: repos must be an object");
|
|
3112
|
+
}
|
|
3113
|
+
const repos = obj.repos;
|
|
3114
|
+
for (const [name, entry] of Object.entries(repos)) {
|
|
3115
|
+
if (typeof entry !== "object" || entry === null) {
|
|
3116
|
+
throw new Error(
|
|
3117
|
+
`Invalid workspace file: repos.${name} must be an object`
|
|
3118
|
+
);
|
|
3119
|
+
}
|
|
3120
|
+
const repoEntry = entry;
|
|
3121
|
+
if (typeof repoEntry.path !== "string" || repoEntry.path.length === 0) {
|
|
3122
|
+
throw new Error(
|
|
3123
|
+
`Invalid workspace file: repos.${name}.path must be a non-empty string`
|
|
3124
|
+
);
|
|
3125
|
+
}
|
|
3126
|
+
}
|
|
3127
|
+
}
|
|
3128
|
+
var WORKSPACE_FILENAME;
|
|
3129
|
+
var init_workspace = __esm({
|
|
3130
|
+
"src/lib/workspace.ts"() {
|
|
3131
|
+
"use strict";
|
|
3132
|
+
init_fs_ops();
|
|
3133
|
+
WORKSPACE_FILENAME = ".flydocs-workspace.json";
|
|
3134
|
+
}
|
|
3135
|
+
});
|
|
3136
|
+
|
|
3137
|
+
// src/commands/init.ts
|
|
3138
|
+
var init_exports = {};
|
|
3139
|
+
__export(init_exports, {
|
|
3140
|
+
default: () => init_default
|
|
3141
|
+
});
|
|
3142
|
+
import { defineCommand as defineCommand2 } from "citty";
|
|
3143
|
+
import { text as text2, confirm as confirm3, isCancel as isCancel4, cancel as cancel3 } from "@clack/prompts";
|
|
3144
|
+
import pc7 from "picocolors";
|
|
3145
|
+
import { join as join19 } from "path";
|
|
3146
|
+
import { mkdir as mkdir9, writeFile as writeFile12 } from "fs/promises";
|
|
3147
|
+
async function resolveAndValidateKey(keyArg, targetDir) {
|
|
3148
|
+
let resolved = await resolveApiKey(keyArg, targetDir);
|
|
3149
|
+
if (!resolved) {
|
|
3150
|
+
console.log(
|
|
3151
|
+
` ${pc7.dim("Get your API key (fdk_...) from your FlyDocs dashboard")}`
|
|
3152
|
+
);
|
|
3153
|
+
console.log();
|
|
3154
|
+
const keyInput = await text2({
|
|
3155
|
+
message: "Enter your API key",
|
|
3156
|
+
placeholder: "fdk_...",
|
|
3157
|
+
validate(value) {
|
|
3158
|
+
if (!value.trim()) return "API key is required";
|
|
3159
|
+
if (detectKeyType(value.trim()) !== "relay") {
|
|
3160
|
+
return "Key must start with fdk_ (FlyDocs API key)";
|
|
3161
|
+
}
|
|
3162
|
+
return void 0;
|
|
3163
|
+
}
|
|
3164
|
+
});
|
|
3165
|
+
if (isCancel4(keyInput)) {
|
|
3166
|
+
cancel3("Init cancelled.");
|
|
3167
|
+
process.exit(0);
|
|
3168
|
+
}
|
|
3169
|
+
resolved = { key: keyInput.trim(), source: "prompt" };
|
|
3170
|
+
} else {
|
|
3171
|
+
printInfo(`Using key from ${resolved.source}`);
|
|
3172
|
+
}
|
|
3173
|
+
const apiKey = resolved.key;
|
|
3174
|
+
printInfo("Validating API key...");
|
|
3175
|
+
try {
|
|
3176
|
+
const result = await validateRelayKey(apiKey);
|
|
3177
|
+
if (!result.valid) {
|
|
3178
|
+
printError("Invalid API key. Check your key and try again.");
|
|
3179
|
+
process.exit(1);
|
|
3180
|
+
}
|
|
3181
|
+
printStatus(`Authenticated with ${pc7.bold(result.org)}`);
|
|
3182
|
+
} catch {
|
|
3183
|
+
printError(
|
|
3184
|
+
"Could not reach FlyDocs API. Check your network and try again."
|
|
3185
|
+
);
|
|
3186
|
+
console.log(
|
|
3187
|
+
` ${pc7.dim("flydocs init requires server access. For offline use, run flydocs install instead.")}`
|
|
3188
|
+
);
|
|
3189
|
+
process.exit(1);
|
|
3190
|
+
}
|
|
3191
|
+
await writeGlobalCredential({
|
|
3192
|
+
apiKey,
|
|
3193
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3194
|
+
lastValidated: (/* @__PURE__ */ new Date()).toISOString()
|
|
3195
|
+
});
|
|
3196
|
+
await checkCredentialPermissions();
|
|
3197
|
+
return apiKey;
|
|
3198
|
+
}
|
|
3199
|
+
async function pullServerConfig(apiKey, targetDir) {
|
|
3200
|
+
printInfo("Pulling config from server...");
|
|
3201
|
+
const isFirstInit = !await pathExists(
|
|
3202
|
+
join19(targetDir, ".flydocs", "config.json")
|
|
3203
|
+
);
|
|
3204
|
+
try {
|
|
3205
|
+
const response = await fetchConfigV2(apiKey, {
|
|
3206
|
+
includeContext: isFirstInit
|
|
3207
|
+
});
|
|
3208
|
+
if (!response.valid) {
|
|
3209
|
+
printError("Server returned invalid config. Contact support.");
|
|
3210
|
+
process.exit(1);
|
|
3211
|
+
}
|
|
3212
|
+
return response;
|
|
3213
|
+
} catch (err) {
|
|
3214
|
+
if (err instanceof RelayError) {
|
|
3215
|
+
printError(`Server error: ${err.message}`);
|
|
3216
|
+
if (err.status === 401) {
|
|
3217
|
+
console.log(
|
|
3218
|
+
` ${pc7.dim("Your API key may be revoked. Run flydocs auth with a new key.")}`
|
|
3219
|
+
);
|
|
3220
|
+
}
|
|
3221
|
+
} else {
|
|
3222
|
+
printError("Could not reach server. Check your network.");
|
|
3223
|
+
}
|
|
3224
|
+
process.exit(1);
|
|
3225
|
+
}
|
|
3226
|
+
}
|
|
3227
|
+
async function initSingleRepo(targetDir, apiKey, serverResponse) {
|
|
3228
|
+
const actions = [];
|
|
3229
|
+
const skipped = [];
|
|
3230
|
+
await mkdir9(join19(targetDir, ".flydocs"), { recursive: true });
|
|
3231
|
+
const configWithHash = applyConfigHash(serverResponse.config);
|
|
3232
|
+
await writeConfig(targetDir, configWithHash);
|
|
3233
|
+
actions.push("Wrote .flydocs/config.json (from server)");
|
|
3234
|
+
if (serverResponse.identity) {
|
|
3235
|
+
await writeGlobalIdentity({
|
|
3236
|
+
name: serverResponse.identity.name,
|
|
3237
|
+
email: serverResponse.identity.email,
|
|
3238
|
+
providerIdentities: serverResponse.identity.providerIdentities
|
|
3239
|
+
});
|
|
3240
|
+
actions.push("Wrote ~/.flydocs/me.json");
|
|
3241
|
+
}
|
|
3242
|
+
if (serverResponse.context) {
|
|
3243
|
+
const contextDir = join19(targetDir, "flydocs", "context");
|
|
3244
|
+
await mkdir9(contextDir, { recursive: true });
|
|
3245
|
+
const projectMdPath = join19(contextDir, "project.md");
|
|
3246
|
+
if (!await pathExists(projectMdPath)) {
|
|
3247
|
+
await writeFile12(projectMdPath, serverResponse.context.projectMd, "utf-8");
|
|
3248
|
+
actions.push("Wrote flydocs/context/project.md");
|
|
3249
|
+
} else {
|
|
3250
|
+
skipped.push("flydocs/context/project.md (already exists)");
|
|
3251
|
+
}
|
|
3252
|
+
const serviceJsonPath = join19(contextDir, "service.json");
|
|
3253
|
+
if (serverResponse.context.serviceJson && !await pathExists(serviceJsonPath)) {
|
|
3254
|
+
await writeFile12(
|
|
3255
|
+
serviceJsonPath,
|
|
3256
|
+
JSON.stringify(serverResponse.context.serviceJson, null, 2) + "\n",
|
|
3257
|
+
"utf-8"
|
|
3258
|
+
);
|
|
3259
|
+
actions.push("Wrote flydocs/context/service.json");
|
|
3260
|
+
} else if (await pathExists(serviceJsonPath)) {
|
|
3261
|
+
skipped.push("flydocs/context/service.json (already exists)");
|
|
3262
|
+
}
|
|
3263
|
+
}
|
|
3264
|
+
await ensureGitignore(targetDir);
|
|
3265
|
+
await ensurePlatformIgnores(targetDir);
|
|
3266
|
+
actions.push("Updated ignore files");
|
|
3267
|
+
return { actions, skipped };
|
|
3268
|
+
}
|
|
3269
|
+
async function isParentDirectory(dir) {
|
|
3270
|
+
const hasGit = await pathExists(join19(dir, ".git"));
|
|
3271
|
+
if (hasGit) return false;
|
|
3272
|
+
const repos = await detectSiblingRepos(dir);
|
|
3273
|
+
return Object.keys(repos).length >= 2;
|
|
3274
|
+
}
|
|
3275
|
+
async function runMultiRepoInit(parentDir, keyArg) {
|
|
3276
|
+
const repos = await detectSiblingRepos(parentDir);
|
|
3277
|
+
const repoNames = Object.keys(repos).sort();
|
|
3278
|
+
printInfo(`Detected ${repoNames.length} repos:`);
|
|
3279
|
+
for (const name of repoNames) {
|
|
3280
|
+
console.log(` ${pc7.cyan(name)}`);
|
|
3281
|
+
}
|
|
3282
|
+
console.log();
|
|
3283
|
+
const shouldContinue = await confirm3({
|
|
3284
|
+
message: `Initialize all ${repoNames.length} repos?`
|
|
3285
|
+
});
|
|
3286
|
+
if (isCancel4(shouldContinue) || !shouldContinue) {
|
|
3287
|
+
cancel3("Init cancelled.");
|
|
3288
|
+
process.exit(0);
|
|
3289
|
+
}
|
|
3290
|
+
const firstRepoDir = join19(parentDir, repoNames[0]);
|
|
3291
|
+
const apiKey = await resolveAndValidateKey(keyArg, firstRepoDir);
|
|
3292
|
+
const allActions = [
|
|
3293
|
+
"Stored credential globally (~/.flydocs/credentials)"
|
|
3294
|
+
];
|
|
3295
|
+
const allSkipped = [];
|
|
3296
|
+
let allWarnings = [];
|
|
3297
|
+
let firstResponse;
|
|
3298
|
+
for (const repoName of repoNames) {
|
|
3299
|
+
const repoDir = join19(parentDir, repoName);
|
|
3300
|
+
console.log();
|
|
3301
|
+
printInfo(`Initializing ${pc7.bold(repoName)}...`);
|
|
3302
|
+
const serverResponse = await pullServerConfig(apiKey, repoDir);
|
|
3303
|
+
if (!firstResponse) firstResponse = serverResponse;
|
|
3304
|
+
const { actions, skipped } = await initSingleRepo(
|
|
3305
|
+
repoDir,
|
|
3306
|
+
apiKey,
|
|
3307
|
+
serverResponse
|
|
3308
|
+
);
|
|
3309
|
+
for (const action of actions) {
|
|
3310
|
+
allActions.push(`[${repoName}] ${action}`);
|
|
3311
|
+
}
|
|
3312
|
+
for (const skip of skipped) {
|
|
3313
|
+
allSkipped.push(`[${repoName}] ${skip}`);
|
|
3314
|
+
}
|
|
3315
|
+
allWarnings = [...allWarnings, ...serverResponse.warnings];
|
|
3316
|
+
printStatus(`${repoName} initialized`);
|
|
3317
|
+
}
|
|
3318
|
+
if (firstResponse) {
|
|
3319
|
+
const existing = await readWorkspaceFile(parentDir);
|
|
3320
|
+
if (existing) {
|
|
3321
|
+
allSkipped.push(".flydocs-workspace.json (already exists)");
|
|
3322
|
+
} else {
|
|
3323
|
+
const workspaceFile = buildWorkspaceFile(
|
|
3324
|
+
firstResponse.workspaceId,
|
|
3325
|
+
repos
|
|
3326
|
+
);
|
|
3327
|
+
await writeWorkspaceFile(parentDir, workspaceFile);
|
|
3328
|
+
allActions.push(`.flydocs-workspace.json (${repoNames.length} repos)`);
|
|
3329
|
+
}
|
|
3330
|
+
const contextDir = join19(parentDir, "flydocs", "context");
|
|
3331
|
+
const workspaceMdPath = join19(contextDir, "workspace.md");
|
|
3332
|
+
if (await pathExists(workspaceMdPath)) {
|
|
3333
|
+
allSkipped.push("flydocs/context/workspace.md (already exists)");
|
|
3334
|
+
} else {
|
|
3335
|
+
await mkdir9(contextDir, { recursive: true });
|
|
3336
|
+
const workspaceJson = await readWorkspaceFile(parentDir) ?? buildWorkspaceFile(firstResponse.workspaceId, repos);
|
|
3337
|
+
const content = firstResponse.context?.workspaceMd ?? await generateWorkspaceMd(parentDir, workspaceJson);
|
|
3338
|
+
await writeFile12(workspaceMdPath, content, "utf-8");
|
|
3339
|
+
const source = firstResponse.context?.workspaceMd ? "from server" : "generated locally";
|
|
3340
|
+
allActions.push(`Wrote flydocs/context/workspace.md (${source})`);
|
|
3341
|
+
}
|
|
3342
|
+
}
|
|
3343
|
+
console.log();
|
|
3344
|
+
printInitReport(allActions, allSkipped, allWarnings);
|
|
3345
|
+
}
|
|
3346
|
+
function printInitReport(actions, skipped, warnings) {
|
|
3347
|
+
console.log();
|
|
3348
|
+
const lines = [];
|
|
3349
|
+
for (const action of actions) {
|
|
3350
|
+
lines.push(`${pc7.green("+")} ${action}`);
|
|
3351
|
+
}
|
|
3352
|
+
for (const skip of skipped) {
|
|
3353
|
+
lines.push(`${pc7.dim("-")} ${skip}`);
|
|
3354
|
+
}
|
|
3355
|
+
if (warnings.length > 0) {
|
|
3356
|
+
lines.push("");
|
|
3357
|
+
for (const warning of warnings) {
|
|
3358
|
+
lines.push(`${pc7.yellow("!")} ${warning}`);
|
|
3359
|
+
}
|
|
3360
|
+
}
|
|
3361
|
+
printCompletionBox("FlyDocs Initialized", lines);
|
|
3362
|
+
console.log();
|
|
3363
|
+
console.log(` Next steps:`);
|
|
3364
|
+
console.log(
|
|
3365
|
+
` ${pc7.cyan("flydocs sync")} \u2014 pull latest config and templates`
|
|
3366
|
+
);
|
|
3367
|
+
console.log(` ${pc7.cyan("/start-session")} \u2014 begin working`);
|
|
3368
|
+
console.log();
|
|
3369
|
+
}
|
|
3370
|
+
var init_default;
|
|
3371
|
+
var init_init = __esm({
|
|
3372
|
+
"src/commands/init.ts"() {
|
|
3373
|
+
"use strict";
|
|
3374
|
+
init_ui();
|
|
3375
|
+
init_api_key();
|
|
3376
|
+
init_global_config();
|
|
3377
|
+
init_config();
|
|
3378
|
+
init_config_integrity();
|
|
3379
|
+
init_gitignore();
|
|
3380
|
+
init_fs_ops();
|
|
3381
|
+
init_relay_client();
|
|
3382
|
+
init_workspace();
|
|
3383
|
+
init_default = defineCommand2({
|
|
3384
|
+
meta: {
|
|
3385
|
+
name: "init",
|
|
3386
|
+
description: "Initialize FlyDocs in this project (unified setup)"
|
|
3387
|
+
},
|
|
3388
|
+
args: {
|
|
3389
|
+
key: {
|
|
3390
|
+
type: "string",
|
|
3391
|
+
description: "FlyDocs API key (fdk_...)"
|
|
3392
|
+
},
|
|
3393
|
+
path: {
|
|
3394
|
+
type: "string",
|
|
3395
|
+
description: "Path to project directory"
|
|
3396
|
+
}
|
|
3397
|
+
},
|
|
3398
|
+
async run({ args }) {
|
|
3399
|
+
const targetDir = args.path ?? process.cwd();
|
|
3400
|
+
console.log();
|
|
3401
|
+
console.log(` ${pc7.bold("FlyDocs Init")}`);
|
|
3402
|
+
console.log();
|
|
3403
|
+
if (await isParentDirectory(targetDir)) {
|
|
3404
|
+
await runMultiRepoInit(targetDir, args.key);
|
|
3405
|
+
return;
|
|
3406
|
+
}
|
|
3407
|
+
const apiKey = await resolveAndValidateKey(args.key, targetDir);
|
|
3408
|
+
const serverResponse = await pullServerConfig(apiKey, targetDir);
|
|
3409
|
+
const { actions, skipped } = await initSingleRepo(
|
|
3410
|
+
targetDir,
|
|
3411
|
+
apiKey,
|
|
3412
|
+
serverResponse
|
|
3413
|
+
);
|
|
3414
|
+
actions.unshift("Stored credential globally (~/.flydocs/credentials)");
|
|
3415
|
+
const topology = serverResponse.config.topology;
|
|
3416
|
+
if (topology?.type === 4 && topology.label === "sibling-repos") {
|
|
3417
|
+
const parentDir = join19(targetDir, "..");
|
|
3418
|
+
const existing = await readWorkspaceFile(parentDir);
|
|
3419
|
+
if (existing) {
|
|
3420
|
+
skipped.push(".flydocs-workspace.json (already exists)");
|
|
3421
|
+
} else {
|
|
3422
|
+
const repos = await detectSiblingRepos(parentDir);
|
|
3423
|
+
if (Object.keys(repos).length > 0) {
|
|
3424
|
+
const workspaceFile = buildWorkspaceFile(
|
|
3425
|
+
serverResponse.workspaceId,
|
|
3426
|
+
repos
|
|
3427
|
+
);
|
|
3428
|
+
await writeWorkspaceFile(parentDir, workspaceFile);
|
|
3429
|
+
actions.push(
|
|
3430
|
+
`.flydocs-workspace.json (${Object.keys(repos).length} repos detected)`
|
|
3431
|
+
);
|
|
3432
|
+
}
|
|
3433
|
+
}
|
|
3434
|
+
}
|
|
3435
|
+
printInitReport(actions, skipped, serverResponse.warnings);
|
|
3436
|
+
}
|
|
3437
|
+
});
|
|
3438
|
+
}
|
|
3439
|
+
});
|
|
3440
|
+
|
|
2762
3441
|
// src/commands/update.ts
|
|
2763
3442
|
var update_exports = {};
|
|
2764
3443
|
__export(update_exports, {
|
|
2765
3444
|
default: () => update_default
|
|
2766
3445
|
});
|
|
2767
|
-
import { defineCommand as
|
|
2768
|
-
import { resolve as
|
|
2769
|
-
import { mkdir as
|
|
2770
|
-
import { select as select2, text as
|
|
2771
|
-
import
|
|
3446
|
+
import { defineCommand as defineCommand3 } from "citty";
|
|
3447
|
+
import { resolve as resolve4, join as join20 } from "path";
|
|
3448
|
+
import { mkdir as mkdir10, cp as cp2, readFile as readFile14, readdir as readdir5, rm as rm4 } from "fs/promises";
|
|
3449
|
+
import { select as select2, text as text3, confirm as confirm4, isCancel as isCancel5, cancel as cancel4 } from "@clack/prompts";
|
|
3450
|
+
import pc8 from "picocolors";
|
|
2772
3451
|
var update_default;
|
|
2773
3452
|
var init_update = __esm({
|
|
2774
3453
|
"src/commands/update.ts"() {
|
|
@@ -2787,7 +3466,7 @@ var init_update = __esm({
|
|
|
2787
3466
|
init_update_check();
|
|
2788
3467
|
init_telemetry();
|
|
2789
3468
|
init_integrity();
|
|
2790
|
-
update_default =
|
|
3469
|
+
update_default = defineCommand3({
|
|
2791
3470
|
meta: {
|
|
2792
3471
|
name: "update",
|
|
2793
3472
|
description: "Update an existing FlyDocs installation"
|
|
@@ -2832,7 +3511,7 @@ var init_update = __esm({
|
|
|
2832
3511
|
await capture("update_started", { template_version: version });
|
|
2833
3512
|
let targetDir;
|
|
2834
3513
|
if (args.path) {
|
|
2835
|
-
targetDir =
|
|
3514
|
+
targetDir = resolve4(args.path.replace(/^~/, process.env.HOME ?? "~"));
|
|
2836
3515
|
} else if (args.here) {
|
|
2837
3516
|
targetDir = process.cwd();
|
|
2838
3517
|
} else {
|
|
@@ -2849,21 +3528,21 @@ var init_update = __esm({
|
|
|
2849
3528
|
}
|
|
2850
3529
|
]
|
|
2851
3530
|
});
|
|
2852
|
-
if (
|
|
2853
|
-
|
|
3531
|
+
if (isCancel5(choice)) {
|
|
3532
|
+
cancel4("Update cancelled.");
|
|
2854
3533
|
process.exit(0);
|
|
2855
3534
|
}
|
|
2856
3535
|
if (choice === "cwd") {
|
|
2857
3536
|
targetDir = process.cwd();
|
|
2858
3537
|
} else {
|
|
2859
|
-
const enteredPath = await
|
|
3538
|
+
const enteredPath = await text3({
|
|
2860
3539
|
message: "Enter project path:"
|
|
2861
3540
|
});
|
|
2862
|
-
if (
|
|
2863
|
-
|
|
3541
|
+
if (isCancel5(enteredPath)) {
|
|
3542
|
+
cancel4("Update cancelled.");
|
|
2864
3543
|
process.exit(0);
|
|
2865
3544
|
}
|
|
2866
|
-
targetDir =
|
|
3545
|
+
targetDir = resolve4(
|
|
2867
3546
|
enteredPath.replace(/^~/, process.env.HOME ?? "~")
|
|
2868
3547
|
);
|
|
2869
3548
|
}
|
|
@@ -2872,11 +3551,11 @@ var init_update = __esm({
|
|
|
2872
3551
|
printError(`Directory does not exist: ${targetDir}`);
|
|
2873
3552
|
process.exit(1);
|
|
2874
3553
|
}
|
|
2875
|
-
targetDir =
|
|
3554
|
+
targetDir = resolve4(targetDir);
|
|
2876
3555
|
process.chdir(targetDir);
|
|
2877
|
-
const hasVersion = await pathExists(
|
|
3556
|
+
const hasVersion = await pathExists(join20(targetDir, ".flydocs", "version"));
|
|
2878
3557
|
const hasConfig = await pathExists(
|
|
2879
|
-
|
|
3558
|
+
join20(targetDir, ".flydocs", "config.json")
|
|
2880
3559
|
);
|
|
2881
3560
|
if (!hasVersion && !hasConfig) {
|
|
2882
3561
|
printError(`Not a FlyDocs project: ${targetDir}`);
|
|
@@ -2887,8 +3566,8 @@ var init_update = __esm({
|
|
|
2887
3566
|
console.log();
|
|
2888
3567
|
let currentVersion = "0.1.0";
|
|
2889
3568
|
if (hasVersion) {
|
|
2890
|
-
const vContent = await
|
|
2891
|
-
|
|
3569
|
+
const vContent = await readFile14(
|
|
3570
|
+
join20(targetDir, ".flydocs", "version"),
|
|
2892
3571
|
"utf-8"
|
|
2893
3572
|
);
|
|
2894
3573
|
currentVersion = vContent.trim();
|
|
@@ -2907,10 +3586,10 @@ var init_update = __esm({
|
|
|
2907
3586
|
printWarning(
|
|
2908
3587
|
`Project version (${currentVersion}) is newer than installer (${version})`
|
|
2909
3588
|
);
|
|
2910
|
-
const shouldContinue = await
|
|
3589
|
+
const shouldContinue = await confirm4({
|
|
2911
3590
|
message: "Continue anyway?"
|
|
2912
3591
|
});
|
|
2913
|
-
if (
|
|
3592
|
+
if (isCancel5(shouldContinue) || !shouldContinue) {
|
|
2914
3593
|
process.exit(0);
|
|
2915
3594
|
}
|
|
2916
3595
|
}
|
|
@@ -2922,10 +3601,10 @@ var init_update = __esm({
|
|
|
2922
3601
|
});
|
|
2923
3602
|
console.log(`Updating: v${currentVersion} \u2192 v${version}`);
|
|
2924
3603
|
console.log();
|
|
2925
|
-
const changelogPath =
|
|
3604
|
+
const changelogPath = join20(templateDir, "CHANGELOG.md");
|
|
2926
3605
|
const whatsNew = await getWhatsNew(changelogPath, currentVersion, version);
|
|
2927
3606
|
if (whatsNew.length > 0) {
|
|
2928
|
-
console.log(
|
|
3607
|
+
console.log(pc8.cyan("What's new:"));
|
|
2929
3608
|
console.log();
|
|
2930
3609
|
for (const entry of whatsNew) {
|
|
2931
3610
|
console.log(` ${entry}`);
|
|
@@ -2934,23 +3613,23 @@ var init_update = __esm({
|
|
|
2934
3613
|
}
|
|
2935
3614
|
const now = /* @__PURE__ */ new Date();
|
|
2936
3615
|
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")}`;
|
|
2937
|
-
const backupDir =
|
|
2938
|
-
await
|
|
3616
|
+
const backupDir = join20(targetDir, ".flydocs", `backup-${ts}`);
|
|
3617
|
+
await mkdir10(backupDir, { recursive: true });
|
|
2939
3618
|
if (hasConfig) {
|
|
2940
3619
|
await cp2(
|
|
2941
|
-
|
|
2942
|
-
|
|
3620
|
+
join20(targetDir, ".flydocs", "config.json"),
|
|
3621
|
+
join20(backupDir, "config.json")
|
|
2943
3622
|
);
|
|
2944
3623
|
printStatus(`Config backed up to .flydocs/backup-${ts}/`);
|
|
2945
3624
|
}
|
|
2946
3625
|
try {
|
|
2947
|
-
const flydocsDir =
|
|
2948
|
-
const entries = await
|
|
3626
|
+
const flydocsDir = join20(targetDir, ".flydocs");
|
|
3627
|
+
const entries = await readdir5(flydocsDir);
|
|
2949
3628
|
const backups = entries.filter((e) => e.startsWith("backup-")).sort();
|
|
2950
3629
|
if (backups.length > 3) {
|
|
2951
3630
|
const toRemove = backups.slice(0, backups.length - 3);
|
|
2952
3631
|
for (const old of toRemove) {
|
|
2953
|
-
await rm4(
|
|
3632
|
+
await rm4(join20(flydocsDir, old), { recursive: true, force: true });
|
|
2954
3633
|
}
|
|
2955
3634
|
}
|
|
2956
3635
|
} catch {
|
|
@@ -2989,17 +3668,17 @@ var init_update = __esm({
|
|
|
2989
3668
|
await ensureDirectories(targetDir, effectiveTier);
|
|
2990
3669
|
console.log("Replacing framework directories...");
|
|
2991
3670
|
await replaceDirectory(
|
|
2992
|
-
|
|
2993
|
-
|
|
3671
|
+
join20(templateDir, ".flydocs", "templates"),
|
|
3672
|
+
join20(targetDir, ".flydocs", "templates")
|
|
2994
3673
|
);
|
|
2995
3674
|
printStatus(".flydocs/templates");
|
|
2996
3675
|
await replaceDirectory(
|
|
2997
|
-
|
|
2998
|
-
|
|
3676
|
+
join20(templateDir, ".claude", "hooks"),
|
|
3677
|
+
join20(targetDir, ".claude", "hooks")
|
|
2999
3678
|
);
|
|
3000
3679
|
printStatus(".claude/hooks");
|
|
3001
3680
|
const hasExistingAgents = await pathExists(
|
|
3002
|
-
|
|
3681
|
+
join20(targetDir, ".claude", "agents")
|
|
3003
3682
|
);
|
|
3004
3683
|
let installAgents;
|
|
3005
3684
|
if (args.yes) {
|
|
@@ -3008,7 +3687,7 @@ var init_update = __esm({
|
|
|
3008
3687
|
installAgents = true;
|
|
3009
3688
|
} else {
|
|
3010
3689
|
console.log();
|
|
3011
|
-
console.log(` ${
|
|
3690
|
+
console.log(` ${pc8.bold(pc8.yellow("Sub-Agents (Recommended)"))}`);
|
|
3012
3691
|
console.log();
|
|
3013
3692
|
console.log(
|
|
3014
3693
|
" Sub-agents are specialized roles (PM, implementation, review,"
|
|
@@ -3020,31 +3699,31 @@ var init_update = __esm({
|
|
|
3020
3699
|
" structure work but are not required \u2014 everything works without them."
|
|
3021
3700
|
);
|
|
3022
3701
|
console.log();
|
|
3023
|
-
const agentConfirm = await
|
|
3702
|
+
const agentConfirm = await confirm4({
|
|
3024
3703
|
message: "Install sub-agents?",
|
|
3025
3704
|
initialValue: true
|
|
3026
3705
|
});
|
|
3027
|
-
if (
|
|
3706
|
+
if (isCancel5(agentConfirm)) {
|
|
3028
3707
|
installAgents = false;
|
|
3029
3708
|
} else {
|
|
3030
3709
|
installAgents = agentConfirm;
|
|
3031
3710
|
}
|
|
3032
3711
|
}
|
|
3033
3712
|
if (installAgents) {
|
|
3034
|
-
const claudeAgentsSrc =
|
|
3713
|
+
const claudeAgentsSrc = join20(templateDir, ".claude", "agents");
|
|
3035
3714
|
if (await pathExists(claudeAgentsSrc)) {
|
|
3036
|
-
await
|
|
3715
|
+
await mkdir10(join20(targetDir, ".claude", "agents"), { recursive: true });
|
|
3037
3716
|
await copyDirectoryContents(
|
|
3038
3717
|
claudeAgentsSrc,
|
|
3039
|
-
|
|
3718
|
+
join20(targetDir, ".claude", "agents")
|
|
3040
3719
|
);
|
|
3041
3720
|
}
|
|
3042
|
-
const cursorAgentsSrc =
|
|
3721
|
+
const cursorAgentsSrc = join20(templateDir, ".cursor", "agents");
|
|
3043
3722
|
if (await pathExists(cursorAgentsSrc)) {
|
|
3044
|
-
await
|
|
3723
|
+
await mkdir10(join20(targetDir, ".cursor", "agents"), { recursive: true });
|
|
3045
3724
|
await copyDirectoryContents(
|
|
3046
3725
|
cursorAgentsSrc,
|
|
3047
|
-
|
|
3726
|
+
join20(targetDir, ".cursor", "agents")
|
|
3048
3727
|
);
|
|
3049
3728
|
}
|
|
3050
3729
|
printStatus(
|
|
@@ -3058,58 +3737,58 @@ var init_update = __esm({
|
|
|
3058
3737
|
console.log();
|
|
3059
3738
|
console.log("Replacing framework files...");
|
|
3060
3739
|
await copyFile(
|
|
3061
|
-
|
|
3062
|
-
|
|
3740
|
+
join20(templateDir, ".claude", "CLAUDE.md"),
|
|
3741
|
+
join20(targetDir, ".claude", "CLAUDE.md")
|
|
3063
3742
|
);
|
|
3064
3743
|
await copyFile(
|
|
3065
|
-
|
|
3066
|
-
|
|
3744
|
+
join20(templateDir, ".claude", "settings.json"),
|
|
3745
|
+
join20(targetDir, ".claude", "settings.json")
|
|
3067
3746
|
);
|
|
3068
3747
|
printStatus(".claude/CLAUDE.md, settings.json");
|
|
3069
3748
|
await copyDirectoryContents(
|
|
3070
|
-
|
|
3071
|
-
|
|
3749
|
+
join20(templateDir, ".claude", "commands"),
|
|
3750
|
+
join20(targetDir, ".claude", "commands")
|
|
3072
3751
|
);
|
|
3073
3752
|
await copyDirectoryContents(
|
|
3074
|
-
|
|
3075
|
-
|
|
3753
|
+
join20(templateDir, ".claude", "commands"),
|
|
3754
|
+
join20(targetDir, ".cursor", "commands")
|
|
3076
3755
|
);
|
|
3077
3756
|
printStatus(".claude/commands, .cursor/commands");
|
|
3078
|
-
const skillsReadmeSrc =
|
|
3757
|
+
const skillsReadmeSrc = join20(templateDir, ".claude", "skills", "README.md");
|
|
3079
3758
|
if (await pathExists(skillsReadmeSrc)) {
|
|
3080
3759
|
await copyFile(
|
|
3081
3760
|
skillsReadmeSrc,
|
|
3082
|
-
|
|
3761
|
+
join20(targetDir, ".claude", "skills", "README.md")
|
|
3083
3762
|
);
|
|
3084
3763
|
}
|
|
3085
3764
|
printStatus(".claude/skills/README.md");
|
|
3086
3765
|
await copyFile(
|
|
3087
|
-
|
|
3088
|
-
|
|
3766
|
+
join20(templateDir, ".cursor", "hooks.json"),
|
|
3767
|
+
join20(targetDir, ".cursor", "hooks.json")
|
|
3089
3768
|
);
|
|
3090
3769
|
printStatus(".cursor/hooks.json");
|
|
3091
3770
|
await copyFile(
|
|
3092
|
-
|
|
3093
|
-
|
|
3771
|
+
join20(templateDir, "AGENTS.md"),
|
|
3772
|
+
join20(targetDir, "AGENTS.md")
|
|
3094
3773
|
);
|
|
3095
3774
|
printStatus("AGENTS.md");
|
|
3096
|
-
const envExampleSrc =
|
|
3775
|
+
const envExampleSrc = join20(templateDir, ".env.example");
|
|
3097
3776
|
if (await pathExists(envExampleSrc)) {
|
|
3098
|
-
await copyFile(envExampleSrc,
|
|
3777
|
+
await copyFile(envExampleSrc, join20(targetDir, ".env.example"));
|
|
3099
3778
|
printStatus(".env.example");
|
|
3100
3779
|
}
|
|
3101
|
-
const knowledgeTemplatesDir =
|
|
3780
|
+
const knowledgeTemplatesDir = join20(
|
|
3102
3781
|
targetDir,
|
|
3103
3782
|
"flydocs",
|
|
3104
3783
|
"knowledge",
|
|
3105
3784
|
"templates"
|
|
3106
3785
|
);
|
|
3107
3786
|
if (!await pathExists(knowledgeTemplatesDir)) {
|
|
3108
|
-
await
|
|
3787
|
+
await mkdir10(knowledgeTemplatesDir, { recursive: true });
|
|
3109
3788
|
}
|
|
3110
3789
|
for (const tmpl of ["decision.md", "feature.md", "note.md"]) {
|
|
3111
|
-
const src =
|
|
3112
|
-
const dest =
|
|
3790
|
+
const src = join20(templateDir, "flydocs", "knowledge", "templates", tmpl);
|
|
3791
|
+
const dest = join20(knowledgeTemplatesDir, tmpl);
|
|
3113
3792
|
if (await pathExists(src) && !await pathExists(dest)) {
|
|
3114
3793
|
await copyFile(src, dest);
|
|
3115
3794
|
}
|
|
@@ -3136,18 +3815,18 @@ var init_update = __esm({
|
|
|
3136
3815
|
printWarning("Config merge failed \u2014 config.json preserved as-is");
|
|
3137
3816
|
}
|
|
3138
3817
|
await copyFile(
|
|
3139
|
-
|
|
3140
|
-
|
|
3818
|
+
join20(templateDir, ".flydocs", "version"),
|
|
3819
|
+
join20(targetDir, ".flydocs", "version")
|
|
3141
3820
|
);
|
|
3142
3821
|
printStatus(`.flydocs/version \u2192 ${version}`);
|
|
3143
|
-
const clSrc =
|
|
3822
|
+
const clSrc = join20(templateDir, "CHANGELOG.md");
|
|
3144
3823
|
if (await pathExists(clSrc)) {
|
|
3145
|
-
await copyFile(clSrc,
|
|
3824
|
+
await copyFile(clSrc, join20(targetDir, ".flydocs", "CHANGELOG.md"));
|
|
3146
3825
|
printStatus(".flydocs/CHANGELOG.md");
|
|
3147
3826
|
}
|
|
3148
|
-
const mfSrc =
|
|
3827
|
+
const mfSrc = join20(templateDir, "manifest.json");
|
|
3149
3828
|
if (await pathExists(mfSrc)) {
|
|
3150
|
-
await copyFile(mfSrc,
|
|
3829
|
+
await copyFile(mfSrc, join20(targetDir, ".flydocs", "manifest.json"));
|
|
3151
3830
|
printStatus(".flydocs/manifest.json");
|
|
3152
3831
|
}
|
|
3153
3832
|
await generateIntegrity(targetDir, version);
|
|
@@ -3209,22 +3888,22 @@ var uninstall_exports = {};
|
|
|
3209
3888
|
__export(uninstall_exports, {
|
|
3210
3889
|
default: () => uninstall_default
|
|
3211
3890
|
});
|
|
3212
|
-
import { defineCommand as
|
|
3213
|
-
import { resolve as
|
|
3214
|
-
import { readdir as
|
|
3215
|
-
import { confirm as
|
|
3216
|
-
import
|
|
3891
|
+
import { defineCommand as defineCommand4 } from "citty";
|
|
3892
|
+
import { resolve as resolve5, join as join21 } from "path";
|
|
3893
|
+
import { readdir as readdir6, rm as rm5, rename as rename2 } from "fs/promises";
|
|
3894
|
+
import { confirm as confirm5, select as select3, isCancel as isCancel6, cancel as cancel5 } from "@clack/prompts";
|
|
3895
|
+
import pc9 from "picocolors";
|
|
3217
3896
|
async function removeOwnedSkills(targetDir) {
|
|
3218
|
-
const skillsDir =
|
|
3897
|
+
const skillsDir = join21(targetDir, ".claude", "skills");
|
|
3219
3898
|
const removed = [];
|
|
3220
3899
|
if (!await pathExists(skillsDir)) {
|
|
3221
3900
|
return removed;
|
|
3222
3901
|
}
|
|
3223
3902
|
try {
|
|
3224
|
-
const entries = await
|
|
3903
|
+
const entries = await readdir6(skillsDir);
|
|
3225
3904
|
for (const entry of entries) {
|
|
3226
3905
|
if (entry.startsWith(OWNED_SKILL_PREFIX)) {
|
|
3227
|
-
await rm5(
|
|
3906
|
+
await rm5(join21(skillsDir, entry), { recursive: true, force: true });
|
|
3228
3907
|
removed.push(`.claude/skills/${entry}`);
|
|
3229
3908
|
}
|
|
3230
3909
|
}
|
|
@@ -3233,16 +3912,16 @@ async function removeOwnedSkills(targetDir) {
|
|
|
3233
3912
|
return removed;
|
|
3234
3913
|
}
|
|
3235
3914
|
async function removeOwnedCursorRules(targetDir) {
|
|
3236
|
-
const rulesDir =
|
|
3915
|
+
const rulesDir = join21(targetDir, ".cursor", "rules");
|
|
3237
3916
|
const removed = [];
|
|
3238
3917
|
if (!await pathExists(rulesDir)) {
|
|
3239
3918
|
return removed;
|
|
3240
3919
|
}
|
|
3241
3920
|
try {
|
|
3242
|
-
const entries = await
|
|
3921
|
+
const entries = await readdir6(rulesDir);
|
|
3243
3922
|
for (const entry of entries) {
|
|
3244
3923
|
if (entry.startsWith(OWNED_RULE_PREFIX) && entry.endsWith(".mdc")) {
|
|
3245
|
-
await rm5(
|
|
3924
|
+
await rm5(join21(rulesDir, entry), { force: true });
|
|
3246
3925
|
removed.push(`.cursor/rules/${entry}`);
|
|
3247
3926
|
}
|
|
3248
3927
|
}
|
|
@@ -3252,7 +3931,7 @@ async function removeOwnedCursorRules(targetDir) {
|
|
|
3252
3931
|
}
|
|
3253
3932
|
async function isEmptyDir(dirPath) {
|
|
3254
3933
|
try {
|
|
3255
|
-
const entries = await
|
|
3934
|
+
const entries = await readdir6(dirPath);
|
|
3256
3935
|
return entries.length === 0;
|
|
3257
3936
|
} catch {
|
|
3258
3937
|
return false;
|
|
@@ -3261,7 +3940,7 @@ async function isEmptyDir(dirPath) {
|
|
|
3261
3940
|
async function cleanupEmptyParents(targetDir, dirs) {
|
|
3262
3941
|
const cleaned = [];
|
|
3263
3942
|
for (const dir of dirs) {
|
|
3264
|
-
const fullPath =
|
|
3943
|
+
const fullPath = join21(targetDir, dir);
|
|
3265
3944
|
if (await pathExists(fullPath) && await isEmptyDir(fullPath)) {
|
|
3266
3945
|
await rm5(fullPath, { recursive: true, force: true });
|
|
3267
3946
|
cleaned.push(dir);
|
|
@@ -3293,7 +3972,7 @@ var init_uninstall = __esm({
|
|
|
3293
3972
|
];
|
|
3294
3973
|
OWNED_SKILL_PREFIX = "flydocs-";
|
|
3295
3974
|
OWNED_RULE_PREFIX = "flydocs-";
|
|
3296
|
-
uninstall_default =
|
|
3975
|
+
uninstall_default = defineCommand4({
|
|
3297
3976
|
meta: {
|
|
3298
3977
|
name: "uninstall",
|
|
3299
3978
|
description: "Remove FlyDocs from a project directory"
|
|
@@ -3329,7 +4008,7 @@ var init_uninstall = __esm({
|
|
|
3329
4008
|
printBanner(CLI_VERSION);
|
|
3330
4009
|
let targetDir;
|
|
3331
4010
|
if (args.path) {
|
|
3332
|
-
targetDir =
|
|
4011
|
+
targetDir = resolve5(args.path.replace(/^~/, process.env.HOME ?? "~"));
|
|
3333
4012
|
} else if (args.here) {
|
|
3334
4013
|
targetDir = process.cwd();
|
|
3335
4014
|
} else {
|
|
@@ -3339,9 +4018,9 @@ var init_uninstall = __esm({
|
|
|
3339
4018
|
printError(`Directory does not exist: ${targetDir}`);
|
|
3340
4019
|
process.exit(1);
|
|
3341
4020
|
}
|
|
3342
|
-
targetDir =
|
|
3343
|
-
const hasFlydocs = await pathExists(
|
|
3344
|
-
const hasAgentsMd = await pathExists(
|
|
4021
|
+
targetDir = resolve5(targetDir);
|
|
4022
|
+
const hasFlydocs = await pathExists(join21(targetDir, ".flydocs"));
|
|
4023
|
+
const hasAgentsMd = await pathExists(join21(targetDir, "AGENTS.md"));
|
|
3345
4024
|
if (!hasFlydocs && !hasAgentsMd) {
|
|
3346
4025
|
printError(`Not a FlyDocs project: ${targetDir}`);
|
|
3347
4026
|
printInfo("No .flydocs/ directory or AGENTS.md found.");
|
|
@@ -3353,7 +4032,7 @@ var init_uninstall = __esm({
|
|
|
3353
4032
|
const removeAll = forceAll || args.all;
|
|
3354
4033
|
const skipPrompts = forceAll || args.yes;
|
|
3355
4034
|
let contentAction = "preserve";
|
|
3356
|
-
const hasUserContent = await pathExists(
|
|
4035
|
+
const hasUserContent = await pathExists(join21(targetDir, "flydocs"));
|
|
3357
4036
|
if (hasUserContent) {
|
|
3358
4037
|
if (removeAll) {
|
|
3359
4038
|
contentAction = "remove";
|
|
@@ -3378,8 +4057,8 @@ var init_uninstall = __esm({
|
|
|
3378
4057
|
}
|
|
3379
4058
|
]
|
|
3380
4059
|
});
|
|
3381
|
-
if (
|
|
3382
|
-
|
|
4060
|
+
if (isCancel6(choice)) {
|
|
4061
|
+
cancel5("Uninstall cancelled.");
|
|
3383
4062
|
process.exit(0);
|
|
3384
4063
|
}
|
|
3385
4064
|
contentAction = choice;
|
|
@@ -3387,40 +4066,40 @@ var init_uninstall = __esm({
|
|
|
3387
4066
|
}
|
|
3388
4067
|
if (!skipPrompts) {
|
|
3389
4068
|
console.log();
|
|
3390
|
-
console.log(
|
|
4069
|
+
console.log(pc9.bold("The following will be removed:"));
|
|
3391
4070
|
console.log();
|
|
3392
4071
|
console.log(" Framework files:");
|
|
3393
4072
|
for (const [path] of ALWAYS_REMOVED) {
|
|
3394
|
-
console.log(` ${
|
|
4073
|
+
console.log(` ${pc9.dim(path)}`);
|
|
3395
4074
|
}
|
|
3396
|
-
console.log(` ${
|
|
3397
|
-
console.log(` ${
|
|
4075
|
+
console.log(` ${pc9.dim(".claude/skills/flydocs-*")}`);
|
|
4076
|
+
console.log(` ${pc9.dim(".cursor/rules/flydocs-*.mdc")}`);
|
|
3398
4077
|
if (hasUserContent) {
|
|
3399
4078
|
if (contentAction === "archive") {
|
|
3400
4079
|
console.log();
|
|
3401
4080
|
console.log(
|
|
3402
|
-
` User content: ${
|
|
4081
|
+
` User content: ${pc9.yellow("flydocs/ -> flydocs-archive/")}`
|
|
3403
4082
|
);
|
|
3404
4083
|
} else if (contentAction === "remove") {
|
|
3405
4084
|
console.log();
|
|
3406
|
-
console.log(` User content: ${
|
|
4085
|
+
console.log(` User content: ${pc9.red("flydocs/ (deleted)")}`);
|
|
3407
4086
|
} else {
|
|
3408
4087
|
console.log();
|
|
3409
|
-
console.log(` User content: ${
|
|
4088
|
+
console.log(` User content: ${pc9.green("flydocs/ (preserved)")}`);
|
|
3410
4089
|
}
|
|
3411
4090
|
}
|
|
3412
4091
|
console.log();
|
|
3413
|
-
console.log(
|
|
4092
|
+
console.log(pc9.bold("Preserved:"));
|
|
3414
4093
|
console.log(
|
|
3415
|
-
` ${
|
|
4094
|
+
` ${pc9.dim(".claude/skills/ (non-flydocs community skills)")}`
|
|
3416
4095
|
);
|
|
3417
|
-
console.log(` ${
|
|
4096
|
+
console.log(` ${pc9.dim(".env, .env.local")}`);
|
|
3418
4097
|
console.log();
|
|
3419
|
-
const shouldContinue = await
|
|
4098
|
+
const shouldContinue = await confirm5({
|
|
3420
4099
|
message: "Proceed with uninstall?"
|
|
3421
4100
|
});
|
|
3422
|
-
if (
|
|
3423
|
-
|
|
4101
|
+
if (isCancel6(shouldContinue) || !shouldContinue) {
|
|
4102
|
+
cancel5("Uninstall cancelled.");
|
|
3424
4103
|
process.exit(0);
|
|
3425
4104
|
}
|
|
3426
4105
|
}
|
|
@@ -3436,7 +4115,7 @@ var init_uninstall = __esm({
|
|
|
3436
4115
|
const removedRules = await removeOwnedCursorRules(targetDir);
|
|
3437
4116
|
result.removed.push(...removedRules);
|
|
3438
4117
|
for (const [relativePath, type] of ALWAYS_REMOVED) {
|
|
3439
|
-
const fullPath =
|
|
4118
|
+
const fullPath = join21(targetDir, relativePath);
|
|
3440
4119
|
if (!await pathExists(fullPath)) {
|
|
3441
4120
|
result.skipped.push(relativePath);
|
|
3442
4121
|
continue;
|
|
@@ -3454,9 +4133,9 @@ var init_uninstall = __esm({
|
|
|
3454
4133
|
}
|
|
3455
4134
|
}
|
|
3456
4135
|
if (hasUserContent) {
|
|
3457
|
-
const flydocsPath =
|
|
4136
|
+
const flydocsPath = join21(targetDir, "flydocs");
|
|
3458
4137
|
if (contentAction === "archive") {
|
|
3459
|
-
const archivePath =
|
|
4138
|
+
const archivePath = join21(targetDir, "flydocs-archive");
|
|
3460
4139
|
if (await pathExists(archivePath)) {
|
|
3461
4140
|
await rm5(archivePath, { recursive: true, force: true });
|
|
3462
4141
|
}
|
|
@@ -3482,17 +4161,17 @@ var init_uninstall = __esm({
|
|
|
3482
4161
|
result.restored = originals.map((f) => f.relativePath);
|
|
3483
4162
|
}
|
|
3484
4163
|
console.log();
|
|
3485
|
-
console.log(
|
|
4164
|
+
console.log(pc9.bold("Uninstall Summary"));
|
|
3486
4165
|
console.log();
|
|
3487
4166
|
if (result.removed.length > 0) {
|
|
3488
|
-
console.log(` ${
|
|
4167
|
+
console.log(` ${pc9.green("Removed")} (${result.removed.length}):`);
|
|
3489
4168
|
for (const item of result.removed) {
|
|
3490
4169
|
printStatus(item);
|
|
3491
4170
|
}
|
|
3492
4171
|
}
|
|
3493
4172
|
if (result.archived.length > 0) {
|
|
3494
4173
|
console.log();
|
|
3495
|
-
console.log(` ${
|
|
4174
|
+
console.log(` ${pc9.yellow("Archived")} (${result.archived.length}):`);
|
|
3496
4175
|
for (const item of result.archived) {
|
|
3497
4176
|
printInfo(item);
|
|
3498
4177
|
}
|
|
@@ -3500,7 +4179,7 @@ var init_uninstall = __esm({
|
|
|
3500
4179
|
if (result.restored.length > 0) {
|
|
3501
4180
|
console.log();
|
|
3502
4181
|
console.log(
|
|
3503
|
-
` ${
|
|
4182
|
+
` ${pc9.green("Restored")} (${result.restored.length} pre-FlyDocs original(s)):`
|
|
3504
4183
|
);
|
|
3505
4184
|
for (const item of result.restored) {
|
|
3506
4185
|
printInfo(item);
|
|
@@ -3509,16 +4188,16 @@ var init_uninstall = __esm({
|
|
|
3509
4188
|
if (result.skipped.length > 0) {
|
|
3510
4189
|
console.log();
|
|
3511
4190
|
console.log(
|
|
3512
|
-
` ${
|
|
4191
|
+
` ${pc9.dim("Skipped")} (${result.skipped.length} \u2014 not found):`
|
|
3513
4192
|
);
|
|
3514
4193
|
for (const item of result.skipped) {
|
|
3515
|
-
console.log(` ${
|
|
4194
|
+
console.log(` ${pc9.dim(item)}`);
|
|
3516
4195
|
}
|
|
3517
4196
|
}
|
|
3518
4197
|
console.log();
|
|
3519
4198
|
printStatus("FlyDocs has been removed from this project.");
|
|
3520
4199
|
console.log();
|
|
3521
|
-
printInfo(`To reinstall: ${
|
|
4200
|
+
printInfo(`To reinstall: ${pc9.cyan("npx @flydocs/cli install --here")}`);
|
|
3522
4201
|
console.log();
|
|
3523
4202
|
}
|
|
3524
4203
|
});
|
|
@@ -3530,28 +4209,28 @@ var setup_exports = {};
|
|
|
3530
4209
|
__export(setup_exports, {
|
|
3531
4210
|
default: () => setup_default
|
|
3532
4211
|
});
|
|
3533
|
-
import { defineCommand as
|
|
3534
|
-
import
|
|
4212
|
+
import { defineCommand as defineCommand5 } from "citty";
|
|
4213
|
+
import pc10 from "picocolors";
|
|
3535
4214
|
var setup_default;
|
|
3536
4215
|
var init_setup = __esm({
|
|
3537
4216
|
"src/commands/setup.ts"() {
|
|
3538
4217
|
"use strict";
|
|
3539
|
-
setup_default =
|
|
4218
|
+
setup_default = defineCommand5({
|
|
3540
4219
|
meta: {
|
|
3541
4220
|
name: "setup",
|
|
3542
4221
|
description: "Configure FlyDocs settings for this project"
|
|
3543
4222
|
},
|
|
3544
4223
|
run() {
|
|
3545
4224
|
console.log();
|
|
3546
|
-
console.log(` ${
|
|
4225
|
+
console.log(` ${pc10.bold("FlyDocs Setup")}`);
|
|
3547
4226
|
console.log();
|
|
3548
4227
|
console.log(` Setup runs inside your IDE as an interactive AI command.`);
|
|
3549
4228
|
console.log();
|
|
3550
4229
|
console.log(
|
|
3551
|
-
` ${
|
|
4230
|
+
` ${pc10.cyan("Claude Code:")} Type ${pc10.bold("/flydocs-setup")} in chat`
|
|
3552
4231
|
);
|
|
3553
4232
|
console.log(
|
|
3554
|
-
` ${
|
|
4233
|
+
` ${pc10.cyan("Cursor:")} Type ${pc10.bold("/flydocs-setup")} in chat`
|
|
3555
4234
|
);
|
|
3556
4235
|
console.log();
|
|
3557
4236
|
console.log(` This configures your project context, detects your stack,`);
|
|
@@ -3567,14 +4246,14 @@ var skills_exports = {};
|
|
|
3567
4246
|
__export(skills_exports, {
|
|
3568
4247
|
default: () => skills_default
|
|
3569
4248
|
});
|
|
3570
|
-
import { defineCommand as
|
|
3571
|
-
import
|
|
4249
|
+
import { defineCommand as defineCommand6 } from "citty";
|
|
4250
|
+
import pc11 from "picocolors";
|
|
3572
4251
|
var list, search, add, remove, skills_default;
|
|
3573
4252
|
var init_skills2 = __esm({
|
|
3574
4253
|
"src/commands/skills.ts"() {
|
|
3575
4254
|
"use strict";
|
|
3576
4255
|
init_skill_manager();
|
|
3577
|
-
list =
|
|
4256
|
+
list = defineCommand6({
|
|
3578
4257
|
meta: {
|
|
3579
4258
|
name: "list",
|
|
3580
4259
|
description: "List installed skills"
|
|
@@ -3590,26 +4269,26 @@ var init_skills2 = __esm({
|
|
|
3590
4269
|
console.log(`${total} skill(s) installed:`);
|
|
3591
4270
|
if (result.platform.length > 0) {
|
|
3592
4271
|
console.log();
|
|
3593
|
-
console.log(
|
|
4272
|
+
console.log(pc11.bold("Platform"));
|
|
3594
4273
|
for (const skill of result.platform) {
|
|
3595
4274
|
console.log(
|
|
3596
|
-
` ${skill.name} ${
|
|
4275
|
+
` ${skill.name} ${pc11.dim(`(${skill.triggers} triggers)`)}`
|
|
3597
4276
|
);
|
|
3598
4277
|
}
|
|
3599
4278
|
}
|
|
3600
4279
|
if (result.community.length > 0) {
|
|
3601
4280
|
console.log();
|
|
3602
|
-
console.log(
|
|
4281
|
+
console.log(pc11.bold("Community"));
|
|
3603
4282
|
for (const skill of result.community) {
|
|
3604
4283
|
console.log(
|
|
3605
|
-
` ${skill.name} ${
|
|
4284
|
+
` ${skill.name} ${pc11.dim(`(${skill.triggers} triggers)`)}`
|
|
3606
4285
|
);
|
|
3607
4286
|
}
|
|
3608
4287
|
}
|
|
3609
4288
|
console.log();
|
|
3610
4289
|
}
|
|
3611
4290
|
});
|
|
3612
|
-
search =
|
|
4291
|
+
search = defineCommand6({
|
|
3613
4292
|
meta: {
|
|
3614
4293
|
name: "search",
|
|
3615
4294
|
description: "Search community skills"
|
|
@@ -3625,24 +4304,24 @@ var init_skills2 = __esm({
|
|
|
3625
4304
|
const results = await searchCatalog(args.keyword);
|
|
3626
4305
|
if (results.length === 0) {
|
|
3627
4306
|
console.log(`No skills found for "${args.keyword}".`);
|
|
3628
|
-
console.log(` Browse the catalog at: ${
|
|
4307
|
+
console.log(` Browse the catalog at: ${pc11.cyan("https://skills.sh/")}`);
|
|
3629
4308
|
return;
|
|
3630
4309
|
}
|
|
3631
4310
|
console.log();
|
|
3632
4311
|
console.log(`${results.length} skill(s) matching "${args.keyword}":`);
|
|
3633
4312
|
console.log();
|
|
3634
4313
|
for (const skill of results) {
|
|
3635
|
-
console.log(` ${
|
|
4314
|
+
console.log(` ${pc11.bold(skill.name)}`);
|
|
3636
4315
|
console.log(` ${skill.description}`);
|
|
3637
|
-
console.log(` ${
|
|
4316
|
+
console.log(` ${pc11.dim(skill.repo)}`);
|
|
3638
4317
|
if (skill.tags.length > 0) {
|
|
3639
|
-
console.log(` ${
|
|
4318
|
+
console.log(` ${pc11.dim(skill.tags.join(", "))}`);
|
|
3640
4319
|
}
|
|
3641
4320
|
console.log();
|
|
3642
4321
|
}
|
|
3643
4322
|
}
|
|
3644
4323
|
});
|
|
3645
|
-
add =
|
|
4324
|
+
add = defineCommand6({
|
|
3646
4325
|
meta: {
|
|
3647
4326
|
name: "add",
|
|
3648
4327
|
description: "Install a community skill"
|
|
@@ -3658,7 +4337,7 @@ var init_skills2 = __esm({
|
|
|
3658
4337
|
await addSkill(process.cwd(), args.source);
|
|
3659
4338
|
}
|
|
3660
4339
|
});
|
|
3661
|
-
remove =
|
|
4340
|
+
remove = defineCommand6({
|
|
3662
4341
|
meta: {
|
|
3663
4342
|
name: "remove",
|
|
3664
4343
|
description: "Remove an installed community skill"
|
|
@@ -3674,7 +4353,7 @@ var init_skills2 = __esm({
|
|
|
3674
4353
|
await removeSkill(process.cwd(), args.name);
|
|
3675
4354
|
}
|
|
3676
4355
|
});
|
|
3677
|
-
skills_default =
|
|
4356
|
+
skills_default = defineCommand6({
|
|
3678
4357
|
meta: {
|
|
3679
4358
|
name: "skills",
|
|
3680
4359
|
description: "Manage FlyDocs skills (list, search, add, remove)"
|
|
@@ -3694,10 +4373,10 @@ var connect_exports = {};
|
|
|
3694
4373
|
__export(connect_exports, {
|
|
3695
4374
|
default: () => connect_default
|
|
3696
4375
|
});
|
|
3697
|
-
import { defineCommand as
|
|
3698
|
-
import { text as
|
|
3699
|
-
import
|
|
3700
|
-
import { join as
|
|
4376
|
+
import { defineCommand as defineCommand7 } from "citty";
|
|
4377
|
+
import { text as text4, confirm as confirm6, isCancel as isCancel7, cancel as cancel6 } from "@clack/prompts";
|
|
4378
|
+
import pc12 from "picocolors";
|
|
4379
|
+
import { join as join22 } from "path";
|
|
3701
4380
|
var connect_default;
|
|
3702
4381
|
var init_connect = __esm({
|
|
3703
4382
|
"src/commands/connect.ts"() {
|
|
@@ -3707,7 +4386,7 @@ var init_connect = __esm({
|
|
|
3707
4386
|
init_template();
|
|
3708
4387
|
init_ui();
|
|
3709
4388
|
init_api_key();
|
|
3710
|
-
connect_default =
|
|
4389
|
+
connect_default = defineCommand7({
|
|
3711
4390
|
meta: {
|
|
3712
4391
|
name: "connect",
|
|
3713
4392
|
description: "Connect FlyDocs to a cloud provider"
|
|
@@ -3732,11 +4411,11 @@ var init_connect = __esm({
|
|
|
3732
4411
|
},
|
|
3733
4412
|
async run({ args }) {
|
|
3734
4413
|
const targetDir = args.path ?? process.cwd();
|
|
3735
|
-
const configPath =
|
|
4414
|
+
const configPath = join22(targetDir, ".flydocs", "config.json");
|
|
3736
4415
|
if (!await pathExists(configPath)) {
|
|
3737
4416
|
printError("Not a FlyDocs project (.flydocs/config.json not found).");
|
|
3738
4417
|
console.log(
|
|
3739
|
-
` Run ${
|
|
4418
|
+
` Run ${pc12.cyan("flydocs")} first to install FlyDocs in this project.`
|
|
3740
4419
|
);
|
|
3741
4420
|
process.exit(1);
|
|
3742
4421
|
}
|
|
@@ -3744,24 +4423,24 @@ var init_connect = __esm({
|
|
|
3744
4423
|
if (config.tier === "cloud") {
|
|
3745
4424
|
printInfo("This project is already connected to the cloud tier.");
|
|
3746
4425
|
console.log();
|
|
3747
|
-
const reconnect = await
|
|
4426
|
+
const reconnect = await confirm6({
|
|
3748
4427
|
message: "Want to update your API key?"
|
|
3749
4428
|
});
|
|
3750
|
-
if (
|
|
4429
|
+
if (isCancel7(reconnect) || !reconnect) {
|
|
3751
4430
|
console.log(` No changes made.`);
|
|
3752
4431
|
return;
|
|
3753
4432
|
}
|
|
3754
4433
|
}
|
|
3755
4434
|
console.log();
|
|
3756
|
-
console.log(` ${
|
|
4435
|
+
console.log(` ${pc12.bold("Connect to FlyDocs Cloud")}`);
|
|
3757
4436
|
console.log();
|
|
3758
4437
|
console.log(
|
|
3759
|
-
` ${
|
|
4438
|
+
` ${pc12.dim("Get your API key (fdk_...) from your FlyDocs dashboard")}`
|
|
3760
4439
|
);
|
|
3761
4440
|
console.log();
|
|
3762
4441
|
let apiKey = args.key ?? "";
|
|
3763
4442
|
if (!apiKey) {
|
|
3764
|
-
const keyInput = await
|
|
4443
|
+
const keyInput = await text4({
|
|
3765
4444
|
message: "Enter your API key",
|
|
3766
4445
|
placeholder: "fdk_...",
|
|
3767
4446
|
validate(value) {
|
|
@@ -3772,8 +4451,8 @@ var init_connect = __esm({
|
|
|
3772
4451
|
return void 0;
|
|
3773
4452
|
}
|
|
3774
4453
|
});
|
|
3775
|
-
if (
|
|
3776
|
-
|
|
4454
|
+
if (isCancel7(keyInput)) {
|
|
4455
|
+
cancel6("Connection cancelled.");
|
|
3777
4456
|
process.exit(0);
|
|
3778
4457
|
}
|
|
3779
4458
|
apiKey = keyInput.trim();
|
|
@@ -3794,7 +4473,7 @@ var init_connect = __esm({
|
|
|
3794
4473
|
console.log(` Check your key and try again.`);
|
|
3795
4474
|
process.exit(1);
|
|
3796
4475
|
}
|
|
3797
|
-
printStatus(`Connected to ${
|
|
4476
|
+
printStatus(`Connected to ${pc12.bold(result.org)}`);
|
|
3798
4477
|
} catch {
|
|
3799
4478
|
printError(
|
|
3800
4479
|
"Could not reach relay API. Check your network and try again."
|
|
@@ -3802,7 +4481,7 @@ var init_connect = __esm({
|
|
|
3802
4481
|
process.exit(1);
|
|
3803
4482
|
}
|
|
3804
4483
|
const envFile = await storeEnvKey(targetDir, "FLYDOCS_API_KEY", apiKey);
|
|
3805
|
-
printStatus(`API key stored in ${
|
|
4484
|
+
printStatus(`API key stored in ${pc12.dim(envFile)}`);
|
|
3806
4485
|
} else {
|
|
3807
4486
|
try {
|
|
3808
4487
|
const result = await validateLinearKey(apiKey);
|
|
@@ -3812,7 +4491,7 @@ var init_connect = __esm({
|
|
|
3812
4491
|
process.exit(1);
|
|
3813
4492
|
}
|
|
3814
4493
|
printStatus(
|
|
3815
|
-
`Authenticated as ${
|
|
4494
|
+
`Authenticated as ${pc12.bold(result.name)} (${result.email})`
|
|
3816
4495
|
);
|
|
3817
4496
|
} catch {
|
|
3818
4497
|
printError("Invalid API key or network error.");
|
|
@@ -3820,7 +4499,7 @@ var init_connect = __esm({
|
|
|
3820
4499
|
process.exit(1);
|
|
3821
4500
|
}
|
|
3822
4501
|
const envFile = await storeEnvKey(targetDir, "LINEAR_API_KEY", apiKey);
|
|
3823
|
-
printStatus(`API key stored in ${
|
|
4502
|
+
printStatus(`API key stored in ${pc12.dim(envFile)}`);
|
|
3824
4503
|
}
|
|
3825
4504
|
const wasLocal = config.tier === "local";
|
|
3826
4505
|
config.tier = "cloud";
|
|
@@ -3836,14 +4515,464 @@ var init_connect = __esm({
|
|
|
3836
4515
|
}
|
|
3837
4516
|
console.log();
|
|
3838
4517
|
console.log(
|
|
3839
|
-
` ${
|
|
4518
|
+
` ${pc12.bold("Connected!")} Your project is now on the cloud tier.`
|
|
3840
4519
|
);
|
|
3841
4520
|
console.log();
|
|
3842
4521
|
console.log(` Next steps:`);
|
|
3843
4522
|
console.log(
|
|
3844
|
-
` 1. Run ${
|
|
4523
|
+
` 1. Run ${pc12.cyan("/flydocs-setup")} in your IDE to configure your project`
|
|
3845
4524
|
);
|
|
3846
|
-
console.log(` 2. Run ${
|
|
4525
|
+
console.log(` 2. Run ${pc12.cyan("/start-session")} to begin working`);
|
|
4526
|
+
console.log();
|
|
4527
|
+
}
|
|
4528
|
+
});
|
|
4529
|
+
}
|
|
4530
|
+
});
|
|
4531
|
+
|
|
4532
|
+
// src/commands/auth.ts
|
|
4533
|
+
var auth_exports = {};
|
|
4534
|
+
__export(auth_exports, {
|
|
4535
|
+
default: () => auth_default
|
|
4536
|
+
});
|
|
4537
|
+
import { defineCommand as defineCommand8 } from "citty";
|
|
4538
|
+
import { text as text5, confirm as confirm7, isCancel as isCancel8, cancel as cancel7 } from "@clack/prompts";
|
|
4539
|
+
import pc13 from "picocolors";
|
|
4540
|
+
var auth_default;
|
|
4541
|
+
var init_auth = __esm({
|
|
4542
|
+
"src/commands/auth.ts"() {
|
|
4543
|
+
"use strict";
|
|
4544
|
+
init_ui();
|
|
4545
|
+
init_api_key();
|
|
4546
|
+
init_global_config();
|
|
4547
|
+
auth_default = defineCommand8({
|
|
4548
|
+
meta: {
|
|
4549
|
+
name: "auth",
|
|
4550
|
+
description: "Store API key globally (~/.flydocs/credentials)"
|
|
4551
|
+
},
|
|
4552
|
+
args: {
|
|
4553
|
+
key: {
|
|
4554
|
+
type: "positional",
|
|
4555
|
+
description: "FlyDocs API key (fdk_...)",
|
|
4556
|
+
required: false
|
|
4557
|
+
}
|
|
4558
|
+
},
|
|
4559
|
+
async run({ args }) {
|
|
4560
|
+
console.log();
|
|
4561
|
+
console.log(` ${pc13.bold("FlyDocs Authentication")}`);
|
|
4562
|
+
console.log();
|
|
4563
|
+
let apiKey = args.key ?? "";
|
|
4564
|
+
const existing = await readGlobalCredential();
|
|
4565
|
+
if (existing?.apiKey && !apiKey) {
|
|
4566
|
+
printInfo(
|
|
4567
|
+
`Existing key found: ${pc13.dim(existing.apiKey.slice(0, 8) + "...")}`
|
|
4568
|
+
);
|
|
4569
|
+
const replace = await confirm7({
|
|
4570
|
+
message: "Replace with a new key?"
|
|
4571
|
+
});
|
|
4572
|
+
if (isCancel8(replace) || !replace) {
|
|
4573
|
+
console.log(` No changes made.`);
|
|
4574
|
+
return;
|
|
4575
|
+
}
|
|
4576
|
+
}
|
|
4577
|
+
if (!apiKey) {
|
|
4578
|
+
console.log(
|
|
4579
|
+
` ${pc13.dim("Get your API key (fdk_...) from your FlyDocs dashboard")}`
|
|
4580
|
+
);
|
|
4581
|
+
console.log();
|
|
4582
|
+
const keyInput = await text5({
|
|
4583
|
+
message: "Enter your API key",
|
|
4584
|
+
placeholder: "fdk_...",
|
|
4585
|
+
validate(value) {
|
|
4586
|
+
if (!value.trim()) return "API key is required";
|
|
4587
|
+
if (detectKeyType(value.trim()) !== "relay") {
|
|
4588
|
+
return "Key must start with fdk_ (FlyDocs API key)";
|
|
4589
|
+
}
|
|
4590
|
+
return void 0;
|
|
4591
|
+
}
|
|
4592
|
+
});
|
|
4593
|
+
if (isCancel8(keyInput)) {
|
|
4594
|
+
cancel7("Authentication cancelled.");
|
|
4595
|
+
process.exit(0);
|
|
4596
|
+
}
|
|
4597
|
+
apiKey = keyInput.trim();
|
|
4598
|
+
}
|
|
4599
|
+
if (detectKeyType(apiKey) !== "relay") {
|
|
4600
|
+
printError("Invalid key format. Expected fdk_ prefix (FlyDocs API key).");
|
|
4601
|
+
process.exit(1);
|
|
4602
|
+
}
|
|
4603
|
+
if (existing?.apiKey === apiKey) {
|
|
4604
|
+
printInfo("This key is already stored.");
|
|
4605
|
+
await checkCredentialPermissions();
|
|
4606
|
+
return;
|
|
4607
|
+
}
|
|
4608
|
+
printInfo("Validating API key...");
|
|
4609
|
+
try {
|
|
4610
|
+
const result = await validateRelayKey(apiKey);
|
|
4611
|
+
if (!result.valid) {
|
|
4612
|
+
printError("Invalid API key. Check your key and try again.");
|
|
4613
|
+
process.exit(1);
|
|
4614
|
+
}
|
|
4615
|
+
printStatus(`Authenticated with ${pc13.bold(result.org)}`);
|
|
4616
|
+
} catch {
|
|
4617
|
+
printError(
|
|
4618
|
+
"Could not reach FlyDocs API. Check your network and try again."
|
|
4619
|
+
);
|
|
4620
|
+
process.exit(1);
|
|
4621
|
+
}
|
|
4622
|
+
if (existing?.apiKey && existing.apiKey !== apiKey) {
|
|
4623
|
+
printWarning("Replacing existing key.");
|
|
4624
|
+
}
|
|
4625
|
+
await writeGlobalCredential({
|
|
4626
|
+
apiKey,
|
|
4627
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4628
|
+
lastValidated: (/* @__PURE__ */ new Date()).toISOString()
|
|
4629
|
+
});
|
|
4630
|
+
printStatus(`Key stored at ${pc13.dim(credentialsPath())}`);
|
|
4631
|
+
await checkCredentialPermissions();
|
|
4632
|
+
console.log();
|
|
4633
|
+
console.log(` ${pc13.bold("Authenticated!")} Key stored globally.`);
|
|
4634
|
+
console.log(` All FlyDocs projects on this machine will use this key.`);
|
|
4635
|
+
console.log();
|
|
4636
|
+
}
|
|
4637
|
+
});
|
|
4638
|
+
}
|
|
4639
|
+
});
|
|
4640
|
+
|
|
4641
|
+
// src/commands/sync.ts
|
|
4642
|
+
var sync_exports = {};
|
|
4643
|
+
__export(sync_exports, {
|
|
4644
|
+
default: () => sync_default
|
|
4645
|
+
});
|
|
4646
|
+
import { defineCommand as defineCommand9 } from "citty";
|
|
4647
|
+
import pc14 from "picocolors";
|
|
4648
|
+
import { join as join23 } from "path";
|
|
4649
|
+
import { mkdir as mkdir11, writeFile as writeFile13 } from "fs/promises";
|
|
4650
|
+
var sync_default;
|
|
4651
|
+
var init_sync = __esm({
|
|
4652
|
+
"src/commands/sync.ts"() {
|
|
4653
|
+
"use strict";
|
|
4654
|
+
init_ui();
|
|
4655
|
+
init_global_config();
|
|
4656
|
+
init_config();
|
|
4657
|
+
init_config_integrity();
|
|
4658
|
+
init_fs_ops();
|
|
4659
|
+
init_types();
|
|
4660
|
+
init_relay_client();
|
|
4661
|
+
sync_default = defineCommand9({
|
|
4662
|
+
meta: {
|
|
4663
|
+
name: "sync",
|
|
4664
|
+
description: "Pull latest config and templates from server"
|
|
4665
|
+
},
|
|
4666
|
+
args: {
|
|
4667
|
+
path: {
|
|
4668
|
+
type: "string",
|
|
4669
|
+
description: "Path to project directory"
|
|
4670
|
+
}
|
|
4671
|
+
},
|
|
4672
|
+
async run({ args }) {
|
|
4673
|
+
const targetDir = args.path ?? process.cwd();
|
|
4674
|
+
const changes = [];
|
|
4675
|
+
console.log();
|
|
4676
|
+
printInfo("Syncing with server...");
|
|
4677
|
+
const resolved = await resolveApiKey(void 0, targetDir);
|
|
4678
|
+
if (!resolved) {
|
|
4679
|
+
printError(
|
|
4680
|
+
"No API key found. Run `flydocs auth` or `flydocs init` first."
|
|
4681
|
+
);
|
|
4682
|
+
process.exit(1);
|
|
4683
|
+
}
|
|
4684
|
+
const apiKey = resolved.key;
|
|
4685
|
+
let currentTemplateVersion = 0;
|
|
4686
|
+
try {
|
|
4687
|
+
const currentConfig = await readAnyConfig(targetDir);
|
|
4688
|
+
if (isConfigV2(currentConfig)) {
|
|
4689
|
+
currentTemplateVersion = currentConfig.configVersion ?? 0;
|
|
4690
|
+
}
|
|
4691
|
+
} catch {
|
|
4692
|
+
}
|
|
4693
|
+
let serverResponse;
|
|
4694
|
+
try {
|
|
4695
|
+
serverResponse = await fetchConfigV2(apiKey);
|
|
4696
|
+
} catch (err) {
|
|
4697
|
+
if (err instanceof RelayError) {
|
|
4698
|
+
printWarning(
|
|
4699
|
+
`Server unavailable (${err.status}), using cached config.`
|
|
4700
|
+
);
|
|
4701
|
+
} else {
|
|
4702
|
+
printWarning("Server unreachable, using cached config.");
|
|
4703
|
+
}
|
|
4704
|
+
console.log(` ${pc14.dim("Config may be stale. Retry when connected.")}`);
|
|
4705
|
+
return;
|
|
4706
|
+
}
|
|
4707
|
+
if (!serverResponse.valid) {
|
|
4708
|
+
printWarning("Server returned invalid config. Keeping current config.");
|
|
4709
|
+
return;
|
|
4710
|
+
}
|
|
4711
|
+
await mkdir11(join23(targetDir, ".flydocs"), { recursive: true });
|
|
4712
|
+
const configWithHash = applyConfigHash(serverResponse.config);
|
|
4713
|
+
await writeConfig(targetDir, configWithHash);
|
|
4714
|
+
changes.push("Updated .flydocs/config.json");
|
|
4715
|
+
const serverTemplateVersion = serverResponse.templates.version;
|
|
4716
|
+
if (serverTemplateVersion > currentTemplateVersion) {
|
|
4717
|
+
try {
|
|
4718
|
+
const templatesResponse = await fetchTemplates(
|
|
4719
|
+
apiKey,
|
|
4720
|
+
currentTemplateVersion
|
|
4721
|
+
);
|
|
4722
|
+
if (templatesResponse.templates.length > 0) {
|
|
4723
|
+
const templatesDir = join23(
|
|
4724
|
+
targetDir,
|
|
4725
|
+
".claude",
|
|
4726
|
+
"skills",
|
|
4727
|
+
"flydocs-workflow",
|
|
4728
|
+
"templates"
|
|
4729
|
+
);
|
|
4730
|
+
await mkdir11(templatesDir, { recursive: true });
|
|
4731
|
+
for (const template of templatesResponse.templates) {
|
|
4732
|
+
const filename = `${template.type}.md`;
|
|
4733
|
+
const subdir = template.category === "issue" ? "issues" : template.category === "pr" ? "pr" : template.category === "comment" ? "." : ".";
|
|
4734
|
+
const templateDir = join23(templatesDir, subdir);
|
|
4735
|
+
await mkdir11(templateDir, { recursive: true });
|
|
4736
|
+
await writeFile13(
|
|
4737
|
+
join23(templateDir, filename),
|
|
4738
|
+
template.content,
|
|
4739
|
+
"utf-8"
|
|
4740
|
+
);
|
|
4741
|
+
}
|
|
4742
|
+
changes.push(
|
|
4743
|
+
`Updated ${templatesResponse.templates.length} templates (v${currentTemplateVersion} \u2192 v${serverTemplateVersion})`
|
|
4744
|
+
);
|
|
4745
|
+
}
|
|
4746
|
+
} catch (err) {
|
|
4747
|
+
if (err instanceof RelayError) {
|
|
4748
|
+
printWarning("Could not fetch templates. Will retry on next sync.");
|
|
4749
|
+
} else {
|
|
4750
|
+
printWarning("Template sync failed. Will retry on next sync.");
|
|
4751
|
+
}
|
|
4752
|
+
}
|
|
4753
|
+
}
|
|
4754
|
+
if (changes.length === 0) {
|
|
4755
|
+
printStatus("Already up to date.");
|
|
4756
|
+
} else {
|
|
4757
|
+
for (const change of changes) {
|
|
4758
|
+
printStatus(change);
|
|
4759
|
+
}
|
|
4760
|
+
}
|
|
4761
|
+
console.log();
|
|
4762
|
+
}
|
|
4763
|
+
});
|
|
4764
|
+
}
|
|
4765
|
+
});
|
|
4766
|
+
|
|
4767
|
+
// src/commands/cleanup.ts
|
|
4768
|
+
var cleanup_exports = {};
|
|
4769
|
+
__export(cleanup_exports, {
|
|
4770
|
+
default: () => cleanup_default
|
|
4771
|
+
});
|
|
4772
|
+
import { defineCommand as defineCommand10 } from "citty";
|
|
4773
|
+
import pc15 from "picocolors";
|
|
4774
|
+
import { join as join24 } from "path";
|
|
4775
|
+
import { readFile as readFile15, writeFile as writeFile14, rm as rm6 } from "fs/promises";
|
|
4776
|
+
async function scanArtifacts(targetDir) {
|
|
4777
|
+
const actions = [];
|
|
4778
|
+
const localMePath = join24(targetDir, ".flydocs", "me.json");
|
|
4779
|
+
if (await pathExists(localMePath) && await pathExists(globalMePath())) {
|
|
4780
|
+
actions.push({
|
|
4781
|
+
description: "Remove .flydocs/me.json (migrated to ~/.flydocs/me.json)",
|
|
4782
|
+
path: localMePath,
|
|
4783
|
+
type: "file"
|
|
4784
|
+
});
|
|
4785
|
+
}
|
|
4786
|
+
const validationCachePath = join24(
|
|
4787
|
+
targetDir,
|
|
4788
|
+
".flydocs",
|
|
4789
|
+
"validation-cache.json"
|
|
4790
|
+
);
|
|
4791
|
+
if (await pathExists(validationCachePath)) {
|
|
4792
|
+
actions.push({
|
|
4793
|
+
description: "Remove .flydocs/validation-cache.json (replaced by configVersion)",
|
|
4794
|
+
path: validationCachePath,
|
|
4795
|
+
type: "file"
|
|
4796
|
+
});
|
|
4797
|
+
}
|
|
4798
|
+
const hasGlobalCreds = await pathExists(credentialsPath());
|
|
4799
|
+
for (const envFile of [".env", ".env.local"]) {
|
|
4800
|
+
const envPath = join24(targetDir, envFile);
|
|
4801
|
+
if (!await pathExists(envPath)) continue;
|
|
4802
|
+
const content = await readFile15(envPath, "utf-8");
|
|
4803
|
+
const lines = content.split("\n");
|
|
4804
|
+
for (const line of lines) {
|
|
4805
|
+
const trimmed = line.trim();
|
|
4806
|
+
if (hasGlobalCreds && trimmed.startsWith("FLYDOCS_API_KEY=")) {
|
|
4807
|
+
actions.push({
|
|
4808
|
+
description: `Remove FLYDOCS_API_KEY from ${envFile} (migrated to ~/.flydocs/credentials)`,
|
|
4809
|
+
path: envPath,
|
|
4810
|
+
type: "line"
|
|
4811
|
+
});
|
|
4812
|
+
}
|
|
4813
|
+
if (trimmed.startsWith("FLYDOCS_RELAY_URL=")) {
|
|
4814
|
+
actions.push({
|
|
4815
|
+
description: `Remove FLYDOCS_RELAY_URL from ${envFile}`,
|
|
4816
|
+
path: envPath,
|
|
4817
|
+
type: "line"
|
|
4818
|
+
});
|
|
4819
|
+
}
|
|
4820
|
+
}
|
|
4821
|
+
}
|
|
4822
|
+
try {
|
|
4823
|
+
const config = await readAnyConfig(targetDir);
|
|
4824
|
+
const rawContent = await readFile15(
|
|
4825
|
+
join24(targetDir, ".flydocs", "config.json"),
|
|
4826
|
+
"utf-8"
|
|
4827
|
+
);
|
|
4828
|
+
const raw = JSON.parse(rawContent);
|
|
4829
|
+
const ghostFields = ["provider", "statusMapping"];
|
|
4830
|
+
for (const field of ghostFields) {
|
|
4831
|
+
if (field in raw) {
|
|
4832
|
+
actions.push({
|
|
4833
|
+
description: `Remove ghost field "${field}" from config.json`,
|
|
4834
|
+
path: join24(targetDir, ".flydocs", "config.json"),
|
|
4835
|
+
type: "field"
|
|
4836
|
+
});
|
|
4837
|
+
}
|
|
4838
|
+
}
|
|
4839
|
+
if (isConfigV2(config)) {
|
|
4840
|
+
const v1OnlyFields = [
|
|
4841
|
+
"workspaceId",
|
|
4842
|
+
"issueLabels",
|
|
4843
|
+
"workspace",
|
|
4844
|
+
"onboardComplete",
|
|
4845
|
+
"sourceRepo",
|
|
4846
|
+
"designSystem",
|
|
4847
|
+
"aiLabor"
|
|
4848
|
+
];
|
|
4849
|
+
for (const field of v1OnlyFields) {
|
|
4850
|
+
if (field in raw) {
|
|
4851
|
+
actions.push({
|
|
4852
|
+
description: `Remove v1 field "${field}" from config.json (server-owned in v2)`,
|
|
4853
|
+
path: join24(targetDir, ".flydocs", "config.json"),
|
|
4854
|
+
type: "field"
|
|
4855
|
+
});
|
|
4856
|
+
}
|
|
4857
|
+
}
|
|
4858
|
+
}
|
|
4859
|
+
} catch {
|
|
4860
|
+
}
|
|
4861
|
+
return actions;
|
|
4862
|
+
}
|
|
4863
|
+
async function executeCleanup(targetDir, actions) {
|
|
4864
|
+
const fileRemovals = actions.filter((a) => a.type === "file");
|
|
4865
|
+
const lineRemovals = actions.filter((a) => a.type === "line");
|
|
4866
|
+
const fieldRemovals = actions.filter((a) => a.type === "field");
|
|
4867
|
+
for (const action of fileRemovals) {
|
|
4868
|
+
await rm6(action.path, { force: true });
|
|
4869
|
+
}
|
|
4870
|
+
const envFiles = /* @__PURE__ */ new Map();
|
|
4871
|
+
for (const action of lineRemovals) {
|
|
4872
|
+
if (!envFiles.has(action.path)) {
|
|
4873
|
+
const content = await readFile15(action.path, "utf-8");
|
|
4874
|
+
envFiles.set(action.path, content.split("\n"));
|
|
4875
|
+
}
|
|
4876
|
+
}
|
|
4877
|
+
for (const [envPath, lines] of envFiles) {
|
|
4878
|
+
const filtered = lines.filter((line) => {
|
|
4879
|
+
const trimmed = line.trim();
|
|
4880
|
+
return !trimmed.startsWith("FLYDOCS_API_KEY=") && !trimmed.startsWith("FLYDOCS_RELAY_URL=");
|
|
4881
|
+
});
|
|
4882
|
+
const hasContent = filtered.some(
|
|
4883
|
+
(l) => l.trim().length > 0 && !l.trim().startsWith("#")
|
|
4884
|
+
);
|
|
4885
|
+
if (!hasContent) {
|
|
4886
|
+
await rm6(envPath, { force: true });
|
|
4887
|
+
} else {
|
|
4888
|
+
await writeFile14(envPath, filtered.join("\n"), "utf-8");
|
|
4889
|
+
}
|
|
4890
|
+
}
|
|
4891
|
+
if (fieldRemovals.length > 0) {
|
|
4892
|
+
const configPath = join24(targetDir, ".flydocs", "config.json");
|
|
4893
|
+
const content = await readFile15(configPath, "utf-8");
|
|
4894
|
+
const config = JSON.parse(content);
|
|
4895
|
+
for (const action of fieldRemovals) {
|
|
4896
|
+
const match = action.description.match(/"(\w+)"/);
|
|
4897
|
+
if (match) {
|
|
4898
|
+
delete config[match[1]];
|
|
4899
|
+
}
|
|
4900
|
+
}
|
|
4901
|
+
await writeFile14(
|
|
4902
|
+
configPath,
|
|
4903
|
+
JSON.stringify(config, null, 2) + "\n",
|
|
4904
|
+
"utf-8"
|
|
4905
|
+
);
|
|
4906
|
+
}
|
|
4907
|
+
}
|
|
4908
|
+
var cleanup_default;
|
|
4909
|
+
var init_cleanup = __esm({
|
|
4910
|
+
"src/commands/cleanup.ts"() {
|
|
4911
|
+
"use strict";
|
|
4912
|
+
init_ui();
|
|
4913
|
+
init_fs_ops();
|
|
4914
|
+
init_config();
|
|
4915
|
+
init_types();
|
|
4916
|
+
init_global_config();
|
|
4917
|
+
cleanup_default = defineCommand10({
|
|
4918
|
+
meta: {
|
|
4919
|
+
name: "cleanup",
|
|
4920
|
+
description: "Remove legacy v1 artifacts after migration (dry-run by default)"
|
|
4921
|
+
},
|
|
4922
|
+
args: {
|
|
4923
|
+
confirm: {
|
|
4924
|
+
type: "boolean",
|
|
4925
|
+
description: "Actually remove artifacts (default: dry-run only)",
|
|
4926
|
+
default: false
|
|
4927
|
+
},
|
|
4928
|
+
path: {
|
|
4929
|
+
type: "string",
|
|
4930
|
+
description: "Path to project directory"
|
|
4931
|
+
}
|
|
4932
|
+
},
|
|
4933
|
+
async run({ args }) {
|
|
4934
|
+
const targetDir = args.path ?? process.cwd();
|
|
4935
|
+
console.log();
|
|
4936
|
+
console.log(` ${pc15.bold("FlyDocs Cleanup")}`);
|
|
4937
|
+
console.log();
|
|
4938
|
+
const hasConfig = await pathExists(
|
|
4939
|
+
join24(targetDir, ".flydocs", "config.json")
|
|
4940
|
+
);
|
|
4941
|
+
if (!hasConfig) {
|
|
4942
|
+
printError("No .flydocs/config.json found. Run flydocs init first.");
|
|
4943
|
+
process.exit(1);
|
|
4944
|
+
}
|
|
4945
|
+
const hasGlobalCreds = await pathExists(credentialsPath());
|
|
4946
|
+
if (!hasGlobalCreds) {
|
|
4947
|
+
printWarning(
|
|
4948
|
+
"No global credentials found. Run flydocs init to set up credentials before cleanup."
|
|
4949
|
+
);
|
|
4950
|
+
}
|
|
4951
|
+
const actions = await scanArtifacts(targetDir);
|
|
4952
|
+
if (actions.length === 0) {
|
|
4953
|
+
printStatus("No legacy artifacts found. Already clean.");
|
|
4954
|
+
console.log();
|
|
4955
|
+
return;
|
|
4956
|
+
}
|
|
4957
|
+
const mode = args.confirm ? "Removing" : "Would remove";
|
|
4958
|
+
printInfo(`${mode} ${actions.length} legacy artifact(s):`);
|
|
4959
|
+
console.log();
|
|
4960
|
+
for (const action of actions) {
|
|
4961
|
+
const icon = args.confirm ? pc15.red("-") : pc15.yellow("?");
|
|
4962
|
+
console.log(` ${icon} ${action.description}`);
|
|
4963
|
+
}
|
|
4964
|
+
console.log();
|
|
4965
|
+
if (!args.confirm) {
|
|
4966
|
+
printInfo(
|
|
4967
|
+
`Dry-run complete. Run ${pc15.cyan("flydocs cleanup --confirm")} to remove.`
|
|
4968
|
+
);
|
|
4969
|
+
console.log();
|
|
4970
|
+
return;
|
|
4971
|
+
}
|
|
4972
|
+
await executeCleanup(targetDir, actions);
|
|
4973
|
+
printCompletionBox("Cleanup Complete", [
|
|
4974
|
+
`${pc15.green("+")} Removed ${actions.length} legacy artifact(s)`
|
|
4975
|
+
]);
|
|
3847
4976
|
console.log();
|
|
3848
4977
|
}
|
|
3849
4978
|
});
|
|
@@ -3855,15 +4984,15 @@ var upgrade_exports = {};
|
|
|
3855
4984
|
__export(upgrade_exports, {
|
|
3856
4985
|
default: () => upgrade_default
|
|
3857
4986
|
});
|
|
3858
|
-
import { defineCommand as
|
|
3859
|
-
import
|
|
4987
|
+
import { defineCommand as defineCommand11 } from "citty";
|
|
4988
|
+
import pc16 from "picocolors";
|
|
3860
4989
|
var upgrade_default;
|
|
3861
4990
|
var init_upgrade = __esm({
|
|
3862
4991
|
"src/commands/upgrade.ts"() {
|
|
3863
4992
|
"use strict";
|
|
3864
4993
|
init_config();
|
|
3865
4994
|
init_fs_ops();
|
|
3866
|
-
upgrade_default =
|
|
4995
|
+
upgrade_default = defineCommand11({
|
|
3867
4996
|
meta: {
|
|
3868
4997
|
name: "upgrade",
|
|
3869
4998
|
description: "Learn about FlyDocs Cloud tier and upgrade from local"
|
|
@@ -3892,34 +5021,34 @@ var init_upgrade = __esm({
|
|
|
3892
5021
|
console.log();
|
|
3893
5022
|
if (currentTier === "cloud") {
|
|
3894
5023
|
console.log(
|
|
3895
|
-
` ${
|
|
5024
|
+
` ${pc16.green("\u2713")} You're already on the ${pc16.bold("cloud")} tier.`
|
|
3896
5025
|
);
|
|
3897
5026
|
console.log();
|
|
3898
5027
|
console.log(` Your issues sync with your provider via the relay API.`);
|
|
3899
5028
|
console.log(
|
|
3900
|
-
` Run ${
|
|
5029
|
+
` Run ${pc16.cyan("flydocs connect")} to update your connection settings.`
|
|
3901
5030
|
);
|
|
3902
5031
|
console.log();
|
|
3903
5032
|
return;
|
|
3904
5033
|
}
|
|
3905
|
-
console.log(` ${
|
|
5034
|
+
console.log(` ${pc16.bold("FlyDocs Cloud Tier")}`);
|
|
3906
5035
|
console.log();
|
|
3907
|
-
console.log(` You're currently on the ${
|
|
5036
|
+
console.log(` You're currently on the ${pc16.yellow("local")} tier.`);
|
|
3908
5037
|
console.log(` Upgrade to cloud for:`);
|
|
3909
5038
|
console.log();
|
|
3910
|
-
console.log(` ${
|
|
3911
|
-
console.log(` ${
|
|
3912
|
-
console.log(` ${
|
|
3913
|
-
console.log(` ${
|
|
3914
|
-
console.log(` ${
|
|
5039
|
+
console.log(` ${pc16.cyan("\u2192")} Issue sync with Linear, Jira, and more`);
|
|
5040
|
+
console.log(` ${pc16.cyan("\u2192")} Project milestones and cycle management`);
|
|
5041
|
+
console.log(` ${pc16.cyan("\u2192")} Team assignment and priority tracking`);
|
|
5042
|
+
console.log(` ${pc16.cyan("\u2192")} Project health updates and dashboards`);
|
|
5043
|
+
console.log(` ${pc16.cyan("\u2192")} Cross-project issue linking`);
|
|
3915
5044
|
console.log();
|
|
3916
|
-
console.log(` ${
|
|
5045
|
+
console.log(` ${pc16.bold("How to upgrade:")}`);
|
|
3917
5046
|
console.log();
|
|
3918
|
-
console.log(` Option 1: Run ${
|
|
5047
|
+
console.log(` Option 1: Run ${pc16.cyan("/flydocs-upgrade")} in your IDE`);
|
|
3919
5048
|
console.log(` Guided migration with issue transfer`);
|
|
3920
5049
|
console.log();
|
|
3921
5050
|
console.log(
|
|
3922
|
-
` Option 2: Run ${
|
|
5051
|
+
` Option 2: Run ${pc16.cyan("flydocs connect")} from terminal`
|
|
3923
5052
|
);
|
|
3924
5053
|
console.log(` Quick tier swap (no issue migration)`);
|
|
3925
5054
|
console.log();
|
|
@@ -3933,23 +5062,23 @@ var self_update_exports = {};
|
|
|
3933
5062
|
__export(self_update_exports, {
|
|
3934
5063
|
default: () => self_update_default
|
|
3935
5064
|
});
|
|
3936
|
-
import { defineCommand as
|
|
5065
|
+
import { defineCommand as defineCommand12 } from "citty";
|
|
3937
5066
|
import { execSync } from "child_process";
|
|
3938
|
-
import
|
|
5067
|
+
import pc17 from "picocolors";
|
|
3939
5068
|
var self_update_default;
|
|
3940
5069
|
var init_self_update = __esm({
|
|
3941
5070
|
"src/commands/self-update.ts"() {
|
|
3942
5071
|
"use strict";
|
|
3943
5072
|
init_constants();
|
|
3944
5073
|
init_ui();
|
|
3945
|
-
self_update_default =
|
|
5074
|
+
self_update_default = defineCommand12({
|
|
3946
5075
|
meta: {
|
|
3947
5076
|
name: "self-update",
|
|
3948
5077
|
description: "Update FlyDocs CLI to the latest version"
|
|
3949
5078
|
},
|
|
3950
5079
|
async run() {
|
|
3951
5080
|
console.log();
|
|
3952
|
-
console.log(` Updating ${
|
|
5081
|
+
console.log(` Updating ${pc17.cyan(PACKAGE_NAME)}...`);
|
|
3953
5082
|
console.log();
|
|
3954
5083
|
try {
|
|
3955
5084
|
execSync(`npm install -g ${PACKAGE_NAME}@beta`, {
|
|
@@ -3974,15 +5103,15 @@ var telemetry_exports = {};
|
|
|
3974
5103
|
__export(telemetry_exports, {
|
|
3975
5104
|
default: () => telemetry_default
|
|
3976
5105
|
});
|
|
3977
|
-
import { defineCommand as
|
|
3978
|
-
import
|
|
5106
|
+
import { defineCommand as defineCommand13 } from "citty";
|
|
5107
|
+
import pc18 from "picocolors";
|
|
3979
5108
|
var enable, disable, status, telemetry_default;
|
|
3980
5109
|
var init_telemetry2 = __esm({
|
|
3981
5110
|
"src/commands/telemetry.ts"() {
|
|
3982
5111
|
"use strict";
|
|
3983
5112
|
init_telemetry();
|
|
3984
5113
|
init_ui();
|
|
3985
|
-
enable =
|
|
5114
|
+
enable = defineCommand13({
|
|
3986
5115
|
meta: {
|
|
3987
5116
|
name: "enable",
|
|
3988
5117
|
description: "Enable anonymous usage analytics"
|
|
@@ -3997,7 +5126,7 @@ var init_telemetry2 = __esm({
|
|
|
3997
5126
|
}
|
|
3998
5127
|
}
|
|
3999
5128
|
});
|
|
4000
|
-
disable =
|
|
5129
|
+
disable = defineCommand13({
|
|
4001
5130
|
meta: {
|
|
4002
5131
|
name: "disable",
|
|
4003
5132
|
description: "Disable anonymous usage analytics"
|
|
@@ -4015,7 +5144,7 @@ var init_telemetry2 = __esm({
|
|
|
4015
5144
|
}
|
|
4016
5145
|
}
|
|
4017
5146
|
});
|
|
4018
|
-
status =
|
|
5147
|
+
status = defineCommand13({
|
|
4019
5148
|
meta: {
|
|
4020
5149
|
name: "status",
|
|
4021
5150
|
description: "Show current telemetry status"
|
|
@@ -4023,37 +5152,37 @@ var init_telemetry2 = __esm({
|
|
|
4023
5152
|
async run() {
|
|
4024
5153
|
const info = await getStatus();
|
|
4025
5154
|
console.log();
|
|
4026
|
-
console.log(
|
|
5155
|
+
console.log(pc18.bold("Telemetry Status"));
|
|
4027
5156
|
console.log();
|
|
4028
5157
|
const effectivelyEnabled = info.enabled && !info.envOverride;
|
|
4029
5158
|
console.log(
|
|
4030
|
-
` Enabled: ${effectivelyEnabled ?
|
|
5159
|
+
` Enabled: ${effectivelyEnabled ? pc18.green("yes") : pc18.yellow("no")}`
|
|
4031
5160
|
);
|
|
4032
5161
|
if (info.envOverride) {
|
|
4033
5162
|
console.log(
|
|
4034
|
-
` Env override: ${
|
|
5163
|
+
` Env override: ${pc18.yellow("FLYDOCS_TELEMETRY=0 (disabled via env)")}`
|
|
4035
5164
|
);
|
|
4036
5165
|
}
|
|
4037
5166
|
if (info.anonymousId) {
|
|
4038
|
-
console.log(` Anonymous ID: ${
|
|
5167
|
+
console.log(` Anonymous ID: ${pc18.dim(info.anonymousId)}`);
|
|
4039
5168
|
} else {
|
|
4040
5169
|
console.log(
|
|
4041
|
-
` Anonymous ID: ${
|
|
5170
|
+
` Anonymous ID: ${pc18.dim("(not yet created \u2014 generated on first run)")}`
|
|
4042
5171
|
);
|
|
4043
5172
|
}
|
|
4044
5173
|
console.log();
|
|
4045
5174
|
console.log(
|
|
4046
|
-
|
|
5175
|
+
pc18.dim(
|
|
4047
5176
|
" FlyDocs collects anonymous usage analytics to improve the CLI."
|
|
4048
5177
|
)
|
|
4049
5178
|
);
|
|
4050
5179
|
console.log(
|
|
4051
|
-
|
|
5180
|
+
pc18.dim(" No personal data, file contents, or code is ever collected.")
|
|
4052
5181
|
);
|
|
4053
5182
|
console.log();
|
|
4054
5183
|
}
|
|
4055
5184
|
});
|
|
4056
|
-
telemetry_default =
|
|
5185
|
+
telemetry_default = defineCommand13({
|
|
4057
5186
|
meta: {
|
|
4058
5187
|
name: "telemetry",
|
|
4059
5188
|
description: "Manage anonymous usage analytics (enable, disable, status)"
|
|
@@ -4069,14 +5198,18 @@ var init_telemetry2 = __esm({
|
|
|
4069
5198
|
|
|
4070
5199
|
// src/cli.ts
|
|
4071
5200
|
init_constants();
|
|
4072
|
-
import { defineCommand as
|
|
5201
|
+
import { defineCommand as defineCommand14, runMain } from "citty";
|
|
4073
5202
|
var SUB_COMMANDS = /* @__PURE__ */ new Set([
|
|
4074
5203
|
"install",
|
|
5204
|
+
"init",
|
|
4075
5205
|
"update",
|
|
4076
5206
|
"uninstall",
|
|
4077
5207
|
"setup",
|
|
4078
5208
|
"skills",
|
|
4079
5209
|
"connect",
|
|
5210
|
+
"auth",
|
|
5211
|
+
"sync",
|
|
5212
|
+
"cleanup",
|
|
4080
5213
|
"upgrade",
|
|
4081
5214
|
"self-update",
|
|
4082
5215
|
"telemetry"
|
|
@@ -4089,7 +5222,7 @@ var firstPositional = userArgs.find((a) => !a.startsWith("-"));
|
|
|
4089
5222
|
if (!hasMetaFlag && (!firstPositional || !SUB_COMMANDS.has(firstPositional))) {
|
|
4090
5223
|
process.argv.splice(2, 0, "install");
|
|
4091
5224
|
}
|
|
4092
|
-
var main =
|
|
5225
|
+
var main = defineCommand14({
|
|
4093
5226
|
meta: {
|
|
4094
5227
|
name: CLI_NAME,
|
|
4095
5228
|
version: CLI_VERSION,
|
|
@@ -4097,11 +5230,15 @@ var main = defineCommand10({
|
|
|
4097
5230
|
},
|
|
4098
5231
|
subCommands: {
|
|
4099
5232
|
install: () => Promise.resolve().then(() => (init_install(), install_exports)).then((m) => m.default),
|
|
5233
|
+
init: () => Promise.resolve().then(() => (init_init(), init_exports)).then((m) => m.default),
|
|
4100
5234
|
update: () => Promise.resolve().then(() => (init_update(), update_exports)).then((m) => m.default),
|
|
4101
5235
|
uninstall: () => Promise.resolve().then(() => (init_uninstall(), uninstall_exports)).then((m) => m.default),
|
|
4102
5236
|
setup: () => Promise.resolve().then(() => (init_setup(), setup_exports)).then((m) => m.default),
|
|
4103
5237
|
skills: () => Promise.resolve().then(() => (init_skills2(), skills_exports)).then((m) => m.default),
|
|
4104
5238
|
connect: () => Promise.resolve().then(() => (init_connect(), connect_exports)).then((m) => m.default),
|
|
5239
|
+
auth: () => Promise.resolve().then(() => (init_auth(), auth_exports)).then((m) => m.default),
|
|
5240
|
+
sync: () => Promise.resolve().then(() => (init_sync(), sync_exports)).then((m) => m.default),
|
|
5241
|
+
cleanup: () => Promise.resolve().then(() => (init_cleanup(), cleanup_exports)).then((m) => m.default),
|
|
4105
5242
|
upgrade: () => Promise.resolve().then(() => (init_upgrade(), upgrade_exports)).then((m) => m.default),
|
|
4106
5243
|
"self-update": () => Promise.resolve().then(() => (init_self_update(), self_update_exports)).then((m) => m.default),
|
|
4107
5244
|
telemetry: () => Promise.resolve().then(() => (init_telemetry2(), telemetry_exports)).then((m) => m.default)
|