coding-friend-cli 1.10.0 → 1.12.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 +28 -7
- package/dist/{chunk-4C4EKYM3.js → chunk-56U7US6J.js} +1 -1
- package/dist/{chunk-AHGBESGW.js → chunk-EMAINEYB.js} +47 -1
- package/dist/{chunk-EDVZPZ3B.js → chunk-KB4JM2EB.js} +1 -1
- package/dist/{chunk-BCYBFGVD.js → chunk-KJUGTLPQ.js} +66 -2
- package/dist/{chunk-YAOUAJZP.js → chunk-QG6XYVJU.js} +1 -1
- package/dist/{chunk-HQ5BPWEV.js → chunk-RWUTFVRB.js} +31 -27
- package/dist/{chunk-UR5XUEH5.js → chunk-YZ7IZ46F.js} +22 -6
- package/dist/chunk-ZOOFPF5I.js +68 -0
- package/dist/{config-6P3SE3NS.js → config-PTMK6XBN.js} +16 -16
- package/dist/{dev-4NLCK6YG.js → dev-UBYW6NRX.js} +5 -5
- package/dist/disable-3N2NCMTU.js +35 -0
- package/dist/enable-EGG6LTXD.js +32 -0
- package/dist/{host-BPO2STZA.js → host-XHBUWGAW.js} +2 -2
- package/dist/index.js +30 -22
- package/dist/{init-BG2ESQQC.js → init-2LMIUWUY.js} +16 -16
- package/dist/{install-YEAWW7ZX.js → install-FEOOFN4G.js} +39 -12
- package/dist/{mcp-54UB5MF2.js → mcp-XE6NZRPD.js} +2 -2
- package/dist/{permission-GPOUJUZS.js → permission-L2QQR5PO.js} +2 -2
- package/dist/postinstall.js +1 -1
- package/dist/{session-STYOO4A4.js → session-K6YWJLLU.js} +4 -2
- package/dist/{statusline-L2CYEV4H.js → statusline-5ZMM3RYY.js} +2 -2
- package/dist/{uninstall-3ISPGQHE.js → uninstall-2SYDCOAP.js} +62 -6
- package/dist/{update-EN6S3FKT.js → update-4MNVBTI5.js} +5 -4
- package/package.json +1 -1
- package/dist/chunk-TLLWOWYU.js +0 -25
package/README.md
CHANGED
|
@@ -16,10 +16,29 @@ npm i -g coding-friend-cli
|
|
|
16
16
|
## Commands
|
|
17
17
|
|
|
18
18
|
```bash
|
|
19
|
-
cf install
|
|
20
|
-
|
|
21
|
-
cf
|
|
22
|
-
|
|
19
|
+
cf install # Install plugin (interactive scope chooser)
|
|
20
|
+
cf install --user # Install at user scope (all projects)
|
|
21
|
+
cf install --global # Same as --user
|
|
22
|
+
cf install --project # Install at project scope (shared via git)
|
|
23
|
+
cf install --local # Install at local scope (this machine only)
|
|
24
|
+
# 💡 Safe to run multiple times (idempotent).
|
|
25
|
+
cf uninstall # Uninstall plugin (interactive scope chooser)
|
|
26
|
+
cf uninstall --user # Uninstall from user scope (full cleanup)
|
|
27
|
+
cf uninstall --global # Same as --user
|
|
28
|
+
cf uninstall --project # Uninstall from project scope only
|
|
29
|
+
cf uninstall --local # Uninstall from local scope only
|
|
30
|
+
# 💡 Interactive — asks for confirmation before acting.
|
|
31
|
+
cf disable # Disable plugin (interactive scope chooser)
|
|
32
|
+
cf disable --user # Disable at user scope (all projects)
|
|
33
|
+
cf disable --global # Same as --user
|
|
34
|
+
cf disable --project # Disable at project scope
|
|
35
|
+
cf disable --local # Disable at local scope
|
|
36
|
+
# 💡 Plugin stays installed but won't load.
|
|
37
|
+
cf enable # Re-enable plugin (interactive scope chooser)
|
|
38
|
+
cf enable --user # Enable at user scope (all projects)
|
|
39
|
+
cf enable --global # Same as --user
|
|
40
|
+
cf enable --project # Enable at project scope
|
|
41
|
+
cf enable --local # Enable at local scope
|
|
23
42
|
cf init # Initialize workspace (interactive)
|
|
24
43
|
# 💡 You can run this anywhere, anytime.
|
|
25
44
|
cf config # Manage Coding Friend configuration (interactive menu)
|
|
@@ -32,10 +51,12 @@ cf mcp [path] # Setup MCP server for LLM integration
|
|
|
32
51
|
cf permission # Manage Claude Code permission rules for Coding Friend
|
|
33
52
|
cf permission --all # Apply all recommended permissions without prompts
|
|
34
53
|
cf statusline # Setup coding-friend statusline
|
|
35
|
-
cf update
|
|
36
|
-
cf update --cli
|
|
37
|
-
cf update --plugin
|
|
54
|
+
cf update # Update plugin + CLI + statusline
|
|
55
|
+
cf update --cli # Update only the CLI (npm package)
|
|
56
|
+
cf update --plugin # Update only the Claude Code plugin
|
|
38
57
|
cf update --statusline # Update only the statusline
|
|
58
|
+
cf update --project # Update plugin at project scope
|
|
59
|
+
cf update --local # Update plugin at local scope
|
|
39
60
|
cf dev on [path] # Switch to local plugin source for development
|
|
40
61
|
cf dev off # Switch back to remote marketplace
|
|
41
62
|
cf dev status # Show current dev mode (local or remote)
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
globalConfigPath,
|
|
6
6
|
localConfigPath,
|
|
7
7
|
readJson
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-RWUTFVRB.js";
|
|
9
9
|
import {
|
|
10
10
|
log
|
|
11
11
|
} from "./chunk-W5CD7WTX.js";
|
|
@@ -33,6 +33,51 @@ async function askScope(label = "Save to:") {
|
|
|
33
33
|
]
|
|
34
34
|
});
|
|
35
35
|
}
|
|
36
|
+
async function askPluginScope(message = "Where should the plugin be installed?") {
|
|
37
|
+
return select({
|
|
38
|
+
message,
|
|
39
|
+
choices: [
|
|
40
|
+
{
|
|
41
|
+
name: "User / Global \u2014 available in all projects",
|
|
42
|
+
value: "user"
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
name: "Project \u2014 shared with team via <project>.claude/settings.json",
|
|
46
|
+
value: "project"
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
name: "Local \u2014 this machine only via <project>.claude/settings.local.json, not shared (gitignored)",
|
|
50
|
+
value: "local"
|
|
51
|
+
}
|
|
52
|
+
]
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
async function resolveScope(opts, message) {
|
|
56
|
+
const flags = [
|
|
57
|
+
{ key: "user", scope: "user" },
|
|
58
|
+
{ key: "global", scope: "user" },
|
|
59
|
+
{ key: "project", scope: "project" },
|
|
60
|
+
{ key: "local", scope: "local" }
|
|
61
|
+
];
|
|
62
|
+
const active = flags.filter((f) => opts[f.key] === true);
|
|
63
|
+
const uniqueScopes = new Set(active.map((f) => f.scope));
|
|
64
|
+
if (uniqueScopes.size > 1) {
|
|
65
|
+
log.error(
|
|
66
|
+
"Only one scope flag can be used at a time: --user, --global, --project, or --local"
|
|
67
|
+
);
|
|
68
|
+
process.exit(1);
|
|
69
|
+
}
|
|
70
|
+
if (uniqueScopes.size === 1) {
|
|
71
|
+
return active[0].scope;
|
|
72
|
+
}
|
|
73
|
+
if (!process.stdin.isTTY) {
|
|
74
|
+
log.error(
|
|
75
|
+
"No scope flag provided and stdin is not interactive. Use --user (or --global), --project, or --local."
|
|
76
|
+
);
|
|
77
|
+
process.exit(1);
|
|
78
|
+
}
|
|
79
|
+
return askPluginScope(message);
|
|
80
|
+
}
|
|
36
81
|
function showConfigHint() {
|
|
37
82
|
console.log(chalk.dim("Config files:"));
|
|
38
83
|
console.log(chalk.dim(" Global: ~/.coding-friend/config.json"));
|
|
@@ -127,6 +172,7 @@ export {
|
|
|
127
172
|
BACK,
|
|
128
173
|
injectBackChoice,
|
|
129
174
|
askScope,
|
|
175
|
+
resolveScope,
|
|
130
176
|
showConfigHint,
|
|
131
177
|
getScopeLabel,
|
|
132
178
|
formatScopeLabel,
|
|
@@ -21,7 +21,9 @@ ${MARKER_START}
|
|
|
21
21
|
_cf_completions() {
|
|
22
22
|
local cur="\${COMP_WORDS[COMP_CWORD]}"
|
|
23
23
|
local prev="\${COMP_WORDS[COMP_CWORD-1]}"
|
|
24
|
-
local commands="install uninstall init config host mcp permission statusline update dev session"
|
|
24
|
+
local commands="install uninstall disable enable init config host mcp permission statusline update dev session"
|
|
25
|
+
local scope_flags="--user --global --project --local"
|
|
26
|
+
local update_flags="--cli --plugin --statusline --user --global --project --local"
|
|
25
27
|
|
|
26
28
|
# Subcommands for 'dev'
|
|
27
29
|
if [[ "\${COMP_WORDS[1]}" == "dev" && \${COMP_CWORD} -eq 2 ]]; then
|
|
@@ -41,6 +43,18 @@ _cf_completions() {
|
|
|
41
43
|
return
|
|
42
44
|
fi
|
|
43
45
|
|
|
46
|
+
# Flag completion for install/uninstall/disable/enable
|
|
47
|
+
if [[ "\${COMP_WORDS[1]}" == "install" || "\${COMP_WORDS[1]}" == "uninstall" || "\${COMP_WORDS[1]}" == "disable" || "\${COMP_WORDS[1]}" == "enable" ]] && [[ "$cur" == -* ]]; then
|
|
48
|
+
COMPREPLY=($(compgen -W "$scope_flags" -- "$cur"))
|
|
49
|
+
return
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
# Flag completion for update
|
|
53
|
+
if [[ "\${COMP_WORDS[1]}" == "update" && "$cur" == -* ]]; then
|
|
54
|
+
COMPREPLY=($(compgen -W "$update_flags" -- "$cur"))
|
|
55
|
+
return
|
|
56
|
+
fi
|
|
57
|
+
|
|
44
58
|
COMPREPLY=($(compgen -W "$commands" -- "$cur"))
|
|
45
59
|
}
|
|
46
60
|
complete -o default -F _cf_completions cf
|
|
@@ -51,6 +65,8 @@ var ZSH_FUNCTION_BODY = `_cf() {
|
|
|
51
65
|
commands=(
|
|
52
66
|
'install:Install the Coding Friend plugin into Claude Code'
|
|
53
67
|
'uninstall:Uninstall the Coding Friend plugin from Claude Code'
|
|
68
|
+
'disable:Disable the Coding Friend plugin without uninstalling'
|
|
69
|
+
'enable:Re-enable the Coding Friend plugin'
|
|
54
70
|
'init:Initialize coding-friend in current project'
|
|
55
71
|
'config:Manage Coding Friend configuration'
|
|
56
72
|
'host:Build and serve learning docs as a static website'
|
|
@@ -62,8 +78,31 @@ var ZSH_FUNCTION_BODY = `_cf() {
|
|
|
62
78
|
'session:Save and load Claude Code sessions across machines'
|
|
63
79
|
)
|
|
64
80
|
|
|
81
|
+
local -a scope_flags
|
|
82
|
+
scope_flags=(
|
|
83
|
+
'--user[Install at user scope (all projects)]'
|
|
84
|
+
'--global[Install at user scope (all projects)]'
|
|
85
|
+
'--project[Install at project scope (shared via git)]'
|
|
86
|
+
'--local[Install at local scope (this machine only)]'
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
local -a update_flags
|
|
90
|
+
update_flags=(
|
|
91
|
+
'--cli[Update only the CLI (npm package)]'
|
|
92
|
+
'--plugin[Update only the Claude Code plugin]'
|
|
93
|
+
'--statusline[Update only the statusline]'
|
|
94
|
+
'--user[Update plugin at user scope (all projects)]'
|
|
95
|
+
'--global[Update plugin at user scope (all projects)]'
|
|
96
|
+
'--project[Update plugin at project scope]'
|
|
97
|
+
'--local[Update plugin at local scope]'
|
|
98
|
+
)
|
|
99
|
+
|
|
65
100
|
if (( CURRENT == 2 )); then
|
|
66
101
|
_describe 'command' commands
|
|
102
|
+
elif (( CURRENT >= 3 )) && [[ "\${words[2]}" == "install" || "\${words[2]}" == "uninstall" || "\${words[2]}" == "disable" || "\${words[2]}" == "enable" ]]; then
|
|
103
|
+
_values 'flags' $scope_flags
|
|
104
|
+
elif (( CURRENT >= 3 )) && [[ "\${words[2]}" == "update" ]]; then
|
|
105
|
+
_values 'flags' $update_flags
|
|
67
106
|
elif (( CURRENT == 3 )) && [[ "\${words[2]}" == "dev" ]]; then
|
|
68
107
|
local -a subcommands
|
|
69
108
|
subcommands=(
|
|
@@ -100,6 +139,8 @@ var FISH_CONTENT = `# coding-friend CLI completions
|
|
|
100
139
|
complete -c cf -f
|
|
101
140
|
complete -c cf -n "__fish_use_subcommand" -a install -d "Install the Coding Friend plugin into Claude Code"
|
|
102
141
|
complete -c cf -n "__fish_use_subcommand" -a uninstall -d "Uninstall the Coding Friend plugin from Claude Code"
|
|
142
|
+
complete -c cf -n "__fish_use_subcommand" -a disable -d "Disable the Coding Friend plugin without uninstalling"
|
|
143
|
+
complete -c cf -n "__fish_use_subcommand" -a enable -d "Re-enable the Coding Friend plugin"
|
|
103
144
|
complete -c cf -n "__fish_use_subcommand" -a init -d "Initialize coding-friend in current project"
|
|
104
145
|
complete -c cf -n "__fish_use_subcommand" -a config -d "Manage Coding Friend configuration"
|
|
105
146
|
complete -c cf -n "__fish_use_subcommand" -a host -d "Build and serve learning docs as a static website"
|
|
@@ -109,12 +150,27 @@ complete -c cf -n "__fish_use_subcommand" -a statusline -d "Setup coding-friend
|
|
|
109
150
|
complete -c cf -n "__fish_use_subcommand" -a update -d "Update coding-friend plugin and refresh statusline"
|
|
110
151
|
complete -c cf -n "__fish_use_subcommand" -a dev -d "Switch between local and remote plugin for development"
|
|
111
152
|
complete -c cf -n "__fish_use_subcommand" -a session -d "Save and load Claude Code sessions across machines"
|
|
153
|
+
# Scope flags for install/uninstall/disable/enable
|
|
154
|
+
complete -c cf -n "__fish_seen_subcommand_from install uninstall disable enable" -l user -d "User scope (all projects)"
|
|
155
|
+
complete -c cf -n "__fish_seen_subcommand_from install uninstall disable enable" -l global -d "User scope (all projects)"
|
|
156
|
+
complete -c cf -n "__fish_seen_subcommand_from install uninstall disable enable" -l project -d "Project scope (shared via git)"
|
|
157
|
+
complete -c cf -n "__fish_seen_subcommand_from install uninstall disable enable" -l local -d "Local scope (this machine only)"
|
|
158
|
+
# Flags for update
|
|
159
|
+
complete -c cf -n "__fish_seen_subcommand_from update" -l cli -d "Update only the CLI"
|
|
160
|
+
complete -c cf -n "__fish_seen_subcommand_from update" -l plugin -d "Update only the plugin"
|
|
161
|
+
complete -c cf -n "__fish_seen_subcommand_from update" -l statusline -d "Update only the statusline"
|
|
162
|
+
complete -c cf -n "__fish_seen_subcommand_from update" -l user -d "User scope (all projects)"
|
|
163
|
+
complete -c cf -n "__fish_seen_subcommand_from update" -l global -d "User scope (all projects)"
|
|
164
|
+
complete -c cf -n "__fish_seen_subcommand_from update" -l project -d "Project scope"
|
|
165
|
+
complete -c cf -n "__fish_seen_subcommand_from update" -l local -d "Local scope"
|
|
166
|
+
# Dev subcommands
|
|
112
167
|
complete -c cf -n "__fish_seen_subcommand_from dev" -a on -d "Switch to local plugin source"
|
|
113
168
|
complete -c cf -n "__fish_seen_subcommand_from dev" -a off -d "Switch back to remote marketplace"
|
|
114
169
|
complete -c cf -n "__fish_seen_subcommand_from dev" -a status -d "Show current dev mode"
|
|
115
170
|
complete -c cf -n "__fish_seen_subcommand_from dev" -a restart -d "Restart dev mode"
|
|
116
171
|
complete -c cf -n "__fish_seen_subcommand_from dev" -a sync -d "Sync local plugin files"
|
|
117
172
|
complete -c cf -n "__fish_seen_subcommand_from dev" -a update -d "Update local dev plugin"
|
|
173
|
+
# Session subcommands
|
|
118
174
|
complete -c cf -n "__fish_seen_subcommand_from session" -a save -d "Save current session to docs/sessions/"
|
|
119
175
|
complete -c cf -n "__fish_seen_subcommand_from session" -a load -d "Load a saved session from docs/sessions/"
|
|
120
176
|
`;
|
|
@@ -123,9 +179,11 @@ var POWERSHELL_BLOCK = `
|
|
|
123
179
|
${MARKER_START}
|
|
124
180
|
Register-ArgumentCompleter -Native -CommandName cf -ScriptBlock {
|
|
125
181
|
param($wordToComplete, $commandAst, $cursorPosition)
|
|
126
|
-
$commands = @('install','uninstall','init','config','host','mcp','permission','statusline','update','dev','session')
|
|
182
|
+
$commands = @('install','uninstall','disable','enable','init','config','host','mcp','permission','statusline','update','dev','session')
|
|
127
183
|
$devSubcommands = @('on','off','status','restart','sync','update')
|
|
128
184
|
$sessionSubcommands = @('save','load')
|
|
185
|
+
$scopeFlags = @('--user','--global','--project','--local')
|
|
186
|
+
$updateFlags = @('--cli','--plugin','--statusline','--user','--global','--project','--local')
|
|
129
187
|
$words = $commandAst.CommandElements
|
|
130
188
|
if ($words.Count -ge 2 -and $words[1].ToString() -eq 'dev') {
|
|
131
189
|
$devSubcommands | Where-Object { $_ -like "$wordToComplete*" } |
|
|
@@ -133,6 +191,12 @@ Register-ArgumentCompleter -Native -CommandName cf -ScriptBlock {
|
|
|
133
191
|
} elseif ($words.Count -ge 2 -and $words[1].ToString() -eq 'session') {
|
|
134
192
|
$sessionSubcommands | Where-Object { $_ -like "$wordToComplete*" } |
|
|
135
193
|
ForEach-Object { [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) }
|
|
194
|
+
} elseif ($words.Count -ge 2 -and ($words[1].ToString() -eq 'install' -or $words[1].ToString() -eq 'uninstall' -or $words[1].ToString() -eq 'disable' -or $words[1].ToString() -eq 'enable')) {
|
|
195
|
+
$scopeFlags | Where-Object { $_ -like "$wordToComplete*" } |
|
|
196
|
+
ForEach-Object { [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) }
|
|
197
|
+
} elseif ($words.Count -ge 2 -and $words[1].ToString() -eq 'update') {
|
|
198
|
+
$updateFlags | Where-Object { $_ -like "$wordToComplete*" } |
|
|
199
|
+
ForEach-Object { [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) }
|
|
136
200
|
} else {
|
|
137
201
|
$commands | Where-Object { $_ -like "$wordToComplete*" } |
|
|
138
202
|
ForEach-Object { [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) }
|
|
@@ -1,26 +1,3 @@
|
|
|
1
|
-
// src/lib/json.ts
|
|
2
|
-
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "fs";
|
|
3
|
-
import { dirname } from "path";
|
|
4
|
-
function readJson(filePath) {
|
|
5
|
-
try {
|
|
6
|
-
const content = readFileSync(filePath, "utf-8");
|
|
7
|
-
return JSON.parse(content);
|
|
8
|
-
} catch {
|
|
9
|
-
return null;
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
function writeJson(filePath, data) {
|
|
13
|
-
const dir = dirname(filePath);
|
|
14
|
-
if (!existsSync(dir)) {
|
|
15
|
-
mkdirSync(dir, { recursive: true });
|
|
16
|
-
}
|
|
17
|
-
writeFileSync(filePath, JSON.stringify(data, null, 2) + "\n", "utf-8");
|
|
18
|
-
}
|
|
19
|
-
function mergeJson(filePath, data) {
|
|
20
|
-
const existing = readJson(filePath) ?? {};
|
|
21
|
-
writeJson(filePath, { ...existing, ...data });
|
|
22
|
-
}
|
|
23
|
-
|
|
24
1
|
// src/lib/paths.ts
|
|
25
2
|
import { homedir } from "os";
|
|
26
3
|
import { resolve, join } from "path";
|
|
@@ -38,6 +15,9 @@ function globalConfigPath() {
|
|
|
38
15
|
function claudeSettingsPath() {
|
|
39
16
|
return join(homedir(), ".claude", "settings.json");
|
|
40
17
|
}
|
|
18
|
+
function claudeProjectSettingsPath() {
|
|
19
|
+
return resolve(process.cwd(), ".claude", "settings.json");
|
|
20
|
+
}
|
|
41
21
|
function claudeLocalSettingsPath() {
|
|
42
22
|
return resolve(process.cwd(), ".claude", "settings.local.json");
|
|
43
23
|
}
|
|
@@ -91,14 +71,35 @@ function claudeSessionDir(encodedPath) {
|
|
|
91
71
|
return join(claudeProjectsDir(), encodedPath);
|
|
92
72
|
}
|
|
93
73
|
|
|
74
|
+
// src/lib/json.ts
|
|
75
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "fs";
|
|
76
|
+
import { dirname } from "path";
|
|
77
|
+
function readJson(filePath) {
|
|
78
|
+
try {
|
|
79
|
+
const content = readFileSync(filePath, "utf-8");
|
|
80
|
+
return JSON.parse(content);
|
|
81
|
+
} catch {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
function writeJson(filePath, data) {
|
|
86
|
+
const dir = dirname(filePath);
|
|
87
|
+
if (!existsSync(dir)) {
|
|
88
|
+
mkdirSync(dir, { recursive: true });
|
|
89
|
+
}
|
|
90
|
+
writeFileSync(filePath, JSON.stringify(data, null, 2) + "\n", "utf-8");
|
|
91
|
+
}
|
|
92
|
+
function mergeJson(filePath, data) {
|
|
93
|
+
const existing = readJson(filePath) ?? {};
|
|
94
|
+
writeJson(filePath, { ...existing, ...data });
|
|
95
|
+
}
|
|
96
|
+
|
|
94
97
|
export {
|
|
95
|
-
readJson,
|
|
96
|
-
writeJson,
|
|
97
|
-
mergeJson,
|
|
98
98
|
resolvePath,
|
|
99
99
|
localConfigPath,
|
|
100
100
|
globalConfigPath,
|
|
101
101
|
claudeSettingsPath,
|
|
102
|
+
claudeProjectSettingsPath,
|
|
102
103
|
claudeLocalSettingsPath,
|
|
103
104
|
installedPluginsPath,
|
|
104
105
|
pluginCachePath,
|
|
@@ -108,5 +109,8 @@ export {
|
|
|
108
109
|
marketplaceClonePath,
|
|
109
110
|
globalConfigDir,
|
|
110
111
|
encodeProjectPath,
|
|
111
|
-
claudeSessionDir
|
|
112
|
+
claudeSessionDir,
|
|
113
|
+
readJson,
|
|
114
|
+
writeJson,
|
|
115
|
+
mergeJson
|
|
112
116
|
};
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ensureStatusline,
|
|
3
3
|
getInstalledVersion
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-QG6XYVJU.js";
|
|
5
5
|
import {
|
|
6
6
|
ensureShellCompletion
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-KJUGTLPQ.js";
|
|
8
|
+
import {
|
|
9
|
+
resolveScope
|
|
10
|
+
} from "./chunk-EMAINEYB.js";
|
|
8
11
|
import {
|
|
9
12
|
commandExists,
|
|
10
13
|
run,
|
|
@@ -13,7 +16,7 @@ import {
|
|
|
13
16
|
import {
|
|
14
17
|
claudeSettingsPath,
|
|
15
18
|
readJson
|
|
16
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-RWUTFVRB.js";
|
|
17
20
|
import {
|
|
18
21
|
log
|
|
19
22
|
} from "./chunk-W5CD7WTX.js";
|
|
@@ -86,6 +89,13 @@ async function updateCommand(opts) {
|
|
|
86
89
|
const doCli = updateAll || !!opts.cli;
|
|
87
90
|
const doPlugin = updateAll || !!opts.plugin;
|
|
88
91
|
const doStatusline = updateAll || !!opts.statusline;
|
|
92
|
+
const hasScopeFlag = !!(opts.user || opts.global || opts.project || opts.local);
|
|
93
|
+
let scope;
|
|
94
|
+
if (doPlugin && hasScopeFlag) {
|
|
95
|
+
scope = await resolveScope(opts);
|
|
96
|
+
} else if (doPlugin && !hasScopeFlag) {
|
|
97
|
+
scope = "user";
|
|
98
|
+
}
|
|
89
99
|
console.log("=== \u{1F33F} Coding Friend Update \u{1F33F} ===");
|
|
90
100
|
console.log();
|
|
91
101
|
const currentVersion = getInstalledVersion();
|
|
@@ -135,12 +145,18 @@ async function updateCommand(opts) {
|
|
|
135
145
|
"Claude CLI not found. Install it first, or run: claude plugin update coding-friend@coding-friend-marketplace"
|
|
136
146
|
);
|
|
137
147
|
} else {
|
|
138
|
-
log.step(
|
|
139
|
-
|
|
148
|
+
log.step(
|
|
149
|
+
`Updating plugin${scope && scope !== "user" ? ` (${scope} scope)` : ""}...`
|
|
150
|
+
);
|
|
151
|
+
const updateArgs = [
|
|
140
152
|
"plugin",
|
|
141
153
|
"update",
|
|
142
154
|
"coding-friend@coding-friend-marketplace"
|
|
143
|
-
]
|
|
155
|
+
];
|
|
156
|
+
if (scope) {
|
|
157
|
+
updateArgs.push("--scope", scope);
|
|
158
|
+
}
|
|
159
|
+
const result = run("claude", updateArgs);
|
|
144
160
|
if (result === null) {
|
|
145
161
|
log.error(
|
|
146
162
|
"Plugin update failed. Try manually: claude plugin update coding-friend@coding-friend-marketplace"
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import {
|
|
2
|
+
claudeLocalSettingsPath,
|
|
3
|
+
claudeProjectSettingsPath,
|
|
4
|
+
claudeSettingsPath,
|
|
5
|
+
installedPluginsPath,
|
|
6
|
+
knownMarketplacesPath,
|
|
7
|
+
readJson,
|
|
8
|
+
writeJson
|
|
9
|
+
} from "./chunk-RWUTFVRB.js";
|
|
10
|
+
|
|
11
|
+
// src/lib/plugin-state.ts
|
|
12
|
+
var MARKETPLACE_NAME = "coding-friend-marketplace";
|
|
13
|
+
var PLUGIN_NAME = "coding-friend";
|
|
14
|
+
var PLUGIN_ID = `${PLUGIN_NAME}@${MARKETPLACE_NAME}`;
|
|
15
|
+
function isPluginInstalled() {
|
|
16
|
+
const data = readJson(installedPluginsPath());
|
|
17
|
+
if (!data) return false;
|
|
18
|
+
const plugins = data.plugins ?? data;
|
|
19
|
+
return Object.keys(plugins).some((k) => k.includes(PLUGIN_NAME));
|
|
20
|
+
}
|
|
21
|
+
function isMarketplaceRegistered() {
|
|
22
|
+
const data = readJson(knownMarketplacesPath());
|
|
23
|
+
if (!data) return false;
|
|
24
|
+
return MARKETPLACE_NAME in data;
|
|
25
|
+
}
|
|
26
|
+
function settingsPathForScope(scope) {
|
|
27
|
+
switch (scope) {
|
|
28
|
+
case "user":
|
|
29
|
+
return claudeSettingsPath();
|
|
30
|
+
case "project":
|
|
31
|
+
return claudeProjectSettingsPath();
|
|
32
|
+
case "local":
|
|
33
|
+
return claudeLocalSettingsPath();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function isPluginDisabled(scope) {
|
|
37
|
+
const settings = readJson(
|
|
38
|
+
settingsPathForScope(scope)
|
|
39
|
+
);
|
|
40
|
+
if (!settings) return false;
|
|
41
|
+
const enabled = settings.enabledPlugins;
|
|
42
|
+
if (!enabled) return false;
|
|
43
|
+
return enabled[PLUGIN_ID] === false;
|
|
44
|
+
}
|
|
45
|
+
function setPluginEnabled(scope, enabled) {
|
|
46
|
+
const filePath = settingsPathForScope(scope);
|
|
47
|
+
const settings = readJson(filePath) ?? {};
|
|
48
|
+
const enabledPlugins = settings.enabledPlugins ?? {};
|
|
49
|
+
if (enabled) {
|
|
50
|
+
delete enabledPlugins[PLUGIN_ID];
|
|
51
|
+
if (Object.keys(enabledPlugins).length === 0) {
|
|
52
|
+
delete settings.enabledPlugins;
|
|
53
|
+
} else {
|
|
54
|
+
settings.enabledPlugins = enabledPlugins;
|
|
55
|
+
}
|
|
56
|
+
} else {
|
|
57
|
+
enabledPlugins[PLUGIN_ID] = false;
|
|
58
|
+
settings.enabledPlugins = enabledPlugins;
|
|
59
|
+
}
|
|
60
|
+
writeJson(filePath, settings);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export {
|
|
64
|
+
isPluginInstalled,
|
|
65
|
+
isMarketplaceRegistered,
|
|
66
|
+
isPluginDisabled,
|
|
67
|
+
setPluginEnabled
|
|
68
|
+
};
|
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
import {
|
|
2
|
-
BACK,
|
|
3
|
-
applyDocsDirChange,
|
|
4
|
-
askScope,
|
|
5
|
-
formatScopeLabel,
|
|
6
|
-
getMergedValue,
|
|
7
|
-
getScopeLabel,
|
|
8
|
-
injectBackChoice,
|
|
9
|
-
showConfigHint
|
|
10
|
-
} from "./chunk-AHGBESGW.js";
|
|
11
1
|
import {
|
|
12
2
|
findStatuslineHookPath,
|
|
13
3
|
isStatuslineConfigured,
|
|
14
4
|
saveStatuslineConfig,
|
|
15
5
|
selectStatuslineComponents,
|
|
16
6
|
writeStatuslineSettings
|
|
17
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-QG6XYVJU.js";
|
|
8
|
+
import {
|
|
9
|
+
ALL_COMPONENT_IDS,
|
|
10
|
+
DEFAULT_CONFIG
|
|
11
|
+
} from "./chunk-PGLUEN7D.js";
|
|
18
12
|
import {
|
|
19
13
|
ensureShellCompletion,
|
|
20
14
|
hasShellCompletion,
|
|
21
15
|
removeShellCompletion
|
|
22
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-KJUGTLPQ.js";
|
|
23
17
|
import {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
18
|
+
BACK,
|
|
19
|
+
applyDocsDirChange,
|
|
20
|
+
askScope,
|
|
21
|
+
formatScopeLabel,
|
|
22
|
+
getMergedValue,
|
|
23
|
+
getScopeLabel,
|
|
24
|
+
injectBackChoice,
|
|
25
|
+
showConfigHint
|
|
26
|
+
} from "./chunk-EMAINEYB.js";
|
|
27
27
|
import {
|
|
28
28
|
run
|
|
29
29
|
} from "./chunk-UFGNO6CW.js";
|
|
@@ -33,7 +33,7 @@ import {
|
|
|
33
33
|
mergeJson,
|
|
34
34
|
readJson,
|
|
35
35
|
resolvePath
|
|
36
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-RWUTFVRB.js";
|
|
37
37
|
import {
|
|
38
38
|
log
|
|
39
39
|
} from "./chunk-W5CD7WTX.js";
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
2
|
isMarketplaceRegistered,
|
|
3
3
|
isPluginInstalled
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-ZOOFPF5I.js";
|
|
5
5
|
import {
|
|
6
6
|
ensureStatusline
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-QG6XYVJU.js";
|
|
8
|
+
import "./chunk-PGLUEN7D.js";
|
|
8
9
|
import {
|
|
9
10
|
ensureShellCompletion
|
|
10
|
-
} from "./chunk-
|
|
11
|
-
import "./chunk-PGLUEN7D.js";
|
|
11
|
+
} from "./chunk-KJUGTLPQ.js";
|
|
12
12
|
import {
|
|
13
13
|
commandExists,
|
|
14
14
|
run
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
pluginCachePath,
|
|
20
20
|
readJson,
|
|
21
21
|
writeJson
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-RWUTFVRB.js";
|
|
23
23
|
import {
|
|
24
24
|
log
|
|
25
25
|
} from "./chunk-W5CD7WTX.js";
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isPluginDisabled,
|
|
3
|
+
setPluginEnabled
|
|
4
|
+
} from "./chunk-ZOOFPF5I.js";
|
|
5
|
+
import {
|
|
6
|
+
resolveScope
|
|
7
|
+
} from "./chunk-EMAINEYB.js";
|
|
8
|
+
import "./chunk-UFGNO6CW.js";
|
|
9
|
+
import "./chunk-RWUTFVRB.js";
|
|
10
|
+
import {
|
|
11
|
+
log
|
|
12
|
+
} from "./chunk-W5CD7WTX.js";
|
|
13
|
+
|
|
14
|
+
// src/commands/disable.ts
|
|
15
|
+
import chalk from "chalk";
|
|
16
|
+
async function disableCommand(opts = {}) {
|
|
17
|
+
const scope = await resolveScope(
|
|
18
|
+
opts,
|
|
19
|
+
"Where should Coding Friend be disabled?"
|
|
20
|
+
);
|
|
21
|
+
if (isPluginDisabled(scope)) {
|
|
22
|
+
log.info(
|
|
23
|
+
`Coding Friend is already disabled at ${chalk.cyan(scope)} scope.`
|
|
24
|
+
);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
log.step(`Disabling plugin (${chalk.cyan(scope)} scope)...`);
|
|
28
|
+
setPluginEnabled(scope, false);
|
|
29
|
+
log.success(`Coding Friend disabled at ${chalk.cyan(scope)} scope.`);
|
|
30
|
+
log.dim("Restart Claude Code for the change to take effect.");
|
|
31
|
+
log.dim(`Run ${chalk.bold(`cf enable --${scope}`)} to re-enable.`);
|
|
32
|
+
}
|
|
33
|
+
export {
|
|
34
|
+
disableCommand
|
|
35
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isPluginDisabled,
|
|
3
|
+
setPluginEnabled
|
|
4
|
+
} from "./chunk-ZOOFPF5I.js";
|
|
5
|
+
import {
|
|
6
|
+
resolveScope
|
|
7
|
+
} from "./chunk-EMAINEYB.js";
|
|
8
|
+
import "./chunk-UFGNO6CW.js";
|
|
9
|
+
import "./chunk-RWUTFVRB.js";
|
|
10
|
+
import {
|
|
11
|
+
log
|
|
12
|
+
} from "./chunk-W5CD7WTX.js";
|
|
13
|
+
|
|
14
|
+
// src/commands/enable.ts
|
|
15
|
+
import chalk from "chalk";
|
|
16
|
+
async function enableCommand(opts = {}) {
|
|
17
|
+
const scope = await resolveScope(
|
|
18
|
+
opts,
|
|
19
|
+
"Where should Coding Friend be enabled?"
|
|
20
|
+
);
|
|
21
|
+
if (!isPluginDisabled(scope)) {
|
|
22
|
+
log.info(`Coding Friend is already enabled at ${chalk.cyan(scope)} scope.`);
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
log.step(`Enabling plugin (${chalk.cyan(scope)} scope)...`);
|
|
26
|
+
setPluginEnabled(scope, true);
|
|
27
|
+
log.success(`Coding Friend enabled at ${chalk.cyan(scope)} scope.`);
|
|
28
|
+
log.dim("Restart Claude Code for the change to take effect.");
|
|
29
|
+
}
|
|
30
|
+
export {
|
|
31
|
+
enableCommand
|
|
32
|
+
};
|
|
@@ -3,13 +3,13 @@ import {
|
|
|
3
3
|
} from "./chunk-RZRT7NGT.js";
|
|
4
4
|
import {
|
|
5
5
|
resolveDocsDir
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-KB4JM2EB.js";
|
|
7
7
|
import "./chunk-PGLUEN7D.js";
|
|
8
8
|
import {
|
|
9
9
|
run,
|
|
10
10
|
streamExec
|
|
11
11
|
} from "./chunk-UFGNO6CW.js";
|
|
12
|
-
import "./chunk-
|
|
12
|
+
import "./chunk-RWUTFVRB.js";
|
|
13
13
|
import {
|
|
14
14
|
log
|
|
15
15
|
} from "./chunk-W5CD7WTX.js";
|
package/dist/index.js
CHANGED
|
@@ -13,40 +13,48 @@ 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-
|
|
18
|
-
await installCommand();
|
|
16
|
+
program.command("install").description("Install the Coding Friend plugin into Claude Code").option("--user", "Install at user scope (all projects)").option("--global", "Install at user scope (all projects)").option("--project", "Install at project scope (shared via git)").option("--local", "Install at local scope (this machine only)").action(async (opts) => {
|
|
17
|
+
const { installCommand } = await import("./install-FEOOFN4G.js");
|
|
18
|
+
await installCommand(opts);
|
|
19
19
|
});
|
|
20
|
-
program.command("uninstall").description("Uninstall the Coding Friend plugin from Claude Code").action(async () => {
|
|
21
|
-
const { uninstallCommand } = await import("./uninstall-
|
|
22
|
-
await uninstallCommand();
|
|
20
|
+
program.command("uninstall").description("Uninstall the Coding Friend plugin from Claude Code").option("--user", "Uninstall from user scope (all projects)").option("--global", "Uninstall from user scope (all projects)").option("--project", "Uninstall from project scope").option("--local", "Uninstall from local scope").action(async (opts) => {
|
|
21
|
+
const { uninstallCommand } = await import("./uninstall-2SYDCOAP.js");
|
|
22
|
+
await uninstallCommand(opts);
|
|
23
|
+
});
|
|
24
|
+
program.command("disable").description("Disable the Coding Friend plugin without uninstalling").option("--user", "Disable at user scope (all projects)").option("--global", "Disable at user scope (all projects)").option("--project", "Disable at project scope").option("--local", "Disable at local scope").action(async (opts) => {
|
|
25
|
+
const { disableCommand } = await import("./disable-3N2NCMTU.js");
|
|
26
|
+
await disableCommand(opts);
|
|
27
|
+
});
|
|
28
|
+
program.command("enable").description("Re-enable the Coding Friend plugin").option("--user", "Enable at user scope (all projects)").option("--global", "Enable at user scope (all projects)").option("--project", "Enable at project scope").option("--local", "Enable at local scope").action(async (opts) => {
|
|
29
|
+
const { enableCommand } = await import("./enable-EGG6LTXD.js");
|
|
30
|
+
await enableCommand(opts);
|
|
23
31
|
});
|
|
24
32
|
program.command("init").description("Initialize coding-friend in current project").action(async () => {
|
|
25
|
-
const { initCommand } = await import("./init-
|
|
33
|
+
const { initCommand } = await import("./init-2LMIUWUY.js");
|
|
26
34
|
await initCommand();
|
|
27
35
|
});
|
|
28
36
|
program.command("config").description("Manage Coding Friend configuration").action(async () => {
|
|
29
|
-
const { configCommand } = await import("./config-
|
|
37
|
+
const { configCommand } = await import("./config-PTMK6XBN.js");
|
|
30
38
|
await configCommand();
|
|
31
39
|
});
|
|
32
40
|
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) => {
|
|
33
|
-
const { hostCommand } = await import("./host-
|
|
41
|
+
const { hostCommand } = await import("./host-XHBUWGAW.js");
|
|
34
42
|
await hostCommand(path, opts);
|
|
35
43
|
});
|
|
36
44
|
program.command("mcp").description("Setup MCP server for learning docs").argument("[path]", "path to docs folder").action(async (path) => {
|
|
37
|
-
const { mcpCommand } = await import("./mcp-
|
|
45
|
+
const { mcpCommand } = await import("./mcp-XE6NZRPD.js");
|
|
38
46
|
await mcpCommand(path);
|
|
39
47
|
});
|
|
40
48
|
program.command("permission").description("Manage Claude Code permission rules for Coding Friend").option("--all", "Apply all recommended permissions without prompts").action(async (opts) => {
|
|
41
|
-
const { permissionCommand } = await import("./permission-
|
|
49
|
+
const { permissionCommand } = await import("./permission-L2QQR5PO.js");
|
|
42
50
|
await permissionCommand(opts);
|
|
43
51
|
});
|
|
44
52
|
program.command("statusline").description("Setup coding-friend statusline in Claude Code").action(async () => {
|
|
45
|
-
const { statuslineCommand } = await import("./statusline-
|
|
53
|
+
const { statuslineCommand } = await import("./statusline-5ZMM3RYY.js");
|
|
46
54
|
await statuslineCommand();
|
|
47
55
|
});
|
|
48
|
-
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) => {
|
|
49
|
-
const { updateCommand } = await import("./update-
|
|
56
|
+
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").option("--user", "Update plugin at user scope (all projects)").option("--global", "Update plugin at user scope (all projects)").option("--project", "Update plugin at project scope").option("--local", "Update plugin at local scope").action(async (opts) => {
|
|
57
|
+
const { updateCommand } = await import("./update-4MNVBTI5.js");
|
|
50
58
|
await updateCommand(opts);
|
|
51
59
|
});
|
|
52
60
|
var session = program.command("session").description("Save and load Claude Code sessions across machines");
|
|
@@ -61,11 +69,11 @@ session.command("save").description("Save current Claude Code session to sync fo
|
|
|
61
69
|
"-s, --session-id <id>",
|
|
62
70
|
"session UUID to save (default: auto-detect newest)"
|
|
63
71
|
).option("-l, --label <label>", "label for this session").action(async (opts) => {
|
|
64
|
-
const { sessionSaveCommand } = await import("./session-
|
|
72
|
+
const { sessionSaveCommand } = await import("./session-K6YWJLLU.js");
|
|
65
73
|
await sessionSaveCommand(opts);
|
|
66
74
|
});
|
|
67
75
|
session.command("load").description("Load a saved session from sync folder").action(async () => {
|
|
68
|
-
const { sessionLoadCommand } = await import("./session-
|
|
76
|
+
const { sessionLoadCommand } = await import("./session-K6YWJLLU.js");
|
|
69
77
|
await sessionLoadCommand();
|
|
70
78
|
});
|
|
71
79
|
var dev = program.command("dev").description("Development mode commands");
|
|
@@ -81,35 +89,35 @@ Dev subcommands:
|
|
|
81
89
|
dev update [path] Update local dev plugin to latest version`
|
|
82
90
|
);
|
|
83
91
|
dev.command("on").description("Switch to local plugin source").argument("[path]", "path to local coding-friend repo (default: cwd)").action(async (path) => {
|
|
84
|
-
const { devOnCommand } = await import("./dev-
|
|
92
|
+
const { devOnCommand } = await import("./dev-UBYW6NRX.js");
|
|
85
93
|
await devOnCommand(path);
|
|
86
94
|
});
|
|
87
95
|
dev.command("off").description("Switch back to remote marketplace").action(async () => {
|
|
88
|
-
const { devOffCommand } = await import("./dev-
|
|
96
|
+
const { devOffCommand } = await import("./dev-UBYW6NRX.js");
|
|
89
97
|
await devOffCommand();
|
|
90
98
|
});
|
|
91
99
|
dev.command("status").description("Show current dev mode").action(async () => {
|
|
92
|
-
const { devStatusCommand } = await import("./dev-
|
|
100
|
+
const { devStatusCommand } = await import("./dev-UBYW6NRX.js");
|
|
93
101
|
await devStatusCommand();
|
|
94
102
|
});
|
|
95
103
|
dev.command("sync").description(
|
|
96
104
|
"Copy local source files to plugin cache (no version bump needed)"
|
|
97
105
|
).action(async () => {
|
|
98
|
-
const { devSyncCommand } = await import("./dev-
|
|
106
|
+
const { devSyncCommand } = await import("./dev-UBYW6NRX.js");
|
|
99
107
|
await devSyncCommand();
|
|
100
108
|
});
|
|
101
109
|
dev.command("restart").description("Reinstall local dev plugin (off + on)").argument(
|
|
102
110
|
"[path]",
|
|
103
111
|
"path to local coding-friend repo (default: saved path or cwd)"
|
|
104
112
|
).action(async (path) => {
|
|
105
|
-
const { devRestartCommand } = await import("./dev-
|
|
113
|
+
const { devRestartCommand } = await import("./dev-UBYW6NRX.js");
|
|
106
114
|
await devRestartCommand(path);
|
|
107
115
|
});
|
|
108
116
|
dev.command("update").description("Update local dev plugin to latest version (off + on)").argument(
|
|
109
117
|
"[path]",
|
|
110
118
|
"path to local coding-friend repo (default: saved path or cwd)"
|
|
111
119
|
).action(async (path) => {
|
|
112
|
-
const { devUpdateCommand } = await import("./dev-
|
|
120
|
+
const { devUpdateCommand } = await import("./dev-UBYW6NRX.js");
|
|
113
121
|
await devUpdateCommand(path);
|
|
114
122
|
});
|
|
115
123
|
program.parse();
|
|
@@ -3,31 +3,31 @@ import {
|
|
|
3
3
|
buildLearnDirRules,
|
|
4
4
|
getExistingRules,
|
|
5
5
|
getMissingRules
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import {
|
|
8
|
-
BACK,
|
|
9
|
-
applyDocsDirChange,
|
|
10
|
-
askScope,
|
|
11
|
-
formatScopeLabel,
|
|
12
|
-
getMergedValue,
|
|
13
|
-
getScopeLabel,
|
|
14
|
-
injectBackChoice,
|
|
15
|
-
showConfigHint
|
|
16
|
-
} from "./chunk-AHGBESGW.js";
|
|
6
|
+
} from "./chunk-56U7US6J.js";
|
|
17
7
|
import {
|
|
18
8
|
findStatuslineHookPath,
|
|
19
9
|
isStatuslineConfigured,
|
|
20
10
|
saveStatuslineConfig,
|
|
21
11
|
selectStatuslineComponents,
|
|
22
12
|
writeStatuslineSettings
|
|
23
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-QG6XYVJU.js";
|
|
14
|
+
import {
|
|
15
|
+
DEFAULT_CONFIG
|
|
16
|
+
} from "./chunk-PGLUEN7D.js";
|
|
24
17
|
import {
|
|
25
18
|
ensureShellCompletion,
|
|
26
19
|
hasShellCompletion
|
|
27
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-KJUGTLPQ.js";
|
|
28
21
|
import {
|
|
29
|
-
|
|
30
|
-
|
|
22
|
+
BACK,
|
|
23
|
+
applyDocsDirChange,
|
|
24
|
+
askScope,
|
|
25
|
+
formatScopeLabel,
|
|
26
|
+
getMergedValue,
|
|
27
|
+
getScopeLabel,
|
|
28
|
+
injectBackChoice,
|
|
29
|
+
showConfigHint
|
|
30
|
+
} from "./chunk-EMAINEYB.js";
|
|
31
31
|
import {
|
|
32
32
|
run
|
|
33
33
|
} from "./chunk-UFGNO6CW.js";
|
|
@@ -38,7 +38,7 @@ import {
|
|
|
38
38
|
mergeJson,
|
|
39
39
|
readJson,
|
|
40
40
|
resolvePath
|
|
41
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-RWUTFVRB.js";
|
|
42
42
|
import {
|
|
43
43
|
log
|
|
44
44
|
} from "./chunk-W5CD7WTX.js";
|
|
@@ -1,27 +1,36 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getLatestVersion,
|
|
3
3
|
semverCompare
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-YZ7IZ46F.js";
|
|
5
5
|
import {
|
|
6
|
-
isMarketplaceRegistered
|
|
7
|
-
|
|
6
|
+
isMarketplaceRegistered,
|
|
7
|
+
isPluginDisabled
|
|
8
|
+
} from "./chunk-ZOOFPF5I.js";
|
|
8
9
|
import {
|
|
9
10
|
getInstalledVersion
|
|
10
|
-
} from "./chunk-
|
|
11
|
-
import "./chunk-BCYBFGVD.js";
|
|
11
|
+
} from "./chunk-QG6XYVJU.js";
|
|
12
12
|
import "./chunk-PGLUEN7D.js";
|
|
13
|
+
import {
|
|
14
|
+
ensureShellCompletion
|
|
15
|
+
} from "./chunk-KJUGTLPQ.js";
|
|
16
|
+
import {
|
|
17
|
+
resolveScope
|
|
18
|
+
} from "./chunk-EMAINEYB.js";
|
|
13
19
|
import {
|
|
14
20
|
commandExists,
|
|
15
21
|
run
|
|
16
22
|
} from "./chunk-UFGNO6CW.js";
|
|
17
|
-
import
|
|
23
|
+
import {
|
|
24
|
+
devStatePath
|
|
25
|
+
} from "./chunk-RWUTFVRB.js";
|
|
18
26
|
import {
|
|
19
27
|
log
|
|
20
28
|
} from "./chunk-W5CD7WTX.js";
|
|
21
29
|
|
|
22
30
|
// src/commands/install.ts
|
|
31
|
+
import { existsSync } from "fs";
|
|
23
32
|
import chalk from "chalk";
|
|
24
|
-
async function installCommand() {
|
|
33
|
+
async function installCommand(opts = {}) {
|
|
25
34
|
console.log("=== \u{1F33F} Coding Friend Install \u{1F33F} ===");
|
|
26
35
|
console.log();
|
|
27
36
|
if (!commandExists("claude")) {
|
|
@@ -30,6 +39,14 @@ async function installCommand() {
|
|
|
30
39
|
);
|
|
31
40
|
process.exit(1);
|
|
32
41
|
}
|
|
42
|
+
if (existsSync(devStatePath())) {
|
|
43
|
+
log.warn("Dev mode is currently active.");
|
|
44
|
+
log.dim(
|
|
45
|
+
`Run ${chalk.bold("cf dev off")} first, then install. Or use ${chalk.bold("cf dev sync")} to update the dev plugin.`
|
|
46
|
+
);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const scope = await resolveScope(opts);
|
|
33
50
|
if (isMarketplaceRegistered()) {
|
|
34
51
|
log.success("Marketplace already registered.");
|
|
35
52
|
} else {
|
|
@@ -49,12 +66,14 @@ async function installCommand() {
|
|
|
49
66
|
log.success("Marketplace added.");
|
|
50
67
|
}
|
|
51
68
|
const installedVersion = getInstalledVersion();
|
|
52
|
-
if (!installedVersion) {
|
|
53
|
-
log.step(
|
|
69
|
+
if (!installedVersion || scope !== "user") {
|
|
70
|
+
log.step(`Installing plugin (${chalk.cyan(scope)} scope)...`);
|
|
54
71
|
const result = run("claude", [
|
|
55
72
|
"plugin",
|
|
56
73
|
"install",
|
|
57
|
-
"coding-friend@coding-friend-marketplace"
|
|
74
|
+
"coding-friend@coding-friend-marketplace",
|
|
75
|
+
"--scope",
|
|
76
|
+
scope
|
|
58
77
|
]);
|
|
59
78
|
if (result === null) {
|
|
60
79
|
log.error(
|
|
@@ -67,6 +86,11 @@ async function installCommand() {
|
|
|
67
86
|
log.success(
|
|
68
87
|
`Plugin already installed (${chalk.green(`v${installedVersion}`)}).`
|
|
69
88
|
);
|
|
89
|
+
if (isPluginDisabled(scope)) {
|
|
90
|
+
log.warn(
|
|
91
|
+
`Plugin is installed but disabled at ${chalk.cyan(scope)} scope. Run ${chalk.bold(`cf enable --${scope}`)} to re-enable.`
|
|
92
|
+
);
|
|
93
|
+
}
|
|
70
94
|
const latestVersion = getLatestVersion();
|
|
71
95
|
if (latestVersion) {
|
|
72
96
|
const cmp = semverCompare(installedVersion, latestVersion);
|
|
@@ -81,12 +105,15 @@ async function installCommand() {
|
|
|
81
105
|
log.dim("Could not check for updates (no network or GitHub rate limit).");
|
|
82
106
|
}
|
|
83
107
|
}
|
|
108
|
+
ensureShellCompletion({ silent: false });
|
|
84
109
|
console.log();
|
|
85
110
|
log.info("Next steps:");
|
|
86
|
-
log
|
|
111
|
+
console.log(
|
|
87
112
|
` ${chalk.cyan("cf init")} Initialize workspace (docs folders, config)`
|
|
88
113
|
);
|
|
89
|
-
log
|
|
114
|
+
console.log(
|
|
115
|
+
` ${chalk.cyan("cf statusline")} Setup statusline in Claude Code to show more real-time info`
|
|
116
|
+
);
|
|
90
117
|
console.log();
|
|
91
118
|
log.dim("Restart Claude Code (or start a new session) to use the plugin.");
|
|
92
119
|
}
|
|
@@ -3,12 +3,12 @@ import {
|
|
|
3
3
|
} from "./chunk-RZRT7NGT.js";
|
|
4
4
|
import {
|
|
5
5
|
resolveDocsDir
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-KB4JM2EB.js";
|
|
7
7
|
import "./chunk-PGLUEN7D.js";
|
|
8
8
|
import {
|
|
9
9
|
run
|
|
10
10
|
} from "./chunk-UFGNO6CW.js";
|
|
11
|
-
import "./chunk-
|
|
11
|
+
import "./chunk-RWUTFVRB.js";
|
|
12
12
|
import {
|
|
13
13
|
log
|
|
14
14
|
} from "./chunk-W5CD7WTX.js";
|
|
@@ -3,10 +3,10 @@ import {
|
|
|
3
3
|
applyPermissions,
|
|
4
4
|
getExistingRules,
|
|
5
5
|
groupByCategory
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-56U7US6J.js";
|
|
7
7
|
import {
|
|
8
8
|
claudeLocalSettingsPath
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-RWUTFVRB.js";
|
|
10
10
|
import {
|
|
11
11
|
log
|
|
12
12
|
} from "./chunk-W5CD7WTX.js";
|
package/dist/postinstall.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
2
|
loadConfig
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-KB4JM2EB.js";
|
|
4
4
|
import "./chunk-PGLUEN7D.js";
|
|
5
5
|
import {
|
|
6
6
|
claudeSessionDir,
|
|
7
7
|
encodeProjectPath,
|
|
8
8
|
readJson,
|
|
9
|
+
resolvePath,
|
|
9
10
|
writeJson
|
|
10
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-RWUTFVRB.js";
|
|
11
12
|
import {
|
|
12
13
|
log
|
|
13
14
|
} from "./chunk-W5CD7WTX.js";
|
|
@@ -212,6 +213,7 @@ Remapped to: ${remapped}`
|
|
|
212
213
|
});
|
|
213
214
|
localProjectPath = confirmed.trim() || remapped;
|
|
214
215
|
}
|
|
216
|
+
localProjectPath = resolvePath(localProjectPath);
|
|
215
217
|
loadSession(chosen, localProjectPath, docsDir);
|
|
216
218
|
log.success(`Session "${chosen.label}" loaded.`);
|
|
217
219
|
log.info(`To resume, run:`);
|
|
@@ -4,11 +4,11 @@ import {
|
|
|
4
4
|
saveStatuslineConfig,
|
|
5
5
|
selectStatuslineComponents,
|
|
6
6
|
writeStatuslineSettings
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-QG6XYVJU.js";
|
|
8
8
|
import {
|
|
9
9
|
ALL_COMPONENT_IDS
|
|
10
10
|
} from "./chunk-PGLUEN7D.js";
|
|
11
|
-
import "./chunk-
|
|
11
|
+
import "./chunk-RWUTFVRB.js";
|
|
12
12
|
import {
|
|
13
13
|
log
|
|
14
14
|
} from "./chunk-W5CD7WTX.js";
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
2
|
isMarketplaceRegistered,
|
|
3
3
|
isPluginInstalled
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-ZOOFPF5I.js";
|
|
5
5
|
import {
|
|
6
6
|
hasShellCompletion,
|
|
7
7
|
removeShellCompletion
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-KJUGTLPQ.js";
|
|
9
|
+
import {
|
|
10
|
+
resolveScope
|
|
11
|
+
} from "./chunk-EMAINEYB.js";
|
|
9
12
|
import {
|
|
10
13
|
commandExists,
|
|
11
14
|
run
|
|
@@ -18,7 +21,7 @@ import {
|
|
|
18
21
|
marketplaceClonePath,
|
|
19
22
|
readJson,
|
|
20
23
|
writeJson
|
|
21
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-RWUTFVRB.js";
|
|
22
25
|
import {
|
|
23
26
|
log
|
|
24
27
|
} from "./chunk-W5CD7WTX.js";
|
|
@@ -76,7 +79,43 @@ function displayDetection(d) {
|
|
|
76
79
|
function nothingToRemove(d) {
|
|
77
80
|
return !d.pluginInstalled && !d.marketplaceRegistered && !d.cacheExists && !d.cloneExists && !d.statuslineConfigured && !d.shellCompletionExists && !d.globalConfigExists;
|
|
78
81
|
}
|
|
79
|
-
async function
|
|
82
|
+
async function uninstallScoped(scope) {
|
|
83
|
+
const proceed = await confirm({
|
|
84
|
+
message: `Uninstall Coding Friend from ${chalk.cyan(scope)} scope?`,
|
|
85
|
+
default: false
|
|
86
|
+
});
|
|
87
|
+
if (!proceed) {
|
|
88
|
+
log.info("Uninstall cancelled.");
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
log.step(`Uninstalling plugin from ${scope} scope...`);
|
|
92
|
+
const result = run("claude", [
|
|
93
|
+
"plugin",
|
|
94
|
+
"uninstall",
|
|
95
|
+
PLUGIN_ID,
|
|
96
|
+
"--scope",
|
|
97
|
+
scope
|
|
98
|
+
]);
|
|
99
|
+
if (result === null) {
|
|
100
|
+
const fallback = run("claude", [
|
|
101
|
+
"plugin",
|
|
102
|
+
"uninstall",
|
|
103
|
+
PLUGIN_NAME,
|
|
104
|
+
"--scope",
|
|
105
|
+
scope
|
|
106
|
+
]);
|
|
107
|
+
if (fallback === null) {
|
|
108
|
+
log.warn(
|
|
109
|
+
"Could not uninstall plugin (may not be installed at this scope)."
|
|
110
|
+
);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
log.success(`Plugin uninstalled from ${scope} scope.`);
|
|
115
|
+
console.log();
|
|
116
|
+
log.dim("Restart Claude Code to complete the uninstall.");
|
|
117
|
+
}
|
|
118
|
+
async function uninstallCommand(opts = {}) {
|
|
80
119
|
console.log(`
|
|
81
120
|
=== \u{1F44B} ${chalk.red("Coding Friend Uninstall")} \u{1F44B} ===`);
|
|
82
121
|
if (!commandExists("claude")) {
|
|
@@ -86,17 +125,34 @@ async function uninstallCommand() {
|
|
|
86
125
|
);
|
|
87
126
|
return;
|
|
88
127
|
}
|
|
89
|
-
|
|
90
|
-
if (detection.devModeActive) {
|
|
128
|
+
if (existsSync(devStatePath())) {
|
|
91
129
|
log.warn("Dev mode is currently active.");
|
|
92
130
|
log.dim(`Run ${chalk.bold("cf dev off")} first, then try again.`);
|
|
93
131
|
return;
|
|
94
132
|
}
|
|
133
|
+
const scope = await resolveScope(
|
|
134
|
+
opts,
|
|
135
|
+
"Where should the plugin be uninstalled from?"
|
|
136
|
+
);
|
|
137
|
+
if (scope === "project" || scope === "local") {
|
|
138
|
+
await uninstallScoped(scope);
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
const detection = detect();
|
|
95
142
|
if (nothingToRemove(detection)) {
|
|
96
143
|
log.info("Nothing to uninstall \u2014 Coding Friend is not installed.");
|
|
97
144
|
return;
|
|
98
145
|
}
|
|
99
146
|
displayDetection(detection);
|
|
147
|
+
log.warn("This removes the plugin cache and marketplace data globally.");
|
|
148
|
+
log.dim(
|
|
149
|
+
"If Coding Friend is also installed at project or local scope in other"
|
|
150
|
+
);
|
|
151
|
+
log.dim("projects, those installations may stop working.");
|
|
152
|
+
log.dim(
|
|
153
|
+
`Run ${chalk.bold("cf install --project")} in those projects to reinstall.`
|
|
154
|
+
);
|
|
155
|
+
console.log();
|
|
100
156
|
const proceed = await confirm({
|
|
101
157
|
message: "This will remove Coding Friend from Claude Code. Continue?",
|
|
102
158
|
default: false
|
|
@@ -2,12 +2,13 @@ import {
|
|
|
2
2
|
getLatestVersion,
|
|
3
3
|
semverCompare,
|
|
4
4
|
updateCommand
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import "./chunk-
|
|
7
|
-
import "./chunk-BCYBFGVD.js";
|
|
5
|
+
} from "./chunk-YZ7IZ46F.js";
|
|
6
|
+
import "./chunk-QG6XYVJU.js";
|
|
8
7
|
import "./chunk-PGLUEN7D.js";
|
|
8
|
+
import "./chunk-KJUGTLPQ.js";
|
|
9
|
+
import "./chunk-EMAINEYB.js";
|
|
9
10
|
import "./chunk-UFGNO6CW.js";
|
|
10
|
-
import "./chunk-
|
|
11
|
+
import "./chunk-RWUTFVRB.js";
|
|
11
12
|
import "./chunk-W5CD7WTX.js";
|
|
12
13
|
export {
|
|
13
14
|
getLatestVersion,
|
package/package.json
CHANGED
package/dist/chunk-TLLWOWYU.js
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
installedPluginsPath,
|
|
3
|
-
knownMarketplacesPath,
|
|
4
|
-
readJson
|
|
5
|
-
} from "./chunk-HQ5BPWEV.js";
|
|
6
|
-
|
|
7
|
-
// src/lib/plugin-state.ts
|
|
8
|
-
var MARKETPLACE_NAME = "coding-friend-marketplace";
|
|
9
|
-
var PLUGIN_NAME = "coding-friend";
|
|
10
|
-
function isPluginInstalled() {
|
|
11
|
-
const data = readJson(installedPluginsPath());
|
|
12
|
-
if (!data) return false;
|
|
13
|
-
const plugins = data.plugins ?? data;
|
|
14
|
-
return Object.keys(plugins).some((k) => k.includes(PLUGIN_NAME));
|
|
15
|
-
}
|
|
16
|
-
function isMarketplaceRegistered() {
|
|
17
|
-
const data = readJson(knownMarketplacesPath());
|
|
18
|
-
if (!data) return false;
|
|
19
|
-
return MARKETPLACE_NAME in data;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export {
|
|
23
|
-
isPluginInstalled,
|
|
24
|
-
isMarketplaceRegistered
|
|
25
|
-
};
|