@flydocs/cli 0.6.0-alpha.2 → 0.6.0-alpha.20
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 +678 -392
- package/package.json +1 -1
- package/template/.claude/CLAUDE.md +62 -63
- package/template/.claude/agents/implementation-agent.md +1 -1
- package/template/.claude/agents/pm-agent.md +1 -1
- package/template/.claude/commands/activate.md +1 -1
- package/template/.claude/commands/attach.md +1 -1
- package/template/.claude/commands/block.md +2 -2
- package/template/.claude/commands/capture.md +1 -1
- package/template/.claude/commands/close.md +1 -1
- package/template/.claude/commands/flydocs-setup.md +387 -74
- package/template/.claude/commands/flydocs-upgrade.md +48 -37
- package/template/.claude/commands/implement.md +1 -1
- package/template/.claude/commands/knowledge.md +61 -0
- package/template/.claude/commands/new-project.md +1 -1
- package/template/.claude/commands/onboard.md +275 -0
- package/template/.claude/commands/project-update.md +1 -1
- package/template/.claude/commands/refine.md +1 -1
- package/template/.claude/commands/review.md +1 -1
- package/template/.claude/commands/start-session.md +1 -1
- package/template/.claude/commands/status.md +1 -1
- package/template/.claude/commands/validate.md +1 -1
- package/template/.claude/commands/wrap-session.md +1 -1
- package/template/.claude/hooks/auto-approve.py +132 -0
- package/template/.claude/hooks/post-pr-check.py +108 -0
- package/template/.claude/hooks/post-transition-check.py +94 -0
- package/template/.claude/hooks/prompt-submit.py +513 -0
- package/template/.claude/hooks/session-start.py +146 -0
- package/template/.claude/hooks/stop-gate.py +109 -0
- package/template/.claude/settings.json +41 -4
- package/template/.claude/skills/README.md +23 -25
- package/template/.claude/skills/flydocs-workflow/SKILL.md +134 -42
- package/template/.claude/skills/flydocs-workflow/cursor-rule.mdc +9 -8
- package/template/.claude/skills/flydocs-workflow/reference/comment-templates.md +1 -0
- package/template/.claude/skills/flydocs-workflow/reference/golden-rules.md +28 -17
- package/template/.claude/skills/flydocs-workflow/reference/graph-schema.md +116 -0
- package/template/.claude/skills/flydocs-workflow/reference/pr-workflow.md +120 -0
- package/template/.claude/skills/flydocs-workflow/reference/priority-estimates.md +37 -15
- package/template/.claude/skills/flydocs-workflow/reference/service-descriptor-schema.md +251 -0
- package/template/.claude/skills/flydocs-workflow/reference/status-workflow.md +26 -26
- package/template/.claude/skills/flydocs-workflow/scripts/_local/__init__.py +0 -0
- package/template/.claude/skills/{flydocs-local/scripts/flydocs_api.py → flydocs-workflow/scripts/_local/file_store.py} +137 -47
- package/template/.claude/skills/flydocs-workflow/scripts/flydocs_api.py +693 -0
- package/template/{.flydocs → .claude/skills/flydocs-workflow}/scripts/generate_manifest.py +4 -4
- package/template/.claude/skills/{flydocs-context-graph → flydocs-workflow}/scripts/graph_build.py +132 -1
- package/template/.claude/skills/{flydocs-context-graph → flydocs-workflow}/scripts/graph_query.py +18 -5
- package/template/.claude/skills/{flydocs-context-graph → flydocs-workflow}/scripts/graph_session.py +1 -10
- package/template/.claude/skills/{flydocs-context-graph → flydocs-workflow}/scripts/graph_update.py +4 -4
- package/template/.claude/skills/{flydocs-context-graph → flydocs-workflow}/scripts/graph_utils.py +2 -1
- package/template/.claude/skills/flydocs-workflow/scripts/issues.py +489 -0
- package/template/.claude/skills/flydocs-workflow/scripts/projects.py +144 -0
- package/template/.claude/skills/flydocs-workflow/scripts/pull_services.py +128 -0
- package/template/.claude/skills/flydocs-workflow/scripts/push_service.py +132 -0
- package/template/.claude/skills/flydocs-workflow/scripts/session.py +54 -0
- package/template/.claude/skills/flydocs-workflow/scripts/workspace.py +860 -0
- package/template/.claude/skills/flydocs-workflow/session.md +63 -25
- package/template/.claude/skills/flydocs-workflow/stages/activate.md +18 -7
- package/template/.claude/skills/flydocs-workflow/stages/capture.md +10 -5
- package/template/.claude/skills/flydocs-workflow/stages/close.md +4 -3
- package/template/.claude/skills/flydocs-workflow/stages/implement.md +33 -9
- package/template/.claude/skills/flydocs-workflow/stages/refine.md +22 -6
- package/template/.claude/skills/flydocs-workflow/stages/review.md +16 -4
- package/template/.claude/skills/flydocs-workflow/stages/validate.md +3 -1
- package/template/.claude/skills/flydocs-workflow/templates/pr/default.md +33 -0
- package/template/.cursor/agents/implementation-agent.md +1 -1
- package/template/.cursor/agents/pm-agent.md +2 -2
- package/template/.cursor/hooks.json +10 -3
- package/template/.env.example +6 -6
- package/template/.flydocs/config.json +5 -18
- package/template/.flydocs/templates/README.md +13 -14
- package/template/.flydocs/templates/quick-capture.md +4 -8
- package/template/.flydocs/version +1 -1
- package/template/AGENTS.md +39 -32
- package/template/CHANGELOG.md +39 -0
- package/template/flydocs/README.md +1 -3
- package/template/flydocs/context/project.md +6 -3
- package/template/flydocs/design-system/README.md +3 -3
- package/template/flydocs/knowledge/INDEX.md +38 -53
- package/template/flydocs/knowledge/README.md +60 -9
- package/template/flydocs/knowledge/templates/decision.md +47 -0
- package/template/flydocs/knowledge/templates/feature.md +35 -0
- package/template/flydocs/knowledge/templates/note.md +25 -0
- package/template/manifest.json +24 -20
- package/template/.claude/skills/flydocs-cloud/SKILL.md +0 -111
- package/template/.claude/skills/flydocs-cloud/cursor-rule.mdc +0 -50
- package/template/.claude/skills/flydocs-cloud/scripts/assign.py +0 -22
- package/template/.claude/skills/flydocs-cloud/scripts/assign_cycle.py +0 -28
- package/template/.claude/skills/flydocs-cloud/scripts/assign_milestone.py +0 -22
- package/template/.claude/skills/flydocs-cloud/scripts/comment.py +0 -29
- package/template/.claude/skills/flydocs-cloud/scripts/create_issue.py +0 -63
- package/template/.claude/skills/flydocs-cloud/scripts/create_milestone.py +0 -35
- package/template/.claude/skills/flydocs-cloud/scripts/create_project.py +0 -33
- package/template/.claude/skills/flydocs-cloud/scripts/create_team.py +0 -39
- package/template/.claude/skills/flydocs-cloud/scripts/estimate.py +0 -29
- package/template/.claude/skills/flydocs-cloud/scripts/flydocs_api.py +0 -210
- package/template/.claude/skills/flydocs-cloud/scripts/get_issue.py +0 -24
- package/template/.claude/skills/flydocs-cloud/scripts/link.py +0 -28
- package/template/.claude/skills/flydocs-cloud/scripts/list_cycles.py +0 -28
- package/template/.claude/skills/flydocs-cloud/scripts/list_issues.py +0 -44
- package/template/.claude/skills/flydocs-cloud/scripts/list_labels.py +0 -19
- package/template/.claude/skills/flydocs-cloud/scripts/list_milestones.py +0 -28
- package/template/.claude/skills/flydocs-cloud/scripts/list_projects.py +0 -31
- package/template/.claude/skills/flydocs-cloud/scripts/list_teams.py +0 -19
- package/template/.claude/skills/flydocs-cloud/scripts/priority.py +0 -29
- package/template/.claude/skills/flydocs-cloud/scripts/project_update.py +0 -45
- package/template/.claude/skills/flydocs-cloud/scripts/set_labels.py +0 -68
- package/template/.claude/skills/flydocs-cloud/scripts/set_team.py +0 -41
- package/template/.claude/skills/flydocs-cloud/scripts/transition.py +0 -26
- package/template/.claude/skills/flydocs-cloud/scripts/update_description.py +0 -36
- package/template/.claude/skills/flydocs-cloud/scripts/update_issue.py +0 -82
- package/template/.claude/skills/flydocs-context-graph/SKILL.md +0 -87
- package/template/.claude/skills/flydocs-context-graph/schema.md +0 -78
- package/template/.claude/skills/flydocs-context-graph/scripts/graph_context.py +0 -338
- package/template/.claude/skills/flydocs-context7/SKILL.md +0 -105
- package/template/.claude/skills/flydocs-context7/cursor-rule.mdc +0 -49
- package/template/.claude/skills/flydocs-context7/scripts/context7.py +0 -293
- package/template/.claude/skills/flydocs-estimates/SKILL.md +0 -384
- package/template/.claude/skills/flydocs-figma/SKILL.md +0 -377
- package/template/.claude/skills/flydocs-figma/references/PROMPTING.md +0 -108
- package/template/.claude/skills/flydocs-figma/references/TROUBLESHOOTING.md +0 -112
- package/template/.claude/skills/flydocs-local/SKILL.md +0 -103
- package/template/.claude/skills/flydocs-local/cursor-rule.mdc +0 -43
- package/template/.claude/skills/flydocs-local/scripts/assign.py +0 -20
- package/template/.claude/skills/flydocs-local/scripts/comment.py +0 -27
- package/template/.claude/skills/flydocs-local/scripts/create_issue.py +0 -44
- package/template/.claude/skills/flydocs-local/scripts/estimate.py +0 -37
- package/template/.claude/skills/flydocs-local/scripts/get_issue.py +0 -20
- package/template/.claude/skills/flydocs-local/scripts/link.py +0 -41
- package/template/.claude/skills/flydocs-local/scripts/list_issues.py +0 -34
- package/template/.claude/skills/flydocs-local/scripts/priority.py +0 -37
- package/template/.claude/skills/flydocs-local/scripts/project_update.py +0 -67
- package/template/.claude/skills/flydocs-local/scripts/status_summary.py +0 -16
- package/template/.claude/skills/flydocs-local/scripts/transition.py +0 -24
- package/template/.claude/skills/flydocs-local/scripts/update_description.py +0 -35
- package/template/.claude/skills/flydocs-local/scripts/update_issue.py +0 -84
- package/template/.flydocs/hooks/auto-approve.py +0 -71
- package/template/.flydocs/hooks/prompt-submit.py +0 -277
- package/template/.flydocs/scripts/skill_manager.py +0 -541
- package/template/.flydocs/templates/bug.md +0 -166
- package/template/.flydocs/templates/chore.md +0 -110
- package/template/.flydocs/templates/feature.md +0 -173
- package/template/.flydocs/templates/idea.md +0 -122
- /package/template/{.flydocs → .claude}/hooks/post-edit.py +0 -0
- /package/template/.claude/skills/{flydocs-estimates/references → flydocs-workflow/reference}/provider-costs.md +0 -0
- /package/template/.claude/skills/flydocs-workflow/templates/{bug.md → issues/bug.md} +0 -0
- /package/template/.claude/skills/flydocs-workflow/templates/{chore.md → issues/chore.md} +0 -0
- /package/template/.claude/skills/flydocs-workflow/templates/{feature.md → issues/feature.md} +0 -0
- /package/template/.claude/skills/flydocs-workflow/templates/{idea.md → issues/idea.md} +0 -0
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.20";
|
|
19
19
|
CLI_NAME = "flydocs";
|
|
20
20
|
PACKAGE_NAME = "@flydocs/cli";
|
|
21
21
|
POSTHOG_API_KEY = "phc_v1MSJTQDFkMS90CBh3mxIz3v8bYCCnKU6v1ir6bz0Xn";
|
|
@@ -50,6 +50,7 @@ async function ensureDirectories(targetDir, tier) {
|
|
|
50
50
|
"flydocs/knowledge/decisions",
|
|
51
51
|
"flydocs/knowledge/notes",
|
|
52
52
|
"flydocs/knowledge/product",
|
|
53
|
+
"flydocs/knowledge/templates",
|
|
53
54
|
"flydocs/design-system"
|
|
54
55
|
];
|
|
55
56
|
if (tier === "local") {
|
|
@@ -135,8 +136,8 @@ var init_template = __esm({
|
|
|
135
136
|
|
|
136
137
|
// src/lib/ui.ts
|
|
137
138
|
import pc2 from "picocolors";
|
|
138
|
-
function shadow(
|
|
139
|
-
return `\x1B[38;2;55;45;70m${
|
|
139
|
+
function shadow(text4) {
|
|
140
|
+
return `\x1B[38;2;55;45;70m${text4}\x1B[0m`;
|
|
140
141
|
}
|
|
141
142
|
function renderBannerBlock() {
|
|
142
143
|
const height = BANNER_ROWS.length;
|
|
@@ -292,12 +293,13 @@ function extractPreservedValues(config) {
|
|
|
292
293
|
return {
|
|
293
294
|
tier: config.tier,
|
|
294
295
|
setupComplete: config.setupComplete ?? false,
|
|
295
|
-
|
|
296
|
+
workspaceId: config.workspaceId ?? null,
|
|
297
|
+
configVersion: config.configVersion,
|
|
296
298
|
workspace: config.workspace ?? {},
|
|
297
299
|
issueLabels: config.issueLabels ?? {},
|
|
298
|
-
statusMapping: config.statusMapping ?? {},
|
|
299
300
|
detectedStack: config.detectedStack ?? {},
|
|
300
301
|
skills: config.skills ?? {},
|
|
302
|
+
topology: config.topology,
|
|
301
303
|
designSystem: config.designSystem ?? null,
|
|
302
304
|
aiLabor: config.aiLabor ?? {}
|
|
303
305
|
};
|
|
@@ -311,11 +313,9 @@ async function mergeConfig(templateDir, version, tierFlag, preserved) {
|
|
|
311
313
|
config.version = version;
|
|
312
314
|
config.tier = tierFlag ?? preserved.tier;
|
|
313
315
|
config.setupComplete = preserved.setupComplete;
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
}
|
|
318
|
-
config.provider.teamId = preserved.providerTeamId;
|
|
316
|
+
config.workspaceId = preserved.workspaceId;
|
|
317
|
+
if (preserved.configVersion !== void 0) {
|
|
318
|
+
config.configVersion = preserved.configVersion;
|
|
319
319
|
}
|
|
320
320
|
if (Object.keys(preserved.workspace).length > 0) {
|
|
321
321
|
config.workspace = preserved.workspace;
|
|
@@ -323,15 +323,15 @@ async function mergeConfig(templateDir, version, tierFlag, preserved) {
|
|
|
323
323
|
if (Object.keys(preserved.issueLabels).length > 0) {
|
|
324
324
|
config.issueLabels = preserved.issueLabels;
|
|
325
325
|
}
|
|
326
|
-
if (Object.keys(preserved.statusMapping).length > 0) {
|
|
327
|
-
config.statusMapping = preserved.statusMapping;
|
|
328
|
-
}
|
|
329
326
|
if (Object.keys(preserved.detectedStack).length > 0) {
|
|
330
327
|
config.detectedStack = preserved.detectedStack;
|
|
331
328
|
}
|
|
332
329
|
if (Object.keys(preserved.skills).length > 0) {
|
|
333
330
|
config.skills = preserved.skills;
|
|
334
331
|
}
|
|
332
|
+
if (preserved.topology !== void 0) {
|
|
333
|
+
config.topology = preserved.topology;
|
|
334
|
+
}
|
|
335
335
|
if (preserved.designSystem !== null) {
|
|
336
336
|
config.designSystem = preserved.designSystem;
|
|
337
337
|
}
|
|
@@ -348,75 +348,32 @@ var init_config = __esm({
|
|
|
348
348
|
|
|
349
349
|
// src/lib/skills.ts
|
|
350
350
|
import { join as join4 } from "path";
|
|
351
|
-
async function installOwnedSkills(templateDir, targetDir,
|
|
351
|
+
async function installOwnedSkills(templateDir, targetDir, _tier) {
|
|
352
352
|
const skillsDir = join4(targetDir, ".claude", "skills");
|
|
353
353
|
const templateSkillsDir = join4(templateDir, ".claude", "skills");
|
|
354
354
|
await replaceDirectory(
|
|
355
|
-
join4(templateSkillsDir,
|
|
356
|
-
join4(skillsDir,
|
|
355
|
+
join4(templateSkillsDir, OWNED_SKILL),
|
|
356
|
+
join4(skillsDir, OWNED_SKILL)
|
|
357
357
|
);
|
|
358
|
-
const activeMech = MECHANISM_SKILLS[tier];
|
|
359
|
-
const inactiveMech = tier === "local" ? MECHANISM_SKILLS.cloud : MECHANISM_SKILLS.local;
|
|
360
|
-
await replaceDirectory(
|
|
361
|
-
join4(templateSkillsDir, activeMech),
|
|
362
|
-
join4(skillsDir, activeMech)
|
|
363
|
-
);
|
|
364
|
-
const { rm: rm6 } = await import("fs/promises");
|
|
365
|
-
const inactivePath = join4(skillsDir, inactiveMech);
|
|
366
|
-
if (await pathExists(inactivePath)) {
|
|
367
|
-
await rm6(inactivePath, { recursive: true, force: true });
|
|
368
|
-
}
|
|
369
|
-
for (const skill of CORE_SKILLS) {
|
|
370
|
-
if (skill === "flydocs-workflow") continue;
|
|
371
|
-
const src = join4(templateSkillsDir, skill);
|
|
372
|
-
if (await pathExists(src)) {
|
|
373
|
-
await replaceDirectory(src, join4(skillsDir, skill));
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
if (tier === "cloud") {
|
|
377
|
-
for (const skill of CLOUD_ONLY_SKILLS) {
|
|
378
|
-
const src = join4(templateSkillsDir, skill);
|
|
379
|
-
if (await pathExists(src)) {
|
|
380
|
-
await replaceDirectory(src, join4(skillsDir, skill));
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
358
|
const readmeSrc = join4(templateSkillsDir, "README.md");
|
|
385
359
|
if (await pathExists(readmeSrc)) {
|
|
386
360
|
await copyFile(readmeSrc, join4(skillsDir, "README.md"));
|
|
387
361
|
}
|
|
388
362
|
}
|
|
389
|
-
async function replaceOwnedSkills(templateDir, targetDir,
|
|
363
|
+
async function replaceOwnedSkills(templateDir, targetDir, _tier) {
|
|
390
364
|
const skillsDir = join4(targetDir, ".claude", "skills");
|
|
391
365
|
const templateSkillsDir = join4(templateDir, ".claude", "skills");
|
|
392
366
|
const { rm: rm6 } = await import("fs/promises");
|
|
393
|
-
for (const skill of CORE_SKILLS) {
|
|
394
|
-
const src = join4(templateSkillsDir, skill);
|
|
395
|
-
if (await pathExists(src)) {
|
|
396
|
-
await replaceDirectory(src, join4(skillsDir, skill));
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
for (const skill of CLOUD_ONLY_SKILLS) {
|
|
400
|
-
const dest = join4(skillsDir, skill);
|
|
401
|
-
if (tier === "cloud") {
|
|
402
|
-
const src = join4(templateSkillsDir, skill);
|
|
403
|
-
if (await pathExists(src)) {
|
|
404
|
-
await replaceDirectory(src, dest);
|
|
405
|
-
}
|
|
406
|
-
} else if (await pathExists(dest)) {
|
|
407
|
-
await rm6(dest, { recursive: true, force: true });
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
const activeMech = MECHANISM_SKILLS[tier];
|
|
411
|
-
const inactiveMech = tier === "local" ? MECHANISM_SKILLS.cloud : MECHANISM_SKILLS.local;
|
|
412
|
-
const inactivePath = join4(skillsDir, inactiveMech);
|
|
413
|
-
if (await pathExists(inactivePath)) {
|
|
414
|
-
await rm6(inactivePath, { recursive: true, force: true });
|
|
415
|
-
}
|
|
416
367
|
await replaceDirectory(
|
|
417
|
-
join4(templateSkillsDir,
|
|
418
|
-
join4(skillsDir,
|
|
368
|
+
join4(templateSkillsDir, OWNED_SKILL),
|
|
369
|
+
join4(skillsDir, OWNED_SKILL)
|
|
419
370
|
);
|
|
371
|
+
for (const legacy of LEGACY_SKILLS) {
|
|
372
|
+
const legacyPath = join4(skillsDir, legacy);
|
|
373
|
+
if (await pathExists(legacyPath)) {
|
|
374
|
+
await rm6(legacyPath, { recursive: true, force: true });
|
|
375
|
+
}
|
|
376
|
+
}
|
|
420
377
|
const readmeSrc = join4(templateSkillsDir, "README.md");
|
|
421
378
|
if (await pathExists(readmeSrc)) {
|
|
422
379
|
await copyFile(readmeSrc, join4(skillsDir, "README.md"));
|
|
@@ -430,50 +387,34 @@ async function copyCursorRules(targetDir) {
|
|
|
430
387
|
targetDir,
|
|
431
388
|
".claude",
|
|
432
389
|
"skills",
|
|
433
|
-
|
|
390
|
+
OWNED_SKILL,
|
|
434
391
|
"cursor-rule.mdc"
|
|
435
392
|
);
|
|
436
393
|
if (await pathExists(workflowRule)) {
|
|
437
394
|
await copyFile(workflowRule, join4(rulesDir, "flydocs-workflow.mdc"));
|
|
438
395
|
}
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
mech,
|
|
445
|
-
"cursor-rule.mdc"
|
|
446
|
-
);
|
|
447
|
-
if (await pathExists(mechRule)) {
|
|
448
|
-
await copyFile(mechRule, join4(rulesDir, "flydocs-mechanism.mdc"));
|
|
396
|
+
const { rm: rm6 } = await import("fs/promises");
|
|
397
|
+
for (const legacy of ["flydocs-mechanism.mdc", "flydocs-context7.mdc"]) {
|
|
398
|
+
const legacyRule = join4(rulesDir, legacy);
|
|
399
|
+
if (await pathExists(legacyRule)) {
|
|
400
|
+
await rm6(legacyRule, { force: true });
|
|
449
401
|
}
|
|
450
402
|
}
|
|
451
|
-
const context7Rule = join4(
|
|
452
|
-
targetDir,
|
|
453
|
-
".claude",
|
|
454
|
-
"skills",
|
|
455
|
-
"flydocs-context7",
|
|
456
|
-
"cursor-rule.mdc"
|
|
457
|
-
);
|
|
458
|
-
if (await pathExists(context7Rule)) {
|
|
459
|
-
await copyFile(context7Rule, join4(rulesDir, "flydocs-context7.mdc"));
|
|
460
|
-
}
|
|
461
403
|
}
|
|
462
|
-
var
|
|
404
|
+
var OWNED_SKILL, LEGACY_SKILLS;
|
|
463
405
|
var init_skills = __esm({
|
|
464
406
|
"src/lib/skills.ts"() {
|
|
465
407
|
"use strict";
|
|
466
408
|
init_fs_ops();
|
|
467
|
-
|
|
468
|
-
|
|
409
|
+
OWNED_SKILL = "flydocs-workflow";
|
|
410
|
+
LEGACY_SKILLS = [
|
|
411
|
+
"flydocs-cloud",
|
|
412
|
+
"flydocs-local",
|
|
469
413
|
"flydocs-context-graph",
|
|
470
|
-
"flydocs-context7"
|
|
414
|
+
"flydocs-context7",
|
|
415
|
+
"flydocs-figma",
|
|
416
|
+
"flydocs-estimates"
|
|
471
417
|
];
|
|
472
|
-
CLOUD_ONLY_SKILLS = ["flydocs-figma", "flydocs-estimates"];
|
|
473
|
-
MECHANISM_SKILLS = {
|
|
474
|
-
local: "flydocs-local",
|
|
475
|
-
cloud: "flydocs-cloud"
|
|
476
|
-
};
|
|
477
418
|
}
|
|
478
419
|
});
|
|
479
420
|
|
|
@@ -485,6 +426,18 @@ import {
|
|
|
485
426
|
writeFile as writeFile2
|
|
486
427
|
} from "fs/promises";
|
|
487
428
|
import { join as join5, dirname as dirname2 } from "path";
|
|
429
|
+
async function detectExistingConfigs(targetDir) {
|
|
430
|
+
const existing = [];
|
|
431
|
+
const backupDir = join5(targetDir, BACKUP_ORIGINALS_DIR);
|
|
432
|
+
for (const relativePath of RESTORABLE_FILES) {
|
|
433
|
+
const filePath = join5(targetDir, relativePath);
|
|
434
|
+
const backupPath = join5(backupDir, relativePath);
|
|
435
|
+
if (await pathExists(filePath) && !await pathExists(backupPath)) {
|
|
436
|
+
existing.push(relativePath);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
return existing;
|
|
440
|
+
}
|
|
488
441
|
async function backupOriginals(targetDir, files = RESTORABLE_FILES) {
|
|
489
442
|
const backedUp = [];
|
|
490
443
|
const backupDir = join5(targetDir, BACKUP_ORIGINALS_DIR);
|
|
@@ -703,7 +656,9 @@ import { join as join7 } from "path";
|
|
|
703
656
|
async function runManifestGeneration(targetDir) {
|
|
704
657
|
const scriptPath = join7(
|
|
705
658
|
targetDir,
|
|
706
|
-
".
|
|
659
|
+
".claude",
|
|
660
|
+
"skills",
|
|
661
|
+
"flydocs-workflow",
|
|
707
662
|
"scripts",
|
|
708
663
|
"generate_manifest.py"
|
|
709
664
|
);
|
|
@@ -723,7 +678,7 @@ async function runContextGraphBuild(targetDir) {
|
|
|
723
678
|
targetDir,
|
|
724
679
|
".claude",
|
|
725
680
|
"skills",
|
|
726
|
-
"flydocs-
|
|
681
|
+
"flydocs-workflow",
|
|
727
682
|
"scripts",
|
|
728
683
|
"graph_build.py"
|
|
729
684
|
);
|
|
@@ -760,8 +715,8 @@ function flushFrontmatterValue(mode, lines) {
|
|
|
760
715
|
return lines.join("\n").trim();
|
|
761
716
|
}
|
|
762
717
|
}
|
|
763
|
-
function parseFrontmatter(
|
|
764
|
-
const match =
|
|
718
|
+
function parseFrontmatter(text4) {
|
|
719
|
+
const match = text4.match(/^---\s*\n([\s\S]*?)\n---/);
|
|
765
720
|
if (!match) return null;
|
|
766
721
|
const block = match[1];
|
|
767
722
|
const result = {};
|
|
@@ -947,7 +902,8 @@ function searchCatalog(keyword) {
|
|
|
947
902
|
return searchable.includes(lower);
|
|
948
903
|
});
|
|
949
904
|
}
|
|
950
|
-
async function addSkill(targetDir, source) {
|
|
905
|
+
async function addSkill(targetDir, source, options) {
|
|
906
|
+
const quiet = options?.quiet ?? false;
|
|
951
907
|
if (isPlatformSkill(source)) {
|
|
952
908
|
printError(`Cannot install platform skill '${source}'.`);
|
|
953
909
|
console.log(" Platform skills (flydocs-*) are managed by the installer.");
|
|
@@ -965,11 +921,13 @@ async function addSkill(targetDir, source) {
|
|
|
965
921
|
console.log(` Remove first: flydocs skills remove ${skillName}`);
|
|
966
922
|
return;
|
|
967
923
|
}
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
924
|
+
if (!quiet) {
|
|
925
|
+
console.log();
|
|
926
|
+
console.log(
|
|
927
|
+
`${pc3.blue("->")} Installing ${pc3.cyan(skillName)} from ${repo}...`
|
|
928
|
+
);
|
|
929
|
+
console.log();
|
|
930
|
+
}
|
|
973
931
|
let success;
|
|
974
932
|
try {
|
|
975
933
|
success = await downloadSkillTree(repo, skillName, skillsDir);
|
|
@@ -1003,19 +961,23 @@ async function addSkill(targetDir, source) {
|
|
|
1003
961
|
);
|
|
1004
962
|
return;
|
|
1005
963
|
}
|
|
1006
|
-
if (!fm["triggers"]) {
|
|
964
|
+
if (!fm["triggers"] && !quiet) {
|
|
1007
965
|
printWarning(
|
|
1008
966
|
"SKILL.md has no triggers -- skill won't appear in manifest index."
|
|
1009
967
|
);
|
|
1010
968
|
}
|
|
1011
|
-
|
|
969
|
+
if (!quiet) {
|
|
970
|
+
printStatus("Downloaded skill files");
|
|
971
|
+
}
|
|
1012
972
|
const cursorRuleSrc = join8(skillsDir, "cursor-rule.mdc");
|
|
1013
973
|
if (await pathExists(cursorRuleSrc)) {
|
|
1014
974
|
const cursorRulesDir = join8(targetDir, ".cursor", "rules");
|
|
1015
975
|
await mkdir3(cursorRulesDir, { recursive: true });
|
|
1016
976
|
const cursorRuleDest = join8(cursorRulesDir, `${skillName}.mdc`);
|
|
1017
977
|
await copyFile(cursorRuleSrc, cursorRuleDest);
|
|
1018
|
-
|
|
978
|
+
if (!quiet) {
|
|
979
|
+
printStatus("Installed cursor rule");
|
|
980
|
+
}
|
|
1019
981
|
}
|
|
1020
982
|
const config = await readConfig(targetDir);
|
|
1021
983
|
const installed = config.skills?.installed ?? [];
|
|
@@ -1027,12 +989,16 @@ async function addSkill(targetDir, source) {
|
|
|
1027
989
|
}
|
|
1028
990
|
config.skills.installed = installed;
|
|
1029
991
|
await writeConfig(targetDir, config);
|
|
1030
|
-
|
|
992
|
+
if (!quiet) {
|
|
993
|
+
printStatus("Updated config.json");
|
|
994
|
+
}
|
|
1031
995
|
}
|
|
1032
996
|
await runManifestGeneration(targetDir);
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
997
|
+
if (!quiet) {
|
|
998
|
+
console.log();
|
|
999
|
+
printStatus(`Installed ${pc3.cyan(skillName)}`);
|
|
1000
|
+
console.log();
|
|
1001
|
+
}
|
|
1036
1002
|
}
|
|
1037
1003
|
async function removeSkill(targetDir, name) {
|
|
1038
1004
|
if (isPlatformSkill(name)) {
|
|
@@ -1187,7 +1153,8 @@ async function promptCommunitySkills(targetDir, stack, autoYes) {
|
|
|
1187
1153
|
let successCount = 0;
|
|
1188
1154
|
for (const skill of selected) {
|
|
1189
1155
|
try {
|
|
1190
|
-
await addSkill(targetDir, `${skill.repo}:${skill.name}
|
|
1156
|
+
await addSkill(targetDir, `${skill.repo}:${skill.name}`, { quiet: true });
|
|
1157
|
+
printStatus(`Installed ${pc4.cyan(skill.name)}`);
|
|
1191
1158
|
successCount++;
|
|
1192
1159
|
} catch {
|
|
1193
1160
|
printError(`${skill.name} (failed)`);
|
|
@@ -1312,10 +1279,19 @@ async function scanDeprecated(targetDir) {
|
|
|
1312
1279
|
found.push(dir);
|
|
1313
1280
|
}
|
|
1314
1281
|
}
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
if (await pathExists(
|
|
1318
|
-
found.push(
|
|
1282
|
+
const foundFlydocsDirs = /* @__PURE__ */ new Set();
|
|
1283
|
+
for (const dir of DEPRECATED_FLYDOCS_DIRS) {
|
|
1284
|
+
if (await pathExists(join10(targetDir, dir))) {
|
|
1285
|
+
found.push(dir);
|
|
1286
|
+
foundFlydocsDirs.add(dir);
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
1289
|
+
if (!foundFlydocsDirs.has(".flydocs/hooks")) {
|
|
1290
|
+
for (const hook of DEPRECATED_HOOKS) {
|
|
1291
|
+
const p = join10(targetDir, ".flydocs", "hooks", hook);
|
|
1292
|
+
if (await pathExists(p)) {
|
|
1293
|
+
found.push(`.flydocs/hooks/${hook}`);
|
|
1294
|
+
}
|
|
1319
1295
|
}
|
|
1320
1296
|
}
|
|
1321
1297
|
for (const rule of DEPRECATED_CURSOR_RULES) {
|
|
@@ -1400,7 +1376,7 @@ async function promptCleanup(targetDir, paths) {
|
|
|
1400
1376
|
printStatus(`Deleted: ${p}`);
|
|
1401
1377
|
}
|
|
1402
1378
|
}
|
|
1403
|
-
var DEPRECATED_DIRS, DEPRECATED_FILES, DEPRECATED_SKILLS, DEPRECATED_RULES_DIR, DEPRECATED_HOOKS, DEPRECATED_CURSOR_RULES, DEPRECATED_CURSOR_RULE_DIRS, DEPRECATED_COMMANDS;
|
|
1379
|
+
var DEPRECATED_DIRS, DEPRECATED_FILES, DEPRECATED_SKILLS, DEPRECATED_RULES_DIR, DEPRECATED_FLYDOCS_DIRS, DEPRECATED_HOOKS, DEPRECATED_CURSOR_RULES, DEPRECATED_CURSOR_RULE_DIRS, DEPRECATED_COMMANDS;
|
|
1404
1380
|
var init_deprecated = __esm({
|
|
1405
1381
|
"src/lib/deprecated.ts"() {
|
|
1406
1382
|
"use strict";
|
|
@@ -1416,10 +1392,14 @@ var init_deprecated = __esm({
|
|
|
1416
1392
|
"figma-mcp"
|
|
1417
1393
|
];
|
|
1418
1394
|
DEPRECATED_RULES_DIR = [".flydocs/rules"];
|
|
1395
|
+
DEPRECATED_FLYDOCS_DIRS = [".flydocs/hooks", ".flydocs/scripts"];
|
|
1419
1396
|
DEPRECATED_HOOKS = [
|
|
1420
1397
|
"linear-auto-approve.py",
|
|
1421
1398
|
"session-end.py",
|
|
1422
|
-
"prefer-scripts.py"
|
|
1399
|
+
"prefer-scripts.py",
|
|
1400
|
+
"auto-approve.py",
|
|
1401
|
+
"post-edit.py",
|
|
1402
|
+
"prompt-submit.py"
|
|
1423
1403
|
];
|
|
1424
1404
|
DEPRECATED_CURSOR_RULES = [
|
|
1425
1405
|
"designer-agent.mdc",
|
|
@@ -1466,8 +1446,9 @@ async function ensureGitignore(targetDir) {
|
|
|
1466
1446
|
async function migrateGitignore(targetDir) {
|
|
1467
1447
|
const gitignorePath = join11(targetDir, ".gitignore");
|
|
1468
1448
|
if (!await pathExists(gitignorePath)) return;
|
|
1469
|
-
|
|
1470
|
-
|
|
1449
|
+
let content = await readFile6(gitignorePath, "utf-8");
|
|
1450
|
+
for (const entry of FLYDOCS_GITIGNORE_ENTRIES) {
|
|
1451
|
+
if (content.includes(entry)) continue;
|
|
1471
1452
|
if (content.includes("# FlyDocs")) {
|
|
1472
1453
|
const lines = content.split("\n");
|
|
1473
1454
|
const flyDocsIdx = lines.findIndex((l) => l.trim() === "# FlyDocs");
|
|
@@ -1476,23 +1457,22 @@ async function migrateGitignore(targetDir) {
|
|
|
1476
1457
|
while (insertIdx < lines.length && lines[insertIdx].trim() !== "" && !lines[insertIdx].startsWith("#")) {
|
|
1477
1458
|
insertIdx++;
|
|
1478
1459
|
}
|
|
1479
|
-
lines.splice(insertIdx, 0,
|
|
1480
|
-
|
|
1460
|
+
lines.splice(insertIdx, 0, entry);
|
|
1461
|
+
content = lines.join("\n");
|
|
1462
|
+
await writeFile4(gitignorePath, content, "utf-8");
|
|
1481
1463
|
} else {
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
);
|
|
1464
|
+
content += `
|
|
1465
|
+
${entry}
|
|
1466
|
+
`;
|
|
1467
|
+
await writeFile4(gitignorePath, content, "utf-8");
|
|
1487
1468
|
}
|
|
1488
1469
|
} else {
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
);
|
|
1470
|
+
content += `
|
|
1471
|
+
${entry}
|
|
1472
|
+
`;
|
|
1473
|
+
await writeFile4(gitignorePath, content, "utf-8");
|
|
1494
1474
|
}
|
|
1495
|
-
printStatus(
|
|
1475
|
+
printStatus(`Added ${entry} to .gitignore`);
|
|
1496
1476
|
}
|
|
1497
1477
|
}
|
|
1498
1478
|
var FLYDOCS_GITIGNORE_ENTRIES, FULL_GITIGNORE_TEMPLATE;
|
|
@@ -1507,6 +1487,10 @@ var init_gitignore = __esm({
|
|
|
1507
1487
|
".flydocs/session.json",
|
|
1508
1488
|
".flydocs/logs/",
|
|
1509
1489
|
".flydocs/backup-*/",
|
|
1490
|
+
".flydocs/me.json",
|
|
1491
|
+
".flydocs/validation-cache.json",
|
|
1492
|
+
".flydocs/integrity-cache.json",
|
|
1493
|
+
".flydocs/session/",
|
|
1510
1494
|
"flydocs/context/graph.json"
|
|
1511
1495
|
];
|
|
1512
1496
|
FULL_GITIGNORE_TEMPLATE = `# Environment
|
|
@@ -1518,6 +1502,10 @@ var init_gitignore = __esm({
|
|
|
1518
1502
|
.flydocs/session.json
|
|
1519
1503
|
.flydocs/logs/
|
|
1520
1504
|
.flydocs/backup-*/
|
|
1505
|
+
.flydocs/me.json
|
|
1506
|
+
.flydocs/validation-cache.json
|
|
1507
|
+
.flydocs/integrity-cache.json
|
|
1508
|
+
.flydocs/session/
|
|
1521
1509
|
flydocs/context/graph.json
|
|
1522
1510
|
|
|
1523
1511
|
# Dependencies
|
|
@@ -1840,6 +1828,143 @@ var init_telemetry = __esm({
|
|
|
1840
1828
|
}
|
|
1841
1829
|
});
|
|
1842
1830
|
|
|
1831
|
+
// src/lib/api-key.ts
|
|
1832
|
+
import { readFile as readFile10, writeFile as writeFile7, appendFile as appendFile2 } from "fs/promises";
|
|
1833
|
+
import { join as join14 } from "path";
|
|
1834
|
+
function detectKeyType(key) {
|
|
1835
|
+
if (key.startsWith("fdk_")) return "relay";
|
|
1836
|
+
if (key.startsWith("lin_api_")) return "direct";
|
|
1837
|
+
return "unknown";
|
|
1838
|
+
}
|
|
1839
|
+
async function validateRelayKey(apiKey) {
|
|
1840
|
+
const baseUrl = process.env.FLYDOCS_RELAY_URL?.replace(/\/$/, "") ?? "https://app.flydocs.ai/api/relay";
|
|
1841
|
+
const response = await fetch(`${baseUrl}/auth/validate`, {
|
|
1842
|
+
method: "POST",
|
|
1843
|
+
headers: {
|
|
1844
|
+
Authorization: `Bearer ${apiKey}`,
|
|
1845
|
+
"Content-Type": "application/json"
|
|
1846
|
+
},
|
|
1847
|
+
signal: AbortSignal.timeout(15e3)
|
|
1848
|
+
});
|
|
1849
|
+
if (!response.ok) return { valid: false };
|
|
1850
|
+
const data = await response.json();
|
|
1851
|
+
if (!data.valid) return { valid: false };
|
|
1852
|
+
return { valid: true, org: data.org ?? "your organization" };
|
|
1853
|
+
}
|
|
1854
|
+
async function fetchWorkspaces(apiKey) {
|
|
1855
|
+
const baseUrl = process.env.FLYDOCS_RELAY_URL?.replace(/\/$/, "") ?? "https://app.flydocs.ai/api/relay";
|
|
1856
|
+
const response = await fetch(`${baseUrl}/auth/workspaces`, {
|
|
1857
|
+
method: "GET",
|
|
1858
|
+
headers: {
|
|
1859
|
+
Authorization: `Bearer ${apiKey}`
|
|
1860
|
+
},
|
|
1861
|
+
signal: AbortSignal.timeout(15e3)
|
|
1862
|
+
});
|
|
1863
|
+
if (!response.ok) {
|
|
1864
|
+
throw new Error(`Failed to fetch workspaces: ${response.status}`);
|
|
1865
|
+
}
|
|
1866
|
+
const data = await response.json();
|
|
1867
|
+
return data;
|
|
1868
|
+
}
|
|
1869
|
+
async function fetchMe(apiKey) {
|
|
1870
|
+
const baseUrl = process.env.FLYDOCS_RELAY_URL?.replace(/\/$/, "") ?? "https://app.flydocs.ai/api/relay";
|
|
1871
|
+
const response = await fetch(`${baseUrl}/auth/me`, {
|
|
1872
|
+
method: "GET",
|
|
1873
|
+
headers: {
|
|
1874
|
+
Authorization: `Bearer ${apiKey}`
|
|
1875
|
+
},
|
|
1876
|
+
signal: AbortSignal.timeout(15e3)
|
|
1877
|
+
});
|
|
1878
|
+
if (!response.ok) {
|
|
1879
|
+
throw new Error(`Failed to fetch user identity: ${response.status}`);
|
|
1880
|
+
}
|
|
1881
|
+
const data = await response.json();
|
|
1882
|
+
return {
|
|
1883
|
+
displayName: data.displayName ?? null,
|
|
1884
|
+
email: data.email ?? null,
|
|
1885
|
+
providerId: data.providerId ?? null,
|
|
1886
|
+
provider: data.provider ?? null,
|
|
1887
|
+
providerIdentities: data.providerIdentities ?? [],
|
|
1888
|
+
preferences: data.preferences ?? {}
|
|
1889
|
+
};
|
|
1890
|
+
}
|
|
1891
|
+
async function validateLinearKey(apiKey) {
|
|
1892
|
+
const response = await fetch("https://api.linear.app/graphql", {
|
|
1893
|
+
method: "POST",
|
|
1894
|
+
headers: {
|
|
1895
|
+
Authorization: apiKey,
|
|
1896
|
+
"Content-Type": "application/json"
|
|
1897
|
+
},
|
|
1898
|
+
body: JSON.stringify({ query: "{ viewer { id name email } }" }),
|
|
1899
|
+
signal: AbortSignal.timeout(15e3)
|
|
1900
|
+
});
|
|
1901
|
+
if (!response.ok) return { valid: false };
|
|
1902
|
+
const data = await response.json();
|
|
1903
|
+
if (!data.data?.viewer) return { valid: false };
|
|
1904
|
+
return {
|
|
1905
|
+
valid: true,
|
|
1906
|
+
name: data.data.viewer.name,
|
|
1907
|
+
email: data.data.viewer.email
|
|
1908
|
+
};
|
|
1909
|
+
}
|
|
1910
|
+
async function storeEnvKey(targetDir, envVarName, value) {
|
|
1911
|
+
const envPath = join14(targetDir, ".env");
|
|
1912
|
+
const envLocalPath = join14(targetDir, ".env.local");
|
|
1913
|
+
const targetEnvPath = await pathExists(envLocalPath) ? envLocalPath : envPath;
|
|
1914
|
+
const pattern = new RegExp(`${envVarName}=.*`);
|
|
1915
|
+
if (await pathExists(targetEnvPath)) {
|
|
1916
|
+
const envContent = await readFile10(targetEnvPath, "utf-8");
|
|
1917
|
+
if (pattern.test(envContent)) {
|
|
1918
|
+
const updated = envContent.replace(pattern, `${envVarName}=${value}`);
|
|
1919
|
+
await writeFile7(targetEnvPath, updated, "utf-8");
|
|
1920
|
+
} else {
|
|
1921
|
+
await appendFile2(targetEnvPath, `
|
|
1922
|
+
${envVarName}=${value}
|
|
1923
|
+
`);
|
|
1924
|
+
}
|
|
1925
|
+
} else {
|
|
1926
|
+
await writeFile7(targetEnvPath, `${envVarName}=${value}
|
|
1927
|
+
`, "utf-8");
|
|
1928
|
+
}
|
|
1929
|
+
return targetEnvPath === envLocalPath ? ".env.local" : ".env";
|
|
1930
|
+
}
|
|
1931
|
+
var init_api_key = __esm({
|
|
1932
|
+
"src/lib/api-key.ts"() {
|
|
1933
|
+
"use strict";
|
|
1934
|
+
init_fs_ops();
|
|
1935
|
+
}
|
|
1936
|
+
});
|
|
1937
|
+
|
|
1938
|
+
// src/lib/integrity.ts
|
|
1939
|
+
import { readFile as readFile11, writeFile as writeFile8 } from "fs/promises";
|
|
1940
|
+
import { join as join15 } from "path";
|
|
1941
|
+
async function generateIntegrity(targetDir, version) {
|
|
1942
|
+
const manifestPath = join15(targetDir, ".flydocs", "manifest.json");
|
|
1943
|
+
if (!await pathExists(manifestPath)) return;
|
|
1944
|
+
const manifest = JSON.parse(await readFile11(manifestPath, "utf-8"));
|
|
1945
|
+
const ownership = manifest.ownership;
|
|
1946
|
+
if (!ownership) return;
|
|
1947
|
+
const ownedDirs = ownership.owned_directories?.paths ?? [];
|
|
1948
|
+
const ownedFiles = ownership.owned_files?.paths ?? [];
|
|
1949
|
+
const integrity = {
|
|
1950
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1951
|
+
version,
|
|
1952
|
+
ownedFiles,
|
|
1953
|
+
ownedDirectories: ownedDirs
|
|
1954
|
+
};
|
|
1955
|
+
await writeFile8(
|
|
1956
|
+
join15(targetDir, ".flydocs", "integrity.json"),
|
|
1957
|
+
JSON.stringify(integrity, null, 2) + "\n",
|
|
1958
|
+
"utf-8"
|
|
1959
|
+
);
|
|
1960
|
+
}
|
|
1961
|
+
var init_integrity = __esm({
|
|
1962
|
+
"src/lib/integrity.ts"() {
|
|
1963
|
+
"use strict";
|
|
1964
|
+
init_fs_ops();
|
|
1965
|
+
}
|
|
1966
|
+
});
|
|
1967
|
+
|
|
1843
1968
|
// src/commands/install.ts
|
|
1844
1969
|
var install_exports = {};
|
|
1845
1970
|
__export(install_exports, {
|
|
@@ -1847,9 +1972,9 @@ __export(install_exports, {
|
|
|
1847
1972
|
});
|
|
1848
1973
|
import { defineCommand } from "citty";
|
|
1849
1974
|
import { resolve as resolve2 } from "path";
|
|
1850
|
-
import { join as
|
|
1851
|
-
import { mkdir as mkdir7 } from "fs/promises";
|
|
1852
|
-
import { confirm as confirm2, select, isCancel as isCancel3, cancel as cancel2 } from "@clack/prompts";
|
|
1975
|
+
import { join as join16 } from "path";
|
|
1976
|
+
import { mkdir as mkdir7, writeFile as writeFile9 } from "fs/promises";
|
|
1977
|
+
import { confirm as confirm2, select, text, isCancel as isCancel3, cancel as cancel2 } from "@clack/prompts";
|
|
1853
1978
|
import pc6 from "picocolors";
|
|
1854
1979
|
var install_default;
|
|
1855
1980
|
var init_install = __esm({
|
|
@@ -1868,6 +1993,8 @@ var init_install = __esm({
|
|
|
1868
1993
|
init_post_install();
|
|
1869
1994
|
init_update_check();
|
|
1870
1995
|
init_telemetry();
|
|
1996
|
+
init_api_key();
|
|
1997
|
+
init_integrity();
|
|
1871
1998
|
install_default = defineCommand({
|
|
1872
1999
|
meta: {
|
|
1873
2000
|
name: "install",
|
|
@@ -1929,7 +2056,7 @@ var init_install = __esm({
|
|
|
1929
2056
|
process.exit(1);
|
|
1930
2057
|
}
|
|
1931
2058
|
tier = args.tier;
|
|
1932
|
-
} else if (await pathExists(
|
|
2059
|
+
} else if (await pathExists(join16(targetDir, ".flydocs", "config.json"))) {
|
|
1933
2060
|
try {
|
|
1934
2061
|
const existing = await readConfig(targetDir);
|
|
1935
2062
|
if (existing.tier) {
|
|
@@ -1951,7 +2078,7 @@ var init_install = __esm({
|
|
|
1951
2078
|
{
|
|
1952
2079
|
value: "cloud",
|
|
1953
2080
|
label: "Cloud (managed)",
|
|
1954
|
-
hint: "Sync with Linear
|
|
2081
|
+
hint: "Sync with Linear, Jira, and more"
|
|
1955
2082
|
}
|
|
1956
2083
|
]
|
|
1957
2084
|
});
|
|
@@ -1978,48 +2105,198 @@ var init_install = __esm({
|
|
|
1978
2105
|
}
|
|
1979
2106
|
printInfo(`Tier: ${tier}`);
|
|
1980
2107
|
await capture("install_tier_selected", { tier });
|
|
1981
|
-
|
|
2108
|
+
let selectedWorkspaceId = null;
|
|
2109
|
+
let selectedWorkspaceName = null;
|
|
2110
|
+
let apiKey = null;
|
|
2111
|
+
if (tier === "cloud") {
|
|
2112
|
+
console.log();
|
|
2113
|
+
console.log(` ${pc6.bold("Connect to FlyDocs Cloud")}`);
|
|
2114
|
+
console.log();
|
|
2115
|
+
console.log(
|
|
2116
|
+
` ${pc6.dim("Get your API key from your FlyDocs dashboard (fdk_...)")}`
|
|
2117
|
+
);
|
|
2118
|
+
console.log();
|
|
2119
|
+
const keyInput = await text({
|
|
2120
|
+
message: "Enter your FlyDocs API key",
|
|
2121
|
+
placeholder: "fdk_...",
|
|
2122
|
+
validate(value) {
|
|
2123
|
+
if (!value.trim()) return "API key is required";
|
|
2124
|
+
const type = detectKeyType(value.trim());
|
|
2125
|
+
if (type !== "relay")
|
|
2126
|
+
return "Cloud tier requires a FlyDocs API key (fdk_...)";
|
|
2127
|
+
return void 0;
|
|
2128
|
+
}
|
|
2129
|
+
});
|
|
2130
|
+
if (isCancel3(keyInput)) {
|
|
2131
|
+
cancel2("Installation cancelled.");
|
|
2132
|
+
process.exit(0);
|
|
2133
|
+
}
|
|
2134
|
+
apiKey = keyInput.trim();
|
|
2135
|
+
printInfo("Validating API key...");
|
|
2136
|
+
try {
|
|
2137
|
+
const result = await validateRelayKey(apiKey);
|
|
2138
|
+
if (!result.valid) {
|
|
2139
|
+
printError("Invalid API key or relay API unreachable.");
|
|
2140
|
+
console.log(` Check your key and try again.`);
|
|
2141
|
+
process.exit(1);
|
|
2142
|
+
}
|
|
2143
|
+
printStatus(`Connected to ${pc6.bold(result.org)}`);
|
|
2144
|
+
} catch {
|
|
2145
|
+
printError(
|
|
2146
|
+
"Could not reach relay API. Check your network and try again."
|
|
2147
|
+
);
|
|
2148
|
+
process.exit(1);
|
|
2149
|
+
}
|
|
2150
|
+
const envFile = await storeEnvKey(targetDir, "FLYDOCS_API_KEY", apiKey);
|
|
2151
|
+
printStatus(`API key stored in ${pc6.dim(envFile)}`);
|
|
2152
|
+
console.log();
|
|
2153
|
+
printInfo("Fetching workspaces...");
|
|
2154
|
+
try {
|
|
2155
|
+
const workspaces = await fetchWorkspaces(apiKey);
|
|
2156
|
+
if (workspaces.length === 0) {
|
|
2157
|
+
printError(
|
|
2158
|
+
"No workspaces found. Create a workspace in the FlyDocs dashboard first, then re-run install."
|
|
2159
|
+
);
|
|
2160
|
+
process.exit(1);
|
|
2161
|
+
}
|
|
2162
|
+
if (workspaces.length === 1) {
|
|
2163
|
+
selectedWorkspaceId = workspaces[0].id;
|
|
2164
|
+
selectedWorkspaceName = workspaces[0].name;
|
|
2165
|
+
printStatus(
|
|
2166
|
+
`Workspace: ${pc6.bold(selectedWorkspaceName)} (auto-selected)`
|
|
2167
|
+
);
|
|
2168
|
+
} else {
|
|
2169
|
+
const workspaceChoice = await select({
|
|
2170
|
+
message: "Select a workspace",
|
|
2171
|
+
options: workspaces.map((ws) => ({
|
|
2172
|
+
value: ws.id,
|
|
2173
|
+
label: `${ws.name} (${ws.provider.type})`,
|
|
2174
|
+
hint: ws.team.name
|
|
2175
|
+
}))
|
|
2176
|
+
});
|
|
2177
|
+
if (isCancel3(workspaceChoice)) {
|
|
2178
|
+
cancel2("Installation cancelled.");
|
|
2179
|
+
process.exit(0);
|
|
2180
|
+
}
|
|
2181
|
+
selectedWorkspaceId = workspaceChoice;
|
|
2182
|
+
const chosen = workspaces.find((ws) => ws.id === selectedWorkspaceId);
|
|
2183
|
+
selectedWorkspaceName = chosen?.name ?? "Unknown";
|
|
2184
|
+
printStatus(`Workspace: ${pc6.bold(selectedWorkspaceName)}`);
|
|
2185
|
+
}
|
|
2186
|
+
} catch {
|
|
2187
|
+
printError(
|
|
2188
|
+
"Could not fetch workspaces. Check your network and try again."
|
|
2189
|
+
);
|
|
2190
|
+
process.exit(1);
|
|
2191
|
+
}
|
|
2192
|
+
}
|
|
2193
|
+
let skipConfigOverwrite = false;
|
|
2194
|
+
if (!await pathExists(join16(targetDir, ".git"))) {
|
|
1982
2195
|
printWarning("No git repository detected. Run git init when ready.");
|
|
1983
2196
|
}
|
|
1984
2197
|
await ensureDirectories(targetDir, tier);
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
2198
|
+
if (tier === "cloud" && apiKey) {
|
|
2199
|
+
try {
|
|
2200
|
+
const me = await fetchMe(apiKey);
|
|
2201
|
+
const meData = {
|
|
2202
|
+
displayName: me.displayName,
|
|
2203
|
+
email: me.email,
|
|
2204
|
+
providerId: me.providerId,
|
|
2205
|
+
provider: me.provider,
|
|
2206
|
+
providerIdentities: me.providerIdentities,
|
|
2207
|
+
preferences: me.preferences
|
|
2208
|
+
};
|
|
2209
|
+
const mePath = join16(targetDir, ".flydocs", "me.json");
|
|
2210
|
+
await writeFile9(
|
|
2211
|
+
mePath,
|
|
2212
|
+
JSON.stringify(meData, null, 2) + "\n",
|
|
2213
|
+
"utf-8"
|
|
2214
|
+
);
|
|
2215
|
+
if (me.displayName) {
|
|
2216
|
+
printStatus(`Identity: ${pc6.bold(me.displayName)}`);
|
|
2217
|
+
}
|
|
2218
|
+
} catch {
|
|
2219
|
+
printWarning(
|
|
2220
|
+
"Could not fetch user identity. Run /flydocs-setup to configure later."
|
|
2221
|
+
);
|
|
2222
|
+
}
|
|
2223
|
+
}
|
|
2224
|
+
const existingFiles = await detectExistingConfigs(targetDir);
|
|
2225
|
+
if (existingFiles.length > 0) {
|
|
2226
|
+
console.log();
|
|
2227
|
+
printWarning(
|
|
2228
|
+
`Found ${existingFiles.length} existing config file(s) that FlyDocs will overwrite:`
|
|
1989
2229
|
);
|
|
1990
|
-
for (const f of
|
|
1991
|
-
|
|
2230
|
+
for (const f of existingFiles) {
|
|
2231
|
+
console.log(` ${pc6.dim(f)}`);
|
|
2232
|
+
}
|
|
2233
|
+
console.log();
|
|
2234
|
+
if (!args.yes) {
|
|
2235
|
+
const overwriteChoice = await select({
|
|
2236
|
+
message: "How should FlyDocs handle these files?",
|
|
2237
|
+
options: [
|
|
2238
|
+
{
|
|
2239
|
+
value: "backup",
|
|
2240
|
+
label: "Overwrite (backed up)",
|
|
2241
|
+
hint: "Files are saved to .flydocs/backup-originals/ and restored on uninstall"
|
|
2242
|
+
},
|
|
2243
|
+
{
|
|
2244
|
+
value: "skip",
|
|
2245
|
+
label: "Skip overwriting",
|
|
2246
|
+
hint: "Keep your existing files \u2014 FlyDocs config may be incomplete"
|
|
2247
|
+
}
|
|
2248
|
+
]
|
|
2249
|
+
});
|
|
2250
|
+
if (isCancel3(overwriteChoice)) {
|
|
2251
|
+
cancel2("Installation cancelled.");
|
|
2252
|
+
process.exit(0);
|
|
2253
|
+
}
|
|
2254
|
+
if (overwriteChoice === "skip") {
|
|
2255
|
+
printInfo(
|
|
2256
|
+
"Keeping existing files. Run /flydocs-setup to merge your config manually."
|
|
2257
|
+
);
|
|
2258
|
+
skipConfigOverwrite = true;
|
|
2259
|
+
}
|
|
2260
|
+
}
|
|
2261
|
+
if (!skipConfigOverwrite) {
|
|
2262
|
+
const backedUp = await backupOriginals(targetDir);
|
|
2263
|
+
if (backedUp.length > 0) {
|
|
2264
|
+
printStatus(
|
|
2265
|
+
`Backed up ${backedUp.length} file(s) to .flydocs/backup-originals/`
|
|
2266
|
+
);
|
|
2267
|
+
}
|
|
1992
2268
|
}
|
|
1993
2269
|
}
|
|
1994
2270
|
console.log("Installing framework files...");
|
|
1995
2271
|
await replaceDirectory(
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
);
|
|
1999
|
-
await replaceDirectory(
|
|
2000
|
-
join14(templateDir, ".flydocs", "hooks"),
|
|
2001
|
-
join14(targetDir, ".flydocs", "hooks")
|
|
2272
|
+
join16(templateDir, ".flydocs", "templates"),
|
|
2273
|
+
join16(targetDir, ".flydocs", "templates")
|
|
2002
2274
|
);
|
|
2003
2275
|
await replaceDirectory(
|
|
2004
|
-
|
|
2005
|
-
|
|
2276
|
+
join16(templateDir, ".claude", "hooks"),
|
|
2277
|
+
join16(targetDir, ".claude", "hooks")
|
|
2006
2278
|
);
|
|
2007
2279
|
await copyFile(
|
|
2008
|
-
|
|
2009
|
-
|
|
2280
|
+
join16(templateDir, ".flydocs", "version"),
|
|
2281
|
+
join16(targetDir, ".flydocs", "version")
|
|
2010
2282
|
);
|
|
2011
|
-
const manifestSrc =
|
|
2283
|
+
const manifestSrc = join16(templateDir, "manifest.json");
|
|
2012
2284
|
if (await pathExists(manifestSrc)) {
|
|
2013
|
-
await copyFile(manifestSrc,
|
|
2285
|
+
await copyFile(manifestSrc, join16(targetDir, ".flydocs", "manifest.json"));
|
|
2014
2286
|
}
|
|
2015
|
-
const changelogSrc =
|
|
2287
|
+
const changelogSrc = join16(templateDir, "CHANGELOG.md");
|
|
2016
2288
|
if (await pathExists(changelogSrc)) {
|
|
2017
|
-
await copyFile(changelogSrc,
|
|
2289
|
+
await copyFile(changelogSrc, join16(targetDir, ".flydocs", "CHANGELOG.md"));
|
|
2018
2290
|
}
|
|
2019
|
-
printStatus(
|
|
2020
|
-
|
|
2291
|
+
printStatus(
|
|
2292
|
+
".flydocs/templates, .claude/hooks, version, manifest, changelog"
|
|
2293
|
+
);
|
|
2294
|
+
const configPath = join16(targetDir, ".flydocs", "config.json");
|
|
2021
2295
|
if (!await pathExists(configPath)) {
|
|
2022
2296
|
const config = await createFreshConfig(templateDir, version, tier);
|
|
2297
|
+
if (selectedWorkspaceId) {
|
|
2298
|
+
config.workspaceId = selectedWorkspaceId;
|
|
2299
|
+
}
|
|
2023
2300
|
await writeConfig(targetDir, config);
|
|
2024
2301
|
printStatus(`.flydocs/config.json (new, tier: ${tier})`);
|
|
2025
2302
|
} else if (args.tier) {
|
|
@@ -2027,15 +2304,34 @@ var init_install = __esm({
|
|
|
2027
2304
|
const existing = await readConfig(targetDir);
|
|
2028
2305
|
existing.version = version;
|
|
2029
2306
|
existing.tier = tier;
|
|
2307
|
+
if (selectedWorkspaceId) {
|
|
2308
|
+
existing.workspaceId = selectedWorkspaceId;
|
|
2309
|
+
}
|
|
2030
2310
|
await writeConfig(targetDir, existing);
|
|
2031
2311
|
printStatus(`.flydocs/config.json (tier updated: ${tier})`);
|
|
2032
2312
|
} catch {
|
|
2033
2313
|
const config = await createFreshConfig(templateDir, version, tier);
|
|
2314
|
+
if (selectedWorkspaceId) {
|
|
2315
|
+
config.workspaceId = selectedWorkspaceId;
|
|
2316
|
+
}
|
|
2034
2317
|
await writeConfig(targetDir, config);
|
|
2035
2318
|
printStatus(`.flydocs/config.json (recreated, tier: ${tier})`);
|
|
2036
2319
|
}
|
|
2037
2320
|
} else {
|
|
2038
|
-
|
|
2321
|
+
if (selectedWorkspaceId) {
|
|
2322
|
+
try {
|
|
2323
|
+
const existing = await readConfig(targetDir);
|
|
2324
|
+
existing.workspaceId = selectedWorkspaceId;
|
|
2325
|
+
await writeConfig(targetDir, existing);
|
|
2326
|
+
printWarning(
|
|
2327
|
+
".flydocs/config.json exists, preserving (workspace updated)"
|
|
2328
|
+
);
|
|
2329
|
+
} catch {
|
|
2330
|
+
printWarning(".flydocs/config.json exists, preserving");
|
|
2331
|
+
}
|
|
2332
|
+
} else {
|
|
2333
|
+
printWarning(".flydocs/config.json exists, preserving");
|
|
2334
|
+
}
|
|
2039
2335
|
}
|
|
2040
2336
|
console.log();
|
|
2041
2337
|
console.log(`Installing skills (tier: ${tier})...`);
|
|
@@ -2071,20 +2367,20 @@ var init_install = __esm({
|
|
|
2071
2367
|
}
|
|
2072
2368
|
await capture("install_agents_chosen", { install_agents: installAgents });
|
|
2073
2369
|
if (installAgents) {
|
|
2074
|
-
const claudeAgentsSrc =
|
|
2370
|
+
const claudeAgentsSrc = join16(templateDir, ".claude", "agents");
|
|
2075
2371
|
if (await pathExists(claudeAgentsSrc)) {
|
|
2076
|
-
await mkdir7(
|
|
2372
|
+
await mkdir7(join16(targetDir, ".claude", "agents"), { recursive: true });
|
|
2077
2373
|
await copyDirectoryContents(
|
|
2078
2374
|
claudeAgentsSrc,
|
|
2079
|
-
|
|
2375
|
+
join16(targetDir, ".claude", "agents")
|
|
2080
2376
|
);
|
|
2081
2377
|
}
|
|
2082
|
-
const cursorAgentsSrc =
|
|
2378
|
+
const cursorAgentsSrc = join16(templateDir, ".cursor", "agents");
|
|
2083
2379
|
if (await pathExists(cursorAgentsSrc)) {
|
|
2084
|
-
await mkdir7(
|
|
2380
|
+
await mkdir7(join16(targetDir, ".cursor", "agents"), { recursive: true });
|
|
2085
2381
|
await copyDirectoryContents(
|
|
2086
2382
|
cursorAgentsSrc,
|
|
2087
|
-
|
|
2383
|
+
join16(targetDir, ".cursor", "agents")
|
|
2088
2384
|
);
|
|
2089
2385
|
}
|
|
2090
2386
|
printStatus("Sub-agents installed (.claude/agents, .cursor/agents)");
|
|
@@ -2094,74 +2390,88 @@ var init_install = __esm({
|
|
|
2094
2390
|
console.log();
|
|
2095
2391
|
console.log("Installing commands and settings...");
|
|
2096
2392
|
await copyDirectoryContents(
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
);
|
|
2100
|
-
await copyFile(
|
|
2101
|
-
join14(templateDir, ".claude", "CLAUDE.md"),
|
|
2102
|
-
join14(targetDir, ".claude", "CLAUDE.md")
|
|
2393
|
+
join16(templateDir, ".claude", "commands"),
|
|
2394
|
+
join16(targetDir, ".claude", "commands")
|
|
2103
2395
|
);
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2396
|
+
if (!skipConfigOverwrite) {
|
|
2397
|
+
await copyFile(
|
|
2398
|
+
join16(templateDir, ".claude", "CLAUDE.md"),
|
|
2399
|
+
join16(targetDir, ".claude", "CLAUDE.md")
|
|
2400
|
+
);
|
|
2401
|
+
await copyFile(
|
|
2402
|
+
join16(templateDir, ".claude", "settings.json"),
|
|
2403
|
+
join16(targetDir, ".claude", "settings.json")
|
|
2404
|
+
);
|
|
2405
|
+
printStatus(".claude/ (commands, CLAUDE.md, settings)");
|
|
2406
|
+
} else {
|
|
2407
|
+
printStatus(".claude/ (commands only \u2014 existing config preserved)");
|
|
2408
|
+
}
|
|
2109
2409
|
await copyDirectoryContents(
|
|
2110
|
-
|
|
2111
|
-
|
|
2410
|
+
join16(templateDir, ".claude", "commands"),
|
|
2411
|
+
join16(targetDir, ".cursor", "commands")
|
|
2112
2412
|
);
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2413
|
+
if (!skipConfigOverwrite) {
|
|
2414
|
+
await copyFile(
|
|
2415
|
+
join16(templateDir, ".cursor", "hooks.json"),
|
|
2416
|
+
join16(targetDir, ".cursor", "hooks.json")
|
|
2417
|
+
);
|
|
2418
|
+
printStatus(".cursor/ (commands, hooks)");
|
|
2419
|
+
} else {
|
|
2420
|
+
printStatus(".cursor/ (commands only \u2014 existing hooks preserved)");
|
|
2421
|
+
}
|
|
2118
2422
|
await copyCursorRules(targetDir);
|
|
2119
2423
|
printStatus(".cursor/rules/");
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2424
|
+
if (!skipConfigOverwrite) {
|
|
2425
|
+
await copyFile(
|
|
2426
|
+
join16(templateDir, "AGENTS.md"),
|
|
2427
|
+
join16(targetDir, "AGENTS.md")
|
|
2428
|
+
);
|
|
2429
|
+
printStatus("AGENTS.md");
|
|
2430
|
+
} else {
|
|
2431
|
+
printInfo("AGENTS.md preserved (existing)");
|
|
2432
|
+
}
|
|
2125
2433
|
await runManifestGeneration(targetDir);
|
|
2126
2434
|
await runContextGraphBuild(targetDir);
|
|
2435
|
+
await generateIntegrity(targetDir, version);
|
|
2436
|
+
printStatus("Install integrity recorded");
|
|
2127
2437
|
console.log();
|
|
2128
2438
|
console.log("Installing project templates...");
|
|
2129
2439
|
const userFiles = [
|
|
2130
2440
|
{
|
|
2131
|
-
src:
|
|
2132
|
-
dest:
|
|
2441
|
+
src: join16(templateDir, "flydocs", "context", "project.md"),
|
|
2442
|
+
dest: join16(targetDir, "flydocs", "context", "project.md"),
|
|
2133
2443
|
label: "flydocs/context/project.md"
|
|
2134
2444
|
},
|
|
2135
2445
|
{
|
|
2136
|
-
src:
|
|
2137
|
-
dest:
|
|
2446
|
+
src: join16(templateDir, "flydocs", "knowledge", "INDEX.md"),
|
|
2447
|
+
dest: join16(targetDir, "flydocs", "knowledge", "INDEX.md"),
|
|
2138
2448
|
label: "flydocs/knowledge/INDEX.md"
|
|
2139
2449
|
},
|
|
2140
2450
|
{
|
|
2141
|
-
src:
|
|
2142
|
-
dest:
|
|
2451
|
+
src: join16(templateDir, "flydocs", "knowledge", "README.md"),
|
|
2452
|
+
dest: join16(targetDir, "flydocs", "knowledge", "README.md"),
|
|
2143
2453
|
label: "flydocs/knowledge/README.md"
|
|
2144
2454
|
},
|
|
2145
2455
|
{
|
|
2146
|
-
src:
|
|
2456
|
+
src: join16(
|
|
2147
2457
|
templateDir,
|
|
2148
2458
|
"flydocs",
|
|
2149
2459
|
"knowledge",
|
|
2150
2460
|
"product",
|
|
2151
2461
|
"personas.md"
|
|
2152
2462
|
),
|
|
2153
|
-
dest:
|
|
2463
|
+
dest: join16(targetDir, "flydocs", "knowledge", "product", "personas.md"),
|
|
2154
2464
|
label: "flydocs/knowledge/product/personas.md"
|
|
2155
2465
|
},
|
|
2156
2466
|
{
|
|
2157
|
-
src:
|
|
2467
|
+
src: join16(
|
|
2158
2468
|
templateDir,
|
|
2159
2469
|
"flydocs",
|
|
2160
2470
|
"knowledge",
|
|
2161
2471
|
"product",
|
|
2162
2472
|
"user-flows.md"
|
|
2163
2473
|
),
|
|
2164
|
-
dest:
|
|
2474
|
+
dest: join16(
|
|
2165
2475
|
targetDir,
|
|
2166
2476
|
"flydocs",
|
|
2167
2477
|
"knowledge",
|
|
@@ -2171,18 +2481,57 @@ var init_install = __esm({
|
|
|
2171
2481
|
label: "flydocs/knowledge/product/user-flows.md"
|
|
2172
2482
|
},
|
|
2173
2483
|
{
|
|
2174
|
-
src:
|
|
2175
|
-
|
|
2484
|
+
src: join16(
|
|
2485
|
+
templateDir,
|
|
2486
|
+
"flydocs",
|
|
2487
|
+
"knowledge",
|
|
2488
|
+
"templates",
|
|
2489
|
+
"decision.md"
|
|
2490
|
+
),
|
|
2491
|
+
dest: join16(
|
|
2492
|
+
targetDir,
|
|
2493
|
+
"flydocs",
|
|
2494
|
+
"knowledge",
|
|
2495
|
+
"templates",
|
|
2496
|
+
"decision.md"
|
|
2497
|
+
),
|
|
2498
|
+
label: "flydocs/knowledge/templates/decision.md"
|
|
2499
|
+
},
|
|
2500
|
+
{
|
|
2501
|
+
src: join16(
|
|
2502
|
+
templateDir,
|
|
2503
|
+
"flydocs",
|
|
2504
|
+
"knowledge",
|
|
2505
|
+
"templates",
|
|
2506
|
+
"feature.md"
|
|
2507
|
+
),
|
|
2508
|
+
dest: join16(
|
|
2509
|
+
targetDir,
|
|
2510
|
+
"flydocs",
|
|
2511
|
+
"knowledge",
|
|
2512
|
+
"templates",
|
|
2513
|
+
"feature.md"
|
|
2514
|
+
),
|
|
2515
|
+
label: "flydocs/knowledge/templates/feature.md"
|
|
2516
|
+
},
|
|
2517
|
+
{
|
|
2518
|
+
src: join16(templateDir, "flydocs", "knowledge", "templates", "note.md"),
|
|
2519
|
+
dest: join16(targetDir, "flydocs", "knowledge", "templates", "note.md"),
|
|
2520
|
+
label: "flydocs/knowledge/templates/note.md"
|
|
2521
|
+
},
|
|
2522
|
+
{
|
|
2523
|
+
src: join16(templateDir, "flydocs", "design-system", "README.md"),
|
|
2524
|
+
dest: join16(targetDir, "flydocs", "design-system", "README.md"),
|
|
2176
2525
|
label: "flydocs/design-system/README.md"
|
|
2177
2526
|
},
|
|
2178
2527
|
{
|
|
2179
|
-
src:
|
|
2528
|
+
src: join16(
|
|
2180
2529
|
templateDir,
|
|
2181
2530
|
"flydocs",
|
|
2182
2531
|
"design-system",
|
|
2183
2532
|
"component-patterns.md"
|
|
2184
2533
|
),
|
|
2185
|
-
dest:
|
|
2534
|
+
dest: join16(
|
|
2186
2535
|
targetDir,
|
|
2187
2536
|
"flydocs",
|
|
2188
2537
|
"design-system",
|
|
@@ -2191,13 +2540,13 @@ var init_install = __esm({
|
|
|
2191
2540
|
label: "flydocs/design-system/component-patterns.md"
|
|
2192
2541
|
},
|
|
2193
2542
|
{
|
|
2194
|
-
src:
|
|
2195
|
-
dest:
|
|
2543
|
+
src: join16(templateDir, "flydocs", "design-system", "token-mapping.md"),
|
|
2544
|
+
dest: join16(targetDir, "flydocs", "design-system", "token-mapping.md"),
|
|
2196
2545
|
label: "flydocs/design-system/token-mapping.md"
|
|
2197
2546
|
},
|
|
2198
2547
|
{
|
|
2199
|
-
src:
|
|
2200
|
-
dest:
|
|
2548
|
+
src: join16(templateDir, "flydocs", "README.md"),
|
|
2549
|
+
dest: join16(targetDir, "flydocs", "README.md"),
|
|
2201
2550
|
label: "flydocs/README.md"
|
|
2202
2551
|
}
|
|
2203
2552
|
];
|
|
@@ -2211,9 +2560,9 @@ var init_install = __esm({
|
|
|
2211
2560
|
}
|
|
2212
2561
|
}
|
|
2213
2562
|
}
|
|
2214
|
-
const envExampleSrc =
|
|
2563
|
+
const envExampleSrc = join16(templateDir, ".env.example");
|
|
2215
2564
|
if (await pathExists(envExampleSrc)) {
|
|
2216
|
-
await copyFile(envExampleSrc,
|
|
2565
|
+
await copyFile(envExampleSrc, join16(targetDir, ".env.example"));
|
|
2217
2566
|
printStatus(".env.example");
|
|
2218
2567
|
}
|
|
2219
2568
|
await ensureGitignore(targetDir);
|
|
@@ -2253,9 +2602,8 @@ var init_install = __esm({
|
|
|
2253
2602
|
`Version: ${version}`,
|
|
2254
2603
|
"",
|
|
2255
2604
|
"Next steps:",
|
|
2256
|
-
" 1. Run flydocs
|
|
2257
|
-
" 2.
|
|
2258
|
-
" 3. Start working with /start-session",
|
|
2605
|
+
" 1. Run /flydocs-setup to configure your workspace",
|
|
2606
|
+
" 2. Start working with /start-session",
|
|
2259
2607
|
"",
|
|
2260
2608
|
"Docs: https://www.flydocs.ai/docs"
|
|
2261
2609
|
];
|
|
@@ -2392,9 +2740,9 @@ __export(update_exports, {
|
|
|
2392
2740
|
default: () => update_default
|
|
2393
2741
|
});
|
|
2394
2742
|
import { defineCommand as defineCommand2 } from "citty";
|
|
2395
|
-
import { resolve as resolve3, join as
|
|
2396
|
-
import { mkdir as mkdir8, cp as cp2, readFile as
|
|
2397
|
-
import { select as select2, text, confirm as confirm3, isCancel as isCancel4, cancel as cancel3 } from "@clack/prompts";
|
|
2743
|
+
import { resolve as resolve3, join as join17 } from "path";
|
|
2744
|
+
import { mkdir as mkdir8, cp as cp2, readFile as readFile12, readdir as readdir4, rm as rm4 } from "fs/promises";
|
|
2745
|
+
import { select as select2, text as text2, confirm as confirm3, isCancel as isCancel4, cancel as cancel3 } from "@clack/prompts";
|
|
2398
2746
|
import pc7 from "picocolors";
|
|
2399
2747
|
var update_default;
|
|
2400
2748
|
var init_update = __esm({
|
|
@@ -2413,6 +2761,7 @@ var init_update = __esm({
|
|
|
2413
2761
|
init_post_install();
|
|
2414
2762
|
init_update_check();
|
|
2415
2763
|
init_telemetry();
|
|
2764
|
+
init_integrity();
|
|
2416
2765
|
update_default = defineCommand2({
|
|
2417
2766
|
meta: {
|
|
2418
2767
|
name: "update",
|
|
@@ -2482,7 +2831,7 @@ var init_update = __esm({
|
|
|
2482
2831
|
if (choice === "cwd") {
|
|
2483
2832
|
targetDir = process.cwd();
|
|
2484
2833
|
} else {
|
|
2485
|
-
const enteredPath = await
|
|
2834
|
+
const enteredPath = await text2({
|
|
2486
2835
|
message: "Enter project path:"
|
|
2487
2836
|
});
|
|
2488
2837
|
if (isCancel4(enteredPath)) {
|
|
@@ -2500,9 +2849,9 @@ var init_update = __esm({
|
|
|
2500
2849
|
}
|
|
2501
2850
|
targetDir = resolve3(targetDir);
|
|
2502
2851
|
process.chdir(targetDir);
|
|
2503
|
-
const hasVersion = await pathExists(
|
|
2852
|
+
const hasVersion = await pathExists(join17(targetDir, ".flydocs", "version"));
|
|
2504
2853
|
const hasConfig = await pathExists(
|
|
2505
|
-
|
|
2854
|
+
join17(targetDir, ".flydocs", "config.json")
|
|
2506
2855
|
);
|
|
2507
2856
|
if (!hasVersion && !hasConfig) {
|
|
2508
2857
|
printError(`Not a FlyDocs project: ${targetDir}`);
|
|
@@ -2513,8 +2862,8 @@ var init_update = __esm({
|
|
|
2513
2862
|
console.log();
|
|
2514
2863
|
let currentVersion = "0.1.0";
|
|
2515
2864
|
if (hasVersion) {
|
|
2516
|
-
const vContent = await
|
|
2517
|
-
|
|
2865
|
+
const vContent = await readFile12(
|
|
2866
|
+
join17(targetDir, ".flydocs", "version"),
|
|
2518
2867
|
"utf-8"
|
|
2519
2868
|
);
|
|
2520
2869
|
currentVersion = vContent.trim();
|
|
@@ -2548,7 +2897,7 @@ var init_update = __esm({
|
|
|
2548
2897
|
});
|
|
2549
2898
|
console.log(`Updating: v${currentVersion} \u2192 v${version}`);
|
|
2550
2899
|
console.log();
|
|
2551
|
-
const changelogPath =
|
|
2900
|
+
const changelogPath = join17(templateDir, "CHANGELOG.md");
|
|
2552
2901
|
const whatsNew = await getWhatsNew(changelogPath, currentVersion, version);
|
|
2553
2902
|
if (whatsNew.length > 0) {
|
|
2554
2903
|
console.log(pc7.cyan("What's new:"));
|
|
@@ -2560,36 +2909,37 @@ var init_update = __esm({
|
|
|
2560
2909
|
}
|
|
2561
2910
|
const now = /* @__PURE__ */ new Date();
|
|
2562
2911
|
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")}`;
|
|
2563
|
-
const backupDir =
|
|
2912
|
+
const backupDir = join17(targetDir, ".flydocs", `backup-${ts}`);
|
|
2564
2913
|
await mkdir8(backupDir, { recursive: true });
|
|
2565
2914
|
if (hasConfig) {
|
|
2566
2915
|
await cp2(
|
|
2567
|
-
|
|
2568
|
-
|
|
2916
|
+
join17(targetDir, ".flydocs", "config.json"),
|
|
2917
|
+
join17(backupDir, "config.json")
|
|
2569
2918
|
);
|
|
2570
2919
|
printStatus(`Config backed up to .flydocs/backup-${ts}/`);
|
|
2571
2920
|
}
|
|
2572
2921
|
try {
|
|
2573
|
-
const flydocsDir =
|
|
2574
|
-
const entries = await
|
|
2922
|
+
const flydocsDir = join17(targetDir, ".flydocs");
|
|
2923
|
+
const entries = await readdir4(flydocsDir);
|
|
2575
2924
|
const backups = entries.filter((e) => e.startsWith("backup-")).sort();
|
|
2576
2925
|
if (backups.length > 3) {
|
|
2577
2926
|
const toRemove = backups.slice(0, backups.length - 3);
|
|
2578
2927
|
for (const old of toRemove) {
|
|
2579
|
-
await rm4(
|
|
2928
|
+
await rm4(join17(flydocsDir, old), { recursive: true, force: true });
|
|
2580
2929
|
}
|
|
2581
2930
|
}
|
|
2582
2931
|
} catch {
|
|
2583
2932
|
}
|
|
2584
2933
|
let preserved = {
|
|
2585
|
-
tier: "
|
|
2934
|
+
tier: "local",
|
|
2586
2935
|
setupComplete: false,
|
|
2587
|
-
|
|
2936
|
+
workspaceId: null,
|
|
2937
|
+
configVersion: void 0,
|
|
2588
2938
|
workspace: {},
|
|
2589
2939
|
issueLabels: {},
|
|
2590
|
-
statusMapping: {},
|
|
2591
2940
|
detectedStack: {},
|
|
2592
2941
|
skills: {},
|
|
2942
|
+
topology: void 0,
|
|
2593
2943
|
designSystem: null,
|
|
2594
2944
|
aiLabor: {}
|
|
2595
2945
|
};
|
|
@@ -2611,22 +2961,20 @@ var init_update = __esm({
|
|
|
2611
2961
|
} else {
|
|
2612
2962
|
effectiveTier = preserved.tier;
|
|
2613
2963
|
}
|
|
2964
|
+
await ensureDirectories(targetDir, effectiveTier);
|
|
2614
2965
|
console.log("Replacing framework directories...");
|
|
2615
2966
|
await replaceDirectory(
|
|
2616
|
-
|
|
2617
|
-
|
|
2967
|
+
join17(templateDir, ".flydocs", "templates"),
|
|
2968
|
+
join17(targetDir, ".flydocs", "templates")
|
|
2618
2969
|
);
|
|
2970
|
+
printStatus(".flydocs/templates");
|
|
2619
2971
|
await replaceDirectory(
|
|
2620
|
-
|
|
2621
|
-
|
|
2972
|
+
join17(templateDir, ".claude", "hooks"),
|
|
2973
|
+
join17(targetDir, ".claude", "hooks")
|
|
2622
2974
|
);
|
|
2623
|
-
|
|
2624
|
-
join15(templateDir, ".flydocs", "scripts"),
|
|
2625
|
-
join15(targetDir, ".flydocs", "scripts")
|
|
2626
|
-
);
|
|
2627
|
-
printStatus(".flydocs/templates, hooks, scripts");
|
|
2975
|
+
printStatus(".claude/hooks");
|
|
2628
2976
|
const hasExistingAgents = await pathExists(
|
|
2629
|
-
|
|
2977
|
+
join17(targetDir, ".claude", "agents")
|
|
2630
2978
|
);
|
|
2631
2979
|
let installAgents;
|
|
2632
2980
|
if (args.yes) {
|
|
@@ -2658,20 +3006,20 @@ var init_update = __esm({
|
|
|
2658
3006
|
}
|
|
2659
3007
|
}
|
|
2660
3008
|
if (installAgents) {
|
|
2661
|
-
const claudeAgentsSrc =
|
|
3009
|
+
const claudeAgentsSrc = join17(templateDir, ".claude", "agents");
|
|
2662
3010
|
if (await pathExists(claudeAgentsSrc)) {
|
|
2663
|
-
await mkdir8(
|
|
3011
|
+
await mkdir8(join17(targetDir, ".claude", "agents"), { recursive: true });
|
|
2664
3012
|
await copyDirectoryContents(
|
|
2665
3013
|
claudeAgentsSrc,
|
|
2666
|
-
|
|
3014
|
+
join17(targetDir, ".claude", "agents")
|
|
2667
3015
|
);
|
|
2668
3016
|
}
|
|
2669
|
-
const cursorAgentsSrc =
|
|
3017
|
+
const cursorAgentsSrc = join17(templateDir, ".cursor", "agents");
|
|
2670
3018
|
if (await pathExists(cursorAgentsSrc)) {
|
|
2671
|
-
await mkdir8(
|
|
3019
|
+
await mkdir8(join17(targetDir, ".cursor", "agents"), { recursive: true });
|
|
2672
3020
|
await copyDirectoryContents(
|
|
2673
3021
|
cursorAgentsSrc,
|
|
2674
|
-
|
|
3022
|
+
join17(targetDir, ".cursor", "agents")
|
|
2675
3023
|
);
|
|
2676
3024
|
}
|
|
2677
3025
|
printStatus(
|
|
@@ -2685,46 +3033,62 @@ var init_update = __esm({
|
|
|
2685
3033
|
console.log();
|
|
2686
3034
|
console.log("Replacing framework files...");
|
|
2687
3035
|
await copyFile(
|
|
2688
|
-
|
|
2689
|
-
|
|
3036
|
+
join17(templateDir, ".claude", "CLAUDE.md"),
|
|
3037
|
+
join17(targetDir, ".claude", "CLAUDE.md")
|
|
2690
3038
|
);
|
|
2691
3039
|
await copyFile(
|
|
2692
|
-
|
|
2693
|
-
|
|
3040
|
+
join17(templateDir, ".claude", "settings.json"),
|
|
3041
|
+
join17(targetDir, ".claude", "settings.json")
|
|
2694
3042
|
);
|
|
2695
3043
|
printStatus(".claude/CLAUDE.md, settings.json");
|
|
2696
3044
|
await copyDirectoryContents(
|
|
2697
|
-
|
|
2698
|
-
|
|
3045
|
+
join17(templateDir, ".claude", "commands"),
|
|
3046
|
+
join17(targetDir, ".claude", "commands")
|
|
2699
3047
|
);
|
|
2700
3048
|
await copyDirectoryContents(
|
|
2701
|
-
|
|
2702
|
-
|
|
3049
|
+
join17(templateDir, ".claude", "commands"),
|
|
3050
|
+
join17(targetDir, ".cursor", "commands")
|
|
2703
3051
|
);
|
|
2704
3052
|
printStatus(".claude/commands, .cursor/commands");
|
|
2705
|
-
const skillsReadmeSrc =
|
|
3053
|
+
const skillsReadmeSrc = join17(templateDir, ".claude", "skills", "README.md");
|
|
2706
3054
|
if (await pathExists(skillsReadmeSrc)) {
|
|
2707
3055
|
await copyFile(
|
|
2708
3056
|
skillsReadmeSrc,
|
|
2709
|
-
|
|
3057
|
+
join17(targetDir, ".claude", "skills", "README.md")
|
|
2710
3058
|
);
|
|
2711
3059
|
}
|
|
2712
3060
|
printStatus(".claude/skills/README.md");
|
|
2713
3061
|
await copyFile(
|
|
2714
|
-
|
|
2715
|
-
|
|
3062
|
+
join17(templateDir, ".cursor", "hooks.json"),
|
|
3063
|
+
join17(targetDir, ".cursor", "hooks.json")
|
|
2716
3064
|
);
|
|
2717
3065
|
printStatus(".cursor/hooks.json");
|
|
2718
3066
|
await copyFile(
|
|
2719
|
-
|
|
2720
|
-
|
|
3067
|
+
join17(templateDir, "AGENTS.md"),
|
|
3068
|
+
join17(targetDir, "AGENTS.md")
|
|
2721
3069
|
);
|
|
2722
3070
|
printStatus("AGENTS.md");
|
|
2723
|
-
const envExampleSrc =
|
|
3071
|
+
const envExampleSrc = join17(templateDir, ".env.example");
|
|
2724
3072
|
if (await pathExists(envExampleSrc)) {
|
|
2725
|
-
await copyFile(envExampleSrc,
|
|
3073
|
+
await copyFile(envExampleSrc, join17(targetDir, ".env.example"));
|
|
2726
3074
|
printStatus(".env.example");
|
|
2727
3075
|
}
|
|
3076
|
+
const knowledgeTemplatesDir = join17(
|
|
3077
|
+
targetDir,
|
|
3078
|
+
"flydocs",
|
|
3079
|
+
"knowledge",
|
|
3080
|
+
"templates"
|
|
3081
|
+
);
|
|
3082
|
+
if (!await pathExists(knowledgeTemplatesDir)) {
|
|
3083
|
+
await mkdir8(knowledgeTemplatesDir, { recursive: true });
|
|
3084
|
+
}
|
|
3085
|
+
for (const tmpl of ["decision.md", "feature.md", "note.md"]) {
|
|
3086
|
+
const src = join17(templateDir, "flydocs", "knowledge", "templates", tmpl);
|
|
3087
|
+
const dest = join17(knowledgeTemplatesDir, tmpl);
|
|
3088
|
+
if (await pathExists(src) && !await pathExists(dest)) {
|
|
3089
|
+
await copyFile(src, dest);
|
|
3090
|
+
}
|
|
3091
|
+
}
|
|
2728
3092
|
await runManifestGeneration(targetDir);
|
|
2729
3093
|
await runContextGraphBuild(targetDir);
|
|
2730
3094
|
console.log();
|
|
@@ -2747,20 +3111,22 @@ var init_update = __esm({
|
|
|
2747
3111
|
printWarning("Config merge failed \u2014 config.json preserved as-is");
|
|
2748
3112
|
}
|
|
2749
3113
|
await copyFile(
|
|
2750
|
-
|
|
2751
|
-
|
|
3114
|
+
join17(templateDir, ".flydocs", "version"),
|
|
3115
|
+
join17(targetDir, ".flydocs", "version")
|
|
2752
3116
|
);
|
|
2753
3117
|
printStatus(`.flydocs/version \u2192 ${version}`);
|
|
2754
|
-
const clSrc =
|
|
3118
|
+
const clSrc = join17(templateDir, "CHANGELOG.md");
|
|
2755
3119
|
if (await pathExists(clSrc)) {
|
|
2756
|
-
await copyFile(clSrc,
|
|
3120
|
+
await copyFile(clSrc, join17(targetDir, ".flydocs", "CHANGELOG.md"));
|
|
2757
3121
|
printStatus(".flydocs/CHANGELOG.md");
|
|
2758
3122
|
}
|
|
2759
|
-
const mfSrc =
|
|
3123
|
+
const mfSrc = join17(templateDir, "manifest.json");
|
|
2760
3124
|
if (await pathExists(mfSrc)) {
|
|
2761
|
-
await copyFile(mfSrc,
|
|
3125
|
+
await copyFile(mfSrc, join17(targetDir, ".flydocs", "manifest.json"));
|
|
2762
3126
|
printStatus(".flydocs/manifest.json");
|
|
2763
3127
|
}
|
|
3128
|
+
await generateIntegrity(targetDir, version);
|
|
3129
|
+
printStatus("Install integrity recorded");
|
|
2764
3130
|
console.log();
|
|
2765
3131
|
console.log("Detecting project stack...");
|
|
2766
3132
|
const stack = await detectStack(targetDir);
|
|
@@ -2818,21 +3184,21 @@ __export(uninstall_exports, {
|
|
|
2818
3184
|
default: () => uninstall_default
|
|
2819
3185
|
});
|
|
2820
3186
|
import { defineCommand as defineCommand3 } from "citty";
|
|
2821
|
-
import { resolve as resolve4, join as
|
|
2822
|
-
import { readdir as
|
|
3187
|
+
import { resolve as resolve4, join as join18 } from "path";
|
|
3188
|
+
import { readdir as readdir5, rm as rm5, rename as rename2 } from "fs/promises";
|
|
2823
3189
|
import { confirm as confirm4, select as select3, isCancel as isCancel5, cancel as cancel4 } from "@clack/prompts";
|
|
2824
3190
|
import pc8 from "picocolors";
|
|
2825
3191
|
async function removeOwnedSkills(targetDir) {
|
|
2826
|
-
const skillsDir =
|
|
3192
|
+
const skillsDir = join18(targetDir, ".claude", "skills");
|
|
2827
3193
|
const removed = [];
|
|
2828
3194
|
if (!await pathExists(skillsDir)) {
|
|
2829
3195
|
return removed;
|
|
2830
3196
|
}
|
|
2831
3197
|
try {
|
|
2832
|
-
const entries = await
|
|
3198
|
+
const entries = await readdir5(skillsDir);
|
|
2833
3199
|
for (const entry of entries) {
|
|
2834
3200
|
if (entry.startsWith(OWNED_SKILL_PREFIX)) {
|
|
2835
|
-
await rm5(
|
|
3201
|
+
await rm5(join18(skillsDir, entry), { recursive: true, force: true });
|
|
2836
3202
|
removed.push(`.claude/skills/${entry}`);
|
|
2837
3203
|
}
|
|
2838
3204
|
}
|
|
@@ -2841,16 +3207,16 @@ async function removeOwnedSkills(targetDir) {
|
|
|
2841
3207
|
return removed;
|
|
2842
3208
|
}
|
|
2843
3209
|
async function removeOwnedCursorRules(targetDir) {
|
|
2844
|
-
const rulesDir =
|
|
3210
|
+
const rulesDir = join18(targetDir, ".cursor", "rules");
|
|
2845
3211
|
const removed = [];
|
|
2846
3212
|
if (!await pathExists(rulesDir)) {
|
|
2847
3213
|
return removed;
|
|
2848
3214
|
}
|
|
2849
3215
|
try {
|
|
2850
|
-
const entries = await
|
|
3216
|
+
const entries = await readdir5(rulesDir);
|
|
2851
3217
|
for (const entry of entries) {
|
|
2852
3218
|
if (entry.startsWith(OWNED_RULE_PREFIX) && entry.endsWith(".mdc")) {
|
|
2853
|
-
await rm5(
|
|
3219
|
+
await rm5(join18(rulesDir, entry), { force: true });
|
|
2854
3220
|
removed.push(`.cursor/rules/${entry}`);
|
|
2855
3221
|
}
|
|
2856
3222
|
}
|
|
@@ -2860,7 +3226,7 @@ async function removeOwnedCursorRules(targetDir) {
|
|
|
2860
3226
|
}
|
|
2861
3227
|
async function isEmptyDir(dirPath) {
|
|
2862
3228
|
try {
|
|
2863
|
-
const entries = await
|
|
3229
|
+
const entries = await readdir5(dirPath);
|
|
2864
3230
|
return entries.length === 0;
|
|
2865
3231
|
} catch {
|
|
2866
3232
|
return false;
|
|
@@ -2869,7 +3235,7 @@ async function isEmptyDir(dirPath) {
|
|
|
2869
3235
|
async function cleanupEmptyParents(targetDir, dirs) {
|
|
2870
3236
|
const cleaned = [];
|
|
2871
3237
|
for (const dir of dirs) {
|
|
2872
|
-
const fullPath =
|
|
3238
|
+
const fullPath = join18(targetDir, dir);
|
|
2873
3239
|
if (await pathExists(fullPath) && await isEmptyDir(fullPath)) {
|
|
2874
3240
|
await rm5(fullPath, { recursive: true, force: true });
|
|
2875
3241
|
cleaned.push(dir);
|
|
@@ -2890,9 +3256,11 @@ var init_uninstall = __esm({
|
|
|
2890
3256
|
[".claude/settings.json", "file"],
|
|
2891
3257
|
[".claude/agents", "dir"],
|
|
2892
3258
|
[".claude/commands", "dir"],
|
|
3259
|
+
[".claude/hooks", "dir"],
|
|
2893
3260
|
[".claude/skills/README.md", "file"],
|
|
2894
3261
|
[".cursor/hooks.json", "file"],
|
|
2895
3262
|
[".cursor/agents", "dir"],
|
|
3263
|
+
[".cursor/commands", "dir"],
|
|
2896
3264
|
[".flydocs", "dir"],
|
|
2897
3265
|
["AGENTS.md", "file"],
|
|
2898
3266
|
[".env.example", "file"]
|
|
@@ -2946,8 +3314,8 @@ var init_uninstall = __esm({
|
|
|
2946
3314
|
process.exit(1);
|
|
2947
3315
|
}
|
|
2948
3316
|
targetDir = resolve4(targetDir);
|
|
2949
|
-
const hasFlydocs = await pathExists(
|
|
2950
|
-
const hasAgentsMd = await pathExists(
|
|
3317
|
+
const hasFlydocs = await pathExists(join18(targetDir, ".flydocs"));
|
|
3318
|
+
const hasAgentsMd = await pathExists(join18(targetDir, "AGENTS.md"));
|
|
2951
3319
|
if (!hasFlydocs && !hasAgentsMd) {
|
|
2952
3320
|
printError(`Not a FlyDocs project: ${targetDir}`);
|
|
2953
3321
|
printInfo("No .flydocs/ directory or AGENTS.md found.");
|
|
@@ -2959,7 +3327,7 @@ var init_uninstall = __esm({
|
|
|
2959
3327
|
const removeAll = forceAll || args.all;
|
|
2960
3328
|
const skipPrompts = forceAll || args.yes;
|
|
2961
3329
|
let contentAction = "preserve";
|
|
2962
|
-
const hasUserContent = await pathExists(
|
|
3330
|
+
const hasUserContent = await pathExists(join18(targetDir, "flydocs"));
|
|
2963
3331
|
if (hasUserContent) {
|
|
2964
3332
|
if (removeAll) {
|
|
2965
3333
|
contentAction = "remove";
|
|
@@ -3042,7 +3410,7 @@ var init_uninstall = __esm({
|
|
|
3042
3410
|
const removedRules = await removeOwnedCursorRules(targetDir);
|
|
3043
3411
|
result.removed.push(...removedRules);
|
|
3044
3412
|
for (const [relativePath, type] of ALWAYS_REMOVED) {
|
|
3045
|
-
const fullPath =
|
|
3413
|
+
const fullPath = join18(targetDir, relativePath);
|
|
3046
3414
|
if (!await pathExists(fullPath)) {
|
|
3047
3415
|
result.skipped.push(relativePath);
|
|
3048
3416
|
continue;
|
|
@@ -3060,9 +3428,9 @@ var init_uninstall = __esm({
|
|
|
3060
3428
|
}
|
|
3061
3429
|
}
|
|
3062
3430
|
if (hasUserContent) {
|
|
3063
|
-
const flydocsPath =
|
|
3431
|
+
const flydocsPath = join18(targetDir, "flydocs");
|
|
3064
3432
|
if (contentAction === "archive") {
|
|
3065
|
-
const archivePath =
|
|
3433
|
+
const archivePath = join18(targetDir, "flydocs-archive");
|
|
3066
3434
|
if (await pathExists(archivePath)) {
|
|
3067
3435
|
await rm5(archivePath, { recursive: true, force: true });
|
|
3068
3436
|
}
|
|
@@ -3301,70 +3669,9 @@ __export(connect_exports, {
|
|
|
3301
3669
|
default: () => connect_default
|
|
3302
3670
|
});
|
|
3303
3671
|
import { defineCommand as defineCommand6 } from "citty";
|
|
3304
|
-
import { text as
|
|
3672
|
+
import { text as text3, confirm as confirm5, isCancel as isCancel6, cancel as cancel5 } from "@clack/prompts";
|
|
3305
3673
|
import pc11 from "picocolors";
|
|
3306
|
-
import {
|
|
3307
|
-
import { join as join17 } from "path";
|
|
3308
|
-
function detectKeyType(key) {
|
|
3309
|
-
if (key.startsWith("fdk_")) return "relay";
|
|
3310
|
-
if (key.startsWith("lin_api_")) return "direct";
|
|
3311
|
-
return "unknown";
|
|
3312
|
-
}
|
|
3313
|
-
async function validateRelayKey(apiKey) {
|
|
3314
|
-
const baseUrl = process.env.FLYDOCS_RELAY_URL?.replace(/\/$/, "") ?? "https://app.flydocs.ai/api/relay";
|
|
3315
|
-
const response = await fetch(`${baseUrl}/auth/validate`, {
|
|
3316
|
-
method: "POST",
|
|
3317
|
-
headers: {
|
|
3318
|
-
Authorization: `Bearer ${apiKey}`,
|
|
3319
|
-
"Content-Type": "application/json"
|
|
3320
|
-
},
|
|
3321
|
-
signal: AbortSignal.timeout(15e3)
|
|
3322
|
-
});
|
|
3323
|
-
if (!response.ok) return { valid: false };
|
|
3324
|
-
const data = await response.json();
|
|
3325
|
-
if (!data.valid) return { valid: false };
|
|
3326
|
-
return { valid: true, org: data.org ?? "your organization" };
|
|
3327
|
-
}
|
|
3328
|
-
async function validateLinearKey(apiKey) {
|
|
3329
|
-
const response = await fetch("https://api.linear.app/graphql", {
|
|
3330
|
-
method: "POST",
|
|
3331
|
-
headers: {
|
|
3332
|
-
Authorization: apiKey,
|
|
3333
|
-
"Content-Type": "application/json"
|
|
3334
|
-
},
|
|
3335
|
-
body: JSON.stringify({ query: "{ viewer { id name email } }" }),
|
|
3336
|
-
signal: AbortSignal.timeout(15e3)
|
|
3337
|
-
});
|
|
3338
|
-
if (!response.ok) return { valid: false };
|
|
3339
|
-
const data = await response.json();
|
|
3340
|
-
if (!data.data?.viewer) return { valid: false };
|
|
3341
|
-
return {
|
|
3342
|
-
valid: true,
|
|
3343
|
-
name: data.data.viewer.name,
|
|
3344
|
-
email: data.data.viewer.email
|
|
3345
|
-
};
|
|
3346
|
-
}
|
|
3347
|
-
async function storeEnvKey(targetDir, envVarName, value) {
|
|
3348
|
-
const envPath = join17(targetDir, ".env");
|
|
3349
|
-
const envLocalPath = join17(targetDir, ".env.local");
|
|
3350
|
-
const targetEnvPath = await pathExists(envLocalPath) ? envLocalPath : envPath;
|
|
3351
|
-
const pattern = new RegExp(`${envVarName}=.*`);
|
|
3352
|
-
if (await pathExists(targetEnvPath)) {
|
|
3353
|
-
const envContent = await readFile11(targetEnvPath, "utf-8");
|
|
3354
|
-
if (pattern.test(envContent)) {
|
|
3355
|
-
const updated = envContent.replace(pattern, `${envVarName}=${value}`);
|
|
3356
|
-
await writeFile7(targetEnvPath, updated, "utf-8");
|
|
3357
|
-
} else {
|
|
3358
|
-
await appendFile2(targetEnvPath, `
|
|
3359
|
-
${envVarName}=${value}
|
|
3360
|
-
`);
|
|
3361
|
-
}
|
|
3362
|
-
} else {
|
|
3363
|
-
await writeFile7(targetEnvPath, `${envVarName}=${value}
|
|
3364
|
-
`, "utf-8");
|
|
3365
|
-
}
|
|
3366
|
-
return targetEnvPath === envLocalPath ? ".env.local" : ".env";
|
|
3367
|
-
}
|
|
3674
|
+
import { join as join19 } from "path";
|
|
3368
3675
|
var connect_default;
|
|
3369
3676
|
var init_connect = __esm({
|
|
3370
3677
|
"src/commands/connect.ts"() {
|
|
@@ -3373,6 +3680,7 @@ var init_connect = __esm({
|
|
|
3373
3680
|
init_fs_ops();
|
|
3374
3681
|
init_template();
|
|
3375
3682
|
init_ui();
|
|
3683
|
+
init_api_key();
|
|
3376
3684
|
connect_default = defineCommand6({
|
|
3377
3685
|
meta: {
|
|
3378
3686
|
name: "connect",
|
|
@@ -3393,12 +3701,12 @@ var init_connect = __esm({
|
|
|
3393
3701
|
},
|
|
3394
3702
|
key: {
|
|
3395
3703
|
type: "string",
|
|
3396
|
-
description: "API key (fdk_
|
|
3704
|
+
description: "FlyDocs API key (fdk_...)"
|
|
3397
3705
|
}
|
|
3398
3706
|
},
|
|
3399
3707
|
async run({ args }) {
|
|
3400
3708
|
const targetDir = args.path ?? process.cwd();
|
|
3401
|
-
const configPath =
|
|
3709
|
+
const configPath = join19(targetDir, ".flydocs", "config.json");
|
|
3402
3710
|
if (!await pathExists(configPath)) {
|
|
3403
3711
|
printError("Not a FlyDocs project (.flydocs/config.json not found).");
|
|
3404
3712
|
console.log(
|
|
@@ -3422,22 +3730,19 @@ var init_connect = __esm({
|
|
|
3422
3730
|
console.log(` ${pc11.bold("Connect to FlyDocs Cloud")}`);
|
|
3423
3731
|
console.log();
|
|
3424
3732
|
console.log(
|
|
3425
|
-
` ${pc11.dim("
|
|
3426
|
-
);
|
|
3427
|
-
console.log(
|
|
3428
|
-
` ${pc11.dim("Linear API key (lin_api_...): Get from Linear \u2192 Settings \u2192 API")}`
|
|
3733
|
+
` ${pc11.dim("Get your API key (fdk_...) from your FlyDocs dashboard")}`
|
|
3429
3734
|
);
|
|
3430
3735
|
console.log();
|
|
3431
3736
|
let apiKey = args.key ?? "";
|
|
3432
3737
|
if (!apiKey) {
|
|
3433
|
-
const keyInput = await
|
|
3738
|
+
const keyInput = await text3({
|
|
3434
3739
|
message: "Enter your API key",
|
|
3435
|
-
placeholder: "fdk_...
|
|
3740
|
+
placeholder: "fdk_...",
|
|
3436
3741
|
validate(value) {
|
|
3437
3742
|
if (!value.trim()) return "API key is required";
|
|
3438
3743
|
const type = detectKeyType(value.trim());
|
|
3439
3744
|
if (type === "unknown")
|
|
3440
|
-
return "Key must start with fdk_ (FlyDocs
|
|
3745
|
+
return "Key must start with fdk_ (FlyDocs API key)";
|
|
3441
3746
|
return void 0;
|
|
3442
3747
|
}
|
|
3443
3748
|
});
|
|
@@ -3449,7 +3754,9 @@ var init_connect = __esm({
|
|
|
3449
3754
|
}
|
|
3450
3755
|
const keyType = detectKeyType(apiKey);
|
|
3451
3756
|
if (keyType === "unknown") {
|
|
3452
|
-
printError(
|
|
3757
|
+
printError(
|
|
3758
|
+
"Unrecognized key format. Expected fdk_ prefix (FlyDocs API key)."
|
|
3759
|
+
);
|
|
3453
3760
|
process.exit(1);
|
|
3454
3761
|
}
|
|
3455
3762
|
printInfo("Validating API key...");
|
|
@@ -3491,32 +3798,15 @@ var init_connect = __esm({
|
|
|
3491
3798
|
}
|
|
3492
3799
|
const wasLocal = config.tier === "local";
|
|
3493
3800
|
config.tier = "cloud";
|
|
3494
|
-
|
|
3495
|
-
|
|
3801
|
+
const configRecord = config;
|
|
3802
|
+
delete configRecord.statusMapping;
|
|
3803
|
+
delete configRecord.provider;
|
|
3496
3804
|
await writeConfig(targetDir, config);
|
|
3497
3805
|
printStatus("Config updated to cloud tier");
|
|
3498
3806
|
if (wasLocal) {
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
|
|
3502
|
-
);
|
|
3503
|
-
const templateSkillsDir = join17(templateDir, ".claude", "skills");
|
|
3504
|
-
const skillsDir = join17(targetDir, ".claude", "skills");
|
|
3505
|
-
await replaceDirectory(
|
|
3506
|
-
join17(templateSkillsDir, "flydocs-cloud"),
|
|
3507
|
-
join17(skillsDir, "flydocs-cloud")
|
|
3508
|
-
);
|
|
3509
|
-
const { rm: rm6 } = await import("fs/promises");
|
|
3510
|
-
const localSkillDir = join17(skillsDir, "flydocs-local");
|
|
3511
|
-
if (await pathExists(localSkillDir)) {
|
|
3512
|
-
await rm6(localSkillDir, { recursive: true, force: true });
|
|
3513
|
-
}
|
|
3514
|
-
printStatus("Cloud mechanism skill installed");
|
|
3515
|
-
} catch {
|
|
3516
|
-
printInfo(
|
|
3517
|
-
"Could not swap mechanism skills automatically. Run flydocs update to complete."
|
|
3518
|
-
);
|
|
3519
|
-
}
|
|
3807
|
+
printInfo(
|
|
3808
|
+
"Tier changed to cloud. Run flydocs update to refresh skill scripts."
|
|
3809
|
+
);
|
|
3520
3810
|
}
|
|
3521
3811
|
console.log();
|
|
3522
3812
|
console.log(
|
|
@@ -3579,9 +3869,7 @@ var init_upgrade = __esm({
|
|
|
3579
3869
|
` ${pc12.green("\u2713")} You're already on the ${pc12.bold("cloud")} tier.`
|
|
3580
3870
|
);
|
|
3581
3871
|
console.log();
|
|
3582
|
-
console.log(
|
|
3583
|
-
` Your issues sync with Linear via the cloud mechanism skill.`
|
|
3584
|
-
);
|
|
3872
|
+
console.log(` Your issues sync with your provider via the relay API.`);
|
|
3585
3873
|
console.log(
|
|
3586
3874
|
` Run ${pc12.cyan("flydocs connect")} to update your connection settings.`
|
|
3587
3875
|
);
|
|
@@ -3593,9 +3881,7 @@ var init_upgrade = __esm({
|
|
|
3593
3881
|
console.log(` You're currently on the ${pc12.yellow("local")} tier.`);
|
|
3594
3882
|
console.log(` Upgrade to cloud for:`);
|
|
3595
3883
|
console.log();
|
|
3596
|
-
console.log(
|
|
3597
|
-
` ${pc12.cyan("\u2192")} Issue sync with Linear (Jira coming soon)`
|
|
3598
|
-
);
|
|
3884
|
+
console.log(` ${pc12.cyan("\u2192")} Issue sync with Linear, Jira, and more`);
|
|
3599
3885
|
console.log(` ${pc12.cyan("\u2192")} Project milestones and cycle management`);
|
|
3600
3886
|
console.log(` ${pc12.cyan("\u2192")} Team assignment and priority tracking`);
|
|
3601
3887
|
console.log(` ${pc12.cyan("\u2192")} Project health updates and dashboards`);
|