@flydocs/cli 0.6.0-alpha.2 → 0.6.0-alpha.21
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 +705 -393
- 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.21";
|
|
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,37 +1457,64 @@ 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
|
+
async function ensurePlatformIgnores(targetDir) {
|
|
1479
|
+
for (const filename of PLATFORM_IGNORE_FILES) {
|
|
1480
|
+
const filePath = join11(targetDir, filename);
|
|
1481
|
+
if (!await pathExists(filePath)) continue;
|
|
1482
|
+
const content = await readFile6(filePath, "utf-8");
|
|
1483
|
+
if (content.includes("# FlyDocs")) continue;
|
|
1484
|
+
const section = "\n# FlyDocs \u2014 exclude from builds and deploys\n" + FLYDOCS_DEPLOY_EXCLUSIONS.join("\n") + "\n";
|
|
1485
|
+
await appendFile(filePath, section, "utf-8");
|
|
1486
|
+
printStatus(`Added FlyDocs exclusions to ${filename}`);
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
1489
|
+
var PLATFORM_IGNORE_FILES, FLYDOCS_DEPLOY_EXCLUSIONS, FLYDOCS_GITIGNORE_ENTRIES, FULL_GITIGNORE_TEMPLATE;
|
|
1499
1490
|
var init_gitignore = __esm({
|
|
1500
1491
|
"src/lib/gitignore.ts"() {
|
|
1501
1492
|
"use strict";
|
|
1502
1493
|
init_fs_ops();
|
|
1503
1494
|
init_ui();
|
|
1495
|
+
PLATFORM_IGNORE_FILES = [
|
|
1496
|
+
".gcloudignore",
|
|
1497
|
+
".dockerignore",
|
|
1498
|
+
".vercelignore",
|
|
1499
|
+
".npmignore"
|
|
1500
|
+
];
|
|
1501
|
+
FLYDOCS_DEPLOY_EXCLUSIONS = [
|
|
1502
|
+
".flydocs/",
|
|
1503
|
+
".claude/",
|
|
1504
|
+
".cursor/",
|
|
1505
|
+
"flydocs/",
|
|
1506
|
+
"AGENTS.md"
|
|
1507
|
+
];
|
|
1504
1508
|
FLYDOCS_GITIGNORE_ENTRIES = [
|
|
1505
1509
|
".env",
|
|
1506
1510
|
".env.local",
|
|
1507
1511
|
".flydocs/session.json",
|
|
1508
1512
|
".flydocs/logs/",
|
|
1509
1513
|
".flydocs/backup-*/",
|
|
1514
|
+
".flydocs/me.json",
|
|
1515
|
+
".flydocs/validation-cache.json",
|
|
1516
|
+
".flydocs/integrity-cache.json",
|
|
1517
|
+
".flydocs/session/",
|
|
1510
1518
|
"flydocs/context/graph.json"
|
|
1511
1519
|
];
|
|
1512
1520
|
FULL_GITIGNORE_TEMPLATE = `# Environment
|
|
@@ -1518,6 +1526,10 @@ var init_gitignore = __esm({
|
|
|
1518
1526
|
.flydocs/session.json
|
|
1519
1527
|
.flydocs/logs/
|
|
1520
1528
|
.flydocs/backup-*/
|
|
1529
|
+
.flydocs/me.json
|
|
1530
|
+
.flydocs/validation-cache.json
|
|
1531
|
+
.flydocs/integrity-cache.json
|
|
1532
|
+
.flydocs/session/
|
|
1521
1533
|
flydocs/context/graph.json
|
|
1522
1534
|
|
|
1523
1535
|
# Dependencies
|
|
@@ -1840,6 +1852,143 @@ var init_telemetry = __esm({
|
|
|
1840
1852
|
}
|
|
1841
1853
|
});
|
|
1842
1854
|
|
|
1855
|
+
// src/lib/api-key.ts
|
|
1856
|
+
import { readFile as readFile10, writeFile as writeFile7, appendFile as appendFile2 } from "fs/promises";
|
|
1857
|
+
import { join as join14 } from "path";
|
|
1858
|
+
function detectKeyType(key) {
|
|
1859
|
+
if (key.startsWith("fdk_")) return "relay";
|
|
1860
|
+
if (key.startsWith("lin_api_")) return "direct";
|
|
1861
|
+
return "unknown";
|
|
1862
|
+
}
|
|
1863
|
+
async function validateRelayKey(apiKey) {
|
|
1864
|
+
const baseUrl = process.env.FLYDOCS_RELAY_URL?.replace(/\/$/, "") ?? "https://app.flydocs.ai/api/relay";
|
|
1865
|
+
const response = await fetch(`${baseUrl}/auth/validate`, {
|
|
1866
|
+
method: "POST",
|
|
1867
|
+
headers: {
|
|
1868
|
+
Authorization: `Bearer ${apiKey}`,
|
|
1869
|
+
"Content-Type": "application/json"
|
|
1870
|
+
},
|
|
1871
|
+
signal: AbortSignal.timeout(15e3)
|
|
1872
|
+
});
|
|
1873
|
+
if (!response.ok) return { valid: false };
|
|
1874
|
+
const data = await response.json();
|
|
1875
|
+
if (!data.valid) return { valid: false };
|
|
1876
|
+
return { valid: true, org: data.org ?? "your organization" };
|
|
1877
|
+
}
|
|
1878
|
+
async function fetchWorkspaces(apiKey) {
|
|
1879
|
+
const baseUrl = process.env.FLYDOCS_RELAY_URL?.replace(/\/$/, "") ?? "https://app.flydocs.ai/api/relay";
|
|
1880
|
+
const response = await fetch(`${baseUrl}/auth/workspaces`, {
|
|
1881
|
+
method: "GET",
|
|
1882
|
+
headers: {
|
|
1883
|
+
Authorization: `Bearer ${apiKey}`
|
|
1884
|
+
},
|
|
1885
|
+
signal: AbortSignal.timeout(15e3)
|
|
1886
|
+
});
|
|
1887
|
+
if (!response.ok) {
|
|
1888
|
+
throw new Error(`Failed to fetch workspaces: ${response.status}`);
|
|
1889
|
+
}
|
|
1890
|
+
const data = await response.json();
|
|
1891
|
+
return data;
|
|
1892
|
+
}
|
|
1893
|
+
async function fetchMe(apiKey) {
|
|
1894
|
+
const baseUrl = process.env.FLYDOCS_RELAY_URL?.replace(/\/$/, "") ?? "https://app.flydocs.ai/api/relay";
|
|
1895
|
+
const response = await fetch(`${baseUrl}/auth/me`, {
|
|
1896
|
+
method: "GET",
|
|
1897
|
+
headers: {
|
|
1898
|
+
Authorization: `Bearer ${apiKey}`
|
|
1899
|
+
},
|
|
1900
|
+
signal: AbortSignal.timeout(15e3)
|
|
1901
|
+
});
|
|
1902
|
+
if (!response.ok) {
|
|
1903
|
+
throw new Error(`Failed to fetch user identity: ${response.status}`);
|
|
1904
|
+
}
|
|
1905
|
+
const data = await response.json();
|
|
1906
|
+
return {
|
|
1907
|
+
displayName: data.displayName ?? null,
|
|
1908
|
+
email: data.email ?? null,
|
|
1909
|
+
providerId: data.providerId ?? null,
|
|
1910
|
+
provider: data.provider ?? null,
|
|
1911
|
+
providerIdentities: data.providerIdentities ?? [],
|
|
1912
|
+
preferences: data.preferences ?? {}
|
|
1913
|
+
};
|
|
1914
|
+
}
|
|
1915
|
+
async function validateLinearKey(apiKey) {
|
|
1916
|
+
const response = await fetch("https://api.linear.app/graphql", {
|
|
1917
|
+
method: "POST",
|
|
1918
|
+
headers: {
|
|
1919
|
+
Authorization: apiKey,
|
|
1920
|
+
"Content-Type": "application/json"
|
|
1921
|
+
},
|
|
1922
|
+
body: JSON.stringify({ query: "{ viewer { id name email } }" }),
|
|
1923
|
+
signal: AbortSignal.timeout(15e3)
|
|
1924
|
+
});
|
|
1925
|
+
if (!response.ok) return { valid: false };
|
|
1926
|
+
const data = await response.json();
|
|
1927
|
+
if (!data.data?.viewer) return { valid: false };
|
|
1928
|
+
return {
|
|
1929
|
+
valid: true,
|
|
1930
|
+
name: data.data.viewer.name,
|
|
1931
|
+
email: data.data.viewer.email
|
|
1932
|
+
};
|
|
1933
|
+
}
|
|
1934
|
+
async function storeEnvKey(targetDir, envVarName, value) {
|
|
1935
|
+
const envPath = join14(targetDir, ".env");
|
|
1936
|
+
const envLocalPath = join14(targetDir, ".env.local");
|
|
1937
|
+
const targetEnvPath = await pathExists(envLocalPath) ? envLocalPath : envPath;
|
|
1938
|
+
const pattern = new RegExp(`${envVarName}=.*`);
|
|
1939
|
+
if (await pathExists(targetEnvPath)) {
|
|
1940
|
+
const envContent = await readFile10(targetEnvPath, "utf-8");
|
|
1941
|
+
if (pattern.test(envContent)) {
|
|
1942
|
+
const updated = envContent.replace(pattern, `${envVarName}=${value}`);
|
|
1943
|
+
await writeFile7(targetEnvPath, updated, "utf-8");
|
|
1944
|
+
} else {
|
|
1945
|
+
await appendFile2(targetEnvPath, `
|
|
1946
|
+
${envVarName}=${value}
|
|
1947
|
+
`);
|
|
1948
|
+
}
|
|
1949
|
+
} else {
|
|
1950
|
+
await writeFile7(targetEnvPath, `${envVarName}=${value}
|
|
1951
|
+
`, "utf-8");
|
|
1952
|
+
}
|
|
1953
|
+
return targetEnvPath === envLocalPath ? ".env.local" : ".env";
|
|
1954
|
+
}
|
|
1955
|
+
var init_api_key = __esm({
|
|
1956
|
+
"src/lib/api-key.ts"() {
|
|
1957
|
+
"use strict";
|
|
1958
|
+
init_fs_ops();
|
|
1959
|
+
}
|
|
1960
|
+
});
|
|
1961
|
+
|
|
1962
|
+
// src/lib/integrity.ts
|
|
1963
|
+
import { readFile as readFile11, writeFile as writeFile8 } from "fs/promises";
|
|
1964
|
+
import { join as join15 } from "path";
|
|
1965
|
+
async function generateIntegrity(targetDir, version) {
|
|
1966
|
+
const manifestPath = join15(targetDir, ".flydocs", "manifest.json");
|
|
1967
|
+
if (!await pathExists(manifestPath)) return;
|
|
1968
|
+
const manifest = JSON.parse(await readFile11(manifestPath, "utf-8"));
|
|
1969
|
+
const ownership = manifest.ownership;
|
|
1970
|
+
if (!ownership) return;
|
|
1971
|
+
const ownedDirs = ownership.owned_directories?.paths ?? [];
|
|
1972
|
+
const ownedFiles = ownership.owned_files?.paths ?? [];
|
|
1973
|
+
const integrity = {
|
|
1974
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1975
|
+
version,
|
|
1976
|
+
ownedFiles,
|
|
1977
|
+
ownedDirectories: ownedDirs
|
|
1978
|
+
};
|
|
1979
|
+
await writeFile8(
|
|
1980
|
+
join15(targetDir, ".flydocs", "integrity.json"),
|
|
1981
|
+
JSON.stringify(integrity, null, 2) + "\n",
|
|
1982
|
+
"utf-8"
|
|
1983
|
+
);
|
|
1984
|
+
}
|
|
1985
|
+
var init_integrity = __esm({
|
|
1986
|
+
"src/lib/integrity.ts"() {
|
|
1987
|
+
"use strict";
|
|
1988
|
+
init_fs_ops();
|
|
1989
|
+
}
|
|
1990
|
+
});
|
|
1991
|
+
|
|
1843
1992
|
// src/commands/install.ts
|
|
1844
1993
|
var install_exports = {};
|
|
1845
1994
|
__export(install_exports, {
|
|
@@ -1847,9 +1996,9 @@ __export(install_exports, {
|
|
|
1847
1996
|
});
|
|
1848
1997
|
import { defineCommand } from "citty";
|
|
1849
1998
|
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";
|
|
1999
|
+
import { join as join16 } from "path";
|
|
2000
|
+
import { mkdir as mkdir7, writeFile as writeFile9 } from "fs/promises";
|
|
2001
|
+
import { confirm as confirm2, select, text, isCancel as isCancel3, cancel as cancel2 } from "@clack/prompts";
|
|
1853
2002
|
import pc6 from "picocolors";
|
|
1854
2003
|
var install_default;
|
|
1855
2004
|
var init_install = __esm({
|
|
@@ -1868,6 +2017,8 @@ var init_install = __esm({
|
|
|
1868
2017
|
init_post_install();
|
|
1869
2018
|
init_update_check();
|
|
1870
2019
|
init_telemetry();
|
|
2020
|
+
init_api_key();
|
|
2021
|
+
init_integrity();
|
|
1871
2022
|
install_default = defineCommand({
|
|
1872
2023
|
meta: {
|
|
1873
2024
|
name: "install",
|
|
@@ -1929,7 +2080,7 @@ var init_install = __esm({
|
|
|
1929
2080
|
process.exit(1);
|
|
1930
2081
|
}
|
|
1931
2082
|
tier = args.tier;
|
|
1932
|
-
} else if (await pathExists(
|
|
2083
|
+
} else if (await pathExists(join16(targetDir, ".flydocs", "config.json"))) {
|
|
1933
2084
|
try {
|
|
1934
2085
|
const existing = await readConfig(targetDir);
|
|
1935
2086
|
if (existing.tier) {
|
|
@@ -1951,7 +2102,7 @@ var init_install = __esm({
|
|
|
1951
2102
|
{
|
|
1952
2103
|
value: "cloud",
|
|
1953
2104
|
label: "Cloud (managed)",
|
|
1954
|
-
hint: "Sync with Linear
|
|
2105
|
+
hint: "Sync with Linear, Jira, and more"
|
|
1955
2106
|
}
|
|
1956
2107
|
]
|
|
1957
2108
|
});
|
|
@@ -1978,48 +2129,198 @@ var init_install = __esm({
|
|
|
1978
2129
|
}
|
|
1979
2130
|
printInfo(`Tier: ${tier}`);
|
|
1980
2131
|
await capture("install_tier_selected", { tier });
|
|
1981
|
-
|
|
2132
|
+
let selectedWorkspaceId = null;
|
|
2133
|
+
let selectedWorkspaceName = null;
|
|
2134
|
+
let apiKey = null;
|
|
2135
|
+
if (tier === "cloud") {
|
|
2136
|
+
console.log();
|
|
2137
|
+
console.log(` ${pc6.bold("Connect to FlyDocs Cloud")}`);
|
|
2138
|
+
console.log();
|
|
2139
|
+
console.log(
|
|
2140
|
+
` ${pc6.dim("Get your API key from your FlyDocs dashboard (fdk_...)")}`
|
|
2141
|
+
);
|
|
2142
|
+
console.log();
|
|
2143
|
+
const keyInput = await text({
|
|
2144
|
+
message: "Enter your FlyDocs API key",
|
|
2145
|
+
placeholder: "fdk_...",
|
|
2146
|
+
validate(value) {
|
|
2147
|
+
if (!value.trim()) return "API key is required";
|
|
2148
|
+
const type = detectKeyType(value.trim());
|
|
2149
|
+
if (type !== "relay")
|
|
2150
|
+
return "Cloud tier requires a FlyDocs API key (fdk_...)";
|
|
2151
|
+
return void 0;
|
|
2152
|
+
}
|
|
2153
|
+
});
|
|
2154
|
+
if (isCancel3(keyInput)) {
|
|
2155
|
+
cancel2("Installation cancelled.");
|
|
2156
|
+
process.exit(0);
|
|
2157
|
+
}
|
|
2158
|
+
apiKey = keyInput.trim();
|
|
2159
|
+
printInfo("Validating API key...");
|
|
2160
|
+
try {
|
|
2161
|
+
const result = await validateRelayKey(apiKey);
|
|
2162
|
+
if (!result.valid) {
|
|
2163
|
+
printError("Invalid API key or relay API unreachable.");
|
|
2164
|
+
console.log(` Check your key and try again.`);
|
|
2165
|
+
process.exit(1);
|
|
2166
|
+
}
|
|
2167
|
+
printStatus(`Connected to ${pc6.bold(result.org)}`);
|
|
2168
|
+
} catch {
|
|
2169
|
+
printError(
|
|
2170
|
+
"Could not reach relay API. Check your network and try again."
|
|
2171
|
+
);
|
|
2172
|
+
process.exit(1);
|
|
2173
|
+
}
|
|
2174
|
+
const envFile = await storeEnvKey(targetDir, "FLYDOCS_API_KEY", apiKey);
|
|
2175
|
+
printStatus(`API key stored in ${pc6.dim(envFile)}`);
|
|
2176
|
+
console.log();
|
|
2177
|
+
printInfo("Fetching workspaces...");
|
|
2178
|
+
try {
|
|
2179
|
+
const workspaces = await fetchWorkspaces(apiKey);
|
|
2180
|
+
if (workspaces.length === 0) {
|
|
2181
|
+
printError(
|
|
2182
|
+
"No workspaces found. Create a workspace in the FlyDocs dashboard first, then re-run install."
|
|
2183
|
+
);
|
|
2184
|
+
process.exit(1);
|
|
2185
|
+
}
|
|
2186
|
+
if (workspaces.length === 1) {
|
|
2187
|
+
selectedWorkspaceId = workspaces[0].id;
|
|
2188
|
+
selectedWorkspaceName = workspaces[0].name;
|
|
2189
|
+
printStatus(
|
|
2190
|
+
`Workspace: ${pc6.bold(selectedWorkspaceName)} (auto-selected)`
|
|
2191
|
+
);
|
|
2192
|
+
} else {
|
|
2193
|
+
const workspaceChoice = await select({
|
|
2194
|
+
message: "Select a workspace",
|
|
2195
|
+
options: workspaces.map((ws) => ({
|
|
2196
|
+
value: ws.id,
|
|
2197
|
+
label: `${ws.name} (${ws.provider.type})`,
|
|
2198
|
+
hint: ws.team.name
|
|
2199
|
+
}))
|
|
2200
|
+
});
|
|
2201
|
+
if (isCancel3(workspaceChoice)) {
|
|
2202
|
+
cancel2("Installation cancelled.");
|
|
2203
|
+
process.exit(0);
|
|
2204
|
+
}
|
|
2205
|
+
selectedWorkspaceId = workspaceChoice;
|
|
2206
|
+
const chosen = workspaces.find((ws) => ws.id === selectedWorkspaceId);
|
|
2207
|
+
selectedWorkspaceName = chosen?.name ?? "Unknown";
|
|
2208
|
+
printStatus(`Workspace: ${pc6.bold(selectedWorkspaceName)}`);
|
|
2209
|
+
}
|
|
2210
|
+
} catch {
|
|
2211
|
+
printError(
|
|
2212
|
+
"Could not fetch workspaces. Check your network and try again."
|
|
2213
|
+
);
|
|
2214
|
+
process.exit(1);
|
|
2215
|
+
}
|
|
2216
|
+
}
|
|
2217
|
+
let skipConfigOverwrite = false;
|
|
2218
|
+
if (!await pathExists(join16(targetDir, ".git"))) {
|
|
1982
2219
|
printWarning("No git repository detected. Run git init when ready.");
|
|
1983
2220
|
}
|
|
1984
2221
|
await ensureDirectories(targetDir, tier);
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
2222
|
+
if (tier === "cloud" && apiKey) {
|
|
2223
|
+
try {
|
|
2224
|
+
const me = await fetchMe(apiKey);
|
|
2225
|
+
const meData = {
|
|
2226
|
+
displayName: me.displayName,
|
|
2227
|
+
email: me.email,
|
|
2228
|
+
providerId: me.providerId,
|
|
2229
|
+
provider: me.provider,
|
|
2230
|
+
providerIdentities: me.providerIdentities,
|
|
2231
|
+
preferences: me.preferences
|
|
2232
|
+
};
|
|
2233
|
+
const mePath = join16(targetDir, ".flydocs", "me.json");
|
|
2234
|
+
await writeFile9(
|
|
2235
|
+
mePath,
|
|
2236
|
+
JSON.stringify(meData, null, 2) + "\n",
|
|
2237
|
+
"utf-8"
|
|
2238
|
+
);
|
|
2239
|
+
if (me.displayName) {
|
|
2240
|
+
printStatus(`Identity: ${pc6.bold(me.displayName)}`);
|
|
2241
|
+
}
|
|
2242
|
+
} catch {
|
|
2243
|
+
printWarning(
|
|
2244
|
+
"Could not fetch user identity. Run /flydocs-setup to configure later."
|
|
2245
|
+
);
|
|
2246
|
+
}
|
|
2247
|
+
}
|
|
2248
|
+
const existingFiles = await detectExistingConfigs(targetDir);
|
|
2249
|
+
if (existingFiles.length > 0) {
|
|
2250
|
+
console.log();
|
|
2251
|
+
printWarning(
|
|
2252
|
+
`Found ${existingFiles.length} existing config file(s) that FlyDocs will overwrite:`
|
|
1989
2253
|
);
|
|
1990
|
-
for (const f of
|
|
1991
|
-
|
|
2254
|
+
for (const f of existingFiles) {
|
|
2255
|
+
console.log(` ${pc6.dim(f)}`);
|
|
2256
|
+
}
|
|
2257
|
+
console.log();
|
|
2258
|
+
if (!args.yes) {
|
|
2259
|
+
const overwriteChoice = await select({
|
|
2260
|
+
message: "How should FlyDocs handle these files?",
|
|
2261
|
+
options: [
|
|
2262
|
+
{
|
|
2263
|
+
value: "backup",
|
|
2264
|
+
label: "Overwrite (backed up)",
|
|
2265
|
+
hint: "Files are saved to .flydocs/backup-originals/ and restored on uninstall"
|
|
2266
|
+
},
|
|
2267
|
+
{
|
|
2268
|
+
value: "skip",
|
|
2269
|
+
label: "Skip overwriting",
|
|
2270
|
+
hint: "Keep your existing files \u2014 FlyDocs config may be incomplete"
|
|
2271
|
+
}
|
|
2272
|
+
]
|
|
2273
|
+
});
|
|
2274
|
+
if (isCancel3(overwriteChoice)) {
|
|
2275
|
+
cancel2("Installation cancelled.");
|
|
2276
|
+
process.exit(0);
|
|
2277
|
+
}
|
|
2278
|
+
if (overwriteChoice === "skip") {
|
|
2279
|
+
printInfo(
|
|
2280
|
+
"Keeping existing files. Run /flydocs-setup to merge your config manually."
|
|
2281
|
+
);
|
|
2282
|
+
skipConfigOverwrite = true;
|
|
2283
|
+
}
|
|
2284
|
+
}
|
|
2285
|
+
if (!skipConfigOverwrite) {
|
|
2286
|
+
const backedUp = await backupOriginals(targetDir);
|
|
2287
|
+
if (backedUp.length > 0) {
|
|
2288
|
+
printStatus(
|
|
2289
|
+
`Backed up ${backedUp.length} file(s) to .flydocs/backup-originals/`
|
|
2290
|
+
);
|
|
2291
|
+
}
|
|
1992
2292
|
}
|
|
1993
2293
|
}
|
|
1994
2294
|
console.log("Installing framework files...");
|
|
1995
2295
|
await replaceDirectory(
|
|
1996
|
-
|
|
1997
|
-
|
|
2296
|
+
join16(templateDir, ".flydocs", "templates"),
|
|
2297
|
+
join16(targetDir, ".flydocs", "templates")
|
|
1998
2298
|
);
|
|
1999
2299
|
await replaceDirectory(
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
);
|
|
2003
|
-
await replaceDirectory(
|
|
2004
|
-
join14(templateDir, ".flydocs", "scripts"),
|
|
2005
|
-
join14(targetDir, ".flydocs", "scripts")
|
|
2300
|
+
join16(templateDir, ".claude", "hooks"),
|
|
2301
|
+
join16(targetDir, ".claude", "hooks")
|
|
2006
2302
|
);
|
|
2007
2303
|
await copyFile(
|
|
2008
|
-
|
|
2009
|
-
|
|
2304
|
+
join16(templateDir, ".flydocs", "version"),
|
|
2305
|
+
join16(targetDir, ".flydocs", "version")
|
|
2010
2306
|
);
|
|
2011
|
-
const manifestSrc =
|
|
2307
|
+
const manifestSrc = join16(templateDir, "manifest.json");
|
|
2012
2308
|
if (await pathExists(manifestSrc)) {
|
|
2013
|
-
await copyFile(manifestSrc,
|
|
2309
|
+
await copyFile(manifestSrc, join16(targetDir, ".flydocs", "manifest.json"));
|
|
2014
2310
|
}
|
|
2015
|
-
const changelogSrc =
|
|
2311
|
+
const changelogSrc = join16(templateDir, "CHANGELOG.md");
|
|
2016
2312
|
if (await pathExists(changelogSrc)) {
|
|
2017
|
-
await copyFile(changelogSrc,
|
|
2313
|
+
await copyFile(changelogSrc, join16(targetDir, ".flydocs", "CHANGELOG.md"));
|
|
2018
2314
|
}
|
|
2019
|
-
printStatus(
|
|
2020
|
-
|
|
2315
|
+
printStatus(
|
|
2316
|
+
".flydocs/templates, .claude/hooks, version, manifest, changelog"
|
|
2317
|
+
);
|
|
2318
|
+
const configPath = join16(targetDir, ".flydocs", "config.json");
|
|
2021
2319
|
if (!await pathExists(configPath)) {
|
|
2022
2320
|
const config = await createFreshConfig(templateDir, version, tier);
|
|
2321
|
+
if (selectedWorkspaceId) {
|
|
2322
|
+
config.workspaceId = selectedWorkspaceId;
|
|
2323
|
+
}
|
|
2023
2324
|
await writeConfig(targetDir, config);
|
|
2024
2325
|
printStatus(`.flydocs/config.json (new, tier: ${tier})`);
|
|
2025
2326
|
} else if (args.tier) {
|
|
@@ -2027,15 +2328,34 @@ var init_install = __esm({
|
|
|
2027
2328
|
const existing = await readConfig(targetDir);
|
|
2028
2329
|
existing.version = version;
|
|
2029
2330
|
existing.tier = tier;
|
|
2331
|
+
if (selectedWorkspaceId) {
|
|
2332
|
+
existing.workspaceId = selectedWorkspaceId;
|
|
2333
|
+
}
|
|
2030
2334
|
await writeConfig(targetDir, existing);
|
|
2031
2335
|
printStatus(`.flydocs/config.json (tier updated: ${tier})`);
|
|
2032
2336
|
} catch {
|
|
2033
2337
|
const config = await createFreshConfig(templateDir, version, tier);
|
|
2338
|
+
if (selectedWorkspaceId) {
|
|
2339
|
+
config.workspaceId = selectedWorkspaceId;
|
|
2340
|
+
}
|
|
2034
2341
|
await writeConfig(targetDir, config);
|
|
2035
2342
|
printStatus(`.flydocs/config.json (recreated, tier: ${tier})`);
|
|
2036
2343
|
}
|
|
2037
2344
|
} else {
|
|
2038
|
-
|
|
2345
|
+
if (selectedWorkspaceId) {
|
|
2346
|
+
try {
|
|
2347
|
+
const existing = await readConfig(targetDir);
|
|
2348
|
+
existing.workspaceId = selectedWorkspaceId;
|
|
2349
|
+
await writeConfig(targetDir, existing);
|
|
2350
|
+
printWarning(
|
|
2351
|
+
".flydocs/config.json exists, preserving (workspace updated)"
|
|
2352
|
+
);
|
|
2353
|
+
} catch {
|
|
2354
|
+
printWarning(".flydocs/config.json exists, preserving");
|
|
2355
|
+
}
|
|
2356
|
+
} else {
|
|
2357
|
+
printWarning(".flydocs/config.json exists, preserving");
|
|
2358
|
+
}
|
|
2039
2359
|
}
|
|
2040
2360
|
console.log();
|
|
2041
2361
|
console.log(`Installing skills (tier: ${tier})...`);
|
|
@@ -2071,20 +2391,20 @@ var init_install = __esm({
|
|
|
2071
2391
|
}
|
|
2072
2392
|
await capture("install_agents_chosen", { install_agents: installAgents });
|
|
2073
2393
|
if (installAgents) {
|
|
2074
|
-
const claudeAgentsSrc =
|
|
2394
|
+
const claudeAgentsSrc = join16(templateDir, ".claude", "agents");
|
|
2075
2395
|
if (await pathExists(claudeAgentsSrc)) {
|
|
2076
|
-
await mkdir7(
|
|
2396
|
+
await mkdir7(join16(targetDir, ".claude", "agents"), { recursive: true });
|
|
2077
2397
|
await copyDirectoryContents(
|
|
2078
2398
|
claudeAgentsSrc,
|
|
2079
|
-
|
|
2399
|
+
join16(targetDir, ".claude", "agents")
|
|
2080
2400
|
);
|
|
2081
2401
|
}
|
|
2082
|
-
const cursorAgentsSrc =
|
|
2402
|
+
const cursorAgentsSrc = join16(templateDir, ".cursor", "agents");
|
|
2083
2403
|
if (await pathExists(cursorAgentsSrc)) {
|
|
2084
|
-
await mkdir7(
|
|
2404
|
+
await mkdir7(join16(targetDir, ".cursor", "agents"), { recursive: true });
|
|
2085
2405
|
await copyDirectoryContents(
|
|
2086
2406
|
cursorAgentsSrc,
|
|
2087
|
-
|
|
2407
|
+
join16(targetDir, ".cursor", "agents")
|
|
2088
2408
|
);
|
|
2089
2409
|
}
|
|
2090
2410
|
printStatus("Sub-agents installed (.claude/agents, .cursor/agents)");
|
|
@@ -2094,74 +2414,88 @@ var init_install = __esm({
|
|
|
2094
2414
|
console.log();
|
|
2095
2415
|
console.log("Installing commands and settings...");
|
|
2096
2416
|
await copyDirectoryContents(
|
|
2097
|
-
|
|
2098
|
-
|
|
2417
|
+
join16(templateDir, ".claude", "commands"),
|
|
2418
|
+
join16(targetDir, ".claude", "commands")
|
|
2099
2419
|
);
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2420
|
+
if (!skipConfigOverwrite) {
|
|
2421
|
+
await copyFile(
|
|
2422
|
+
join16(templateDir, ".claude", "CLAUDE.md"),
|
|
2423
|
+
join16(targetDir, ".claude", "CLAUDE.md")
|
|
2424
|
+
);
|
|
2425
|
+
await copyFile(
|
|
2426
|
+
join16(templateDir, ".claude", "settings.json"),
|
|
2427
|
+
join16(targetDir, ".claude", "settings.json")
|
|
2428
|
+
);
|
|
2429
|
+
printStatus(".claude/ (commands, CLAUDE.md, settings)");
|
|
2430
|
+
} else {
|
|
2431
|
+
printStatus(".claude/ (commands only \u2014 existing config preserved)");
|
|
2432
|
+
}
|
|
2109
2433
|
await copyDirectoryContents(
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
);
|
|
2113
|
-
await copyFile(
|
|
2114
|
-
join14(templateDir, ".cursor", "hooks.json"),
|
|
2115
|
-
join14(targetDir, ".cursor", "hooks.json")
|
|
2434
|
+
join16(templateDir, ".claude", "commands"),
|
|
2435
|
+
join16(targetDir, ".cursor", "commands")
|
|
2116
2436
|
);
|
|
2117
|
-
|
|
2437
|
+
if (!skipConfigOverwrite) {
|
|
2438
|
+
await copyFile(
|
|
2439
|
+
join16(templateDir, ".cursor", "hooks.json"),
|
|
2440
|
+
join16(targetDir, ".cursor", "hooks.json")
|
|
2441
|
+
);
|
|
2442
|
+
printStatus(".cursor/ (commands, hooks)");
|
|
2443
|
+
} else {
|
|
2444
|
+
printStatus(".cursor/ (commands only \u2014 existing hooks preserved)");
|
|
2445
|
+
}
|
|
2118
2446
|
await copyCursorRules(targetDir);
|
|
2119
2447
|
printStatus(".cursor/rules/");
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2448
|
+
if (!skipConfigOverwrite) {
|
|
2449
|
+
await copyFile(
|
|
2450
|
+
join16(templateDir, "AGENTS.md"),
|
|
2451
|
+
join16(targetDir, "AGENTS.md")
|
|
2452
|
+
);
|
|
2453
|
+
printStatus("AGENTS.md");
|
|
2454
|
+
} else {
|
|
2455
|
+
printInfo("AGENTS.md preserved (existing)");
|
|
2456
|
+
}
|
|
2125
2457
|
await runManifestGeneration(targetDir);
|
|
2126
2458
|
await runContextGraphBuild(targetDir);
|
|
2459
|
+
await generateIntegrity(targetDir, version);
|
|
2460
|
+
printStatus("Install integrity recorded");
|
|
2127
2461
|
console.log();
|
|
2128
2462
|
console.log("Installing project templates...");
|
|
2129
2463
|
const userFiles = [
|
|
2130
2464
|
{
|
|
2131
|
-
src:
|
|
2132
|
-
dest:
|
|
2465
|
+
src: join16(templateDir, "flydocs", "context", "project.md"),
|
|
2466
|
+
dest: join16(targetDir, "flydocs", "context", "project.md"),
|
|
2133
2467
|
label: "flydocs/context/project.md"
|
|
2134
2468
|
},
|
|
2135
2469
|
{
|
|
2136
|
-
src:
|
|
2137
|
-
dest:
|
|
2470
|
+
src: join16(templateDir, "flydocs", "knowledge", "INDEX.md"),
|
|
2471
|
+
dest: join16(targetDir, "flydocs", "knowledge", "INDEX.md"),
|
|
2138
2472
|
label: "flydocs/knowledge/INDEX.md"
|
|
2139
2473
|
},
|
|
2140
2474
|
{
|
|
2141
|
-
src:
|
|
2142
|
-
dest:
|
|
2475
|
+
src: join16(templateDir, "flydocs", "knowledge", "README.md"),
|
|
2476
|
+
dest: join16(targetDir, "flydocs", "knowledge", "README.md"),
|
|
2143
2477
|
label: "flydocs/knowledge/README.md"
|
|
2144
2478
|
},
|
|
2145
2479
|
{
|
|
2146
|
-
src:
|
|
2480
|
+
src: join16(
|
|
2147
2481
|
templateDir,
|
|
2148
2482
|
"flydocs",
|
|
2149
2483
|
"knowledge",
|
|
2150
2484
|
"product",
|
|
2151
2485
|
"personas.md"
|
|
2152
2486
|
),
|
|
2153
|
-
dest:
|
|
2487
|
+
dest: join16(targetDir, "flydocs", "knowledge", "product", "personas.md"),
|
|
2154
2488
|
label: "flydocs/knowledge/product/personas.md"
|
|
2155
2489
|
},
|
|
2156
2490
|
{
|
|
2157
|
-
src:
|
|
2491
|
+
src: join16(
|
|
2158
2492
|
templateDir,
|
|
2159
2493
|
"flydocs",
|
|
2160
2494
|
"knowledge",
|
|
2161
2495
|
"product",
|
|
2162
2496
|
"user-flows.md"
|
|
2163
2497
|
),
|
|
2164
|
-
dest:
|
|
2498
|
+
dest: join16(
|
|
2165
2499
|
targetDir,
|
|
2166
2500
|
"flydocs",
|
|
2167
2501
|
"knowledge",
|
|
@@ -2171,18 +2505,57 @@ var init_install = __esm({
|
|
|
2171
2505
|
label: "flydocs/knowledge/product/user-flows.md"
|
|
2172
2506
|
},
|
|
2173
2507
|
{
|
|
2174
|
-
src:
|
|
2175
|
-
|
|
2508
|
+
src: join16(
|
|
2509
|
+
templateDir,
|
|
2510
|
+
"flydocs",
|
|
2511
|
+
"knowledge",
|
|
2512
|
+
"templates",
|
|
2513
|
+
"decision.md"
|
|
2514
|
+
),
|
|
2515
|
+
dest: join16(
|
|
2516
|
+
targetDir,
|
|
2517
|
+
"flydocs",
|
|
2518
|
+
"knowledge",
|
|
2519
|
+
"templates",
|
|
2520
|
+
"decision.md"
|
|
2521
|
+
),
|
|
2522
|
+
label: "flydocs/knowledge/templates/decision.md"
|
|
2523
|
+
},
|
|
2524
|
+
{
|
|
2525
|
+
src: join16(
|
|
2526
|
+
templateDir,
|
|
2527
|
+
"flydocs",
|
|
2528
|
+
"knowledge",
|
|
2529
|
+
"templates",
|
|
2530
|
+
"feature.md"
|
|
2531
|
+
),
|
|
2532
|
+
dest: join16(
|
|
2533
|
+
targetDir,
|
|
2534
|
+
"flydocs",
|
|
2535
|
+
"knowledge",
|
|
2536
|
+
"templates",
|
|
2537
|
+
"feature.md"
|
|
2538
|
+
),
|
|
2539
|
+
label: "flydocs/knowledge/templates/feature.md"
|
|
2540
|
+
},
|
|
2541
|
+
{
|
|
2542
|
+
src: join16(templateDir, "flydocs", "knowledge", "templates", "note.md"),
|
|
2543
|
+
dest: join16(targetDir, "flydocs", "knowledge", "templates", "note.md"),
|
|
2544
|
+
label: "flydocs/knowledge/templates/note.md"
|
|
2545
|
+
},
|
|
2546
|
+
{
|
|
2547
|
+
src: join16(templateDir, "flydocs", "design-system", "README.md"),
|
|
2548
|
+
dest: join16(targetDir, "flydocs", "design-system", "README.md"),
|
|
2176
2549
|
label: "flydocs/design-system/README.md"
|
|
2177
2550
|
},
|
|
2178
2551
|
{
|
|
2179
|
-
src:
|
|
2552
|
+
src: join16(
|
|
2180
2553
|
templateDir,
|
|
2181
2554
|
"flydocs",
|
|
2182
2555
|
"design-system",
|
|
2183
2556
|
"component-patterns.md"
|
|
2184
2557
|
),
|
|
2185
|
-
dest:
|
|
2558
|
+
dest: join16(
|
|
2186
2559
|
targetDir,
|
|
2187
2560
|
"flydocs",
|
|
2188
2561
|
"design-system",
|
|
@@ -2191,13 +2564,13 @@ var init_install = __esm({
|
|
|
2191
2564
|
label: "flydocs/design-system/component-patterns.md"
|
|
2192
2565
|
},
|
|
2193
2566
|
{
|
|
2194
|
-
src:
|
|
2195
|
-
dest:
|
|
2567
|
+
src: join16(templateDir, "flydocs", "design-system", "token-mapping.md"),
|
|
2568
|
+
dest: join16(targetDir, "flydocs", "design-system", "token-mapping.md"),
|
|
2196
2569
|
label: "flydocs/design-system/token-mapping.md"
|
|
2197
2570
|
},
|
|
2198
2571
|
{
|
|
2199
|
-
src:
|
|
2200
|
-
dest:
|
|
2572
|
+
src: join16(templateDir, "flydocs", "README.md"),
|
|
2573
|
+
dest: join16(targetDir, "flydocs", "README.md"),
|
|
2201
2574
|
label: "flydocs/README.md"
|
|
2202
2575
|
}
|
|
2203
2576
|
];
|
|
@@ -2211,12 +2584,13 @@ var init_install = __esm({
|
|
|
2211
2584
|
}
|
|
2212
2585
|
}
|
|
2213
2586
|
}
|
|
2214
|
-
const envExampleSrc =
|
|
2587
|
+
const envExampleSrc = join16(templateDir, ".env.example");
|
|
2215
2588
|
if (await pathExists(envExampleSrc)) {
|
|
2216
|
-
await copyFile(envExampleSrc,
|
|
2589
|
+
await copyFile(envExampleSrc, join16(targetDir, ".env.example"));
|
|
2217
2590
|
printStatus(".env.example");
|
|
2218
2591
|
}
|
|
2219
2592
|
await ensureGitignore(targetDir);
|
|
2593
|
+
await ensurePlatformIgnores(targetDir);
|
|
2220
2594
|
console.log();
|
|
2221
2595
|
console.log("Detecting project stack...");
|
|
2222
2596
|
const stack = await detectStack(targetDir);
|
|
@@ -2253,9 +2627,8 @@ var init_install = __esm({
|
|
|
2253
2627
|
`Version: ${version}`,
|
|
2254
2628
|
"",
|
|
2255
2629
|
"Next steps:",
|
|
2256
|
-
" 1. Run flydocs
|
|
2257
|
-
" 2.
|
|
2258
|
-
" 3. Start working with /start-session",
|
|
2630
|
+
" 1. Run /flydocs-setup to configure your workspace",
|
|
2631
|
+
" 2. Start working with /start-session",
|
|
2259
2632
|
"",
|
|
2260
2633
|
"Docs: https://www.flydocs.ai/docs"
|
|
2261
2634
|
];
|
|
@@ -2392,9 +2765,9 @@ __export(update_exports, {
|
|
|
2392
2765
|
default: () => update_default
|
|
2393
2766
|
});
|
|
2394
2767
|
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";
|
|
2768
|
+
import { resolve as resolve3, join as join17 } from "path";
|
|
2769
|
+
import { mkdir as mkdir8, cp as cp2, readFile as readFile12, readdir as readdir4, rm as rm4 } from "fs/promises";
|
|
2770
|
+
import { select as select2, text as text2, confirm as confirm3, isCancel as isCancel4, cancel as cancel3 } from "@clack/prompts";
|
|
2398
2771
|
import pc7 from "picocolors";
|
|
2399
2772
|
var update_default;
|
|
2400
2773
|
var init_update = __esm({
|
|
@@ -2413,6 +2786,7 @@ var init_update = __esm({
|
|
|
2413
2786
|
init_post_install();
|
|
2414
2787
|
init_update_check();
|
|
2415
2788
|
init_telemetry();
|
|
2789
|
+
init_integrity();
|
|
2416
2790
|
update_default = defineCommand2({
|
|
2417
2791
|
meta: {
|
|
2418
2792
|
name: "update",
|
|
@@ -2482,7 +2856,7 @@ var init_update = __esm({
|
|
|
2482
2856
|
if (choice === "cwd") {
|
|
2483
2857
|
targetDir = process.cwd();
|
|
2484
2858
|
} else {
|
|
2485
|
-
const enteredPath = await
|
|
2859
|
+
const enteredPath = await text2({
|
|
2486
2860
|
message: "Enter project path:"
|
|
2487
2861
|
});
|
|
2488
2862
|
if (isCancel4(enteredPath)) {
|
|
@@ -2500,9 +2874,9 @@ var init_update = __esm({
|
|
|
2500
2874
|
}
|
|
2501
2875
|
targetDir = resolve3(targetDir);
|
|
2502
2876
|
process.chdir(targetDir);
|
|
2503
|
-
const hasVersion = await pathExists(
|
|
2877
|
+
const hasVersion = await pathExists(join17(targetDir, ".flydocs", "version"));
|
|
2504
2878
|
const hasConfig = await pathExists(
|
|
2505
|
-
|
|
2879
|
+
join17(targetDir, ".flydocs", "config.json")
|
|
2506
2880
|
);
|
|
2507
2881
|
if (!hasVersion && !hasConfig) {
|
|
2508
2882
|
printError(`Not a FlyDocs project: ${targetDir}`);
|
|
@@ -2513,8 +2887,8 @@ var init_update = __esm({
|
|
|
2513
2887
|
console.log();
|
|
2514
2888
|
let currentVersion = "0.1.0";
|
|
2515
2889
|
if (hasVersion) {
|
|
2516
|
-
const vContent = await
|
|
2517
|
-
|
|
2890
|
+
const vContent = await readFile12(
|
|
2891
|
+
join17(targetDir, ".flydocs", "version"),
|
|
2518
2892
|
"utf-8"
|
|
2519
2893
|
);
|
|
2520
2894
|
currentVersion = vContent.trim();
|
|
@@ -2548,7 +2922,7 @@ var init_update = __esm({
|
|
|
2548
2922
|
});
|
|
2549
2923
|
console.log(`Updating: v${currentVersion} \u2192 v${version}`);
|
|
2550
2924
|
console.log();
|
|
2551
|
-
const changelogPath =
|
|
2925
|
+
const changelogPath = join17(templateDir, "CHANGELOG.md");
|
|
2552
2926
|
const whatsNew = await getWhatsNew(changelogPath, currentVersion, version);
|
|
2553
2927
|
if (whatsNew.length > 0) {
|
|
2554
2928
|
console.log(pc7.cyan("What's new:"));
|
|
@@ -2560,36 +2934,37 @@ var init_update = __esm({
|
|
|
2560
2934
|
}
|
|
2561
2935
|
const now = /* @__PURE__ */ new Date();
|
|
2562
2936
|
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 =
|
|
2937
|
+
const backupDir = join17(targetDir, ".flydocs", `backup-${ts}`);
|
|
2564
2938
|
await mkdir8(backupDir, { recursive: true });
|
|
2565
2939
|
if (hasConfig) {
|
|
2566
2940
|
await cp2(
|
|
2567
|
-
|
|
2568
|
-
|
|
2941
|
+
join17(targetDir, ".flydocs", "config.json"),
|
|
2942
|
+
join17(backupDir, "config.json")
|
|
2569
2943
|
);
|
|
2570
2944
|
printStatus(`Config backed up to .flydocs/backup-${ts}/`);
|
|
2571
2945
|
}
|
|
2572
2946
|
try {
|
|
2573
|
-
const flydocsDir =
|
|
2574
|
-
const entries = await
|
|
2947
|
+
const flydocsDir = join17(targetDir, ".flydocs");
|
|
2948
|
+
const entries = await readdir4(flydocsDir);
|
|
2575
2949
|
const backups = entries.filter((e) => e.startsWith("backup-")).sort();
|
|
2576
2950
|
if (backups.length > 3) {
|
|
2577
2951
|
const toRemove = backups.slice(0, backups.length - 3);
|
|
2578
2952
|
for (const old of toRemove) {
|
|
2579
|
-
await rm4(
|
|
2953
|
+
await rm4(join17(flydocsDir, old), { recursive: true, force: true });
|
|
2580
2954
|
}
|
|
2581
2955
|
}
|
|
2582
2956
|
} catch {
|
|
2583
2957
|
}
|
|
2584
2958
|
let preserved = {
|
|
2585
|
-
tier: "
|
|
2959
|
+
tier: "local",
|
|
2586
2960
|
setupComplete: false,
|
|
2587
|
-
|
|
2961
|
+
workspaceId: null,
|
|
2962
|
+
configVersion: void 0,
|
|
2588
2963
|
workspace: {},
|
|
2589
2964
|
issueLabels: {},
|
|
2590
|
-
statusMapping: {},
|
|
2591
2965
|
detectedStack: {},
|
|
2592
2966
|
skills: {},
|
|
2967
|
+
topology: void 0,
|
|
2593
2968
|
designSystem: null,
|
|
2594
2969
|
aiLabor: {}
|
|
2595
2970
|
};
|
|
@@ -2611,22 +2986,20 @@ var init_update = __esm({
|
|
|
2611
2986
|
} else {
|
|
2612
2987
|
effectiveTier = preserved.tier;
|
|
2613
2988
|
}
|
|
2989
|
+
await ensureDirectories(targetDir, effectiveTier);
|
|
2614
2990
|
console.log("Replacing framework directories...");
|
|
2615
2991
|
await replaceDirectory(
|
|
2616
|
-
|
|
2617
|
-
|
|
2992
|
+
join17(templateDir, ".flydocs", "templates"),
|
|
2993
|
+
join17(targetDir, ".flydocs", "templates")
|
|
2618
2994
|
);
|
|
2995
|
+
printStatus(".flydocs/templates");
|
|
2619
2996
|
await replaceDirectory(
|
|
2620
|
-
|
|
2621
|
-
|
|
2997
|
+
join17(templateDir, ".claude", "hooks"),
|
|
2998
|
+
join17(targetDir, ".claude", "hooks")
|
|
2622
2999
|
);
|
|
2623
|
-
|
|
2624
|
-
join15(templateDir, ".flydocs", "scripts"),
|
|
2625
|
-
join15(targetDir, ".flydocs", "scripts")
|
|
2626
|
-
);
|
|
2627
|
-
printStatus(".flydocs/templates, hooks, scripts");
|
|
3000
|
+
printStatus(".claude/hooks");
|
|
2628
3001
|
const hasExistingAgents = await pathExists(
|
|
2629
|
-
|
|
3002
|
+
join17(targetDir, ".claude", "agents")
|
|
2630
3003
|
);
|
|
2631
3004
|
let installAgents;
|
|
2632
3005
|
if (args.yes) {
|
|
@@ -2658,20 +3031,20 @@ var init_update = __esm({
|
|
|
2658
3031
|
}
|
|
2659
3032
|
}
|
|
2660
3033
|
if (installAgents) {
|
|
2661
|
-
const claudeAgentsSrc =
|
|
3034
|
+
const claudeAgentsSrc = join17(templateDir, ".claude", "agents");
|
|
2662
3035
|
if (await pathExists(claudeAgentsSrc)) {
|
|
2663
|
-
await mkdir8(
|
|
3036
|
+
await mkdir8(join17(targetDir, ".claude", "agents"), { recursive: true });
|
|
2664
3037
|
await copyDirectoryContents(
|
|
2665
3038
|
claudeAgentsSrc,
|
|
2666
|
-
|
|
3039
|
+
join17(targetDir, ".claude", "agents")
|
|
2667
3040
|
);
|
|
2668
3041
|
}
|
|
2669
|
-
const cursorAgentsSrc =
|
|
3042
|
+
const cursorAgentsSrc = join17(templateDir, ".cursor", "agents");
|
|
2670
3043
|
if (await pathExists(cursorAgentsSrc)) {
|
|
2671
|
-
await mkdir8(
|
|
3044
|
+
await mkdir8(join17(targetDir, ".cursor", "agents"), { recursive: true });
|
|
2672
3045
|
await copyDirectoryContents(
|
|
2673
3046
|
cursorAgentsSrc,
|
|
2674
|
-
|
|
3047
|
+
join17(targetDir, ".cursor", "agents")
|
|
2675
3048
|
);
|
|
2676
3049
|
}
|
|
2677
3050
|
printStatus(
|
|
@@ -2685,46 +3058,62 @@ var init_update = __esm({
|
|
|
2685
3058
|
console.log();
|
|
2686
3059
|
console.log("Replacing framework files...");
|
|
2687
3060
|
await copyFile(
|
|
2688
|
-
|
|
2689
|
-
|
|
3061
|
+
join17(templateDir, ".claude", "CLAUDE.md"),
|
|
3062
|
+
join17(targetDir, ".claude", "CLAUDE.md")
|
|
2690
3063
|
);
|
|
2691
3064
|
await copyFile(
|
|
2692
|
-
|
|
2693
|
-
|
|
3065
|
+
join17(templateDir, ".claude", "settings.json"),
|
|
3066
|
+
join17(targetDir, ".claude", "settings.json")
|
|
2694
3067
|
);
|
|
2695
3068
|
printStatus(".claude/CLAUDE.md, settings.json");
|
|
2696
3069
|
await copyDirectoryContents(
|
|
2697
|
-
|
|
2698
|
-
|
|
3070
|
+
join17(templateDir, ".claude", "commands"),
|
|
3071
|
+
join17(targetDir, ".claude", "commands")
|
|
2699
3072
|
);
|
|
2700
3073
|
await copyDirectoryContents(
|
|
2701
|
-
|
|
2702
|
-
|
|
3074
|
+
join17(templateDir, ".claude", "commands"),
|
|
3075
|
+
join17(targetDir, ".cursor", "commands")
|
|
2703
3076
|
);
|
|
2704
3077
|
printStatus(".claude/commands, .cursor/commands");
|
|
2705
|
-
const skillsReadmeSrc =
|
|
3078
|
+
const skillsReadmeSrc = join17(templateDir, ".claude", "skills", "README.md");
|
|
2706
3079
|
if (await pathExists(skillsReadmeSrc)) {
|
|
2707
3080
|
await copyFile(
|
|
2708
3081
|
skillsReadmeSrc,
|
|
2709
|
-
|
|
3082
|
+
join17(targetDir, ".claude", "skills", "README.md")
|
|
2710
3083
|
);
|
|
2711
3084
|
}
|
|
2712
3085
|
printStatus(".claude/skills/README.md");
|
|
2713
3086
|
await copyFile(
|
|
2714
|
-
|
|
2715
|
-
|
|
3087
|
+
join17(templateDir, ".cursor", "hooks.json"),
|
|
3088
|
+
join17(targetDir, ".cursor", "hooks.json")
|
|
2716
3089
|
);
|
|
2717
3090
|
printStatus(".cursor/hooks.json");
|
|
2718
3091
|
await copyFile(
|
|
2719
|
-
|
|
2720
|
-
|
|
3092
|
+
join17(templateDir, "AGENTS.md"),
|
|
3093
|
+
join17(targetDir, "AGENTS.md")
|
|
2721
3094
|
);
|
|
2722
3095
|
printStatus("AGENTS.md");
|
|
2723
|
-
const envExampleSrc =
|
|
3096
|
+
const envExampleSrc = join17(templateDir, ".env.example");
|
|
2724
3097
|
if (await pathExists(envExampleSrc)) {
|
|
2725
|
-
await copyFile(envExampleSrc,
|
|
3098
|
+
await copyFile(envExampleSrc, join17(targetDir, ".env.example"));
|
|
2726
3099
|
printStatus(".env.example");
|
|
2727
3100
|
}
|
|
3101
|
+
const knowledgeTemplatesDir = join17(
|
|
3102
|
+
targetDir,
|
|
3103
|
+
"flydocs",
|
|
3104
|
+
"knowledge",
|
|
3105
|
+
"templates"
|
|
3106
|
+
);
|
|
3107
|
+
if (!await pathExists(knowledgeTemplatesDir)) {
|
|
3108
|
+
await mkdir8(knowledgeTemplatesDir, { recursive: true });
|
|
3109
|
+
}
|
|
3110
|
+
for (const tmpl of ["decision.md", "feature.md", "note.md"]) {
|
|
3111
|
+
const src = join17(templateDir, "flydocs", "knowledge", "templates", tmpl);
|
|
3112
|
+
const dest = join17(knowledgeTemplatesDir, tmpl);
|
|
3113
|
+
if (await pathExists(src) && !await pathExists(dest)) {
|
|
3114
|
+
await copyFile(src, dest);
|
|
3115
|
+
}
|
|
3116
|
+
}
|
|
2728
3117
|
await runManifestGeneration(targetDir);
|
|
2729
3118
|
await runContextGraphBuild(targetDir);
|
|
2730
3119
|
console.log();
|
|
@@ -2747,20 +3136,22 @@ var init_update = __esm({
|
|
|
2747
3136
|
printWarning("Config merge failed \u2014 config.json preserved as-is");
|
|
2748
3137
|
}
|
|
2749
3138
|
await copyFile(
|
|
2750
|
-
|
|
2751
|
-
|
|
3139
|
+
join17(templateDir, ".flydocs", "version"),
|
|
3140
|
+
join17(targetDir, ".flydocs", "version")
|
|
2752
3141
|
);
|
|
2753
3142
|
printStatus(`.flydocs/version \u2192 ${version}`);
|
|
2754
|
-
const clSrc =
|
|
3143
|
+
const clSrc = join17(templateDir, "CHANGELOG.md");
|
|
2755
3144
|
if (await pathExists(clSrc)) {
|
|
2756
|
-
await copyFile(clSrc,
|
|
3145
|
+
await copyFile(clSrc, join17(targetDir, ".flydocs", "CHANGELOG.md"));
|
|
2757
3146
|
printStatus(".flydocs/CHANGELOG.md");
|
|
2758
3147
|
}
|
|
2759
|
-
const mfSrc =
|
|
3148
|
+
const mfSrc = join17(templateDir, "manifest.json");
|
|
2760
3149
|
if (await pathExists(mfSrc)) {
|
|
2761
|
-
await copyFile(mfSrc,
|
|
3150
|
+
await copyFile(mfSrc, join17(targetDir, ".flydocs", "manifest.json"));
|
|
2762
3151
|
printStatus(".flydocs/manifest.json");
|
|
2763
3152
|
}
|
|
3153
|
+
await generateIntegrity(targetDir, version);
|
|
3154
|
+
printStatus("Install integrity recorded");
|
|
2764
3155
|
console.log();
|
|
2765
3156
|
console.log("Detecting project stack...");
|
|
2766
3157
|
const stack = await detectStack(targetDir);
|
|
@@ -2777,6 +3168,7 @@ var init_update = __esm({
|
|
|
2777
3168
|
printInfo("No framework detected in package.json");
|
|
2778
3169
|
}
|
|
2779
3170
|
await migrateGitignore(targetDir);
|
|
3171
|
+
await ensurePlatformIgnores(targetDir);
|
|
2780
3172
|
console.log();
|
|
2781
3173
|
console.log("Checking for deprecated files...");
|
|
2782
3174
|
await handleLegacyContext(targetDir);
|
|
@@ -2818,21 +3210,21 @@ __export(uninstall_exports, {
|
|
|
2818
3210
|
default: () => uninstall_default
|
|
2819
3211
|
});
|
|
2820
3212
|
import { defineCommand as defineCommand3 } from "citty";
|
|
2821
|
-
import { resolve as resolve4, join as
|
|
2822
|
-
import { readdir as
|
|
3213
|
+
import { resolve as resolve4, join as join18 } from "path";
|
|
3214
|
+
import { readdir as readdir5, rm as rm5, rename as rename2 } from "fs/promises";
|
|
2823
3215
|
import { confirm as confirm4, select as select3, isCancel as isCancel5, cancel as cancel4 } from "@clack/prompts";
|
|
2824
3216
|
import pc8 from "picocolors";
|
|
2825
3217
|
async function removeOwnedSkills(targetDir) {
|
|
2826
|
-
const skillsDir =
|
|
3218
|
+
const skillsDir = join18(targetDir, ".claude", "skills");
|
|
2827
3219
|
const removed = [];
|
|
2828
3220
|
if (!await pathExists(skillsDir)) {
|
|
2829
3221
|
return removed;
|
|
2830
3222
|
}
|
|
2831
3223
|
try {
|
|
2832
|
-
const entries = await
|
|
3224
|
+
const entries = await readdir5(skillsDir);
|
|
2833
3225
|
for (const entry of entries) {
|
|
2834
3226
|
if (entry.startsWith(OWNED_SKILL_PREFIX)) {
|
|
2835
|
-
await rm5(
|
|
3227
|
+
await rm5(join18(skillsDir, entry), { recursive: true, force: true });
|
|
2836
3228
|
removed.push(`.claude/skills/${entry}`);
|
|
2837
3229
|
}
|
|
2838
3230
|
}
|
|
@@ -2841,16 +3233,16 @@ async function removeOwnedSkills(targetDir) {
|
|
|
2841
3233
|
return removed;
|
|
2842
3234
|
}
|
|
2843
3235
|
async function removeOwnedCursorRules(targetDir) {
|
|
2844
|
-
const rulesDir =
|
|
3236
|
+
const rulesDir = join18(targetDir, ".cursor", "rules");
|
|
2845
3237
|
const removed = [];
|
|
2846
3238
|
if (!await pathExists(rulesDir)) {
|
|
2847
3239
|
return removed;
|
|
2848
3240
|
}
|
|
2849
3241
|
try {
|
|
2850
|
-
const entries = await
|
|
3242
|
+
const entries = await readdir5(rulesDir);
|
|
2851
3243
|
for (const entry of entries) {
|
|
2852
3244
|
if (entry.startsWith(OWNED_RULE_PREFIX) && entry.endsWith(".mdc")) {
|
|
2853
|
-
await rm5(
|
|
3245
|
+
await rm5(join18(rulesDir, entry), { force: true });
|
|
2854
3246
|
removed.push(`.cursor/rules/${entry}`);
|
|
2855
3247
|
}
|
|
2856
3248
|
}
|
|
@@ -2860,7 +3252,7 @@ async function removeOwnedCursorRules(targetDir) {
|
|
|
2860
3252
|
}
|
|
2861
3253
|
async function isEmptyDir(dirPath) {
|
|
2862
3254
|
try {
|
|
2863
|
-
const entries = await
|
|
3255
|
+
const entries = await readdir5(dirPath);
|
|
2864
3256
|
return entries.length === 0;
|
|
2865
3257
|
} catch {
|
|
2866
3258
|
return false;
|
|
@@ -2869,7 +3261,7 @@ async function isEmptyDir(dirPath) {
|
|
|
2869
3261
|
async function cleanupEmptyParents(targetDir, dirs) {
|
|
2870
3262
|
const cleaned = [];
|
|
2871
3263
|
for (const dir of dirs) {
|
|
2872
|
-
const fullPath =
|
|
3264
|
+
const fullPath = join18(targetDir, dir);
|
|
2873
3265
|
if (await pathExists(fullPath) && await isEmptyDir(fullPath)) {
|
|
2874
3266
|
await rm5(fullPath, { recursive: true, force: true });
|
|
2875
3267
|
cleaned.push(dir);
|
|
@@ -2890,9 +3282,11 @@ var init_uninstall = __esm({
|
|
|
2890
3282
|
[".claude/settings.json", "file"],
|
|
2891
3283
|
[".claude/agents", "dir"],
|
|
2892
3284
|
[".claude/commands", "dir"],
|
|
3285
|
+
[".claude/hooks", "dir"],
|
|
2893
3286
|
[".claude/skills/README.md", "file"],
|
|
2894
3287
|
[".cursor/hooks.json", "file"],
|
|
2895
3288
|
[".cursor/agents", "dir"],
|
|
3289
|
+
[".cursor/commands", "dir"],
|
|
2896
3290
|
[".flydocs", "dir"],
|
|
2897
3291
|
["AGENTS.md", "file"],
|
|
2898
3292
|
[".env.example", "file"]
|
|
@@ -2946,8 +3340,8 @@ var init_uninstall = __esm({
|
|
|
2946
3340
|
process.exit(1);
|
|
2947
3341
|
}
|
|
2948
3342
|
targetDir = resolve4(targetDir);
|
|
2949
|
-
const hasFlydocs = await pathExists(
|
|
2950
|
-
const hasAgentsMd = await pathExists(
|
|
3343
|
+
const hasFlydocs = await pathExists(join18(targetDir, ".flydocs"));
|
|
3344
|
+
const hasAgentsMd = await pathExists(join18(targetDir, "AGENTS.md"));
|
|
2951
3345
|
if (!hasFlydocs && !hasAgentsMd) {
|
|
2952
3346
|
printError(`Not a FlyDocs project: ${targetDir}`);
|
|
2953
3347
|
printInfo("No .flydocs/ directory or AGENTS.md found.");
|
|
@@ -2959,7 +3353,7 @@ var init_uninstall = __esm({
|
|
|
2959
3353
|
const removeAll = forceAll || args.all;
|
|
2960
3354
|
const skipPrompts = forceAll || args.yes;
|
|
2961
3355
|
let contentAction = "preserve";
|
|
2962
|
-
const hasUserContent = await pathExists(
|
|
3356
|
+
const hasUserContent = await pathExists(join18(targetDir, "flydocs"));
|
|
2963
3357
|
if (hasUserContent) {
|
|
2964
3358
|
if (removeAll) {
|
|
2965
3359
|
contentAction = "remove";
|
|
@@ -3042,7 +3436,7 @@ var init_uninstall = __esm({
|
|
|
3042
3436
|
const removedRules = await removeOwnedCursorRules(targetDir);
|
|
3043
3437
|
result.removed.push(...removedRules);
|
|
3044
3438
|
for (const [relativePath, type] of ALWAYS_REMOVED) {
|
|
3045
|
-
const fullPath =
|
|
3439
|
+
const fullPath = join18(targetDir, relativePath);
|
|
3046
3440
|
if (!await pathExists(fullPath)) {
|
|
3047
3441
|
result.skipped.push(relativePath);
|
|
3048
3442
|
continue;
|
|
@@ -3060,9 +3454,9 @@ var init_uninstall = __esm({
|
|
|
3060
3454
|
}
|
|
3061
3455
|
}
|
|
3062
3456
|
if (hasUserContent) {
|
|
3063
|
-
const flydocsPath =
|
|
3457
|
+
const flydocsPath = join18(targetDir, "flydocs");
|
|
3064
3458
|
if (contentAction === "archive") {
|
|
3065
|
-
const archivePath =
|
|
3459
|
+
const archivePath = join18(targetDir, "flydocs-archive");
|
|
3066
3460
|
if (await pathExists(archivePath)) {
|
|
3067
3461
|
await rm5(archivePath, { recursive: true, force: true });
|
|
3068
3462
|
}
|
|
@@ -3301,70 +3695,9 @@ __export(connect_exports, {
|
|
|
3301
3695
|
default: () => connect_default
|
|
3302
3696
|
});
|
|
3303
3697
|
import { defineCommand as defineCommand6 } from "citty";
|
|
3304
|
-
import { text as
|
|
3698
|
+
import { text as text3, confirm as confirm5, isCancel as isCancel6, cancel as cancel5 } from "@clack/prompts";
|
|
3305
3699
|
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
|
-
}
|
|
3700
|
+
import { join as join19 } from "path";
|
|
3368
3701
|
var connect_default;
|
|
3369
3702
|
var init_connect = __esm({
|
|
3370
3703
|
"src/commands/connect.ts"() {
|
|
@@ -3373,6 +3706,7 @@ var init_connect = __esm({
|
|
|
3373
3706
|
init_fs_ops();
|
|
3374
3707
|
init_template();
|
|
3375
3708
|
init_ui();
|
|
3709
|
+
init_api_key();
|
|
3376
3710
|
connect_default = defineCommand6({
|
|
3377
3711
|
meta: {
|
|
3378
3712
|
name: "connect",
|
|
@@ -3393,12 +3727,12 @@ var init_connect = __esm({
|
|
|
3393
3727
|
},
|
|
3394
3728
|
key: {
|
|
3395
3729
|
type: "string",
|
|
3396
|
-
description: "API key (fdk_
|
|
3730
|
+
description: "FlyDocs API key (fdk_...)"
|
|
3397
3731
|
}
|
|
3398
3732
|
},
|
|
3399
3733
|
async run({ args }) {
|
|
3400
3734
|
const targetDir = args.path ?? process.cwd();
|
|
3401
|
-
const configPath =
|
|
3735
|
+
const configPath = join19(targetDir, ".flydocs", "config.json");
|
|
3402
3736
|
if (!await pathExists(configPath)) {
|
|
3403
3737
|
printError("Not a FlyDocs project (.flydocs/config.json not found).");
|
|
3404
3738
|
console.log(
|
|
@@ -3422,22 +3756,19 @@ var init_connect = __esm({
|
|
|
3422
3756
|
console.log(` ${pc11.bold("Connect to FlyDocs Cloud")}`);
|
|
3423
3757
|
console.log();
|
|
3424
3758
|
console.log(
|
|
3425
|
-
` ${pc11.dim("
|
|
3426
|
-
);
|
|
3427
|
-
console.log(
|
|
3428
|
-
` ${pc11.dim("Linear API key (lin_api_...): Get from Linear \u2192 Settings \u2192 API")}`
|
|
3759
|
+
` ${pc11.dim("Get your API key (fdk_...) from your FlyDocs dashboard")}`
|
|
3429
3760
|
);
|
|
3430
3761
|
console.log();
|
|
3431
3762
|
let apiKey = args.key ?? "";
|
|
3432
3763
|
if (!apiKey) {
|
|
3433
|
-
const keyInput = await
|
|
3764
|
+
const keyInput = await text3({
|
|
3434
3765
|
message: "Enter your API key",
|
|
3435
|
-
placeholder: "fdk_...
|
|
3766
|
+
placeholder: "fdk_...",
|
|
3436
3767
|
validate(value) {
|
|
3437
3768
|
if (!value.trim()) return "API key is required";
|
|
3438
3769
|
const type = detectKeyType(value.trim());
|
|
3439
3770
|
if (type === "unknown")
|
|
3440
|
-
return "Key must start with fdk_ (FlyDocs
|
|
3771
|
+
return "Key must start with fdk_ (FlyDocs API key)";
|
|
3441
3772
|
return void 0;
|
|
3442
3773
|
}
|
|
3443
3774
|
});
|
|
@@ -3449,7 +3780,9 @@ var init_connect = __esm({
|
|
|
3449
3780
|
}
|
|
3450
3781
|
const keyType = detectKeyType(apiKey);
|
|
3451
3782
|
if (keyType === "unknown") {
|
|
3452
|
-
printError(
|
|
3783
|
+
printError(
|
|
3784
|
+
"Unrecognized key format. Expected fdk_ prefix (FlyDocs API key)."
|
|
3785
|
+
);
|
|
3453
3786
|
process.exit(1);
|
|
3454
3787
|
}
|
|
3455
3788
|
printInfo("Validating API key...");
|
|
@@ -3491,32 +3824,15 @@ var init_connect = __esm({
|
|
|
3491
3824
|
}
|
|
3492
3825
|
const wasLocal = config.tier === "local";
|
|
3493
3826
|
config.tier = "cloud";
|
|
3494
|
-
|
|
3495
|
-
|
|
3827
|
+
const configRecord = config;
|
|
3828
|
+
delete configRecord.statusMapping;
|
|
3829
|
+
delete configRecord.provider;
|
|
3496
3830
|
await writeConfig(targetDir, config);
|
|
3497
3831
|
printStatus("Config updated to cloud tier");
|
|
3498
3832
|
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
|
-
}
|
|
3833
|
+
printInfo(
|
|
3834
|
+
"Tier changed to cloud. Run flydocs update to refresh skill scripts."
|
|
3835
|
+
);
|
|
3520
3836
|
}
|
|
3521
3837
|
console.log();
|
|
3522
3838
|
console.log(
|
|
@@ -3579,9 +3895,7 @@ var init_upgrade = __esm({
|
|
|
3579
3895
|
` ${pc12.green("\u2713")} You're already on the ${pc12.bold("cloud")} tier.`
|
|
3580
3896
|
);
|
|
3581
3897
|
console.log();
|
|
3582
|
-
console.log(
|
|
3583
|
-
` Your issues sync with Linear via the cloud mechanism skill.`
|
|
3584
|
-
);
|
|
3898
|
+
console.log(` Your issues sync with your provider via the relay API.`);
|
|
3585
3899
|
console.log(
|
|
3586
3900
|
` Run ${pc12.cyan("flydocs connect")} to update your connection settings.`
|
|
3587
3901
|
);
|
|
@@ -3593,9 +3907,7 @@ var init_upgrade = __esm({
|
|
|
3593
3907
|
console.log(` You're currently on the ${pc12.yellow("local")} tier.`);
|
|
3594
3908
|
console.log(` Upgrade to cloud for:`);
|
|
3595
3909
|
console.log();
|
|
3596
|
-
console.log(
|
|
3597
|
-
` ${pc12.cyan("\u2192")} Issue sync with Linear (Jira coming soon)`
|
|
3598
|
-
);
|
|
3910
|
+
console.log(` ${pc12.cyan("\u2192")} Issue sync with Linear, Jira, and more`);
|
|
3599
3911
|
console.log(` ${pc12.cyan("\u2192")} Project milestones and cycle management`);
|
|
3600
3912
|
console.log(` ${pc12.cyan("\u2192")} Team assignment and priority tracking`);
|
|
3601
3913
|
console.log(` ${pc12.cyan("\u2192")} Project health updates and dashboards`);
|