@flydocs/cli 0.6.0-alpha.2 → 0.6.0-alpha.4
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 +351 -225
- package/package.json +1 -1
- package/template/.claude/commands/flydocs-setup.md +79 -10
- package/template/.claude/commands/flydocs-upgrade.md +27 -15
- package/template/.claude/skills/flydocs-cloud/SKILL.md +20 -16
- package/template/.claude/skills/flydocs-cloud/scripts/create_issue.py +3 -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/set_provider.py +46 -0
- package/template/.claude/skills/flydocs-cloud/scripts/set_status_mapping.py +69 -0
- package/template/.flydocs/config.json +1 -1
- package/template/.flydocs/version +1 -1
- package/template/CHANGELOG.md +39 -0
- package/template/manifest.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -15,7 +15,7 @@ var CLI_VERSION, CLI_NAME, PACKAGE_NAME, POSTHOG_API_KEY;
|
|
|
15
15
|
var init_constants = __esm({
|
|
16
16
|
"src/lib/constants.ts"() {
|
|
17
17
|
"use strict";
|
|
18
|
-
CLI_VERSION = "0.6.0-alpha.
|
|
18
|
+
CLI_VERSION = "0.6.0-alpha.4";
|
|
19
19
|
CLI_NAME = "flydocs";
|
|
20
20
|
PACKAGE_NAME = "@flydocs/cli";
|
|
21
21
|
POSTHOG_API_KEY = "phc_v1MSJTQDFkMS90CBh3mxIz3v8bYCCnKU6v1ir6bz0Xn";
|
|
@@ -135,8 +135,8 @@ var init_template = __esm({
|
|
|
135
135
|
|
|
136
136
|
// src/lib/ui.ts
|
|
137
137
|
import pc2 from "picocolors";
|
|
138
|
-
function shadow(
|
|
139
|
-
return `\x1B[38;2;55;45;70m${
|
|
138
|
+
function shadow(text4) {
|
|
139
|
+
return `\x1B[38;2;55;45;70m${text4}\x1B[0m`;
|
|
140
140
|
}
|
|
141
141
|
function renderBannerBlock() {
|
|
142
142
|
const height = BANNER_ROWS.length;
|
|
@@ -485,6 +485,18 @@ import {
|
|
|
485
485
|
writeFile as writeFile2
|
|
486
486
|
} from "fs/promises";
|
|
487
487
|
import { join as join5, dirname as dirname2 } from "path";
|
|
488
|
+
async function detectExistingConfigs(targetDir) {
|
|
489
|
+
const existing = [];
|
|
490
|
+
const backupDir = join5(targetDir, BACKUP_ORIGINALS_DIR);
|
|
491
|
+
for (const relativePath of RESTORABLE_FILES) {
|
|
492
|
+
const filePath = join5(targetDir, relativePath);
|
|
493
|
+
const backupPath = join5(backupDir, relativePath);
|
|
494
|
+
if (await pathExists(filePath) && !await pathExists(backupPath)) {
|
|
495
|
+
existing.push(relativePath);
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
return existing;
|
|
499
|
+
}
|
|
488
500
|
async function backupOriginals(targetDir, files = RESTORABLE_FILES) {
|
|
489
501
|
const backedUp = [];
|
|
490
502
|
const backupDir = join5(targetDir, BACKUP_ORIGINALS_DIR);
|
|
@@ -760,8 +772,8 @@ function flushFrontmatterValue(mode, lines) {
|
|
|
760
772
|
return lines.join("\n").trim();
|
|
761
773
|
}
|
|
762
774
|
}
|
|
763
|
-
function parseFrontmatter(
|
|
764
|
-
const match =
|
|
775
|
+
function parseFrontmatter(text4) {
|
|
776
|
+
const match = text4.match(/^---\s*\n([\s\S]*?)\n---/);
|
|
765
777
|
if (!match) return null;
|
|
766
778
|
const block = match[1];
|
|
767
779
|
const result = {};
|
|
@@ -947,7 +959,8 @@ function searchCatalog(keyword) {
|
|
|
947
959
|
return searchable.includes(lower);
|
|
948
960
|
});
|
|
949
961
|
}
|
|
950
|
-
async function addSkill(targetDir, source) {
|
|
962
|
+
async function addSkill(targetDir, source, options) {
|
|
963
|
+
const quiet = options?.quiet ?? false;
|
|
951
964
|
if (isPlatformSkill(source)) {
|
|
952
965
|
printError(`Cannot install platform skill '${source}'.`);
|
|
953
966
|
console.log(" Platform skills (flydocs-*) are managed by the installer.");
|
|
@@ -965,11 +978,13 @@ async function addSkill(targetDir, source) {
|
|
|
965
978
|
console.log(` Remove first: flydocs skills remove ${skillName}`);
|
|
966
979
|
return;
|
|
967
980
|
}
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
981
|
+
if (!quiet) {
|
|
982
|
+
console.log();
|
|
983
|
+
console.log(
|
|
984
|
+
`${pc3.blue("->")} Installing ${pc3.cyan(skillName)} from ${repo}...`
|
|
985
|
+
);
|
|
986
|
+
console.log();
|
|
987
|
+
}
|
|
973
988
|
let success;
|
|
974
989
|
try {
|
|
975
990
|
success = await downloadSkillTree(repo, skillName, skillsDir);
|
|
@@ -1003,19 +1018,23 @@ async function addSkill(targetDir, source) {
|
|
|
1003
1018
|
);
|
|
1004
1019
|
return;
|
|
1005
1020
|
}
|
|
1006
|
-
if (!fm["triggers"]) {
|
|
1021
|
+
if (!fm["triggers"] && !quiet) {
|
|
1007
1022
|
printWarning(
|
|
1008
1023
|
"SKILL.md has no triggers -- skill won't appear in manifest index."
|
|
1009
1024
|
);
|
|
1010
1025
|
}
|
|
1011
|
-
|
|
1026
|
+
if (!quiet) {
|
|
1027
|
+
printStatus("Downloaded skill files");
|
|
1028
|
+
}
|
|
1012
1029
|
const cursorRuleSrc = join8(skillsDir, "cursor-rule.mdc");
|
|
1013
1030
|
if (await pathExists(cursorRuleSrc)) {
|
|
1014
1031
|
const cursorRulesDir = join8(targetDir, ".cursor", "rules");
|
|
1015
1032
|
await mkdir3(cursorRulesDir, { recursive: true });
|
|
1016
1033
|
const cursorRuleDest = join8(cursorRulesDir, `${skillName}.mdc`);
|
|
1017
1034
|
await copyFile(cursorRuleSrc, cursorRuleDest);
|
|
1018
|
-
|
|
1035
|
+
if (!quiet) {
|
|
1036
|
+
printStatus("Installed cursor rule");
|
|
1037
|
+
}
|
|
1019
1038
|
}
|
|
1020
1039
|
const config = await readConfig(targetDir);
|
|
1021
1040
|
const installed = config.skills?.installed ?? [];
|
|
@@ -1027,12 +1046,16 @@ async function addSkill(targetDir, source) {
|
|
|
1027
1046
|
}
|
|
1028
1047
|
config.skills.installed = installed;
|
|
1029
1048
|
await writeConfig(targetDir, config);
|
|
1030
|
-
|
|
1049
|
+
if (!quiet) {
|
|
1050
|
+
printStatus("Updated config.json");
|
|
1051
|
+
}
|
|
1031
1052
|
}
|
|
1032
1053
|
await runManifestGeneration(targetDir);
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1054
|
+
if (!quiet) {
|
|
1055
|
+
console.log();
|
|
1056
|
+
printStatus(`Installed ${pc3.cyan(skillName)}`);
|
|
1057
|
+
console.log();
|
|
1058
|
+
}
|
|
1036
1059
|
}
|
|
1037
1060
|
async function removeSkill(targetDir, name) {
|
|
1038
1061
|
if (isPlatformSkill(name)) {
|
|
@@ -1187,7 +1210,8 @@ async function promptCommunitySkills(targetDir, stack, autoYes) {
|
|
|
1187
1210
|
let successCount = 0;
|
|
1188
1211
|
for (const skill of selected) {
|
|
1189
1212
|
try {
|
|
1190
|
-
await addSkill(targetDir, `${skill.repo}:${skill.name}
|
|
1213
|
+
await addSkill(targetDir, `${skill.repo}:${skill.name}`, { quiet: true });
|
|
1214
|
+
printStatus(`Installed ${pc4.cyan(skill.name)}`);
|
|
1191
1215
|
successCount++;
|
|
1192
1216
|
} catch {
|
|
1193
1217
|
printError(`${skill.name} (failed)`);
|
|
@@ -1840,6 +1864,76 @@ var init_telemetry = __esm({
|
|
|
1840
1864
|
}
|
|
1841
1865
|
});
|
|
1842
1866
|
|
|
1867
|
+
// src/lib/api-key.ts
|
|
1868
|
+
import { readFile as readFile10, writeFile as writeFile7, appendFile as appendFile2 } from "fs/promises";
|
|
1869
|
+
import { join as join14 } from "path";
|
|
1870
|
+
function detectKeyType(key) {
|
|
1871
|
+
if (key.startsWith("fdk_")) return "relay";
|
|
1872
|
+
if (key.startsWith("lin_api_")) return "direct";
|
|
1873
|
+
return "unknown";
|
|
1874
|
+
}
|
|
1875
|
+
async function validateRelayKey(apiKey) {
|
|
1876
|
+
const baseUrl = process.env.FLYDOCS_RELAY_URL?.replace(/\/$/, "") ?? "https://app.flydocs.ai/api/relay";
|
|
1877
|
+
const response = await fetch(`${baseUrl}/auth/validate`, {
|
|
1878
|
+
method: "POST",
|
|
1879
|
+
headers: {
|
|
1880
|
+
Authorization: `Bearer ${apiKey}`,
|
|
1881
|
+
"Content-Type": "application/json"
|
|
1882
|
+
},
|
|
1883
|
+
signal: AbortSignal.timeout(15e3)
|
|
1884
|
+
});
|
|
1885
|
+
if (!response.ok) return { valid: false };
|
|
1886
|
+
const data = await response.json();
|
|
1887
|
+
if (!data.valid) return { valid: false };
|
|
1888
|
+
return { valid: true, org: data.org ?? "your organization" };
|
|
1889
|
+
}
|
|
1890
|
+
async function validateLinearKey(apiKey) {
|
|
1891
|
+
const response = await fetch("https://api.linear.app/graphql", {
|
|
1892
|
+
method: "POST",
|
|
1893
|
+
headers: {
|
|
1894
|
+
Authorization: apiKey,
|
|
1895
|
+
"Content-Type": "application/json"
|
|
1896
|
+
},
|
|
1897
|
+
body: JSON.stringify({ query: "{ viewer { id name email } }" }),
|
|
1898
|
+
signal: AbortSignal.timeout(15e3)
|
|
1899
|
+
});
|
|
1900
|
+
if (!response.ok) return { valid: false };
|
|
1901
|
+
const data = await response.json();
|
|
1902
|
+
if (!data.data?.viewer) return { valid: false };
|
|
1903
|
+
return {
|
|
1904
|
+
valid: true,
|
|
1905
|
+
name: data.data.viewer.name,
|
|
1906
|
+
email: data.data.viewer.email
|
|
1907
|
+
};
|
|
1908
|
+
}
|
|
1909
|
+
async function storeEnvKey(targetDir, envVarName, value) {
|
|
1910
|
+
const envPath = join14(targetDir, ".env");
|
|
1911
|
+
const envLocalPath = join14(targetDir, ".env.local");
|
|
1912
|
+
const targetEnvPath = await pathExists(envLocalPath) ? envLocalPath : envPath;
|
|
1913
|
+
const pattern = new RegExp(`${envVarName}=.*`);
|
|
1914
|
+
if (await pathExists(targetEnvPath)) {
|
|
1915
|
+
const envContent = await readFile10(targetEnvPath, "utf-8");
|
|
1916
|
+
if (pattern.test(envContent)) {
|
|
1917
|
+
const updated = envContent.replace(pattern, `${envVarName}=${value}`);
|
|
1918
|
+
await writeFile7(targetEnvPath, updated, "utf-8");
|
|
1919
|
+
} else {
|
|
1920
|
+
await appendFile2(targetEnvPath, `
|
|
1921
|
+
${envVarName}=${value}
|
|
1922
|
+
`);
|
|
1923
|
+
}
|
|
1924
|
+
} else {
|
|
1925
|
+
await writeFile7(targetEnvPath, `${envVarName}=${value}
|
|
1926
|
+
`, "utf-8");
|
|
1927
|
+
}
|
|
1928
|
+
return targetEnvPath === envLocalPath ? ".env.local" : ".env";
|
|
1929
|
+
}
|
|
1930
|
+
var init_api_key = __esm({
|
|
1931
|
+
"src/lib/api-key.ts"() {
|
|
1932
|
+
"use strict";
|
|
1933
|
+
init_fs_ops();
|
|
1934
|
+
}
|
|
1935
|
+
});
|
|
1936
|
+
|
|
1843
1937
|
// src/commands/install.ts
|
|
1844
1938
|
var install_exports = {};
|
|
1845
1939
|
__export(install_exports, {
|
|
@@ -1847,9 +1941,9 @@ __export(install_exports, {
|
|
|
1847
1941
|
});
|
|
1848
1942
|
import { defineCommand } from "citty";
|
|
1849
1943
|
import { resolve as resolve2 } from "path";
|
|
1850
|
-
import { join as
|
|
1944
|
+
import { join as join15 } from "path";
|
|
1851
1945
|
import { mkdir as mkdir7 } from "fs/promises";
|
|
1852
|
-
import { confirm as confirm2, select, isCancel as isCancel3, cancel as cancel2 } from "@clack/prompts";
|
|
1946
|
+
import { confirm as confirm2, select, text, isCancel as isCancel3, cancel as cancel2 } from "@clack/prompts";
|
|
1853
1947
|
import pc6 from "picocolors";
|
|
1854
1948
|
var install_default;
|
|
1855
1949
|
var init_install = __esm({
|
|
@@ -1868,6 +1962,7 @@ var init_install = __esm({
|
|
|
1868
1962
|
init_post_install();
|
|
1869
1963
|
init_update_check();
|
|
1870
1964
|
init_telemetry();
|
|
1965
|
+
init_api_key();
|
|
1871
1966
|
install_default = defineCommand({
|
|
1872
1967
|
meta: {
|
|
1873
1968
|
name: "install",
|
|
@@ -1929,7 +2024,7 @@ var init_install = __esm({
|
|
|
1929
2024
|
process.exit(1);
|
|
1930
2025
|
}
|
|
1931
2026
|
tier = args.tier;
|
|
1932
|
-
} else if (await pathExists(
|
|
2027
|
+
} else if (await pathExists(join15(targetDir, ".flydocs", "config.json"))) {
|
|
1933
2028
|
try {
|
|
1934
2029
|
const existing = await readConfig(targetDir);
|
|
1935
2030
|
if (existing.tier) {
|
|
@@ -1978,46 +2073,126 @@ var init_install = __esm({
|
|
|
1978
2073
|
}
|
|
1979
2074
|
printInfo(`Tier: ${tier}`);
|
|
1980
2075
|
await capture("install_tier_selected", { tier });
|
|
1981
|
-
if (
|
|
2076
|
+
if (tier === "cloud") {
|
|
2077
|
+
console.log();
|
|
2078
|
+
console.log(` ${pc6.bold("Connect to FlyDocs Cloud")}`);
|
|
2079
|
+
console.log();
|
|
2080
|
+
console.log(
|
|
2081
|
+
` ${pc6.dim("Get your API key from your FlyDocs dashboard (fdk_...)")}`
|
|
2082
|
+
);
|
|
2083
|
+
console.log();
|
|
2084
|
+
const keyInput = await text({
|
|
2085
|
+
message: "Enter your FlyDocs API key",
|
|
2086
|
+
placeholder: "fdk_...",
|
|
2087
|
+
validate(value) {
|
|
2088
|
+
if (!value.trim()) return "API key is required";
|
|
2089
|
+
const type = detectKeyType(value.trim());
|
|
2090
|
+
if (type !== "relay")
|
|
2091
|
+
return "Cloud tier requires a FlyDocs API key (fdk_...)";
|
|
2092
|
+
return void 0;
|
|
2093
|
+
}
|
|
2094
|
+
});
|
|
2095
|
+
if (isCancel3(keyInput)) {
|
|
2096
|
+
cancel2("Installation cancelled.");
|
|
2097
|
+
process.exit(0);
|
|
2098
|
+
}
|
|
2099
|
+
const apiKey = keyInput.trim();
|
|
2100
|
+
printInfo("Validating API key...");
|
|
2101
|
+
try {
|
|
2102
|
+
const result = await validateRelayKey(apiKey);
|
|
2103
|
+
if (!result.valid) {
|
|
2104
|
+
printError("Invalid API key or relay API unreachable.");
|
|
2105
|
+
console.log(` Check your key and try again.`);
|
|
2106
|
+
process.exit(1);
|
|
2107
|
+
}
|
|
2108
|
+
printStatus(`Connected to ${pc6.bold(result.org)}`);
|
|
2109
|
+
} catch {
|
|
2110
|
+
printError(
|
|
2111
|
+
"Could not reach relay API. Check your network and try again."
|
|
2112
|
+
);
|
|
2113
|
+
process.exit(1);
|
|
2114
|
+
}
|
|
2115
|
+
const envFile = await storeEnvKey(targetDir, "FLYDOCS_API_KEY", apiKey);
|
|
2116
|
+
printStatus(`API key stored in ${pc6.dim(envFile)}`);
|
|
2117
|
+
}
|
|
2118
|
+
let skipConfigOverwrite = false;
|
|
2119
|
+
if (!await pathExists(join15(targetDir, ".git"))) {
|
|
1982
2120
|
printWarning("No git repository detected. Run git init when ready.");
|
|
1983
2121
|
}
|
|
1984
2122
|
await ensureDirectories(targetDir, tier);
|
|
1985
|
-
const
|
|
1986
|
-
if (
|
|
1987
|
-
|
|
1988
|
-
|
|
2123
|
+
const existingFiles = await detectExistingConfigs(targetDir);
|
|
2124
|
+
if (existingFiles.length > 0) {
|
|
2125
|
+
console.log();
|
|
2126
|
+
printWarning(
|
|
2127
|
+
`Found ${existingFiles.length} existing config file(s) that FlyDocs will overwrite:`
|
|
1989
2128
|
);
|
|
1990
|
-
for (const f of
|
|
1991
|
-
|
|
2129
|
+
for (const f of existingFiles) {
|
|
2130
|
+
console.log(` ${pc6.dim(f)}`);
|
|
2131
|
+
}
|
|
2132
|
+
console.log();
|
|
2133
|
+
if (!args.yes) {
|
|
2134
|
+
const overwriteChoice = await select({
|
|
2135
|
+
message: "How should FlyDocs handle these files?",
|
|
2136
|
+
options: [
|
|
2137
|
+
{
|
|
2138
|
+
value: "backup",
|
|
2139
|
+
label: "Overwrite (backed up)",
|
|
2140
|
+
hint: "Files are saved to .flydocs/backup-originals/ and restored on uninstall"
|
|
2141
|
+
},
|
|
2142
|
+
{
|
|
2143
|
+
value: "skip",
|
|
2144
|
+
label: "Skip overwriting",
|
|
2145
|
+
hint: "Keep your existing files \u2014 FlyDocs config may be incomplete"
|
|
2146
|
+
}
|
|
2147
|
+
]
|
|
2148
|
+
});
|
|
2149
|
+
if (isCancel3(overwriteChoice)) {
|
|
2150
|
+
cancel2("Installation cancelled.");
|
|
2151
|
+
process.exit(0);
|
|
2152
|
+
}
|
|
2153
|
+
if (overwriteChoice === "skip") {
|
|
2154
|
+
printInfo(
|
|
2155
|
+
"Keeping existing files. Run /flydocs-setup to merge your config manually."
|
|
2156
|
+
);
|
|
2157
|
+
skipConfigOverwrite = true;
|
|
2158
|
+
}
|
|
2159
|
+
}
|
|
2160
|
+
if (!skipConfigOverwrite) {
|
|
2161
|
+
const backedUp = await backupOriginals(targetDir);
|
|
2162
|
+
if (backedUp.length > 0) {
|
|
2163
|
+
printStatus(
|
|
2164
|
+
`Backed up ${backedUp.length} file(s) to .flydocs/backup-originals/`
|
|
2165
|
+
);
|
|
2166
|
+
}
|
|
1992
2167
|
}
|
|
1993
2168
|
}
|
|
1994
2169
|
console.log("Installing framework files...");
|
|
1995
2170
|
await replaceDirectory(
|
|
1996
|
-
|
|
1997
|
-
|
|
2171
|
+
join15(templateDir, ".flydocs", "templates"),
|
|
2172
|
+
join15(targetDir, ".flydocs", "templates")
|
|
1998
2173
|
);
|
|
1999
2174
|
await replaceDirectory(
|
|
2000
|
-
|
|
2001
|
-
|
|
2175
|
+
join15(templateDir, ".flydocs", "hooks"),
|
|
2176
|
+
join15(targetDir, ".flydocs", "hooks")
|
|
2002
2177
|
);
|
|
2003
2178
|
await replaceDirectory(
|
|
2004
|
-
|
|
2005
|
-
|
|
2179
|
+
join15(templateDir, ".flydocs", "scripts"),
|
|
2180
|
+
join15(targetDir, ".flydocs", "scripts")
|
|
2006
2181
|
);
|
|
2007
2182
|
await copyFile(
|
|
2008
|
-
|
|
2009
|
-
|
|
2183
|
+
join15(templateDir, ".flydocs", "version"),
|
|
2184
|
+
join15(targetDir, ".flydocs", "version")
|
|
2010
2185
|
);
|
|
2011
|
-
const manifestSrc =
|
|
2186
|
+
const manifestSrc = join15(templateDir, "manifest.json");
|
|
2012
2187
|
if (await pathExists(manifestSrc)) {
|
|
2013
|
-
await copyFile(manifestSrc,
|
|
2188
|
+
await copyFile(manifestSrc, join15(targetDir, ".flydocs", "manifest.json"));
|
|
2014
2189
|
}
|
|
2015
|
-
const changelogSrc =
|
|
2190
|
+
const changelogSrc = join15(templateDir, "CHANGELOG.md");
|
|
2016
2191
|
if (await pathExists(changelogSrc)) {
|
|
2017
|
-
await copyFile(changelogSrc,
|
|
2192
|
+
await copyFile(changelogSrc, join15(targetDir, ".flydocs", "CHANGELOG.md"));
|
|
2018
2193
|
}
|
|
2019
2194
|
printStatus(".flydocs/templates, hooks, version, manifest, changelog");
|
|
2020
|
-
const configPath =
|
|
2195
|
+
const configPath = join15(targetDir, ".flydocs", "config.json");
|
|
2021
2196
|
if (!await pathExists(configPath)) {
|
|
2022
2197
|
const config = await createFreshConfig(templateDir, version, tier);
|
|
2023
2198
|
await writeConfig(targetDir, config);
|
|
@@ -2071,20 +2246,20 @@ var init_install = __esm({
|
|
|
2071
2246
|
}
|
|
2072
2247
|
await capture("install_agents_chosen", { install_agents: installAgents });
|
|
2073
2248
|
if (installAgents) {
|
|
2074
|
-
const claudeAgentsSrc =
|
|
2249
|
+
const claudeAgentsSrc = join15(templateDir, ".claude", "agents");
|
|
2075
2250
|
if (await pathExists(claudeAgentsSrc)) {
|
|
2076
|
-
await mkdir7(
|
|
2251
|
+
await mkdir7(join15(targetDir, ".claude", "agents"), { recursive: true });
|
|
2077
2252
|
await copyDirectoryContents(
|
|
2078
2253
|
claudeAgentsSrc,
|
|
2079
|
-
|
|
2254
|
+
join15(targetDir, ".claude", "agents")
|
|
2080
2255
|
);
|
|
2081
2256
|
}
|
|
2082
|
-
const cursorAgentsSrc =
|
|
2257
|
+
const cursorAgentsSrc = join15(templateDir, ".cursor", "agents");
|
|
2083
2258
|
if (await pathExists(cursorAgentsSrc)) {
|
|
2084
|
-
await mkdir7(
|
|
2259
|
+
await mkdir7(join15(targetDir, ".cursor", "agents"), { recursive: true });
|
|
2085
2260
|
await copyDirectoryContents(
|
|
2086
2261
|
cursorAgentsSrc,
|
|
2087
|
-
|
|
2262
|
+
join15(targetDir, ".cursor", "agents")
|
|
2088
2263
|
);
|
|
2089
2264
|
}
|
|
2090
2265
|
printStatus("Sub-agents installed (.claude/agents, .cursor/agents)");
|
|
@@ -2094,74 +2269,86 @@ var init_install = __esm({
|
|
|
2094
2269
|
console.log();
|
|
2095
2270
|
console.log("Installing commands and settings...");
|
|
2096
2271
|
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")
|
|
2272
|
+
join15(templateDir, ".claude", "commands"),
|
|
2273
|
+
join15(targetDir, ".claude", "commands")
|
|
2107
2274
|
);
|
|
2108
|
-
|
|
2275
|
+
if (!skipConfigOverwrite) {
|
|
2276
|
+
await copyFile(
|
|
2277
|
+
join15(templateDir, ".claude", "CLAUDE.md"),
|
|
2278
|
+
join15(targetDir, ".claude", "CLAUDE.md")
|
|
2279
|
+
);
|
|
2280
|
+
await copyFile(
|
|
2281
|
+
join15(templateDir, ".claude", "settings.json"),
|
|
2282
|
+
join15(targetDir, ".claude", "settings.json")
|
|
2283
|
+
);
|
|
2284
|
+
printStatus(".claude/ (commands, CLAUDE.md, settings)");
|
|
2285
|
+
} else {
|
|
2286
|
+
printStatus(".claude/ (commands only \u2014 existing config preserved)");
|
|
2287
|
+
}
|
|
2109
2288
|
await copyDirectoryContents(
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
);
|
|
2113
|
-
await copyFile(
|
|
2114
|
-
join14(templateDir, ".cursor", "hooks.json"),
|
|
2115
|
-
join14(targetDir, ".cursor", "hooks.json")
|
|
2289
|
+
join15(templateDir, ".claude", "commands"),
|
|
2290
|
+
join15(targetDir, ".cursor", "commands")
|
|
2116
2291
|
);
|
|
2117
|
-
|
|
2292
|
+
if (!skipConfigOverwrite) {
|
|
2293
|
+
await copyFile(
|
|
2294
|
+
join15(templateDir, ".cursor", "hooks.json"),
|
|
2295
|
+
join15(targetDir, ".cursor", "hooks.json")
|
|
2296
|
+
);
|
|
2297
|
+
printStatus(".cursor/ (commands, hooks)");
|
|
2298
|
+
} else {
|
|
2299
|
+
printStatus(".cursor/ (commands only \u2014 existing hooks preserved)");
|
|
2300
|
+
}
|
|
2118
2301
|
await copyCursorRules(targetDir);
|
|
2119
2302
|
printStatus(".cursor/rules/");
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2303
|
+
if (!skipConfigOverwrite) {
|
|
2304
|
+
await copyFile(
|
|
2305
|
+
join15(templateDir, "AGENTS.md"),
|
|
2306
|
+
join15(targetDir, "AGENTS.md")
|
|
2307
|
+
);
|
|
2308
|
+
printStatus("AGENTS.md");
|
|
2309
|
+
} else {
|
|
2310
|
+
printInfo("AGENTS.md preserved (existing)");
|
|
2311
|
+
}
|
|
2125
2312
|
await runManifestGeneration(targetDir);
|
|
2126
2313
|
await runContextGraphBuild(targetDir);
|
|
2127
2314
|
console.log();
|
|
2128
2315
|
console.log("Installing project templates...");
|
|
2129
2316
|
const userFiles = [
|
|
2130
2317
|
{
|
|
2131
|
-
src:
|
|
2132
|
-
dest:
|
|
2318
|
+
src: join15(templateDir, "flydocs", "context", "project.md"),
|
|
2319
|
+
dest: join15(targetDir, "flydocs", "context", "project.md"),
|
|
2133
2320
|
label: "flydocs/context/project.md"
|
|
2134
2321
|
},
|
|
2135
2322
|
{
|
|
2136
|
-
src:
|
|
2137
|
-
dest:
|
|
2323
|
+
src: join15(templateDir, "flydocs", "knowledge", "INDEX.md"),
|
|
2324
|
+
dest: join15(targetDir, "flydocs", "knowledge", "INDEX.md"),
|
|
2138
2325
|
label: "flydocs/knowledge/INDEX.md"
|
|
2139
2326
|
},
|
|
2140
2327
|
{
|
|
2141
|
-
src:
|
|
2142
|
-
dest:
|
|
2328
|
+
src: join15(templateDir, "flydocs", "knowledge", "README.md"),
|
|
2329
|
+
dest: join15(targetDir, "flydocs", "knowledge", "README.md"),
|
|
2143
2330
|
label: "flydocs/knowledge/README.md"
|
|
2144
2331
|
},
|
|
2145
2332
|
{
|
|
2146
|
-
src:
|
|
2333
|
+
src: join15(
|
|
2147
2334
|
templateDir,
|
|
2148
2335
|
"flydocs",
|
|
2149
2336
|
"knowledge",
|
|
2150
2337
|
"product",
|
|
2151
2338
|
"personas.md"
|
|
2152
2339
|
),
|
|
2153
|
-
dest:
|
|
2340
|
+
dest: join15(targetDir, "flydocs", "knowledge", "product", "personas.md"),
|
|
2154
2341
|
label: "flydocs/knowledge/product/personas.md"
|
|
2155
2342
|
},
|
|
2156
2343
|
{
|
|
2157
|
-
src:
|
|
2344
|
+
src: join15(
|
|
2158
2345
|
templateDir,
|
|
2159
2346
|
"flydocs",
|
|
2160
2347
|
"knowledge",
|
|
2161
2348
|
"product",
|
|
2162
2349
|
"user-flows.md"
|
|
2163
2350
|
),
|
|
2164
|
-
dest:
|
|
2351
|
+
dest: join15(
|
|
2165
2352
|
targetDir,
|
|
2166
2353
|
"flydocs",
|
|
2167
2354
|
"knowledge",
|
|
@@ -2171,18 +2358,18 @@ var init_install = __esm({
|
|
|
2171
2358
|
label: "flydocs/knowledge/product/user-flows.md"
|
|
2172
2359
|
},
|
|
2173
2360
|
{
|
|
2174
|
-
src:
|
|
2175
|
-
dest:
|
|
2361
|
+
src: join15(templateDir, "flydocs", "design-system", "README.md"),
|
|
2362
|
+
dest: join15(targetDir, "flydocs", "design-system", "README.md"),
|
|
2176
2363
|
label: "flydocs/design-system/README.md"
|
|
2177
2364
|
},
|
|
2178
2365
|
{
|
|
2179
|
-
src:
|
|
2366
|
+
src: join15(
|
|
2180
2367
|
templateDir,
|
|
2181
2368
|
"flydocs",
|
|
2182
2369
|
"design-system",
|
|
2183
2370
|
"component-patterns.md"
|
|
2184
2371
|
),
|
|
2185
|
-
dest:
|
|
2372
|
+
dest: join15(
|
|
2186
2373
|
targetDir,
|
|
2187
2374
|
"flydocs",
|
|
2188
2375
|
"design-system",
|
|
@@ -2191,13 +2378,13 @@ var init_install = __esm({
|
|
|
2191
2378
|
label: "flydocs/design-system/component-patterns.md"
|
|
2192
2379
|
},
|
|
2193
2380
|
{
|
|
2194
|
-
src:
|
|
2195
|
-
dest:
|
|
2381
|
+
src: join15(templateDir, "flydocs", "design-system", "token-mapping.md"),
|
|
2382
|
+
dest: join15(targetDir, "flydocs", "design-system", "token-mapping.md"),
|
|
2196
2383
|
label: "flydocs/design-system/token-mapping.md"
|
|
2197
2384
|
},
|
|
2198
2385
|
{
|
|
2199
|
-
src:
|
|
2200
|
-
dest:
|
|
2386
|
+
src: join15(templateDir, "flydocs", "README.md"),
|
|
2387
|
+
dest: join15(targetDir, "flydocs", "README.md"),
|
|
2201
2388
|
label: "flydocs/README.md"
|
|
2202
2389
|
}
|
|
2203
2390
|
];
|
|
@@ -2211,9 +2398,9 @@ var init_install = __esm({
|
|
|
2211
2398
|
}
|
|
2212
2399
|
}
|
|
2213
2400
|
}
|
|
2214
|
-
const envExampleSrc =
|
|
2401
|
+
const envExampleSrc = join15(templateDir, ".env.example");
|
|
2215
2402
|
if (await pathExists(envExampleSrc)) {
|
|
2216
|
-
await copyFile(envExampleSrc,
|
|
2403
|
+
await copyFile(envExampleSrc, join15(targetDir, ".env.example"));
|
|
2217
2404
|
printStatus(".env.example");
|
|
2218
2405
|
}
|
|
2219
2406
|
await ensureGitignore(targetDir);
|
|
@@ -2253,9 +2440,8 @@ var init_install = __esm({
|
|
|
2253
2440
|
`Version: ${version}`,
|
|
2254
2441
|
"",
|
|
2255
2442
|
"Next steps:",
|
|
2256
|
-
" 1. Run flydocs
|
|
2257
|
-
" 2.
|
|
2258
|
-
" 3. Start working with /start-session",
|
|
2443
|
+
" 1. Run /flydocs-setup to configure your workspace",
|
|
2444
|
+
" 2. Start working with /start-session",
|
|
2259
2445
|
"",
|
|
2260
2446
|
"Docs: https://www.flydocs.ai/docs"
|
|
2261
2447
|
];
|
|
@@ -2392,9 +2578,9 @@ __export(update_exports, {
|
|
|
2392
2578
|
default: () => update_default
|
|
2393
2579
|
});
|
|
2394
2580
|
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";
|
|
2581
|
+
import { resolve as resolve3, join as join16 } from "path";
|
|
2582
|
+
import { mkdir as mkdir8, cp as cp2, readFile as readFile11, readdir as readdir3, rm as rm4 } from "fs/promises";
|
|
2583
|
+
import { select as select2, text as text2, confirm as confirm3, isCancel as isCancel4, cancel as cancel3 } from "@clack/prompts";
|
|
2398
2584
|
import pc7 from "picocolors";
|
|
2399
2585
|
var update_default;
|
|
2400
2586
|
var init_update = __esm({
|
|
@@ -2482,7 +2668,7 @@ var init_update = __esm({
|
|
|
2482
2668
|
if (choice === "cwd") {
|
|
2483
2669
|
targetDir = process.cwd();
|
|
2484
2670
|
} else {
|
|
2485
|
-
const enteredPath = await
|
|
2671
|
+
const enteredPath = await text2({
|
|
2486
2672
|
message: "Enter project path:"
|
|
2487
2673
|
});
|
|
2488
2674
|
if (isCancel4(enteredPath)) {
|
|
@@ -2500,9 +2686,9 @@ var init_update = __esm({
|
|
|
2500
2686
|
}
|
|
2501
2687
|
targetDir = resolve3(targetDir);
|
|
2502
2688
|
process.chdir(targetDir);
|
|
2503
|
-
const hasVersion = await pathExists(
|
|
2689
|
+
const hasVersion = await pathExists(join16(targetDir, ".flydocs", "version"));
|
|
2504
2690
|
const hasConfig = await pathExists(
|
|
2505
|
-
|
|
2691
|
+
join16(targetDir, ".flydocs", "config.json")
|
|
2506
2692
|
);
|
|
2507
2693
|
if (!hasVersion && !hasConfig) {
|
|
2508
2694
|
printError(`Not a FlyDocs project: ${targetDir}`);
|
|
@@ -2513,8 +2699,8 @@ var init_update = __esm({
|
|
|
2513
2699
|
console.log();
|
|
2514
2700
|
let currentVersion = "0.1.0";
|
|
2515
2701
|
if (hasVersion) {
|
|
2516
|
-
const vContent = await
|
|
2517
|
-
|
|
2702
|
+
const vContent = await readFile11(
|
|
2703
|
+
join16(targetDir, ".flydocs", "version"),
|
|
2518
2704
|
"utf-8"
|
|
2519
2705
|
);
|
|
2520
2706
|
currentVersion = vContent.trim();
|
|
@@ -2548,7 +2734,7 @@ var init_update = __esm({
|
|
|
2548
2734
|
});
|
|
2549
2735
|
console.log(`Updating: v${currentVersion} \u2192 v${version}`);
|
|
2550
2736
|
console.log();
|
|
2551
|
-
const changelogPath =
|
|
2737
|
+
const changelogPath = join16(templateDir, "CHANGELOG.md");
|
|
2552
2738
|
const whatsNew = await getWhatsNew(changelogPath, currentVersion, version);
|
|
2553
2739
|
if (whatsNew.length > 0) {
|
|
2554
2740
|
console.log(pc7.cyan("What's new:"));
|
|
@@ -2560,23 +2746,23 @@ var init_update = __esm({
|
|
|
2560
2746
|
}
|
|
2561
2747
|
const now = /* @__PURE__ */ new Date();
|
|
2562
2748
|
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 =
|
|
2749
|
+
const backupDir = join16(targetDir, ".flydocs", `backup-${ts}`);
|
|
2564
2750
|
await mkdir8(backupDir, { recursive: true });
|
|
2565
2751
|
if (hasConfig) {
|
|
2566
2752
|
await cp2(
|
|
2567
|
-
|
|
2568
|
-
|
|
2753
|
+
join16(targetDir, ".flydocs", "config.json"),
|
|
2754
|
+
join16(backupDir, "config.json")
|
|
2569
2755
|
);
|
|
2570
2756
|
printStatus(`Config backed up to .flydocs/backup-${ts}/`);
|
|
2571
2757
|
}
|
|
2572
2758
|
try {
|
|
2573
|
-
const flydocsDir =
|
|
2759
|
+
const flydocsDir = join16(targetDir, ".flydocs");
|
|
2574
2760
|
const entries = await readdir3(flydocsDir);
|
|
2575
2761
|
const backups = entries.filter((e) => e.startsWith("backup-")).sort();
|
|
2576
2762
|
if (backups.length > 3) {
|
|
2577
2763
|
const toRemove = backups.slice(0, backups.length - 3);
|
|
2578
2764
|
for (const old of toRemove) {
|
|
2579
|
-
await rm4(
|
|
2765
|
+
await rm4(join16(flydocsDir, old), { recursive: true, force: true });
|
|
2580
2766
|
}
|
|
2581
2767
|
}
|
|
2582
2768
|
} catch {
|
|
@@ -2613,20 +2799,20 @@ var init_update = __esm({
|
|
|
2613
2799
|
}
|
|
2614
2800
|
console.log("Replacing framework directories...");
|
|
2615
2801
|
await replaceDirectory(
|
|
2616
|
-
|
|
2617
|
-
|
|
2802
|
+
join16(templateDir, ".flydocs", "templates"),
|
|
2803
|
+
join16(targetDir, ".flydocs", "templates")
|
|
2618
2804
|
);
|
|
2619
2805
|
await replaceDirectory(
|
|
2620
|
-
|
|
2621
|
-
|
|
2806
|
+
join16(templateDir, ".flydocs", "hooks"),
|
|
2807
|
+
join16(targetDir, ".flydocs", "hooks")
|
|
2622
2808
|
);
|
|
2623
2809
|
await replaceDirectory(
|
|
2624
|
-
|
|
2625
|
-
|
|
2810
|
+
join16(templateDir, ".flydocs", "scripts"),
|
|
2811
|
+
join16(targetDir, ".flydocs", "scripts")
|
|
2626
2812
|
);
|
|
2627
2813
|
printStatus(".flydocs/templates, hooks, scripts");
|
|
2628
2814
|
const hasExistingAgents = await pathExists(
|
|
2629
|
-
|
|
2815
|
+
join16(targetDir, ".claude", "agents")
|
|
2630
2816
|
);
|
|
2631
2817
|
let installAgents;
|
|
2632
2818
|
if (args.yes) {
|
|
@@ -2658,20 +2844,20 @@ var init_update = __esm({
|
|
|
2658
2844
|
}
|
|
2659
2845
|
}
|
|
2660
2846
|
if (installAgents) {
|
|
2661
|
-
const claudeAgentsSrc =
|
|
2847
|
+
const claudeAgentsSrc = join16(templateDir, ".claude", "agents");
|
|
2662
2848
|
if (await pathExists(claudeAgentsSrc)) {
|
|
2663
|
-
await mkdir8(
|
|
2849
|
+
await mkdir8(join16(targetDir, ".claude", "agents"), { recursive: true });
|
|
2664
2850
|
await copyDirectoryContents(
|
|
2665
2851
|
claudeAgentsSrc,
|
|
2666
|
-
|
|
2852
|
+
join16(targetDir, ".claude", "agents")
|
|
2667
2853
|
);
|
|
2668
2854
|
}
|
|
2669
|
-
const cursorAgentsSrc =
|
|
2855
|
+
const cursorAgentsSrc = join16(templateDir, ".cursor", "agents");
|
|
2670
2856
|
if (await pathExists(cursorAgentsSrc)) {
|
|
2671
|
-
await mkdir8(
|
|
2857
|
+
await mkdir8(join16(targetDir, ".cursor", "agents"), { recursive: true });
|
|
2672
2858
|
await copyDirectoryContents(
|
|
2673
2859
|
cursorAgentsSrc,
|
|
2674
|
-
|
|
2860
|
+
join16(targetDir, ".cursor", "agents")
|
|
2675
2861
|
);
|
|
2676
2862
|
}
|
|
2677
2863
|
printStatus(
|
|
@@ -2685,44 +2871,44 @@ var init_update = __esm({
|
|
|
2685
2871
|
console.log();
|
|
2686
2872
|
console.log("Replacing framework files...");
|
|
2687
2873
|
await copyFile(
|
|
2688
|
-
|
|
2689
|
-
|
|
2874
|
+
join16(templateDir, ".claude", "CLAUDE.md"),
|
|
2875
|
+
join16(targetDir, ".claude", "CLAUDE.md")
|
|
2690
2876
|
);
|
|
2691
2877
|
await copyFile(
|
|
2692
|
-
|
|
2693
|
-
|
|
2878
|
+
join16(templateDir, ".claude", "settings.json"),
|
|
2879
|
+
join16(targetDir, ".claude", "settings.json")
|
|
2694
2880
|
);
|
|
2695
2881
|
printStatus(".claude/CLAUDE.md, settings.json");
|
|
2696
2882
|
await copyDirectoryContents(
|
|
2697
|
-
|
|
2698
|
-
|
|
2883
|
+
join16(templateDir, ".claude", "commands"),
|
|
2884
|
+
join16(targetDir, ".claude", "commands")
|
|
2699
2885
|
);
|
|
2700
2886
|
await copyDirectoryContents(
|
|
2701
|
-
|
|
2702
|
-
|
|
2887
|
+
join16(templateDir, ".claude", "commands"),
|
|
2888
|
+
join16(targetDir, ".cursor", "commands")
|
|
2703
2889
|
);
|
|
2704
2890
|
printStatus(".claude/commands, .cursor/commands");
|
|
2705
|
-
const skillsReadmeSrc =
|
|
2891
|
+
const skillsReadmeSrc = join16(templateDir, ".claude", "skills", "README.md");
|
|
2706
2892
|
if (await pathExists(skillsReadmeSrc)) {
|
|
2707
2893
|
await copyFile(
|
|
2708
2894
|
skillsReadmeSrc,
|
|
2709
|
-
|
|
2895
|
+
join16(targetDir, ".claude", "skills", "README.md")
|
|
2710
2896
|
);
|
|
2711
2897
|
}
|
|
2712
2898
|
printStatus(".claude/skills/README.md");
|
|
2713
2899
|
await copyFile(
|
|
2714
|
-
|
|
2715
|
-
|
|
2900
|
+
join16(templateDir, ".cursor", "hooks.json"),
|
|
2901
|
+
join16(targetDir, ".cursor", "hooks.json")
|
|
2716
2902
|
);
|
|
2717
2903
|
printStatus(".cursor/hooks.json");
|
|
2718
2904
|
await copyFile(
|
|
2719
|
-
|
|
2720
|
-
|
|
2905
|
+
join16(templateDir, "AGENTS.md"),
|
|
2906
|
+
join16(targetDir, "AGENTS.md")
|
|
2721
2907
|
);
|
|
2722
2908
|
printStatus("AGENTS.md");
|
|
2723
|
-
const envExampleSrc =
|
|
2909
|
+
const envExampleSrc = join16(templateDir, ".env.example");
|
|
2724
2910
|
if (await pathExists(envExampleSrc)) {
|
|
2725
|
-
await copyFile(envExampleSrc,
|
|
2911
|
+
await copyFile(envExampleSrc, join16(targetDir, ".env.example"));
|
|
2726
2912
|
printStatus(".env.example");
|
|
2727
2913
|
}
|
|
2728
2914
|
await runManifestGeneration(targetDir);
|
|
@@ -2747,18 +2933,18 @@ var init_update = __esm({
|
|
|
2747
2933
|
printWarning("Config merge failed \u2014 config.json preserved as-is");
|
|
2748
2934
|
}
|
|
2749
2935
|
await copyFile(
|
|
2750
|
-
|
|
2751
|
-
|
|
2936
|
+
join16(templateDir, ".flydocs", "version"),
|
|
2937
|
+
join16(targetDir, ".flydocs", "version")
|
|
2752
2938
|
);
|
|
2753
2939
|
printStatus(`.flydocs/version \u2192 ${version}`);
|
|
2754
|
-
const clSrc =
|
|
2940
|
+
const clSrc = join16(templateDir, "CHANGELOG.md");
|
|
2755
2941
|
if (await pathExists(clSrc)) {
|
|
2756
|
-
await copyFile(clSrc,
|
|
2942
|
+
await copyFile(clSrc, join16(targetDir, ".flydocs", "CHANGELOG.md"));
|
|
2757
2943
|
printStatus(".flydocs/CHANGELOG.md");
|
|
2758
2944
|
}
|
|
2759
|
-
const mfSrc =
|
|
2945
|
+
const mfSrc = join16(templateDir, "manifest.json");
|
|
2760
2946
|
if (await pathExists(mfSrc)) {
|
|
2761
|
-
await copyFile(mfSrc,
|
|
2947
|
+
await copyFile(mfSrc, join16(targetDir, ".flydocs", "manifest.json"));
|
|
2762
2948
|
printStatus(".flydocs/manifest.json");
|
|
2763
2949
|
}
|
|
2764
2950
|
console.log();
|
|
@@ -2818,12 +3004,12 @@ __export(uninstall_exports, {
|
|
|
2818
3004
|
default: () => uninstall_default
|
|
2819
3005
|
});
|
|
2820
3006
|
import { defineCommand as defineCommand3 } from "citty";
|
|
2821
|
-
import { resolve as resolve4, join as
|
|
3007
|
+
import { resolve as resolve4, join as join17 } from "path";
|
|
2822
3008
|
import { readdir as readdir4, rm as rm5, rename as rename2 } from "fs/promises";
|
|
2823
3009
|
import { confirm as confirm4, select as select3, isCancel as isCancel5, cancel as cancel4 } from "@clack/prompts";
|
|
2824
3010
|
import pc8 from "picocolors";
|
|
2825
3011
|
async function removeOwnedSkills(targetDir) {
|
|
2826
|
-
const skillsDir =
|
|
3012
|
+
const skillsDir = join17(targetDir, ".claude", "skills");
|
|
2827
3013
|
const removed = [];
|
|
2828
3014
|
if (!await pathExists(skillsDir)) {
|
|
2829
3015
|
return removed;
|
|
@@ -2832,7 +3018,7 @@ async function removeOwnedSkills(targetDir) {
|
|
|
2832
3018
|
const entries = await readdir4(skillsDir);
|
|
2833
3019
|
for (const entry of entries) {
|
|
2834
3020
|
if (entry.startsWith(OWNED_SKILL_PREFIX)) {
|
|
2835
|
-
await rm5(
|
|
3021
|
+
await rm5(join17(skillsDir, entry), { recursive: true, force: true });
|
|
2836
3022
|
removed.push(`.claude/skills/${entry}`);
|
|
2837
3023
|
}
|
|
2838
3024
|
}
|
|
@@ -2841,7 +3027,7 @@ async function removeOwnedSkills(targetDir) {
|
|
|
2841
3027
|
return removed;
|
|
2842
3028
|
}
|
|
2843
3029
|
async function removeOwnedCursorRules(targetDir) {
|
|
2844
|
-
const rulesDir =
|
|
3030
|
+
const rulesDir = join17(targetDir, ".cursor", "rules");
|
|
2845
3031
|
const removed = [];
|
|
2846
3032
|
if (!await pathExists(rulesDir)) {
|
|
2847
3033
|
return removed;
|
|
@@ -2850,7 +3036,7 @@ async function removeOwnedCursorRules(targetDir) {
|
|
|
2850
3036
|
const entries = await readdir4(rulesDir);
|
|
2851
3037
|
for (const entry of entries) {
|
|
2852
3038
|
if (entry.startsWith(OWNED_RULE_PREFIX) && entry.endsWith(".mdc")) {
|
|
2853
|
-
await rm5(
|
|
3039
|
+
await rm5(join17(rulesDir, entry), { force: true });
|
|
2854
3040
|
removed.push(`.cursor/rules/${entry}`);
|
|
2855
3041
|
}
|
|
2856
3042
|
}
|
|
@@ -2869,7 +3055,7 @@ async function isEmptyDir(dirPath) {
|
|
|
2869
3055
|
async function cleanupEmptyParents(targetDir, dirs) {
|
|
2870
3056
|
const cleaned = [];
|
|
2871
3057
|
for (const dir of dirs) {
|
|
2872
|
-
const fullPath =
|
|
3058
|
+
const fullPath = join17(targetDir, dir);
|
|
2873
3059
|
if (await pathExists(fullPath) && await isEmptyDir(fullPath)) {
|
|
2874
3060
|
await rm5(fullPath, { recursive: true, force: true });
|
|
2875
3061
|
cleaned.push(dir);
|
|
@@ -2946,8 +3132,8 @@ var init_uninstall = __esm({
|
|
|
2946
3132
|
process.exit(1);
|
|
2947
3133
|
}
|
|
2948
3134
|
targetDir = resolve4(targetDir);
|
|
2949
|
-
const hasFlydocs = await pathExists(
|
|
2950
|
-
const hasAgentsMd = await pathExists(
|
|
3135
|
+
const hasFlydocs = await pathExists(join17(targetDir, ".flydocs"));
|
|
3136
|
+
const hasAgentsMd = await pathExists(join17(targetDir, "AGENTS.md"));
|
|
2951
3137
|
if (!hasFlydocs && !hasAgentsMd) {
|
|
2952
3138
|
printError(`Not a FlyDocs project: ${targetDir}`);
|
|
2953
3139
|
printInfo("No .flydocs/ directory or AGENTS.md found.");
|
|
@@ -2959,7 +3145,7 @@ var init_uninstall = __esm({
|
|
|
2959
3145
|
const removeAll = forceAll || args.all;
|
|
2960
3146
|
const skipPrompts = forceAll || args.yes;
|
|
2961
3147
|
let contentAction = "preserve";
|
|
2962
|
-
const hasUserContent = await pathExists(
|
|
3148
|
+
const hasUserContent = await pathExists(join17(targetDir, "flydocs"));
|
|
2963
3149
|
if (hasUserContent) {
|
|
2964
3150
|
if (removeAll) {
|
|
2965
3151
|
contentAction = "remove";
|
|
@@ -3042,7 +3228,7 @@ var init_uninstall = __esm({
|
|
|
3042
3228
|
const removedRules = await removeOwnedCursorRules(targetDir);
|
|
3043
3229
|
result.removed.push(...removedRules);
|
|
3044
3230
|
for (const [relativePath, type] of ALWAYS_REMOVED) {
|
|
3045
|
-
const fullPath =
|
|
3231
|
+
const fullPath = join17(targetDir, relativePath);
|
|
3046
3232
|
if (!await pathExists(fullPath)) {
|
|
3047
3233
|
result.skipped.push(relativePath);
|
|
3048
3234
|
continue;
|
|
@@ -3060,9 +3246,9 @@ var init_uninstall = __esm({
|
|
|
3060
3246
|
}
|
|
3061
3247
|
}
|
|
3062
3248
|
if (hasUserContent) {
|
|
3063
|
-
const flydocsPath =
|
|
3249
|
+
const flydocsPath = join17(targetDir, "flydocs");
|
|
3064
3250
|
if (contentAction === "archive") {
|
|
3065
|
-
const archivePath =
|
|
3251
|
+
const archivePath = join17(targetDir, "flydocs-archive");
|
|
3066
3252
|
if (await pathExists(archivePath)) {
|
|
3067
3253
|
await rm5(archivePath, { recursive: true, force: true });
|
|
3068
3254
|
}
|
|
@@ -3301,70 +3487,9 @@ __export(connect_exports, {
|
|
|
3301
3487
|
default: () => connect_default
|
|
3302
3488
|
});
|
|
3303
3489
|
import { defineCommand as defineCommand6 } from "citty";
|
|
3304
|
-
import { text as
|
|
3490
|
+
import { text as text3, confirm as confirm5, isCancel as isCancel6, cancel as cancel5 } from "@clack/prompts";
|
|
3305
3491
|
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
|
-
}
|
|
3492
|
+
import { join as join18 } from "path";
|
|
3368
3493
|
var connect_default;
|
|
3369
3494
|
var init_connect = __esm({
|
|
3370
3495
|
"src/commands/connect.ts"() {
|
|
@@ -3373,6 +3498,7 @@ var init_connect = __esm({
|
|
|
3373
3498
|
init_fs_ops();
|
|
3374
3499
|
init_template();
|
|
3375
3500
|
init_ui();
|
|
3501
|
+
init_api_key();
|
|
3376
3502
|
connect_default = defineCommand6({
|
|
3377
3503
|
meta: {
|
|
3378
3504
|
name: "connect",
|
|
@@ -3398,7 +3524,7 @@ var init_connect = __esm({
|
|
|
3398
3524
|
},
|
|
3399
3525
|
async run({ args }) {
|
|
3400
3526
|
const targetDir = args.path ?? process.cwd();
|
|
3401
|
-
const configPath =
|
|
3527
|
+
const configPath = join18(targetDir, ".flydocs", "config.json");
|
|
3402
3528
|
if (!await pathExists(configPath)) {
|
|
3403
3529
|
printError("Not a FlyDocs project (.flydocs/config.json not found).");
|
|
3404
3530
|
console.log(
|
|
@@ -3430,7 +3556,7 @@ var init_connect = __esm({
|
|
|
3430
3556
|
console.log();
|
|
3431
3557
|
let apiKey = args.key ?? "";
|
|
3432
3558
|
if (!apiKey) {
|
|
3433
|
-
const keyInput = await
|
|
3559
|
+
const keyInput = await text3({
|
|
3434
3560
|
message: "Enter your API key",
|
|
3435
3561
|
placeholder: "fdk_... or lin_api_...",
|
|
3436
3562
|
validate(value) {
|
|
@@ -3500,14 +3626,14 @@ var init_connect = __esm({
|
|
|
3500
3626
|
const templateDir = await resolveTemplatePath(
|
|
3501
3627
|
args["local-source"] || void 0
|
|
3502
3628
|
);
|
|
3503
|
-
const templateSkillsDir =
|
|
3504
|
-
const skillsDir =
|
|
3629
|
+
const templateSkillsDir = join18(templateDir, ".claude", "skills");
|
|
3630
|
+
const skillsDir = join18(targetDir, ".claude", "skills");
|
|
3505
3631
|
await replaceDirectory(
|
|
3506
|
-
|
|
3507
|
-
|
|
3632
|
+
join18(templateSkillsDir, "flydocs-cloud"),
|
|
3633
|
+
join18(skillsDir, "flydocs-cloud")
|
|
3508
3634
|
);
|
|
3509
3635
|
const { rm: rm6 } = await import("fs/promises");
|
|
3510
|
-
const localSkillDir =
|
|
3636
|
+
const localSkillDir = join18(skillsDir, "flydocs-local");
|
|
3511
3637
|
if (await pathExists(localSkillDir)) {
|
|
3512
3638
|
await rm6(localSkillDir, { recursive: true, force: true });
|
|
3513
3639
|
}
|