coding-friend-cli 1.3.0 → 1.5.0
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/README.md +4 -0
- package/dist/chunk-5OALHHKR.js +77 -0
- package/dist/{chunk-CSF4FAHL.js → chunk-DDISNOEK.js} +15 -1
- package/dist/{update-GGCBM7U4.js → chunk-GTTSBOHM.js} +6 -2
- package/dist/{chunk-HRVSKMNA.js → chunk-JWAJ4XPK.js} +11 -0
- package/dist/chunk-MRTR7TJ4.js +27 -0
- package/dist/{chunk-6OI37OZX.js → chunk-WHCJT7E2.js} +25 -1
- package/dist/{chunk-Q4DKU5IG.js → chunk-X645ACZJ.js} +1 -1
- package/dist/{dev-VMN2JHA6.js → dev-WINMWRZK.js} +5 -13
- package/dist/{host-2WINWEW7.js → host-VR5POAVU.js} +3 -3
- package/dist/index.js +18 -10
- package/dist/{init-CTCDQKIQ.js → init-K4EVPAHK.js} +30 -4
- package/dist/install-BEFMUMKE.js +93 -0
- package/dist/{mcp-43HCE2KD.js → mcp-JCQUGUPJ.js} +3 -3
- package/dist/postinstall.js +1 -1
- package/dist/statusline-3MQQDRCI.js +55 -0
- package/dist/uninstall-BHYS52L3.js +202 -0
- package/dist/update-TALQ7TAO.js +17 -0
- package/lib/learn-host/CHANGELOG.md +6 -0
- package/lib/learn-host/package.json +1 -1
- package/lib/learn-host/src/app/globals.css +34 -4
- package/lib/learn-host/src/app/layout.tsx +2 -13
- package/lib/learn-host/src/app/page.tsx +45 -15
- package/lib/learn-host/src/components/Breadcrumbs.tsx +2 -5
- package/lib/learn-host/src/components/CodeBlock.tsx +56 -0
- package/lib/learn-host/src/components/DocCard.tsx +4 -6
- package/lib/learn-host/src/components/LayoutShell.tsx +39 -0
- package/lib/learn-host/src/components/MarkdownRenderer.tsx +2 -0
- package/lib/learn-host/src/components/MobileNav.tsx +1 -1
- package/lib/learn-host/src/components/Sidebar.tsx +1 -1
- package/lib/learn-host/src/components/TableOfContents.tsx +2 -2
- package/lib/learn-host/src/components/TagBadge.tsx +1 -1
- package/lib/learn-host/src/components/layout/Footer.tsx +8 -4
- package/lib/learn-host/src/components/layout/Header.tsx +2 -2
- package/lib/learn-host/src/lib/docs.ts +11 -2
- package/lib/learn-mcp/CHANGELOG.md +4 -0
- package/lib/learn-mcp/README.md +18 -0
- package/lib/learn-mcp/package.json +1 -1
- package/lib/learn-mcp/src/index.ts +1 -1
- package/package.json +1 -1
- package/dist/statusline-ARI7I5YM.js +0 -64
- package/lib/learn-host/next-env.d.ts +0 -6
package/README.md
CHANGED
|
@@ -16,6 +16,10 @@ npm i -g coding-friend-cli
|
|
|
16
16
|
## Commands
|
|
17
17
|
|
|
18
18
|
```bash
|
|
19
|
+
cf install # Install the Coding Friend plugin into Claude Code
|
|
20
|
+
# 💡 Safe to run multiple times (idempotent).
|
|
21
|
+
cf uninstall # Completely remove plugin, marketplace, statusline, completion
|
|
22
|
+
# 💡 Interactive — asks for confirmation before acting.
|
|
19
23
|
cf init # Initialize workspace (interactive)
|
|
20
24
|
# 💡 You can run this anywhere, anytime.
|
|
21
25
|
cf host [path] # Build and serve learning docs at localhost:3333
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ALL_COMPONENT_IDS,
|
|
3
|
+
STATUSLINE_COMPONENTS
|
|
4
|
+
} from "./chunk-JWAJ4XPK.js";
|
|
5
|
+
import {
|
|
6
|
+
claudeSettingsPath,
|
|
7
|
+
globalConfigPath,
|
|
8
|
+
pluginCachePath
|
|
9
|
+
} from "./chunk-WHCJT7E2.js";
|
|
10
|
+
import {
|
|
11
|
+
mergeJson,
|
|
12
|
+
readJson,
|
|
13
|
+
writeJson
|
|
14
|
+
} from "./chunk-IUTXHCP7.js";
|
|
15
|
+
|
|
16
|
+
// src/lib/statusline.ts
|
|
17
|
+
import { existsSync, readdirSync } from "fs";
|
|
18
|
+
import { checkbox } from "@inquirer/prompts";
|
|
19
|
+
function findLatestVersion() {
|
|
20
|
+
const cachePath = pluginCachePath();
|
|
21
|
+
if (!existsSync(cachePath)) return null;
|
|
22
|
+
const versions = readdirSync(cachePath, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name).sort().reverse();
|
|
23
|
+
return versions[0] ?? null;
|
|
24
|
+
}
|
|
25
|
+
function findStatuslineHookPath() {
|
|
26
|
+
const version = findLatestVersion();
|
|
27
|
+
if (!version) return null;
|
|
28
|
+
const hookPath = `${pluginCachePath()}/${version}/hooks/statusline.sh`;
|
|
29
|
+
if (!existsSync(hookPath)) return null;
|
|
30
|
+
return { hookPath, version };
|
|
31
|
+
}
|
|
32
|
+
function loadStatuslineComponents() {
|
|
33
|
+
const config = readJson(globalConfigPath());
|
|
34
|
+
const components = config?.statusline?.components;
|
|
35
|
+
if (!components) return ALL_COMPONENT_IDS;
|
|
36
|
+
return components.filter(
|
|
37
|
+
(c) => ALL_COMPONENT_IDS.includes(c)
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
async function selectStatuslineComponents(current) {
|
|
41
|
+
const enabled = current ?? loadStatuslineComponents();
|
|
42
|
+
const selected = await checkbox({
|
|
43
|
+
message: "Which components to show in the statusline?",
|
|
44
|
+
choices: STATUSLINE_COMPONENTS.map((c) => ({
|
|
45
|
+
name: c.label,
|
|
46
|
+
value: c.id,
|
|
47
|
+
checked: enabled.includes(c.id)
|
|
48
|
+
}))
|
|
49
|
+
});
|
|
50
|
+
return selected;
|
|
51
|
+
}
|
|
52
|
+
function saveStatuslineConfig(components) {
|
|
53
|
+
mergeJson(globalConfigPath(), { statusline: { components } });
|
|
54
|
+
}
|
|
55
|
+
function writeStatuslineSettings(hookPath) {
|
|
56
|
+
const settingsPath = claudeSettingsPath();
|
|
57
|
+
const settings = readJson(settingsPath) ?? {};
|
|
58
|
+
settings.statusLine = {
|
|
59
|
+
type: "command",
|
|
60
|
+
command: `bash ${hookPath}`
|
|
61
|
+
};
|
|
62
|
+
writeJson(settingsPath, settings);
|
|
63
|
+
}
|
|
64
|
+
function isStatuslineConfigured() {
|
|
65
|
+
const settings = readJson(claudeSettingsPath());
|
|
66
|
+
if (!settings) return false;
|
|
67
|
+
const sl = settings.statusLine;
|
|
68
|
+
return !!sl?.command;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export {
|
|
72
|
+
findStatuslineHookPath,
|
|
73
|
+
selectStatuslineComponents,
|
|
74
|
+
saveStatuslineConfig,
|
|
75
|
+
writeStatuslineSettings,
|
|
76
|
+
isStatuslineConfigured
|
|
77
|
+
};
|
|
@@ -13,7 +13,7 @@ ${MARKER_START}
|
|
|
13
13
|
_cf_completions() {
|
|
14
14
|
local cur="\${COMP_WORDS[COMP_CWORD]}"
|
|
15
15
|
local prev="\${COMP_WORDS[COMP_CWORD-1]}"
|
|
16
|
-
local commands="init host mcp statusline update dev"
|
|
16
|
+
local commands="install uninstall init host mcp statusline update dev"
|
|
17
17
|
|
|
18
18
|
# Subcommands for 'dev'
|
|
19
19
|
if [[ "\${COMP_WORDS[1]}" == "dev" && \${COMP_CWORD} -eq 2 ]]; then
|
|
@@ -38,6 +38,8 @@ ${MARKER_START}
|
|
|
38
38
|
_cf() {
|
|
39
39
|
local -a commands
|
|
40
40
|
commands=(
|
|
41
|
+
'install:Install the Coding Friend plugin into Claude Code'
|
|
42
|
+
'uninstall:Uninstall the Coding Friend plugin from Claude Code'
|
|
41
43
|
'init:Initialize coding-friend in current project'
|
|
42
44
|
'host:Build and serve learning docs as a static website'
|
|
43
45
|
'mcp:Setup MCP server for learning docs'
|
|
@@ -94,6 +96,17 @@ function replaceBlock(content, newBlock) {
|
|
|
94
96
|
while (sliceStart > 0 && content[sliceStart - 1] === "\n") sliceStart--;
|
|
95
97
|
return content.slice(0, sliceStart) + newBlock + content.slice(endIdx + MARKER_END.length);
|
|
96
98
|
}
|
|
99
|
+
function removeShellCompletion() {
|
|
100
|
+
const rcPath = getShellRcPath();
|
|
101
|
+
if (!existsSync(rcPath)) return false;
|
|
102
|
+
const content = readFileSync(rcPath, "utf-8");
|
|
103
|
+
if (!content.includes(MARKER_START)) return false;
|
|
104
|
+
const updated = replaceBlock(content, "");
|
|
105
|
+
writeFileSync(rcPath, updated, "utf-8");
|
|
106
|
+
const rcName = getRcName(rcPath);
|
|
107
|
+
log.success(`Tab completion removed from ~/${rcName}`);
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
97
110
|
function ensureShellCompletion(opts) {
|
|
98
111
|
const rcPath = getShellRcPath();
|
|
99
112
|
const rcName = getRcName(rcPath);
|
|
@@ -125,5 +138,6 @@ function ensureShellCompletion(opts) {
|
|
|
125
138
|
|
|
126
139
|
export {
|
|
127
140
|
hasShellCompletion,
|
|
141
|
+
removeShellCompletion,
|
|
128
142
|
ensureShellCompletion
|
|
129
143
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ensureShellCompletion
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-DDISNOEK.js";
|
|
4
4
|
import {
|
|
5
5
|
commandExists,
|
|
6
6
|
run,
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
claudeSettingsPath,
|
|
11
11
|
installedPluginsPath,
|
|
12
12
|
pluginCachePath
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-WHCJT7E2.js";
|
|
14
14
|
import {
|
|
15
15
|
log
|
|
16
16
|
} from "./chunk-6DUFTBTO.js";
|
|
@@ -248,6 +248,10 @@ async function updateCommand(opts) {
|
|
|
248
248
|
console.log();
|
|
249
249
|
log.dim("Restart Claude Code (or start a new session) to see changes.");
|
|
250
250
|
}
|
|
251
|
+
|
|
251
252
|
export {
|
|
253
|
+
semverCompare,
|
|
254
|
+
getInstalledVersion,
|
|
255
|
+
getLatestVersion,
|
|
252
256
|
updateCommand
|
|
253
257
|
};
|
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
// src/types.ts
|
|
2
|
+
var STATUSLINE_COMPONENTS = [
|
|
3
|
+
{ id: "version", label: "Plugin version (cf v0.3.0)" },
|
|
4
|
+
{ id: "folder", label: "Project name (MyProject)" },
|
|
5
|
+
{ id: "model", label: "Active model (Opus 4.6)" },
|
|
6
|
+
{ id: "branch", label: "Git branch (\u2387 main)" },
|
|
7
|
+
{ id: "context", label: "Context window usage (ctx 42%)" },
|
|
8
|
+
{ id: "usage", label: "API usage + reset time (15% \u2192 02:30)" }
|
|
9
|
+
];
|
|
10
|
+
var ALL_COMPONENT_IDS = STATUSLINE_COMPONENTS.map((c) => c.id);
|
|
2
11
|
var DEFAULT_CONFIG = {
|
|
3
12
|
language: "en",
|
|
4
13
|
docsDir: "docs",
|
|
@@ -27,5 +36,7 @@ var DEFAULT_CONFIG = {
|
|
|
27
36
|
};
|
|
28
37
|
|
|
29
38
|
export {
|
|
39
|
+
STATUSLINE_COMPONENTS,
|
|
40
|
+
ALL_COMPONENT_IDS,
|
|
30
41
|
DEFAULT_CONFIG
|
|
31
42
|
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import {
|
|
2
|
+
installedPluginsPath,
|
|
3
|
+
knownMarketplacesPath
|
|
4
|
+
} from "./chunk-WHCJT7E2.js";
|
|
5
|
+
import {
|
|
6
|
+
readJson
|
|
7
|
+
} from "./chunk-IUTXHCP7.js";
|
|
8
|
+
|
|
9
|
+
// src/lib/plugin-state.ts
|
|
10
|
+
var MARKETPLACE_NAME = "coding-friend-marketplace";
|
|
11
|
+
var PLUGIN_NAME = "coding-friend";
|
|
12
|
+
function isPluginInstalled() {
|
|
13
|
+
const data = readJson(installedPluginsPath());
|
|
14
|
+
if (!data) return false;
|
|
15
|
+
const plugins = data.plugins ?? data;
|
|
16
|
+
return Object.keys(plugins).some((k) => k.includes(PLUGIN_NAME));
|
|
17
|
+
}
|
|
18
|
+
function isMarketplaceRegistered() {
|
|
19
|
+
const data = readJson(knownMarketplacesPath());
|
|
20
|
+
if (!data) return false;
|
|
21
|
+
return MARKETPLACE_NAME in data;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export {
|
|
25
|
+
isPluginInstalled,
|
|
26
|
+
isMarketplaceRegistered
|
|
27
|
+
};
|
|
@@ -34,6 +34,27 @@ function devStatePath() {
|
|
|
34
34
|
function knownMarketplacesPath() {
|
|
35
35
|
return join(homedir(), ".claude", "plugins", "known_marketplaces.json");
|
|
36
36
|
}
|
|
37
|
+
function marketplaceCachePath() {
|
|
38
|
+
return join(
|
|
39
|
+
homedir(),
|
|
40
|
+
".claude",
|
|
41
|
+
"plugins",
|
|
42
|
+
"cache",
|
|
43
|
+
"coding-friend-marketplace"
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
function marketplaceClonePath() {
|
|
47
|
+
return join(
|
|
48
|
+
homedir(),
|
|
49
|
+
".claude",
|
|
50
|
+
"plugins",
|
|
51
|
+
"marketplaces",
|
|
52
|
+
"coding-friend-marketplace"
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
function globalConfigDir() {
|
|
56
|
+
return join(homedir(), ".coding-friend");
|
|
57
|
+
}
|
|
37
58
|
|
|
38
59
|
export {
|
|
39
60
|
resolvePath,
|
|
@@ -43,5 +64,8 @@ export {
|
|
|
43
64
|
installedPluginsPath,
|
|
44
65
|
pluginCachePath,
|
|
45
66
|
devStatePath,
|
|
46
|
-
knownMarketplacesPath
|
|
67
|
+
knownMarketplacesPath,
|
|
68
|
+
marketplaceCachePath,
|
|
69
|
+
marketplaceClonePath,
|
|
70
|
+
globalConfigDir
|
|
47
71
|
};
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isMarketplaceRegistered,
|
|
3
|
+
isPluginInstalled
|
|
4
|
+
} from "./chunk-MRTR7TJ4.js";
|
|
1
5
|
import {
|
|
2
6
|
commandExists,
|
|
3
7
|
run
|
|
@@ -5,10 +9,9 @@ import {
|
|
|
5
9
|
import {
|
|
6
10
|
claudeSettingsPath,
|
|
7
11
|
devStatePath,
|
|
8
|
-
installedPluginsPath,
|
|
9
12
|
knownMarketplacesPath,
|
|
10
13
|
pluginCachePath
|
|
11
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-WHCJT7E2.js";
|
|
12
15
|
import {
|
|
13
16
|
log
|
|
14
17
|
} from "./chunk-6DUFTBTO.js";
|
|
@@ -35,17 +38,6 @@ var PLUGIN_ID = `${PLUGIN_NAME}@${MARKETPLACE_NAME}`;
|
|
|
35
38
|
function getDevState() {
|
|
36
39
|
return readJson(devStatePath());
|
|
37
40
|
}
|
|
38
|
-
function isPluginInstalled() {
|
|
39
|
-
const data = readJson(installedPluginsPath());
|
|
40
|
-
if (!data) return false;
|
|
41
|
-
const plugins = data.plugins ?? data;
|
|
42
|
-
return Object.keys(plugins).some((k) => k.includes(PLUGIN_NAME));
|
|
43
|
-
}
|
|
44
|
-
function isMarketplaceRegistered() {
|
|
45
|
-
const data = readJson(knownMarketplacesPath());
|
|
46
|
-
if (!data) return false;
|
|
47
|
-
return MARKETPLACE_NAME in data;
|
|
48
|
-
}
|
|
49
41
|
function ensureClaude() {
|
|
50
42
|
if (!commandExists("claude")) {
|
|
51
43
|
log.error(
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getLibPath,
|
|
3
3
|
resolveDocsDir
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-
|
|
4
|
+
} from "./chunk-X645ACZJ.js";
|
|
5
|
+
import "./chunk-JWAJ4XPK.js";
|
|
6
6
|
import {
|
|
7
7
|
run,
|
|
8
8
|
streamExec
|
|
9
9
|
} from "./chunk-UFGNO6CW.js";
|
|
10
|
-
import "./chunk-
|
|
10
|
+
import "./chunk-WHCJT7E2.js";
|
|
11
11
|
import {
|
|
12
12
|
log
|
|
13
13
|
} from "./chunk-6DUFTBTO.js";
|
package/dist/index.js
CHANGED
|
@@ -13,24 +13,32 @@ var program = new Command();
|
|
|
13
13
|
program.name("cf").description(
|
|
14
14
|
"coding-friend CLI \u2014 host learning docs, setup MCP, init projects"
|
|
15
15
|
).version(pkg.version, "-v, --version");
|
|
16
|
+
program.command("install").description("Install the Coding Friend plugin into Claude Code").action(async () => {
|
|
17
|
+
const { installCommand } = await import("./install-BEFMUMKE.js");
|
|
18
|
+
await installCommand();
|
|
19
|
+
});
|
|
20
|
+
program.command("uninstall").description("Uninstall the Coding Friend plugin from Claude Code").action(async () => {
|
|
21
|
+
const { uninstallCommand } = await import("./uninstall-BHYS52L3.js");
|
|
22
|
+
await uninstallCommand();
|
|
23
|
+
});
|
|
16
24
|
program.command("init").description("Initialize coding-friend in current project").action(async () => {
|
|
17
|
-
const { initCommand } = await import("./init-
|
|
25
|
+
const { initCommand } = await import("./init-K4EVPAHK.js");
|
|
18
26
|
await initCommand();
|
|
19
27
|
});
|
|
20
28
|
program.command("host").description("Build and serve learning docs as a static website").argument("[path]", "path to docs folder").option("-p, --port <port>", "port number", "3333").action(async (path, opts) => {
|
|
21
|
-
const { hostCommand } = await import("./host-
|
|
29
|
+
const { hostCommand } = await import("./host-VR5POAVU.js");
|
|
22
30
|
await hostCommand(path, opts);
|
|
23
31
|
});
|
|
24
32
|
program.command("mcp").description("Setup MCP server for learning docs").argument("[path]", "path to docs folder").action(async (path) => {
|
|
25
|
-
const { mcpCommand } = await import("./mcp-
|
|
33
|
+
const { mcpCommand } = await import("./mcp-JCQUGUPJ.js");
|
|
26
34
|
await mcpCommand(path);
|
|
27
35
|
});
|
|
28
36
|
program.command("statusline").description("Setup coding-friend statusline in Claude Code").action(async () => {
|
|
29
|
-
const { statuslineCommand } = await import("./statusline-
|
|
37
|
+
const { statuslineCommand } = await import("./statusline-3MQQDRCI.js");
|
|
30
38
|
await statuslineCommand();
|
|
31
39
|
});
|
|
32
40
|
program.command("update").description("Update coding-friend plugin, CLI, and statusline").option("--cli", "Update only the CLI (npm package)").option("--plugin", "Update only the Claude Code plugin").option("--statusline", "Update only the statusline").action(async (opts) => {
|
|
33
|
-
const { updateCommand } = await import("./update-
|
|
41
|
+
const { updateCommand } = await import("./update-TALQ7TAO.js");
|
|
34
42
|
await updateCommand(opts);
|
|
35
43
|
});
|
|
36
44
|
var dev = program.command("dev").description("Development mode commands");
|
|
@@ -45,28 +53,28 @@ Dev subcommands:
|
|
|
45
53
|
dev restart [path] Reinstall local dev plugin (off + on)`
|
|
46
54
|
);
|
|
47
55
|
dev.command("on").description("Switch to local plugin source").argument("[path]", "path to local coding-friend repo (default: cwd)").action(async (path) => {
|
|
48
|
-
const { devOnCommand } = await import("./dev-
|
|
56
|
+
const { devOnCommand } = await import("./dev-WINMWRZK.js");
|
|
49
57
|
await devOnCommand(path);
|
|
50
58
|
});
|
|
51
59
|
dev.command("off").description("Switch back to remote marketplace").action(async () => {
|
|
52
|
-
const { devOffCommand } = await import("./dev-
|
|
60
|
+
const { devOffCommand } = await import("./dev-WINMWRZK.js");
|
|
53
61
|
await devOffCommand();
|
|
54
62
|
});
|
|
55
63
|
dev.command("status").description("Show current dev mode").action(async () => {
|
|
56
|
-
const { devStatusCommand } = await import("./dev-
|
|
64
|
+
const { devStatusCommand } = await import("./dev-WINMWRZK.js");
|
|
57
65
|
await devStatusCommand();
|
|
58
66
|
});
|
|
59
67
|
dev.command("sync").description(
|
|
60
68
|
"Copy local source files to plugin cache (no version bump needed)"
|
|
61
69
|
).action(async () => {
|
|
62
|
-
const { devSyncCommand } = await import("./dev-
|
|
70
|
+
const { devSyncCommand } = await import("./dev-WINMWRZK.js");
|
|
63
71
|
await devSyncCommand();
|
|
64
72
|
});
|
|
65
73
|
dev.command("restart").description("Reinstall local dev plugin (off + on)").argument(
|
|
66
74
|
"[path]",
|
|
67
75
|
"path to local coding-friend repo (default: saved path or cwd)"
|
|
68
76
|
).action(async (path) => {
|
|
69
|
-
const { devRestartCommand } = await import("./dev-
|
|
77
|
+
const { devRestartCommand } = await import("./dev-WINMWRZK.js");
|
|
70
78
|
await devRestartCommand(path);
|
|
71
79
|
});
|
|
72
80
|
program.parse();
|
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
findStatuslineHookPath,
|
|
3
|
+
isStatuslineConfigured,
|
|
4
|
+
saveStatuslineConfig,
|
|
5
|
+
selectStatuslineComponents,
|
|
6
|
+
writeStatuslineSettings
|
|
7
|
+
} from "./chunk-5OALHHKR.js";
|
|
4
8
|
import {
|
|
5
9
|
ensureShellCompletion,
|
|
6
10
|
hasShellCompletion
|
|
7
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-DDISNOEK.js";
|
|
12
|
+
import {
|
|
13
|
+
DEFAULT_CONFIG
|
|
14
|
+
} from "./chunk-JWAJ4XPK.js";
|
|
8
15
|
import {
|
|
9
16
|
run
|
|
10
17
|
} from "./chunk-UFGNO6CW.js";
|
|
@@ -13,7 +20,7 @@ import {
|
|
|
13
20
|
globalConfigPath,
|
|
14
21
|
localConfigPath,
|
|
15
22
|
resolvePath
|
|
16
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-WHCJT7E2.js";
|
|
17
24
|
import {
|
|
18
25
|
log
|
|
19
26
|
} from "./chunk-6DUFTBTO.js";
|
|
@@ -338,6 +345,11 @@ async function initCommand() {
|
|
|
338
345
|
name: "completion",
|
|
339
346
|
label: "Setup shell tab completion",
|
|
340
347
|
done: hasShellCompletion()
|
|
348
|
+
},
|
|
349
|
+
{
|
|
350
|
+
name: "statusline",
|
|
351
|
+
label: "Configure statusline",
|
|
352
|
+
done: isStatuslineConfigured()
|
|
341
353
|
}
|
|
342
354
|
];
|
|
343
355
|
if (hasExternalDir && resolvedOutputDir) {
|
|
@@ -417,6 +429,20 @@ async function initCommand() {
|
|
|
417
429
|
case "completion":
|
|
418
430
|
ensureShellCompletion();
|
|
419
431
|
break;
|
|
432
|
+
case "statusline": {
|
|
433
|
+
const hookResult = findStatuslineHookPath();
|
|
434
|
+
if (!hookResult) {
|
|
435
|
+
log.warn(
|
|
436
|
+
"coding-friend plugin not found. Install it via Claude Code first, then re-run."
|
|
437
|
+
);
|
|
438
|
+
break;
|
|
439
|
+
}
|
|
440
|
+
const components = await selectStatuslineComponents();
|
|
441
|
+
saveStatuslineConfig(components);
|
|
442
|
+
writeStatuslineSettings(hookResult.hookPath);
|
|
443
|
+
log.success("Statusline configured!");
|
|
444
|
+
break;
|
|
445
|
+
}
|
|
420
446
|
case "permissions":
|
|
421
447
|
if (resolvedOutputDir) {
|
|
422
448
|
await setupClaudePermissions(resolvedOutputDir, learnAutoCommit);
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getInstalledVersion,
|
|
3
|
+
getLatestVersion,
|
|
4
|
+
semverCompare
|
|
5
|
+
} from "./chunk-GTTSBOHM.js";
|
|
6
|
+
import {
|
|
7
|
+
isMarketplaceRegistered
|
|
8
|
+
} from "./chunk-MRTR7TJ4.js";
|
|
9
|
+
import "./chunk-DDISNOEK.js";
|
|
10
|
+
import {
|
|
11
|
+
commandExists,
|
|
12
|
+
run
|
|
13
|
+
} from "./chunk-UFGNO6CW.js";
|
|
14
|
+
import "./chunk-WHCJT7E2.js";
|
|
15
|
+
import {
|
|
16
|
+
log
|
|
17
|
+
} from "./chunk-6DUFTBTO.js";
|
|
18
|
+
import "./chunk-IUTXHCP7.js";
|
|
19
|
+
|
|
20
|
+
// src/commands/install.ts
|
|
21
|
+
import chalk from "chalk";
|
|
22
|
+
async function installCommand() {
|
|
23
|
+
console.log("=== \u{1F33F} Coding Friend Install \u{1F33F} ===");
|
|
24
|
+
console.log();
|
|
25
|
+
if (!commandExists("claude")) {
|
|
26
|
+
log.error(
|
|
27
|
+
"Claude CLI not found. Install it first: https://docs.anthropic.com/en/docs/claude-code/getting-started"
|
|
28
|
+
);
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
if (isMarketplaceRegistered()) {
|
|
32
|
+
log.success("Marketplace already registered.");
|
|
33
|
+
} else {
|
|
34
|
+
log.step("Adding coding-friend marketplace...");
|
|
35
|
+
const result = run("claude", [
|
|
36
|
+
"plugin",
|
|
37
|
+
"marketplace",
|
|
38
|
+
"add",
|
|
39
|
+
"dinhanhthi/coding-friend"
|
|
40
|
+
]);
|
|
41
|
+
if (result === null) {
|
|
42
|
+
log.error(
|
|
43
|
+
"Failed to add marketplace. Try manually: claude plugin marketplace add dinhanhthi/coding-friend"
|
|
44
|
+
);
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
log.success("Marketplace added.");
|
|
48
|
+
}
|
|
49
|
+
const installedVersion = getInstalledVersion();
|
|
50
|
+
if (!installedVersion) {
|
|
51
|
+
log.step("Installing plugin...");
|
|
52
|
+
const result = run("claude", [
|
|
53
|
+
"plugin",
|
|
54
|
+
"install",
|
|
55
|
+
"coding-friend@coding-friend-marketplace"
|
|
56
|
+
]);
|
|
57
|
+
if (result === null) {
|
|
58
|
+
log.error(
|
|
59
|
+
"Failed to install plugin. Try manually: claude plugin install coding-friend@coding-friend-marketplace"
|
|
60
|
+
);
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
log.success("Plugin installed!");
|
|
64
|
+
} else {
|
|
65
|
+
log.success(
|
|
66
|
+
`Plugin already installed (${chalk.green(`v${installedVersion}`)}).`
|
|
67
|
+
);
|
|
68
|
+
const latestVersion = getLatestVersion();
|
|
69
|
+
if (latestVersion) {
|
|
70
|
+
const cmp = semverCompare(installedVersion, latestVersion);
|
|
71
|
+
if (cmp < 0) {
|
|
72
|
+
log.warn(
|
|
73
|
+
`Update available: ${chalk.yellow(`v${installedVersion}`)} \u2192 ${chalk.green(`v${latestVersion}`)}. Run ${chalk.cyan("cf update")} to update.`
|
|
74
|
+
);
|
|
75
|
+
} else {
|
|
76
|
+
log.success("Already on the latest version.");
|
|
77
|
+
}
|
|
78
|
+
} else {
|
|
79
|
+
log.dim("Could not check for updates (no network or GitHub rate limit).");
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
console.log();
|
|
83
|
+
log.info("Next steps:");
|
|
84
|
+
log.dim(
|
|
85
|
+
` ${chalk.cyan("cf init")} Initialize workspace (docs folders, config)`
|
|
86
|
+
);
|
|
87
|
+
log.dim(` ${chalk.cyan("cf statusline")} Setup statusline in Claude Code`);
|
|
88
|
+
console.log();
|
|
89
|
+
log.dim("Restart Claude Code (or start a new session) to use the plugin.");
|
|
90
|
+
}
|
|
91
|
+
export {
|
|
92
|
+
installCommand
|
|
93
|
+
};
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getLibPath,
|
|
3
3
|
resolveDocsDir
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-
|
|
4
|
+
} from "./chunk-X645ACZJ.js";
|
|
5
|
+
import "./chunk-JWAJ4XPK.js";
|
|
6
6
|
import {
|
|
7
7
|
run
|
|
8
8
|
} from "./chunk-UFGNO6CW.js";
|
|
9
|
-
import "./chunk-
|
|
9
|
+
import "./chunk-WHCJT7E2.js";
|
|
10
10
|
import {
|
|
11
11
|
log
|
|
12
12
|
} from "./chunk-6DUFTBTO.js";
|
package/dist/postinstall.js
CHANGED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import {
|
|
2
|
+
findStatuslineHookPath,
|
|
3
|
+
isStatuslineConfigured,
|
|
4
|
+
saveStatuslineConfig,
|
|
5
|
+
selectStatuslineComponents,
|
|
6
|
+
writeStatuslineSettings
|
|
7
|
+
} from "./chunk-5OALHHKR.js";
|
|
8
|
+
import {
|
|
9
|
+
ALL_COMPONENT_IDS
|
|
10
|
+
} from "./chunk-JWAJ4XPK.js";
|
|
11
|
+
import "./chunk-WHCJT7E2.js";
|
|
12
|
+
import {
|
|
13
|
+
log
|
|
14
|
+
} from "./chunk-6DUFTBTO.js";
|
|
15
|
+
import "./chunk-IUTXHCP7.js";
|
|
16
|
+
|
|
17
|
+
// src/commands/statusline.ts
|
|
18
|
+
import { confirm } from "@inquirer/prompts";
|
|
19
|
+
import chalk from "chalk";
|
|
20
|
+
async function statuslineCommand() {
|
|
21
|
+
console.log("=== \u{1F33F} Coding Friend Statusline \u{1F33F} ===");
|
|
22
|
+
console.log();
|
|
23
|
+
const result = findStatuslineHookPath();
|
|
24
|
+
if (!result) {
|
|
25
|
+
log.error(
|
|
26
|
+
"coding-friend plugin not found in cache. Install it first via Claude Code."
|
|
27
|
+
);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
log.info(`Found plugin ${chalk.green(`v${result.version}`)}`);
|
|
31
|
+
if (isStatuslineConfigured()) {
|
|
32
|
+
log.warn("Statusline already configured.");
|
|
33
|
+
const overwrite = await confirm({
|
|
34
|
+
message: "Reconfigure statusline?",
|
|
35
|
+
default: true
|
|
36
|
+
});
|
|
37
|
+
if (!overwrite) {
|
|
38
|
+
log.dim("Skipped.");
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
const components = await selectStatuslineComponents();
|
|
43
|
+
saveStatuslineConfig(components);
|
|
44
|
+
writeStatuslineSettings(result.hookPath);
|
|
45
|
+
log.success("Statusline configured!");
|
|
46
|
+
log.dim("Restart Claude Code (or start a new session) to see it.");
|
|
47
|
+
if (components.length < ALL_COMPONENT_IDS.length) {
|
|
48
|
+
log.dim(`Showing: ${components.join(", ")}`);
|
|
49
|
+
} else {
|
|
50
|
+
log.dim("Showing all components.");
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
export {
|
|
54
|
+
statuslineCommand
|
|
55
|
+
};
|