@flydocs/cli 0.6.0-alpha.1 → 0.6.0-alpha.10
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 +504 -254
- package/package.json +1 -1
- package/template/.claude/CLAUDE.md +11 -9
- package/template/.claude/commands/flydocs-setup.md +114 -17
- package/template/.claude/commands/flydocs-upgrade.md +27 -15
- package/template/.claude/commands/knowledge.md +61 -0
- package/template/.claude/skills/flydocs-cloud/SKILL.md +44 -31
- package/template/.claude/skills/flydocs-cloud/scripts/assign.py +10 -4
- package/template/.claude/skills/flydocs-cloud/scripts/create_issue.py +22 -2
- package/template/.claude/skills/flydocs-cloud/scripts/create_team.py +39 -0
- package/template/.claude/skills/flydocs-cloud/scripts/delete_milestone.py +21 -0
- package/template/.claude/skills/flydocs-cloud/scripts/estimate.py +9 -5
- package/template/.claude/skills/flydocs-cloud/scripts/flydocs_api.py +11 -0
- package/template/.claude/skills/flydocs-cloud/scripts/get_estimate_scale.py +23 -0
- package/template/.claude/skills/flydocs-cloud/scripts/list_providers.py +19 -0
- package/template/.claude/skills/flydocs-cloud/scripts/list_statuses.py +19 -0
- package/template/.claude/skills/flydocs-cloud/scripts/list_teams.py +1 -1
- package/template/.claude/skills/flydocs-cloud/scripts/refresh_labels.py +87 -0
- package/template/.claude/skills/flydocs-cloud/scripts/set_identity.py +38 -0
- package/template/.claude/skills/flydocs-cloud/scripts/set_preferences.py +49 -0
- package/template/.claude/skills/flydocs-cloud/scripts/set_provider.py +46 -0
- package/template/.claude/skills/flydocs-cloud/scripts/set_status_mapping.py +69 -0
- package/template/.claude/skills/flydocs-cloud/scripts/set_team.py +5 -4
- package/template/.claude/skills/flydocs-cloud/scripts/update_issue.py +22 -4
- package/template/.claude/skills/flydocs-cloud/scripts/update_milestone.py +42 -0
- package/template/.claude/skills/flydocs-cloud/scripts/validate_setup.py +139 -0
- package/template/.claude/skills/flydocs-local/SKILL.md +1 -1
- package/template/.claude/skills/flydocs-local/scripts/assign.py +13 -4
- package/template/.claude/skills/flydocs-local/scripts/flydocs_api.py +5 -2
- package/template/.claude/skills/flydocs-workflow/SKILL.md +23 -18
- package/template/.claude/skills/flydocs-workflow/reference/comment-templates.md +1 -0
- package/template/.claude/skills/flydocs-workflow/reference/pr-workflow.md +105 -0
- package/template/.claude/skills/flydocs-workflow/reference/priority-estimates.md +37 -15
- package/template/.claude/skills/flydocs-workflow/session.md +24 -16
- package/template/.claude/skills/flydocs-workflow/stages/capture.md +8 -3
- package/template/.claude/skills/flydocs-workflow/stages/close.md +4 -3
- package/template/.claude/skills/flydocs-workflow/stages/implement.md +28 -4
- package/template/.claude/skills/flydocs-workflow/stages/refine.md +20 -4
- package/template/.claude/skills/flydocs-workflow/stages/review.md +14 -2
- package/template/.flydocs/config.json +4 -18
- package/template/.flydocs/hooks/prompt-submit.py +27 -4
- package/template/.flydocs/version +1 -1
- package/template/AGENTS.md +8 -8
- package/template/CHANGELOG.md +39 -0
- 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 +8 -2
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.10";
|
|
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,10 +293,9 @@ function extractPreservedValues(config) {
|
|
|
292
293
|
return {
|
|
293
294
|
tier: config.tier,
|
|
294
295
|
setupComplete: config.setupComplete ?? false,
|
|
295
|
-
|
|
296
|
+
workspaceId: config.workspaceId ?? null,
|
|
296
297
|
workspace: config.workspace ?? {},
|
|
297
298
|
issueLabels: config.issueLabels ?? {},
|
|
298
|
-
statusMapping: config.statusMapping ?? {},
|
|
299
299
|
detectedStack: config.detectedStack ?? {},
|
|
300
300
|
skills: config.skills ?? {},
|
|
301
301
|
designSystem: config.designSystem ?? null,
|
|
@@ -311,21 +311,13 @@ async function mergeConfig(templateDir, version, tierFlag, preserved) {
|
|
|
311
311
|
config.version = version;
|
|
312
312
|
config.tier = tierFlag ?? preserved.tier;
|
|
313
313
|
config.setupComplete = preserved.setupComplete;
|
|
314
|
-
|
|
315
|
-
if (!config.provider) {
|
|
316
|
-
config.provider = { type: "linear", teamId: null };
|
|
317
|
-
}
|
|
318
|
-
config.provider.teamId = preserved.providerTeamId;
|
|
319
|
-
}
|
|
314
|
+
config.workspaceId = preserved.workspaceId;
|
|
320
315
|
if (Object.keys(preserved.workspace).length > 0) {
|
|
321
316
|
config.workspace = preserved.workspace;
|
|
322
317
|
}
|
|
323
318
|
if (Object.keys(preserved.issueLabels).length > 0) {
|
|
324
319
|
config.issueLabels = preserved.issueLabels;
|
|
325
320
|
}
|
|
326
|
-
if (Object.keys(preserved.statusMapping).length > 0) {
|
|
327
|
-
config.statusMapping = preserved.statusMapping;
|
|
328
|
-
}
|
|
329
321
|
if (Object.keys(preserved.detectedStack).length > 0) {
|
|
330
322
|
config.detectedStack = preserved.detectedStack;
|
|
331
323
|
}
|
|
@@ -485,6 +477,18 @@ import {
|
|
|
485
477
|
writeFile as writeFile2
|
|
486
478
|
} from "fs/promises";
|
|
487
479
|
import { join as join5, dirname as dirname2 } from "path";
|
|
480
|
+
async function detectExistingConfigs(targetDir) {
|
|
481
|
+
const existing = [];
|
|
482
|
+
const backupDir = join5(targetDir, BACKUP_ORIGINALS_DIR);
|
|
483
|
+
for (const relativePath of RESTORABLE_FILES) {
|
|
484
|
+
const filePath = join5(targetDir, relativePath);
|
|
485
|
+
const backupPath = join5(backupDir, relativePath);
|
|
486
|
+
if (await pathExists(filePath) && !await pathExists(backupPath)) {
|
|
487
|
+
existing.push(relativePath);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
return existing;
|
|
491
|
+
}
|
|
488
492
|
async function backupOriginals(targetDir, files = RESTORABLE_FILES) {
|
|
489
493
|
const backedUp = [];
|
|
490
494
|
const backupDir = join5(targetDir, BACKUP_ORIGINALS_DIR);
|
|
@@ -760,8 +764,8 @@ function flushFrontmatterValue(mode, lines) {
|
|
|
760
764
|
return lines.join("\n").trim();
|
|
761
765
|
}
|
|
762
766
|
}
|
|
763
|
-
function parseFrontmatter(
|
|
764
|
-
const match =
|
|
767
|
+
function parseFrontmatter(text4) {
|
|
768
|
+
const match = text4.match(/^---\s*\n([\s\S]*?)\n---/);
|
|
765
769
|
if (!match) return null;
|
|
766
770
|
const block = match[1];
|
|
767
771
|
const result = {};
|
|
@@ -947,7 +951,8 @@ function searchCatalog(keyword) {
|
|
|
947
951
|
return searchable.includes(lower);
|
|
948
952
|
});
|
|
949
953
|
}
|
|
950
|
-
async function addSkill(targetDir, source) {
|
|
954
|
+
async function addSkill(targetDir, source, options) {
|
|
955
|
+
const quiet = options?.quiet ?? false;
|
|
951
956
|
if (isPlatformSkill(source)) {
|
|
952
957
|
printError(`Cannot install platform skill '${source}'.`);
|
|
953
958
|
console.log(" Platform skills (flydocs-*) are managed by the installer.");
|
|
@@ -965,11 +970,13 @@ async function addSkill(targetDir, source) {
|
|
|
965
970
|
console.log(` Remove first: flydocs skills remove ${skillName}`);
|
|
966
971
|
return;
|
|
967
972
|
}
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
+
if (!quiet) {
|
|
974
|
+
console.log();
|
|
975
|
+
console.log(
|
|
976
|
+
`${pc3.blue("->")} Installing ${pc3.cyan(skillName)} from ${repo}...`
|
|
977
|
+
);
|
|
978
|
+
console.log();
|
|
979
|
+
}
|
|
973
980
|
let success;
|
|
974
981
|
try {
|
|
975
982
|
success = await downloadSkillTree(repo, skillName, skillsDir);
|
|
@@ -1003,19 +1010,23 @@ async function addSkill(targetDir, source) {
|
|
|
1003
1010
|
);
|
|
1004
1011
|
return;
|
|
1005
1012
|
}
|
|
1006
|
-
if (!fm["triggers"]) {
|
|
1013
|
+
if (!fm["triggers"] && !quiet) {
|
|
1007
1014
|
printWarning(
|
|
1008
1015
|
"SKILL.md has no triggers -- skill won't appear in manifest index."
|
|
1009
1016
|
);
|
|
1010
1017
|
}
|
|
1011
|
-
|
|
1018
|
+
if (!quiet) {
|
|
1019
|
+
printStatus("Downloaded skill files");
|
|
1020
|
+
}
|
|
1012
1021
|
const cursorRuleSrc = join8(skillsDir, "cursor-rule.mdc");
|
|
1013
1022
|
if (await pathExists(cursorRuleSrc)) {
|
|
1014
1023
|
const cursorRulesDir = join8(targetDir, ".cursor", "rules");
|
|
1015
1024
|
await mkdir3(cursorRulesDir, { recursive: true });
|
|
1016
1025
|
const cursorRuleDest = join8(cursorRulesDir, `${skillName}.mdc`);
|
|
1017
1026
|
await copyFile(cursorRuleSrc, cursorRuleDest);
|
|
1018
|
-
|
|
1027
|
+
if (!quiet) {
|
|
1028
|
+
printStatus("Installed cursor rule");
|
|
1029
|
+
}
|
|
1019
1030
|
}
|
|
1020
1031
|
const config = await readConfig(targetDir);
|
|
1021
1032
|
const installed = config.skills?.installed ?? [];
|
|
@@ -1027,12 +1038,16 @@ async function addSkill(targetDir, source) {
|
|
|
1027
1038
|
}
|
|
1028
1039
|
config.skills.installed = installed;
|
|
1029
1040
|
await writeConfig(targetDir, config);
|
|
1030
|
-
|
|
1041
|
+
if (!quiet) {
|
|
1042
|
+
printStatus("Updated config.json");
|
|
1043
|
+
}
|
|
1031
1044
|
}
|
|
1032
1045
|
await runManifestGeneration(targetDir);
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1046
|
+
if (!quiet) {
|
|
1047
|
+
console.log();
|
|
1048
|
+
printStatus(`Installed ${pc3.cyan(skillName)}`);
|
|
1049
|
+
console.log();
|
|
1050
|
+
}
|
|
1036
1051
|
}
|
|
1037
1052
|
async function removeSkill(targetDir, name) {
|
|
1038
1053
|
if (isPlatformSkill(name)) {
|
|
@@ -1187,7 +1202,8 @@ async function promptCommunitySkills(targetDir, stack, autoYes) {
|
|
|
1187
1202
|
let successCount = 0;
|
|
1188
1203
|
for (const skill of selected) {
|
|
1189
1204
|
try {
|
|
1190
|
-
await addSkill(targetDir, `${skill.repo}:${skill.name}
|
|
1205
|
+
await addSkill(targetDir, `${skill.repo}:${skill.name}`, { quiet: true });
|
|
1206
|
+
printStatus(`Installed ${pc4.cyan(skill.name)}`);
|
|
1191
1207
|
successCount++;
|
|
1192
1208
|
} catch {
|
|
1193
1209
|
printError(`${skill.name} (failed)`);
|
|
@@ -1840,6 +1856,91 @@ var init_telemetry = __esm({
|
|
|
1840
1856
|
}
|
|
1841
1857
|
});
|
|
1842
1858
|
|
|
1859
|
+
// src/lib/api-key.ts
|
|
1860
|
+
import { readFile as readFile10, writeFile as writeFile7, appendFile as appendFile2 } from "fs/promises";
|
|
1861
|
+
import { join as join14 } from "path";
|
|
1862
|
+
function detectKeyType(key) {
|
|
1863
|
+
if (key.startsWith("fdk_")) return "relay";
|
|
1864
|
+
if (key.startsWith("lin_api_")) return "direct";
|
|
1865
|
+
return "unknown";
|
|
1866
|
+
}
|
|
1867
|
+
async function validateRelayKey(apiKey) {
|
|
1868
|
+
const baseUrl = process.env.FLYDOCS_RELAY_URL?.replace(/\/$/, "") ?? "https://app.flydocs.ai/api/relay";
|
|
1869
|
+
const response = await fetch(`${baseUrl}/auth/validate`, {
|
|
1870
|
+
method: "POST",
|
|
1871
|
+
headers: {
|
|
1872
|
+
Authorization: `Bearer ${apiKey}`,
|
|
1873
|
+
"Content-Type": "application/json"
|
|
1874
|
+
},
|
|
1875
|
+
signal: AbortSignal.timeout(15e3)
|
|
1876
|
+
});
|
|
1877
|
+
if (!response.ok) return { valid: false };
|
|
1878
|
+
const data = await response.json();
|
|
1879
|
+
if (!data.valid) return { valid: false };
|
|
1880
|
+
return { valid: true, org: data.org ?? "your organization" };
|
|
1881
|
+
}
|
|
1882
|
+
async function fetchWorkspaces(apiKey) {
|
|
1883
|
+
const baseUrl = process.env.FLYDOCS_RELAY_URL?.replace(/\/$/, "") ?? "https://app.flydocs.ai/api/relay";
|
|
1884
|
+
const response = await fetch(`${baseUrl}/auth/workspaces`, {
|
|
1885
|
+
method: "GET",
|
|
1886
|
+
headers: {
|
|
1887
|
+
Authorization: `Bearer ${apiKey}`
|
|
1888
|
+
},
|
|
1889
|
+
signal: AbortSignal.timeout(15e3)
|
|
1890
|
+
});
|
|
1891
|
+
if (!response.ok) {
|
|
1892
|
+
throw new Error(`Failed to fetch workspaces: ${response.status}`);
|
|
1893
|
+
}
|
|
1894
|
+
const data = await response.json();
|
|
1895
|
+
return data;
|
|
1896
|
+
}
|
|
1897
|
+
async function validateLinearKey(apiKey) {
|
|
1898
|
+
const response = await fetch("https://api.linear.app/graphql", {
|
|
1899
|
+
method: "POST",
|
|
1900
|
+
headers: {
|
|
1901
|
+
Authorization: apiKey,
|
|
1902
|
+
"Content-Type": "application/json"
|
|
1903
|
+
},
|
|
1904
|
+
body: JSON.stringify({ query: "{ viewer { id name email } }" }),
|
|
1905
|
+
signal: AbortSignal.timeout(15e3)
|
|
1906
|
+
});
|
|
1907
|
+
if (!response.ok) return { valid: false };
|
|
1908
|
+
const data = await response.json();
|
|
1909
|
+
if (!data.data?.viewer) return { valid: false };
|
|
1910
|
+
return {
|
|
1911
|
+
valid: true,
|
|
1912
|
+
name: data.data.viewer.name,
|
|
1913
|
+
email: data.data.viewer.email
|
|
1914
|
+
};
|
|
1915
|
+
}
|
|
1916
|
+
async function storeEnvKey(targetDir, envVarName, value) {
|
|
1917
|
+
const envPath = join14(targetDir, ".env");
|
|
1918
|
+
const envLocalPath = join14(targetDir, ".env.local");
|
|
1919
|
+
const targetEnvPath = await pathExists(envLocalPath) ? envLocalPath : envPath;
|
|
1920
|
+
const pattern = new RegExp(`${envVarName}=.*`);
|
|
1921
|
+
if (await pathExists(targetEnvPath)) {
|
|
1922
|
+
const envContent = await readFile10(targetEnvPath, "utf-8");
|
|
1923
|
+
if (pattern.test(envContent)) {
|
|
1924
|
+
const updated = envContent.replace(pattern, `${envVarName}=${value}`);
|
|
1925
|
+
await writeFile7(targetEnvPath, updated, "utf-8");
|
|
1926
|
+
} else {
|
|
1927
|
+
await appendFile2(targetEnvPath, `
|
|
1928
|
+
${envVarName}=${value}
|
|
1929
|
+
`);
|
|
1930
|
+
}
|
|
1931
|
+
} else {
|
|
1932
|
+
await writeFile7(targetEnvPath, `${envVarName}=${value}
|
|
1933
|
+
`, "utf-8");
|
|
1934
|
+
}
|
|
1935
|
+
return targetEnvPath === envLocalPath ? ".env.local" : ".env";
|
|
1936
|
+
}
|
|
1937
|
+
var init_api_key = __esm({
|
|
1938
|
+
"src/lib/api-key.ts"() {
|
|
1939
|
+
"use strict";
|
|
1940
|
+
init_fs_ops();
|
|
1941
|
+
}
|
|
1942
|
+
});
|
|
1943
|
+
|
|
1843
1944
|
// src/commands/install.ts
|
|
1844
1945
|
var install_exports = {};
|
|
1845
1946
|
__export(install_exports, {
|
|
@@ -1847,9 +1948,9 @@ __export(install_exports, {
|
|
|
1847
1948
|
});
|
|
1848
1949
|
import { defineCommand } from "citty";
|
|
1849
1950
|
import { resolve as resolve2 } from "path";
|
|
1850
|
-
import { join as
|
|
1951
|
+
import { join as join15 } from "path";
|
|
1851
1952
|
import { mkdir as mkdir7 } from "fs/promises";
|
|
1852
|
-
import { confirm as confirm2, select, isCancel as isCancel3, cancel as cancel2 } from "@clack/prompts";
|
|
1953
|
+
import { confirm as confirm2, select, text, isCancel as isCancel3, cancel as cancel2 } from "@clack/prompts";
|
|
1853
1954
|
import pc6 from "picocolors";
|
|
1854
1955
|
var install_default;
|
|
1855
1956
|
var init_install = __esm({
|
|
@@ -1868,6 +1969,7 @@ var init_install = __esm({
|
|
|
1868
1969
|
init_post_install();
|
|
1869
1970
|
init_update_check();
|
|
1870
1971
|
init_telemetry();
|
|
1972
|
+
init_api_key();
|
|
1871
1973
|
install_default = defineCommand({
|
|
1872
1974
|
meta: {
|
|
1873
1975
|
name: "install",
|
|
@@ -1929,7 +2031,7 @@ var init_install = __esm({
|
|
|
1929
2031
|
process.exit(1);
|
|
1930
2032
|
}
|
|
1931
2033
|
tier = args.tier;
|
|
1932
|
-
} else if (await pathExists(
|
|
2034
|
+
} else if (await pathExists(join15(targetDir, ".flydocs", "config.json"))) {
|
|
1933
2035
|
try {
|
|
1934
2036
|
const existing = await readConfig(targetDir);
|
|
1935
2037
|
if (existing.tier) {
|
|
@@ -1951,7 +2053,7 @@ var init_install = __esm({
|
|
|
1951
2053
|
{
|
|
1952
2054
|
value: "cloud",
|
|
1953
2055
|
label: "Cloud (managed)",
|
|
1954
|
-
hint: "Sync with Linear
|
|
2056
|
+
hint: "Sync with Linear, Jira, and more"
|
|
1955
2057
|
}
|
|
1956
2058
|
]
|
|
1957
2059
|
});
|
|
@@ -1978,48 +2080,173 @@ var init_install = __esm({
|
|
|
1978
2080
|
}
|
|
1979
2081
|
printInfo(`Tier: ${tier}`);
|
|
1980
2082
|
await capture("install_tier_selected", { tier });
|
|
1981
|
-
|
|
2083
|
+
let selectedWorkspaceId = null;
|
|
2084
|
+
let selectedWorkspaceName = null;
|
|
2085
|
+
if (tier === "cloud") {
|
|
2086
|
+
console.log();
|
|
2087
|
+
console.log(` ${pc6.bold("Connect to FlyDocs Cloud")}`);
|
|
2088
|
+
console.log();
|
|
2089
|
+
console.log(
|
|
2090
|
+
` ${pc6.dim("Get your API key from your FlyDocs dashboard (fdk_...)")}`
|
|
2091
|
+
);
|
|
2092
|
+
console.log();
|
|
2093
|
+
const keyInput = await text({
|
|
2094
|
+
message: "Enter your FlyDocs API key",
|
|
2095
|
+
placeholder: "fdk_...",
|
|
2096
|
+
validate(value) {
|
|
2097
|
+
if (!value.trim()) return "API key is required";
|
|
2098
|
+
const type = detectKeyType(value.trim());
|
|
2099
|
+
if (type !== "relay")
|
|
2100
|
+
return "Cloud tier requires a FlyDocs API key (fdk_...)";
|
|
2101
|
+
return void 0;
|
|
2102
|
+
}
|
|
2103
|
+
});
|
|
2104
|
+
if (isCancel3(keyInput)) {
|
|
2105
|
+
cancel2("Installation cancelled.");
|
|
2106
|
+
process.exit(0);
|
|
2107
|
+
}
|
|
2108
|
+
const apiKey = keyInput.trim();
|
|
2109
|
+
printInfo("Validating API key...");
|
|
2110
|
+
try {
|
|
2111
|
+
const result = await validateRelayKey(apiKey);
|
|
2112
|
+
if (!result.valid) {
|
|
2113
|
+
printError("Invalid API key or relay API unreachable.");
|
|
2114
|
+
console.log(` Check your key and try again.`);
|
|
2115
|
+
process.exit(1);
|
|
2116
|
+
}
|
|
2117
|
+
printStatus(`Connected to ${pc6.bold(result.org)}`);
|
|
2118
|
+
} catch {
|
|
2119
|
+
printError(
|
|
2120
|
+
"Could not reach relay API. Check your network and try again."
|
|
2121
|
+
);
|
|
2122
|
+
process.exit(1);
|
|
2123
|
+
}
|
|
2124
|
+
const envFile = await storeEnvKey(targetDir, "FLYDOCS_API_KEY", apiKey);
|
|
2125
|
+
printStatus(`API key stored in ${pc6.dim(envFile)}`);
|
|
2126
|
+
console.log();
|
|
2127
|
+
printInfo("Fetching workspaces...");
|
|
2128
|
+
try {
|
|
2129
|
+
const workspaces = await fetchWorkspaces(apiKey);
|
|
2130
|
+
if (workspaces.length === 0) {
|
|
2131
|
+
printError(
|
|
2132
|
+
"No workspaces found. Create a workspace in the FlyDocs dashboard first, then re-run install."
|
|
2133
|
+
);
|
|
2134
|
+
process.exit(1);
|
|
2135
|
+
}
|
|
2136
|
+
if (workspaces.length === 1) {
|
|
2137
|
+
selectedWorkspaceId = workspaces[0].id;
|
|
2138
|
+
selectedWorkspaceName = workspaces[0].name;
|
|
2139
|
+
printStatus(
|
|
2140
|
+
`Workspace: ${pc6.bold(selectedWorkspaceName)} (auto-selected)`
|
|
2141
|
+
);
|
|
2142
|
+
} else {
|
|
2143
|
+
const workspaceChoice = await select({
|
|
2144
|
+
message: "Select a workspace",
|
|
2145
|
+
options: workspaces.map((ws) => ({
|
|
2146
|
+
value: ws.id,
|
|
2147
|
+
label: `${ws.name} (${ws.provider.type})`,
|
|
2148
|
+
hint: ws.team.name
|
|
2149
|
+
}))
|
|
2150
|
+
});
|
|
2151
|
+
if (isCancel3(workspaceChoice)) {
|
|
2152
|
+
cancel2("Installation cancelled.");
|
|
2153
|
+
process.exit(0);
|
|
2154
|
+
}
|
|
2155
|
+
selectedWorkspaceId = workspaceChoice;
|
|
2156
|
+
const chosen = workspaces.find((ws) => ws.id === selectedWorkspaceId);
|
|
2157
|
+
selectedWorkspaceName = chosen?.name ?? "Unknown";
|
|
2158
|
+
printStatus(`Workspace: ${pc6.bold(selectedWorkspaceName)}`);
|
|
2159
|
+
}
|
|
2160
|
+
} catch {
|
|
2161
|
+
printError(
|
|
2162
|
+
"Could not fetch workspaces. Check your network and try again."
|
|
2163
|
+
);
|
|
2164
|
+
process.exit(1);
|
|
2165
|
+
}
|
|
2166
|
+
}
|
|
2167
|
+
let skipConfigOverwrite = false;
|
|
2168
|
+
if (!await pathExists(join15(targetDir, ".git"))) {
|
|
1982
2169
|
printWarning("No git repository detected. Run git init when ready.");
|
|
1983
2170
|
}
|
|
1984
2171
|
await ensureDirectories(targetDir, tier);
|
|
1985
|
-
const
|
|
1986
|
-
if (
|
|
1987
|
-
|
|
1988
|
-
|
|
2172
|
+
const existingFiles = await detectExistingConfigs(targetDir);
|
|
2173
|
+
if (existingFiles.length > 0) {
|
|
2174
|
+
console.log();
|
|
2175
|
+
printWarning(
|
|
2176
|
+
`Found ${existingFiles.length} existing config file(s) that FlyDocs will overwrite:`
|
|
1989
2177
|
);
|
|
1990
|
-
for (const f of
|
|
1991
|
-
|
|
2178
|
+
for (const f of existingFiles) {
|
|
2179
|
+
console.log(` ${pc6.dim(f)}`);
|
|
2180
|
+
}
|
|
2181
|
+
console.log();
|
|
2182
|
+
if (!args.yes) {
|
|
2183
|
+
const overwriteChoice = await select({
|
|
2184
|
+
message: "How should FlyDocs handle these files?",
|
|
2185
|
+
options: [
|
|
2186
|
+
{
|
|
2187
|
+
value: "backup",
|
|
2188
|
+
label: "Overwrite (backed up)",
|
|
2189
|
+
hint: "Files are saved to .flydocs/backup-originals/ and restored on uninstall"
|
|
2190
|
+
},
|
|
2191
|
+
{
|
|
2192
|
+
value: "skip",
|
|
2193
|
+
label: "Skip overwriting",
|
|
2194
|
+
hint: "Keep your existing files \u2014 FlyDocs config may be incomplete"
|
|
2195
|
+
}
|
|
2196
|
+
]
|
|
2197
|
+
});
|
|
2198
|
+
if (isCancel3(overwriteChoice)) {
|
|
2199
|
+
cancel2("Installation cancelled.");
|
|
2200
|
+
process.exit(0);
|
|
2201
|
+
}
|
|
2202
|
+
if (overwriteChoice === "skip") {
|
|
2203
|
+
printInfo(
|
|
2204
|
+
"Keeping existing files. Run /flydocs-setup to merge your config manually."
|
|
2205
|
+
);
|
|
2206
|
+
skipConfigOverwrite = true;
|
|
2207
|
+
}
|
|
2208
|
+
}
|
|
2209
|
+
if (!skipConfigOverwrite) {
|
|
2210
|
+
const backedUp = await backupOriginals(targetDir);
|
|
2211
|
+
if (backedUp.length > 0) {
|
|
2212
|
+
printStatus(
|
|
2213
|
+
`Backed up ${backedUp.length} file(s) to .flydocs/backup-originals/`
|
|
2214
|
+
);
|
|
2215
|
+
}
|
|
1992
2216
|
}
|
|
1993
2217
|
}
|
|
1994
2218
|
console.log("Installing framework files...");
|
|
1995
2219
|
await replaceDirectory(
|
|
1996
|
-
|
|
1997
|
-
|
|
2220
|
+
join15(templateDir, ".flydocs", "templates"),
|
|
2221
|
+
join15(targetDir, ".flydocs", "templates")
|
|
1998
2222
|
);
|
|
1999
2223
|
await replaceDirectory(
|
|
2000
|
-
|
|
2001
|
-
|
|
2224
|
+
join15(templateDir, ".flydocs", "hooks"),
|
|
2225
|
+
join15(targetDir, ".flydocs", "hooks")
|
|
2002
2226
|
);
|
|
2003
2227
|
await replaceDirectory(
|
|
2004
|
-
|
|
2005
|
-
|
|
2228
|
+
join15(templateDir, ".flydocs", "scripts"),
|
|
2229
|
+
join15(targetDir, ".flydocs", "scripts")
|
|
2006
2230
|
);
|
|
2007
2231
|
await copyFile(
|
|
2008
|
-
|
|
2009
|
-
|
|
2232
|
+
join15(templateDir, ".flydocs", "version"),
|
|
2233
|
+
join15(targetDir, ".flydocs", "version")
|
|
2010
2234
|
);
|
|
2011
|
-
const manifestSrc =
|
|
2235
|
+
const manifestSrc = join15(templateDir, "manifest.json");
|
|
2012
2236
|
if (await pathExists(manifestSrc)) {
|
|
2013
|
-
await copyFile(manifestSrc,
|
|
2237
|
+
await copyFile(manifestSrc, join15(targetDir, ".flydocs", "manifest.json"));
|
|
2014
2238
|
}
|
|
2015
|
-
const changelogSrc =
|
|
2239
|
+
const changelogSrc = join15(templateDir, "CHANGELOG.md");
|
|
2016
2240
|
if (await pathExists(changelogSrc)) {
|
|
2017
|
-
await copyFile(changelogSrc,
|
|
2241
|
+
await copyFile(changelogSrc, join15(targetDir, ".flydocs", "CHANGELOG.md"));
|
|
2018
2242
|
}
|
|
2019
2243
|
printStatus(".flydocs/templates, hooks, version, manifest, changelog");
|
|
2020
|
-
const configPath =
|
|
2244
|
+
const configPath = join15(targetDir, ".flydocs", "config.json");
|
|
2021
2245
|
if (!await pathExists(configPath)) {
|
|
2022
2246
|
const config = await createFreshConfig(templateDir, version, tier);
|
|
2247
|
+
if (selectedWorkspaceId) {
|
|
2248
|
+
config.workspaceId = selectedWorkspaceId;
|
|
2249
|
+
}
|
|
2023
2250
|
await writeConfig(targetDir, config);
|
|
2024
2251
|
printStatus(`.flydocs/config.json (new, tier: ${tier})`);
|
|
2025
2252
|
} else if (args.tier) {
|
|
@@ -2027,15 +2254,34 @@ var init_install = __esm({
|
|
|
2027
2254
|
const existing = await readConfig(targetDir);
|
|
2028
2255
|
existing.version = version;
|
|
2029
2256
|
existing.tier = tier;
|
|
2257
|
+
if (selectedWorkspaceId) {
|
|
2258
|
+
existing.workspaceId = selectedWorkspaceId;
|
|
2259
|
+
}
|
|
2030
2260
|
await writeConfig(targetDir, existing);
|
|
2031
2261
|
printStatus(`.flydocs/config.json (tier updated: ${tier})`);
|
|
2032
2262
|
} catch {
|
|
2033
2263
|
const config = await createFreshConfig(templateDir, version, tier);
|
|
2264
|
+
if (selectedWorkspaceId) {
|
|
2265
|
+
config.workspaceId = selectedWorkspaceId;
|
|
2266
|
+
}
|
|
2034
2267
|
await writeConfig(targetDir, config);
|
|
2035
2268
|
printStatus(`.flydocs/config.json (recreated, tier: ${tier})`);
|
|
2036
2269
|
}
|
|
2037
2270
|
} else {
|
|
2038
|
-
|
|
2271
|
+
if (selectedWorkspaceId) {
|
|
2272
|
+
try {
|
|
2273
|
+
const existing = await readConfig(targetDir);
|
|
2274
|
+
existing.workspaceId = selectedWorkspaceId;
|
|
2275
|
+
await writeConfig(targetDir, existing);
|
|
2276
|
+
printWarning(
|
|
2277
|
+
".flydocs/config.json exists, preserving (workspace updated)"
|
|
2278
|
+
);
|
|
2279
|
+
} catch {
|
|
2280
|
+
printWarning(".flydocs/config.json exists, preserving");
|
|
2281
|
+
}
|
|
2282
|
+
} else {
|
|
2283
|
+
printWarning(".flydocs/config.json exists, preserving");
|
|
2284
|
+
}
|
|
2039
2285
|
}
|
|
2040
2286
|
console.log();
|
|
2041
2287
|
console.log(`Installing skills (tier: ${tier})...`);
|
|
@@ -2071,20 +2317,20 @@ var init_install = __esm({
|
|
|
2071
2317
|
}
|
|
2072
2318
|
await capture("install_agents_chosen", { install_agents: installAgents });
|
|
2073
2319
|
if (installAgents) {
|
|
2074
|
-
const claudeAgentsSrc =
|
|
2320
|
+
const claudeAgentsSrc = join15(templateDir, ".claude", "agents");
|
|
2075
2321
|
if (await pathExists(claudeAgentsSrc)) {
|
|
2076
|
-
await mkdir7(
|
|
2322
|
+
await mkdir7(join15(targetDir, ".claude", "agents"), { recursive: true });
|
|
2077
2323
|
await copyDirectoryContents(
|
|
2078
2324
|
claudeAgentsSrc,
|
|
2079
|
-
|
|
2325
|
+
join15(targetDir, ".claude", "agents")
|
|
2080
2326
|
);
|
|
2081
2327
|
}
|
|
2082
|
-
const cursorAgentsSrc =
|
|
2328
|
+
const cursorAgentsSrc = join15(templateDir, ".cursor", "agents");
|
|
2083
2329
|
if (await pathExists(cursorAgentsSrc)) {
|
|
2084
|
-
await mkdir7(
|
|
2330
|
+
await mkdir7(join15(targetDir, ".cursor", "agents"), { recursive: true });
|
|
2085
2331
|
await copyDirectoryContents(
|
|
2086
2332
|
cursorAgentsSrc,
|
|
2087
|
-
|
|
2333
|
+
join15(targetDir, ".cursor", "agents")
|
|
2088
2334
|
);
|
|
2089
2335
|
}
|
|
2090
2336
|
printStatus("Sub-agents installed (.claude/agents, .cursor/agents)");
|
|
@@ -2094,74 +2340,86 @@ var init_install = __esm({
|
|
|
2094
2340
|
console.log();
|
|
2095
2341
|
console.log("Installing commands and settings...");
|
|
2096
2342
|
await copyDirectoryContents(
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
);
|
|
2100
|
-
await copyFile(
|
|
2101
|
-
join14(templateDir, ".claude", "CLAUDE.md"),
|
|
2102
|
-
join14(targetDir, ".claude", "CLAUDE.md")
|
|
2103
|
-
);
|
|
2104
|
-
await copyFile(
|
|
2105
|
-
join14(templateDir, ".claude", "settings.json"),
|
|
2106
|
-
join14(targetDir, ".claude", "settings.json")
|
|
2343
|
+
join15(templateDir, ".claude", "commands"),
|
|
2344
|
+
join15(targetDir, ".claude", "commands")
|
|
2107
2345
|
);
|
|
2108
|
-
|
|
2346
|
+
if (!skipConfigOverwrite) {
|
|
2347
|
+
await copyFile(
|
|
2348
|
+
join15(templateDir, ".claude", "CLAUDE.md"),
|
|
2349
|
+
join15(targetDir, ".claude", "CLAUDE.md")
|
|
2350
|
+
);
|
|
2351
|
+
await copyFile(
|
|
2352
|
+
join15(templateDir, ".claude", "settings.json"),
|
|
2353
|
+
join15(targetDir, ".claude", "settings.json")
|
|
2354
|
+
);
|
|
2355
|
+
printStatus(".claude/ (commands, CLAUDE.md, settings)");
|
|
2356
|
+
} else {
|
|
2357
|
+
printStatus(".claude/ (commands only \u2014 existing config preserved)");
|
|
2358
|
+
}
|
|
2109
2359
|
await copyDirectoryContents(
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
);
|
|
2113
|
-
await copyFile(
|
|
2114
|
-
join14(templateDir, ".cursor", "hooks.json"),
|
|
2115
|
-
join14(targetDir, ".cursor", "hooks.json")
|
|
2360
|
+
join15(templateDir, ".claude", "commands"),
|
|
2361
|
+
join15(targetDir, ".cursor", "commands")
|
|
2116
2362
|
);
|
|
2117
|
-
|
|
2363
|
+
if (!skipConfigOverwrite) {
|
|
2364
|
+
await copyFile(
|
|
2365
|
+
join15(templateDir, ".cursor", "hooks.json"),
|
|
2366
|
+
join15(targetDir, ".cursor", "hooks.json")
|
|
2367
|
+
);
|
|
2368
|
+
printStatus(".cursor/ (commands, hooks)");
|
|
2369
|
+
} else {
|
|
2370
|
+
printStatus(".cursor/ (commands only \u2014 existing hooks preserved)");
|
|
2371
|
+
}
|
|
2118
2372
|
await copyCursorRules(targetDir);
|
|
2119
2373
|
printStatus(".cursor/rules/");
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2374
|
+
if (!skipConfigOverwrite) {
|
|
2375
|
+
await copyFile(
|
|
2376
|
+
join15(templateDir, "AGENTS.md"),
|
|
2377
|
+
join15(targetDir, "AGENTS.md")
|
|
2378
|
+
);
|
|
2379
|
+
printStatus("AGENTS.md");
|
|
2380
|
+
} else {
|
|
2381
|
+
printInfo("AGENTS.md preserved (existing)");
|
|
2382
|
+
}
|
|
2125
2383
|
await runManifestGeneration(targetDir);
|
|
2126
2384
|
await runContextGraphBuild(targetDir);
|
|
2127
2385
|
console.log();
|
|
2128
2386
|
console.log("Installing project templates...");
|
|
2129
2387
|
const userFiles = [
|
|
2130
2388
|
{
|
|
2131
|
-
src:
|
|
2132
|
-
dest:
|
|
2389
|
+
src: join15(templateDir, "flydocs", "context", "project.md"),
|
|
2390
|
+
dest: join15(targetDir, "flydocs", "context", "project.md"),
|
|
2133
2391
|
label: "flydocs/context/project.md"
|
|
2134
2392
|
},
|
|
2135
2393
|
{
|
|
2136
|
-
src:
|
|
2137
|
-
dest:
|
|
2394
|
+
src: join15(templateDir, "flydocs", "knowledge", "INDEX.md"),
|
|
2395
|
+
dest: join15(targetDir, "flydocs", "knowledge", "INDEX.md"),
|
|
2138
2396
|
label: "flydocs/knowledge/INDEX.md"
|
|
2139
2397
|
},
|
|
2140
2398
|
{
|
|
2141
|
-
src:
|
|
2142
|
-
dest:
|
|
2399
|
+
src: join15(templateDir, "flydocs", "knowledge", "README.md"),
|
|
2400
|
+
dest: join15(targetDir, "flydocs", "knowledge", "README.md"),
|
|
2143
2401
|
label: "flydocs/knowledge/README.md"
|
|
2144
2402
|
},
|
|
2145
2403
|
{
|
|
2146
|
-
src:
|
|
2404
|
+
src: join15(
|
|
2147
2405
|
templateDir,
|
|
2148
2406
|
"flydocs",
|
|
2149
2407
|
"knowledge",
|
|
2150
2408
|
"product",
|
|
2151
2409
|
"personas.md"
|
|
2152
2410
|
),
|
|
2153
|
-
dest:
|
|
2411
|
+
dest: join15(targetDir, "flydocs", "knowledge", "product", "personas.md"),
|
|
2154
2412
|
label: "flydocs/knowledge/product/personas.md"
|
|
2155
2413
|
},
|
|
2156
2414
|
{
|
|
2157
|
-
src:
|
|
2415
|
+
src: join15(
|
|
2158
2416
|
templateDir,
|
|
2159
2417
|
"flydocs",
|
|
2160
2418
|
"knowledge",
|
|
2161
2419
|
"product",
|
|
2162
2420
|
"user-flows.md"
|
|
2163
2421
|
),
|
|
2164
|
-
dest:
|
|
2422
|
+
dest: join15(
|
|
2165
2423
|
targetDir,
|
|
2166
2424
|
"flydocs",
|
|
2167
2425
|
"knowledge",
|
|
@@ -2171,18 +2429,57 @@ var init_install = __esm({
|
|
|
2171
2429
|
label: "flydocs/knowledge/product/user-flows.md"
|
|
2172
2430
|
},
|
|
2173
2431
|
{
|
|
2174
|
-
src:
|
|
2175
|
-
|
|
2432
|
+
src: join15(
|
|
2433
|
+
templateDir,
|
|
2434
|
+
"flydocs",
|
|
2435
|
+
"knowledge",
|
|
2436
|
+
"templates",
|
|
2437
|
+
"decision.md"
|
|
2438
|
+
),
|
|
2439
|
+
dest: join15(
|
|
2440
|
+
targetDir,
|
|
2441
|
+
"flydocs",
|
|
2442
|
+
"knowledge",
|
|
2443
|
+
"templates",
|
|
2444
|
+
"decision.md"
|
|
2445
|
+
),
|
|
2446
|
+
label: "flydocs/knowledge/templates/decision.md"
|
|
2447
|
+
},
|
|
2448
|
+
{
|
|
2449
|
+
src: join15(
|
|
2450
|
+
templateDir,
|
|
2451
|
+
"flydocs",
|
|
2452
|
+
"knowledge",
|
|
2453
|
+
"templates",
|
|
2454
|
+
"feature.md"
|
|
2455
|
+
),
|
|
2456
|
+
dest: join15(
|
|
2457
|
+
targetDir,
|
|
2458
|
+
"flydocs",
|
|
2459
|
+
"knowledge",
|
|
2460
|
+
"templates",
|
|
2461
|
+
"feature.md"
|
|
2462
|
+
),
|
|
2463
|
+
label: "flydocs/knowledge/templates/feature.md"
|
|
2464
|
+
},
|
|
2465
|
+
{
|
|
2466
|
+
src: join15(templateDir, "flydocs", "knowledge", "templates", "note.md"),
|
|
2467
|
+
dest: join15(targetDir, "flydocs", "knowledge", "templates", "note.md"),
|
|
2468
|
+
label: "flydocs/knowledge/templates/note.md"
|
|
2469
|
+
},
|
|
2470
|
+
{
|
|
2471
|
+
src: join15(templateDir, "flydocs", "design-system", "README.md"),
|
|
2472
|
+
dest: join15(targetDir, "flydocs", "design-system", "README.md"),
|
|
2176
2473
|
label: "flydocs/design-system/README.md"
|
|
2177
2474
|
},
|
|
2178
2475
|
{
|
|
2179
|
-
src:
|
|
2476
|
+
src: join15(
|
|
2180
2477
|
templateDir,
|
|
2181
2478
|
"flydocs",
|
|
2182
2479
|
"design-system",
|
|
2183
2480
|
"component-patterns.md"
|
|
2184
2481
|
),
|
|
2185
|
-
dest:
|
|
2482
|
+
dest: join15(
|
|
2186
2483
|
targetDir,
|
|
2187
2484
|
"flydocs",
|
|
2188
2485
|
"design-system",
|
|
@@ -2191,13 +2488,13 @@ var init_install = __esm({
|
|
|
2191
2488
|
label: "flydocs/design-system/component-patterns.md"
|
|
2192
2489
|
},
|
|
2193
2490
|
{
|
|
2194
|
-
src:
|
|
2195
|
-
dest:
|
|
2491
|
+
src: join15(templateDir, "flydocs", "design-system", "token-mapping.md"),
|
|
2492
|
+
dest: join15(targetDir, "flydocs", "design-system", "token-mapping.md"),
|
|
2196
2493
|
label: "flydocs/design-system/token-mapping.md"
|
|
2197
2494
|
},
|
|
2198
2495
|
{
|
|
2199
|
-
src:
|
|
2200
|
-
dest:
|
|
2496
|
+
src: join15(templateDir, "flydocs", "README.md"),
|
|
2497
|
+
dest: join15(targetDir, "flydocs", "README.md"),
|
|
2201
2498
|
label: "flydocs/README.md"
|
|
2202
2499
|
}
|
|
2203
2500
|
];
|
|
@@ -2211,9 +2508,9 @@ var init_install = __esm({
|
|
|
2211
2508
|
}
|
|
2212
2509
|
}
|
|
2213
2510
|
}
|
|
2214
|
-
const envExampleSrc =
|
|
2511
|
+
const envExampleSrc = join15(templateDir, ".env.example");
|
|
2215
2512
|
if (await pathExists(envExampleSrc)) {
|
|
2216
|
-
await copyFile(envExampleSrc,
|
|
2513
|
+
await copyFile(envExampleSrc, join15(targetDir, ".env.example"));
|
|
2217
2514
|
printStatus(".env.example");
|
|
2218
2515
|
}
|
|
2219
2516
|
await ensureGitignore(targetDir);
|
|
@@ -2253,9 +2550,8 @@ var init_install = __esm({
|
|
|
2253
2550
|
`Version: ${version}`,
|
|
2254
2551
|
"",
|
|
2255
2552
|
"Next steps:",
|
|
2256
|
-
" 1. Run flydocs
|
|
2257
|
-
" 2.
|
|
2258
|
-
" 3. Start working with /start-session",
|
|
2553
|
+
" 1. Run /flydocs-setup to configure your workspace",
|
|
2554
|
+
" 2. Start working with /start-session",
|
|
2259
2555
|
"",
|
|
2260
2556
|
"Docs: https://www.flydocs.ai/docs"
|
|
2261
2557
|
];
|
|
@@ -2392,9 +2688,9 @@ __export(update_exports, {
|
|
|
2392
2688
|
default: () => update_default
|
|
2393
2689
|
});
|
|
2394
2690
|
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";
|
|
2691
|
+
import { resolve as resolve3, join as join16 } from "path";
|
|
2692
|
+
import { mkdir as mkdir8, cp as cp2, readFile as readFile11, readdir as readdir3, rm as rm4 } from "fs/promises";
|
|
2693
|
+
import { select as select2, text as text2, confirm as confirm3, isCancel as isCancel4, cancel as cancel3 } from "@clack/prompts";
|
|
2398
2694
|
import pc7 from "picocolors";
|
|
2399
2695
|
var update_default;
|
|
2400
2696
|
var init_update = __esm({
|
|
@@ -2482,7 +2778,7 @@ var init_update = __esm({
|
|
|
2482
2778
|
if (choice === "cwd") {
|
|
2483
2779
|
targetDir = process.cwd();
|
|
2484
2780
|
} else {
|
|
2485
|
-
const enteredPath = await
|
|
2781
|
+
const enteredPath = await text2({
|
|
2486
2782
|
message: "Enter project path:"
|
|
2487
2783
|
});
|
|
2488
2784
|
if (isCancel4(enteredPath)) {
|
|
@@ -2500,9 +2796,9 @@ var init_update = __esm({
|
|
|
2500
2796
|
}
|
|
2501
2797
|
targetDir = resolve3(targetDir);
|
|
2502
2798
|
process.chdir(targetDir);
|
|
2503
|
-
const hasVersion = await pathExists(
|
|
2799
|
+
const hasVersion = await pathExists(join16(targetDir, ".flydocs", "version"));
|
|
2504
2800
|
const hasConfig = await pathExists(
|
|
2505
|
-
|
|
2801
|
+
join16(targetDir, ".flydocs", "config.json")
|
|
2506
2802
|
);
|
|
2507
2803
|
if (!hasVersion && !hasConfig) {
|
|
2508
2804
|
printError(`Not a FlyDocs project: ${targetDir}`);
|
|
@@ -2513,8 +2809,8 @@ var init_update = __esm({
|
|
|
2513
2809
|
console.log();
|
|
2514
2810
|
let currentVersion = "0.1.0";
|
|
2515
2811
|
if (hasVersion) {
|
|
2516
|
-
const vContent = await
|
|
2517
|
-
|
|
2812
|
+
const vContent = await readFile11(
|
|
2813
|
+
join16(targetDir, ".flydocs", "version"),
|
|
2518
2814
|
"utf-8"
|
|
2519
2815
|
);
|
|
2520
2816
|
currentVersion = vContent.trim();
|
|
@@ -2548,7 +2844,7 @@ var init_update = __esm({
|
|
|
2548
2844
|
});
|
|
2549
2845
|
console.log(`Updating: v${currentVersion} \u2192 v${version}`);
|
|
2550
2846
|
console.log();
|
|
2551
|
-
const changelogPath =
|
|
2847
|
+
const changelogPath = join16(templateDir, "CHANGELOG.md");
|
|
2552
2848
|
const whatsNew = await getWhatsNew(changelogPath, currentVersion, version);
|
|
2553
2849
|
if (whatsNew.length > 0) {
|
|
2554
2850
|
console.log(pc7.cyan("What's new:"));
|
|
@@ -2560,23 +2856,23 @@ var init_update = __esm({
|
|
|
2560
2856
|
}
|
|
2561
2857
|
const now = /* @__PURE__ */ new Date();
|
|
2562
2858
|
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 =
|
|
2859
|
+
const backupDir = join16(targetDir, ".flydocs", `backup-${ts}`);
|
|
2564
2860
|
await mkdir8(backupDir, { recursive: true });
|
|
2565
2861
|
if (hasConfig) {
|
|
2566
2862
|
await cp2(
|
|
2567
|
-
|
|
2568
|
-
|
|
2863
|
+
join16(targetDir, ".flydocs", "config.json"),
|
|
2864
|
+
join16(backupDir, "config.json")
|
|
2569
2865
|
);
|
|
2570
2866
|
printStatus(`Config backed up to .flydocs/backup-${ts}/`);
|
|
2571
2867
|
}
|
|
2572
2868
|
try {
|
|
2573
|
-
const flydocsDir =
|
|
2869
|
+
const flydocsDir = join16(targetDir, ".flydocs");
|
|
2574
2870
|
const entries = await readdir3(flydocsDir);
|
|
2575
2871
|
const backups = entries.filter((e) => e.startsWith("backup-")).sort();
|
|
2576
2872
|
if (backups.length > 3) {
|
|
2577
2873
|
const toRemove = backups.slice(0, backups.length - 3);
|
|
2578
2874
|
for (const old of toRemove) {
|
|
2579
|
-
await rm4(
|
|
2875
|
+
await rm4(join16(flydocsDir, old), { recursive: true, force: true });
|
|
2580
2876
|
}
|
|
2581
2877
|
}
|
|
2582
2878
|
} catch {
|
|
@@ -2584,10 +2880,9 @@ var init_update = __esm({
|
|
|
2584
2880
|
let preserved = {
|
|
2585
2881
|
tier: "cloud",
|
|
2586
2882
|
setupComplete: false,
|
|
2587
|
-
|
|
2883
|
+
workspaceId: null,
|
|
2588
2884
|
workspace: {},
|
|
2589
2885
|
issueLabels: {},
|
|
2590
|
-
statusMapping: {},
|
|
2591
2886
|
detectedStack: {},
|
|
2592
2887
|
skills: {},
|
|
2593
2888
|
designSystem: null,
|
|
@@ -2611,22 +2906,23 @@ var init_update = __esm({
|
|
|
2611
2906
|
} else {
|
|
2612
2907
|
effectiveTier = preserved.tier;
|
|
2613
2908
|
}
|
|
2909
|
+
await ensureDirectories(targetDir, effectiveTier);
|
|
2614
2910
|
console.log("Replacing framework directories...");
|
|
2615
2911
|
await replaceDirectory(
|
|
2616
|
-
|
|
2617
|
-
|
|
2912
|
+
join16(templateDir, ".flydocs", "templates"),
|
|
2913
|
+
join16(targetDir, ".flydocs", "templates")
|
|
2618
2914
|
);
|
|
2619
2915
|
await replaceDirectory(
|
|
2620
|
-
|
|
2621
|
-
|
|
2916
|
+
join16(templateDir, ".flydocs", "hooks"),
|
|
2917
|
+
join16(targetDir, ".flydocs", "hooks")
|
|
2622
2918
|
);
|
|
2623
2919
|
await replaceDirectory(
|
|
2624
|
-
|
|
2625
|
-
|
|
2920
|
+
join16(templateDir, ".flydocs", "scripts"),
|
|
2921
|
+
join16(targetDir, ".flydocs", "scripts")
|
|
2626
2922
|
);
|
|
2627
2923
|
printStatus(".flydocs/templates, hooks, scripts");
|
|
2628
2924
|
const hasExistingAgents = await pathExists(
|
|
2629
|
-
|
|
2925
|
+
join16(targetDir, ".claude", "agents")
|
|
2630
2926
|
);
|
|
2631
2927
|
let installAgents;
|
|
2632
2928
|
if (args.yes) {
|
|
@@ -2658,20 +2954,20 @@ var init_update = __esm({
|
|
|
2658
2954
|
}
|
|
2659
2955
|
}
|
|
2660
2956
|
if (installAgents) {
|
|
2661
|
-
const claudeAgentsSrc =
|
|
2957
|
+
const claudeAgentsSrc = join16(templateDir, ".claude", "agents");
|
|
2662
2958
|
if (await pathExists(claudeAgentsSrc)) {
|
|
2663
|
-
await mkdir8(
|
|
2959
|
+
await mkdir8(join16(targetDir, ".claude", "agents"), { recursive: true });
|
|
2664
2960
|
await copyDirectoryContents(
|
|
2665
2961
|
claudeAgentsSrc,
|
|
2666
|
-
|
|
2962
|
+
join16(targetDir, ".claude", "agents")
|
|
2667
2963
|
);
|
|
2668
2964
|
}
|
|
2669
|
-
const cursorAgentsSrc =
|
|
2965
|
+
const cursorAgentsSrc = join16(templateDir, ".cursor", "agents");
|
|
2670
2966
|
if (await pathExists(cursorAgentsSrc)) {
|
|
2671
|
-
await mkdir8(
|
|
2967
|
+
await mkdir8(join16(targetDir, ".cursor", "agents"), { recursive: true });
|
|
2672
2968
|
await copyDirectoryContents(
|
|
2673
2969
|
cursorAgentsSrc,
|
|
2674
|
-
|
|
2970
|
+
join16(targetDir, ".cursor", "agents")
|
|
2675
2971
|
);
|
|
2676
2972
|
}
|
|
2677
2973
|
printStatus(
|
|
@@ -2685,46 +2981,62 @@ var init_update = __esm({
|
|
|
2685
2981
|
console.log();
|
|
2686
2982
|
console.log("Replacing framework files...");
|
|
2687
2983
|
await copyFile(
|
|
2688
|
-
|
|
2689
|
-
|
|
2984
|
+
join16(templateDir, ".claude", "CLAUDE.md"),
|
|
2985
|
+
join16(targetDir, ".claude", "CLAUDE.md")
|
|
2690
2986
|
);
|
|
2691
2987
|
await copyFile(
|
|
2692
|
-
|
|
2693
|
-
|
|
2988
|
+
join16(templateDir, ".claude", "settings.json"),
|
|
2989
|
+
join16(targetDir, ".claude", "settings.json")
|
|
2694
2990
|
);
|
|
2695
2991
|
printStatus(".claude/CLAUDE.md, settings.json");
|
|
2696
2992
|
await copyDirectoryContents(
|
|
2697
|
-
|
|
2698
|
-
|
|
2993
|
+
join16(templateDir, ".claude", "commands"),
|
|
2994
|
+
join16(targetDir, ".claude", "commands")
|
|
2699
2995
|
);
|
|
2700
2996
|
await copyDirectoryContents(
|
|
2701
|
-
|
|
2702
|
-
|
|
2997
|
+
join16(templateDir, ".claude", "commands"),
|
|
2998
|
+
join16(targetDir, ".cursor", "commands")
|
|
2703
2999
|
);
|
|
2704
3000
|
printStatus(".claude/commands, .cursor/commands");
|
|
2705
|
-
const skillsReadmeSrc =
|
|
3001
|
+
const skillsReadmeSrc = join16(templateDir, ".claude", "skills", "README.md");
|
|
2706
3002
|
if (await pathExists(skillsReadmeSrc)) {
|
|
2707
3003
|
await copyFile(
|
|
2708
3004
|
skillsReadmeSrc,
|
|
2709
|
-
|
|
3005
|
+
join16(targetDir, ".claude", "skills", "README.md")
|
|
2710
3006
|
);
|
|
2711
3007
|
}
|
|
2712
3008
|
printStatus(".claude/skills/README.md");
|
|
2713
3009
|
await copyFile(
|
|
2714
|
-
|
|
2715
|
-
|
|
3010
|
+
join16(templateDir, ".cursor", "hooks.json"),
|
|
3011
|
+
join16(targetDir, ".cursor", "hooks.json")
|
|
2716
3012
|
);
|
|
2717
3013
|
printStatus(".cursor/hooks.json");
|
|
2718
3014
|
await copyFile(
|
|
2719
|
-
|
|
2720
|
-
|
|
3015
|
+
join16(templateDir, "AGENTS.md"),
|
|
3016
|
+
join16(targetDir, "AGENTS.md")
|
|
2721
3017
|
);
|
|
2722
3018
|
printStatus("AGENTS.md");
|
|
2723
|
-
const envExampleSrc =
|
|
3019
|
+
const envExampleSrc = join16(templateDir, ".env.example");
|
|
2724
3020
|
if (await pathExists(envExampleSrc)) {
|
|
2725
|
-
await copyFile(envExampleSrc,
|
|
3021
|
+
await copyFile(envExampleSrc, join16(targetDir, ".env.example"));
|
|
2726
3022
|
printStatus(".env.example");
|
|
2727
3023
|
}
|
|
3024
|
+
const knowledgeTemplatesDir = join16(
|
|
3025
|
+
targetDir,
|
|
3026
|
+
"flydocs",
|
|
3027
|
+
"knowledge",
|
|
3028
|
+
"templates"
|
|
3029
|
+
);
|
|
3030
|
+
if (!await pathExists(knowledgeTemplatesDir)) {
|
|
3031
|
+
await mkdir8(knowledgeTemplatesDir, { recursive: true });
|
|
3032
|
+
}
|
|
3033
|
+
for (const tmpl of ["decision.md", "feature.md", "note.md"]) {
|
|
3034
|
+
const src = join16(templateDir, "flydocs", "knowledge", "templates", tmpl);
|
|
3035
|
+
const dest = join16(knowledgeTemplatesDir, tmpl);
|
|
3036
|
+
if (await pathExists(src) && !await pathExists(dest)) {
|
|
3037
|
+
await copyFile(src, dest);
|
|
3038
|
+
}
|
|
3039
|
+
}
|
|
2728
3040
|
await runManifestGeneration(targetDir);
|
|
2729
3041
|
await runContextGraphBuild(targetDir);
|
|
2730
3042
|
console.log();
|
|
@@ -2747,18 +3059,18 @@ var init_update = __esm({
|
|
|
2747
3059
|
printWarning("Config merge failed \u2014 config.json preserved as-is");
|
|
2748
3060
|
}
|
|
2749
3061
|
await copyFile(
|
|
2750
|
-
|
|
2751
|
-
|
|
3062
|
+
join16(templateDir, ".flydocs", "version"),
|
|
3063
|
+
join16(targetDir, ".flydocs", "version")
|
|
2752
3064
|
);
|
|
2753
3065
|
printStatus(`.flydocs/version \u2192 ${version}`);
|
|
2754
|
-
const clSrc =
|
|
3066
|
+
const clSrc = join16(templateDir, "CHANGELOG.md");
|
|
2755
3067
|
if (await pathExists(clSrc)) {
|
|
2756
|
-
await copyFile(clSrc,
|
|
3068
|
+
await copyFile(clSrc, join16(targetDir, ".flydocs", "CHANGELOG.md"));
|
|
2757
3069
|
printStatus(".flydocs/CHANGELOG.md");
|
|
2758
3070
|
}
|
|
2759
|
-
const mfSrc =
|
|
3071
|
+
const mfSrc = join16(templateDir, "manifest.json");
|
|
2760
3072
|
if (await pathExists(mfSrc)) {
|
|
2761
|
-
await copyFile(mfSrc,
|
|
3073
|
+
await copyFile(mfSrc, join16(targetDir, ".flydocs", "manifest.json"));
|
|
2762
3074
|
printStatus(".flydocs/manifest.json");
|
|
2763
3075
|
}
|
|
2764
3076
|
console.log();
|
|
@@ -2818,12 +3130,12 @@ __export(uninstall_exports, {
|
|
|
2818
3130
|
default: () => uninstall_default
|
|
2819
3131
|
});
|
|
2820
3132
|
import { defineCommand as defineCommand3 } from "citty";
|
|
2821
|
-
import { resolve as resolve4, join as
|
|
3133
|
+
import { resolve as resolve4, join as join17 } from "path";
|
|
2822
3134
|
import { readdir as readdir4, rm as rm5, rename as rename2 } from "fs/promises";
|
|
2823
3135
|
import { confirm as confirm4, select as select3, isCancel as isCancel5, cancel as cancel4 } from "@clack/prompts";
|
|
2824
3136
|
import pc8 from "picocolors";
|
|
2825
3137
|
async function removeOwnedSkills(targetDir) {
|
|
2826
|
-
const skillsDir =
|
|
3138
|
+
const skillsDir = join17(targetDir, ".claude", "skills");
|
|
2827
3139
|
const removed = [];
|
|
2828
3140
|
if (!await pathExists(skillsDir)) {
|
|
2829
3141
|
return removed;
|
|
@@ -2832,7 +3144,7 @@ async function removeOwnedSkills(targetDir) {
|
|
|
2832
3144
|
const entries = await readdir4(skillsDir);
|
|
2833
3145
|
for (const entry of entries) {
|
|
2834
3146
|
if (entry.startsWith(OWNED_SKILL_PREFIX)) {
|
|
2835
|
-
await rm5(
|
|
3147
|
+
await rm5(join17(skillsDir, entry), { recursive: true, force: true });
|
|
2836
3148
|
removed.push(`.claude/skills/${entry}`);
|
|
2837
3149
|
}
|
|
2838
3150
|
}
|
|
@@ -2841,7 +3153,7 @@ async function removeOwnedSkills(targetDir) {
|
|
|
2841
3153
|
return removed;
|
|
2842
3154
|
}
|
|
2843
3155
|
async function removeOwnedCursorRules(targetDir) {
|
|
2844
|
-
const rulesDir =
|
|
3156
|
+
const rulesDir = join17(targetDir, ".cursor", "rules");
|
|
2845
3157
|
const removed = [];
|
|
2846
3158
|
if (!await pathExists(rulesDir)) {
|
|
2847
3159
|
return removed;
|
|
@@ -2850,7 +3162,7 @@ async function removeOwnedCursorRules(targetDir) {
|
|
|
2850
3162
|
const entries = await readdir4(rulesDir);
|
|
2851
3163
|
for (const entry of entries) {
|
|
2852
3164
|
if (entry.startsWith(OWNED_RULE_PREFIX) && entry.endsWith(".mdc")) {
|
|
2853
|
-
await rm5(
|
|
3165
|
+
await rm5(join17(rulesDir, entry), { force: true });
|
|
2854
3166
|
removed.push(`.cursor/rules/${entry}`);
|
|
2855
3167
|
}
|
|
2856
3168
|
}
|
|
@@ -2869,7 +3181,7 @@ async function isEmptyDir(dirPath) {
|
|
|
2869
3181
|
async function cleanupEmptyParents(targetDir, dirs) {
|
|
2870
3182
|
const cleaned = [];
|
|
2871
3183
|
for (const dir of dirs) {
|
|
2872
|
-
const fullPath =
|
|
3184
|
+
const fullPath = join17(targetDir, dir);
|
|
2873
3185
|
if (await pathExists(fullPath) && await isEmptyDir(fullPath)) {
|
|
2874
3186
|
await rm5(fullPath, { recursive: true, force: true });
|
|
2875
3187
|
cleaned.push(dir);
|
|
@@ -2946,8 +3258,8 @@ var init_uninstall = __esm({
|
|
|
2946
3258
|
process.exit(1);
|
|
2947
3259
|
}
|
|
2948
3260
|
targetDir = resolve4(targetDir);
|
|
2949
|
-
const hasFlydocs = await pathExists(
|
|
2950
|
-
const hasAgentsMd = await pathExists(
|
|
3261
|
+
const hasFlydocs = await pathExists(join17(targetDir, ".flydocs"));
|
|
3262
|
+
const hasAgentsMd = await pathExists(join17(targetDir, "AGENTS.md"));
|
|
2951
3263
|
if (!hasFlydocs && !hasAgentsMd) {
|
|
2952
3264
|
printError(`Not a FlyDocs project: ${targetDir}`);
|
|
2953
3265
|
printInfo("No .flydocs/ directory or AGENTS.md found.");
|
|
@@ -2959,7 +3271,7 @@ var init_uninstall = __esm({
|
|
|
2959
3271
|
const removeAll = forceAll || args.all;
|
|
2960
3272
|
const skipPrompts = forceAll || args.yes;
|
|
2961
3273
|
let contentAction = "preserve";
|
|
2962
|
-
const hasUserContent = await pathExists(
|
|
3274
|
+
const hasUserContent = await pathExists(join17(targetDir, "flydocs"));
|
|
2963
3275
|
if (hasUserContent) {
|
|
2964
3276
|
if (removeAll) {
|
|
2965
3277
|
contentAction = "remove";
|
|
@@ -3042,7 +3354,7 @@ var init_uninstall = __esm({
|
|
|
3042
3354
|
const removedRules = await removeOwnedCursorRules(targetDir);
|
|
3043
3355
|
result.removed.push(...removedRules);
|
|
3044
3356
|
for (const [relativePath, type] of ALWAYS_REMOVED) {
|
|
3045
|
-
const fullPath =
|
|
3357
|
+
const fullPath = join17(targetDir, relativePath);
|
|
3046
3358
|
if (!await pathExists(fullPath)) {
|
|
3047
3359
|
result.skipped.push(relativePath);
|
|
3048
3360
|
continue;
|
|
@@ -3060,9 +3372,9 @@ var init_uninstall = __esm({
|
|
|
3060
3372
|
}
|
|
3061
3373
|
}
|
|
3062
3374
|
if (hasUserContent) {
|
|
3063
|
-
const flydocsPath =
|
|
3375
|
+
const flydocsPath = join17(targetDir, "flydocs");
|
|
3064
3376
|
if (contentAction === "archive") {
|
|
3065
|
-
const archivePath =
|
|
3377
|
+
const archivePath = join17(targetDir, "flydocs-archive");
|
|
3066
3378
|
if (await pathExists(archivePath)) {
|
|
3067
3379
|
await rm5(archivePath, { recursive: true, force: true });
|
|
3068
3380
|
}
|
|
@@ -3301,70 +3613,9 @@ __export(connect_exports, {
|
|
|
3301
3613
|
default: () => connect_default
|
|
3302
3614
|
});
|
|
3303
3615
|
import { defineCommand as defineCommand6 } from "citty";
|
|
3304
|
-
import { text as
|
|
3616
|
+
import { text as text3, confirm as confirm5, isCancel as isCancel6, cancel as cancel5 } from "@clack/prompts";
|
|
3305
3617
|
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
|
-
}
|
|
3618
|
+
import { join as join18 } from "path";
|
|
3368
3619
|
var connect_default;
|
|
3369
3620
|
var init_connect = __esm({
|
|
3370
3621
|
"src/commands/connect.ts"() {
|
|
@@ -3373,6 +3624,7 @@ var init_connect = __esm({
|
|
|
3373
3624
|
init_fs_ops();
|
|
3374
3625
|
init_template();
|
|
3375
3626
|
init_ui();
|
|
3627
|
+
init_api_key();
|
|
3376
3628
|
connect_default = defineCommand6({
|
|
3377
3629
|
meta: {
|
|
3378
3630
|
name: "connect",
|
|
@@ -3393,12 +3645,12 @@ var init_connect = __esm({
|
|
|
3393
3645
|
},
|
|
3394
3646
|
key: {
|
|
3395
3647
|
type: "string",
|
|
3396
|
-
description: "API key (fdk_
|
|
3648
|
+
description: "FlyDocs API key (fdk_...)"
|
|
3397
3649
|
}
|
|
3398
3650
|
},
|
|
3399
3651
|
async run({ args }) {
|
|
3400
3652
|
const targetDir = args.path ?? process.cwd();
|
|
3401
|
-
const configPath =
|
|
3653
|
+
const configPath = join18(targetDir, ".flydocs", "config.json");
|
|
3402
3654
|
if (!await pathExists(configPath)) {
|
|
3403
3655
|
printError("Not a FlyDocs project (.flydocs/config.json not found).");
|
|
3404
3656
|
console.log(
|
|
@@ -3422,22 +3674,19 @@ var init_connect = __esm({
|
|
|
3422
3674
|
console.log(` ${pc11.bold("Connect to FlyDocs Cloud")}`);
|
|
3423
3675
|
console.log();
|
|
3424
3676
|
console.log(
|
|
3425
|
-
` ${pc11.dim("
|
|
3426
|
-
);
|
|
3427
|
-
console.log(
|
|
3428
|
-
` ${pc11.dim("Linear API key (lin_api_...): Get from Linear \u2192 Settings \u2192 API")}`
|
|
3677
|
+
` ${pc11.dim("Get your API key (fdk_...) from your FlyDocs dashboard")}`
|
|
3429
3678
|
);
|
|
3430
3679
|
console.log();
|
|
3431
3680
|
let apiKey = args.key ?? "";
|
|
3432
3681
|
if (!apiKey) {
|
|
3433
|
-
const keyInput = await
|
|
3682
|
+
const keyInput = await text3({
|
|
3434
3683
|
message: "Enter your API key",
|
|
3435
|
-
placeholder: "fdk_...
|
|
3684
|
+
placeholder: "fdk_...",
|
|
3436
3685
|
validate(value) {
|
|
3437
3686
|
if (!value.trim()) return "API key is required";
|
|
3438
3687
|
const type = detectKeyType(value.trim());
|
|
3439
3688
|
if (type === "unknown")
|
|
3440
|
-
return "Key must start with fdk_ (FlyDocs
|
|
3689
|
+
return "Key must start with fdk_ (FlyDocs API key)";
|
|
3441
3690
|
return void 0;
|
|
3442
3691
|
}
|
|
3443
3692
|
});
|
|
@@ -3449,7 +3698,9 @@ var init_connect = __esm({
|
|
|
3449
3698
|
}
|
|
3450
3699
|
const keyType = detectKeyType(apiKey);
|
|
3451
3700
|
if (keyType === "unknown") {
|
|
3452
|
-
printError(
|
|
3701
|
+
printError(
|
|
3702
|
+
"Unrecognized key format. Expected fdk_ prefix (FlyDocs API key)."
|
|
3703
|
+
);
|
|
3453
3704
|
process.exit(1);
|
|
3454
3705
|
}
|
|
3455
3706
|
printInfo("Validating API key...");
|
|
@@ -3491,8 +3742,9 @@ var init_connect = __esm({
|
|
|
3491
3742
|
}
|
|
3492
3743
|
const wasLocal = config.tier === "local";
|
|
3493
3744
|
config.tier = "cloud";
|
|
3494
|
-
|
|
3495
|
-
|
|
3745
|
+
const configRecord = config;
|
|
3746
|
+
delete configRecord.statusMapping;
|
|
3747
|
+
delete configRecord.provider;
|
|
3496
3748
|
await writeConfig(targetDir, config);
|
|
3497
3749
|
printStatus("Config updated to cloud tier");
|
|
3498
3750
|
if (wasLocal) {
|
|
@@ -3500,14 +3752,14 @@ var init_connect = __esm({
|
|
|
3500
3752
|
const templateDir = await resolveTemplatePath(
|
|
3501
3753
|
args["local-source"] || void 0
|
|
3502
3754
|
);
|
|
3503
|
-
const templateSkillsDir =
|
|
3504
|
-
const skillsDir =
|
|
3755
|
+
const templateSkillsDir = join18(templateDir, ".claude", "skills");
|
|
3756
|
+
const skillsDir = join18(targetDir, ".claude", "skills");
|
|
3505
3757
|
await replaceDirectory(
|
|
3506
|
-
|
|
3507
|
-
|
|
3758
|
+
join18(templateSkillsDir, "flydocs-cloud"),
|
|
3759
|
+
join18(skillsDir, "flydocs-cloud")
|
|
3508
3760
|
);
|
|
3509
3761
|
const { rm: rm6 } = await import("fs/promises");
|
|
3510
|
-
const localSkillDir =
|
|
3762
|
+
const localSkillDir = join18(skillsDir, "flydocs-local");
|
|
3511
3763
|
if (await pathExists(localSkillDir)) {
|
|
3512
3764
|
await rm6(localSkillDir, { recursive: true, force: true });
|
|
3513
3765
|
}
|
|
@@ -3580,7 +3832,7 @@ var init_upgrade = __esm({
|
|
|
3580
3832
|
);
|
|
3581
3833
|
console.log();
|
|
3582
3834
|
console.log(
|
|
3583
|
-
` Your issues sync with
|
|
3835
|
+
` Your issues sync with your provider via the cloud mechanism skill.`
|
|
3584
3836
|
);
|
|
3585
3837
|
console.log(
|
|
3586
3838
|
` Run ${pc12.cyan("flydocs connect")} to update your connection settings.`
|
|
@@ -3593,9 +3845,7 @@ var init_upgrade = __esm({
|
|
|
3593
3845
|
console.log(` You're currently on the ${pc12.yellow("local")} tier.`);
|
|
3594
3846
|
console.log(` Upgrade to cloud for:`);
|
|
3595
3847
|
console.log();
|
|
3596
|
-
console.log(
|
|
3597
|
-
` ${pc12.cyan("\u2192")} Issue sync with Linear (Jira coming soon)`
|
|
3598
|
-
);
|
|
3848
|
+
console.log(` ${pc12.cyan("\u2192")} Issue sync with Linear, Jira, and more`);
|
|
3599
3849
|
console.log(` ${pc12.cyan("\u2192")} Project milestones and cycle management`);
|
|
3600
3850
|
console.log(` ${pc12.cyan("\u2192")} Team assignment and priority tracking`);
|
|
3601
3851
|
console.log(` ${pc12.cyan("\u2192")} Project health updates and dashboards`);
|