coding-friend-cli 1.11.0 → 1.12.1

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 CHANGED
@@ -28,6 +28,17 @@ cf uninstall --global # Same as --user
28
28
  cf uninstall --project # Uninstall from project scope only
29
29
  cf uninstall --local # Uninstall from local scope only
30
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
31
42
  cf init # Initialize workspace (interactive)
32
43
  # 💡 You can run this anywhere, anytime.
33
44
  cf config # Manage Coding Friend configuration (interactive menu)
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  readJson,
3
3
  writeJson
4
- } from "./chunk-ZS7BLEYT.js";
4
+ } from "./chunk-RWUTFVRB.js";
5
5
 
6
6
  // src/lib/permissions.ts
7
7
  var PERMISSION_RULES = [
@@ -1,22 +1,23 @@
1
1
  import {
2
2
  ensureStatusline,
3
3
  getInstalledVersion
4
- } from "./chunk-HYLS67T7.js";
5
- import {
6
- resolveScope
7
- } from "./chunk-GJLNN6X5.js";
4
+ } from "./chunk-QG6XYVJU.js";
8
5
  import {
9
6
  ensureShellCompletion
10
- } from "./chunk-4JL3SR5V.js";
7
+ } from "./chunk-KJUGTLPQ.js";
8
+ import {
9
+ resolveScope
10
+ } from "./chunk-PYRGNY5P.js";
11
11
  import {
12
12
  commandExists,
13
13
  run,
14
+ runWithStderr,
14
15
  sleepSync
15
- } from "./chunk-UFGNO6CW.js";
16
+ } from "./chunk-X5WEODUD.js";
16
17
  import {
17
18
  claudeSettingsPath,
18
19
  readJson
19
- } from "./chunk-ZS7BLEYT.js";
20
+ } from "./chunk-RWUTFVRB.js";
20
21
  import {
21
22
  log
22
23
  } from "./chunk-W5CD7WTX.js";
@@ -156,24 +157,35 @@ async function updateCommand(opts) {
156
157
  if (scope) {
157
158
  updateArgs.push("--scope", scope);
158
159
  }
159
- const result = run("claude", updateArgs);
160
- if (result === null) {
160
+ const result = runWithStderr("claude", updateArgs);
161
+ if (result.exitCode !== 0) {
161
162
  log.error(
162
163
  "Plugin update failed. Try manually: claude plugin update coding-friend@coding-friend-marketplace"
163
164
  );
165
+ if (result.stderr) {
166
+ log.dim(`stderr: ${result.stderr}`);
167
+ }
164
168
  } else {
165
- log.success("Plugin updated!");
166
169
  let newVersion = currentVersion;
167
- for (let i = 0; i < 5; i++) {
170
+ for (let i = 0; i < 3; i++) {
168
171
  newVersion = getInstalledVersion();
169
172
  if (newVersion !== currentVersion) break;
170
- if (i < 4) sleepSync(1e3);
173
+ if (i < 2) sleepSync(1e3);
171
174
  }
172
175
  if (newVersion !== currentVersion) {
173
176
  log.success(`Plugin updated to ${chalk.green(`v${newVersion}`)}`);
174
177
  } else {
175
178
  log.warn(
176
- "Version in installed_plugins.json unchanged. Cache may still have been updated."
179
+ "Plugin command succeeded but version in installed_plugins.json is still unchanged."
180
+ );
181
+ if (result.stdout) {
182
+ log.dim(`stdout: ${result.stdout}`);
183
+ }
184
+ if (result.stderr) {
185
+ log.dim(`stderr: ${result.stderr}`);
186
+ }
187
+ log.dim(
188
+ "Try manually: claude plugin update coding-friend@coding-friend-marketplace"
177
189
  );
178
190
  }
179
191
  }
@@ -6,7 +6,7 @@ import {
6
6
  localConfigPath,
7
7
  readJson,
8
8
  resolvePath
9
- } from "./chunk-ZS7BLEYT.js";
9
+ } from "./chunk-RWUTFVRB.js";
10
10
 
11
11
  // src/lib/config.ts
12
12
  function loadConfig() {
@@ -21,7 +21,7 @@ ${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
25
  local scope_flags="--user --global --project --local"
26
26
  local update_flags="--cli --plugin --statusline --user --global --project --local"
27
27
 
@@ -43,8 +43,8 @@ _cf_completions() {
43
43
  return
44
44
  fi
45
45
 
46
- # Flag completion for install/uninstall
47
- if [[ "\${COMP_WORDS[1]}" == "install" || "\${COMP_WORDS[1]}" == "uninstall" ]] && [[ "$cur" == -* ]]; then
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
48
  COMPREPLY=($(compgen -W "$scope_flags" -- "$cur"))
49
49
  return
50
50
  fi
@@ -65,6 +65,8 @@ var ZSH_FUNCTION_BODY = `_cf() {
65
65
  commands=(
66
66
  'install:Install the Coding Friend plugin into Claude Code'
67
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'
68
70
  'init:Initialize coding-friend in current project'
69
71
  'config:Manage Coding Friend configuration'
70
72
  'host:Build and serve learning docs as a static website'
@@ -97,7 +99,7 @@ var ZSH_FUNCTION_BODY = `_cf() {
97
99
 
98
100
  if (( CURRENT == 2 )); then
99
101
  _describe 'command' commands
100
- elif (( CURRENT >= 3 )) && [[ "\${words[2]}" == "install" || "\${words[2]}" == "uninstall" ]]; then
102
+ elif (( CURRENT >= 3 )) && [[ "\${words[2]}" == "install" || "\${words[2]}" == "uninstall" || "\${words[2]}" == "disable" || "\${words[2]}" == "enable" ]]; then
101
103
  _values 'flags' $scope_flags
102
104
  elif (( CURRENT >= 3 )) && [[ "\${words[2]}" == "update" ]]; then
103
105
  _values 'flags' $update_flags
@@ -137,6 +139,8 @@ var FISH_CONTENT = `# coding-friend CLI completions
137
139
  complete -c cf -f
138
140
  complete -c cf -n "__fish_use_subcommand" -a install -d "Install the Coding Friend plugin into Claude Code"
139
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"
140
144
  complete -c cf -n "__fish_use_subcommand" -a init -d "Initialize coding-friend in current project"
141
145
  complete -c cf -n "__fish_use_subcommand" -a config -d "Manage Coding Friend configuration"
142
146
  complete -c cf -n "__fish_use_subcommand" -a host -d "Build and serve learning docs as a static website"
@@ -146,11 +150,11 @@ complete -c cf -n "__fish_use_subcommand" -a statusline -d "Setup coding-friend
146
150
  complete -c cf -n "__fish_use_subcommand" -a update -d "Update coding-friend plugin and refresh statusline"
147
151
  complete -c cf -n "__fish_use_subcommand" -a dev -d "Switch between local and remote plugin for development"
148
152
  complete -c cf -n "__fish_use_subcommand" -a session -d "Save and load Claude Code sessions across machines"
149
- # Scope flags for install/uninstall
150
- complete -c cf -n "__fish_seen_subcommand_from install uninstall" -l user -d "User scope (all projects)"
151
- complete -c cf -n "__fish_seen_subcommand_from install uninstall" -l global -d "User scope (all projects)"
152
- complete -c cf -n "__fish_seen_subcommand_from install uninstall" -l project -d "Project scope (shared via git)"
153
- complete -c cf -n "__fish_seen_subcommand_from install uninstall" -l local -d "Local scope (this machine only)"
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)"
154
158
  # Flags for update
155
159
  complete -c cf -n "__fish_seen_subcommand_from update" -l cli -d "Update only the CLI"
156
160
  complete -c cf -n "__fish_seen_subcommand_from update" -l plugin -d "Update only the plugin"
@@ -175,7 +179,7 @@ var POWERSHELL_BLOCK = `
175
179
  ${MARKER_START}
176
180
  Register-ArgumentCompleter -Native -CommandName cf -ScriptBlock {
177
181
  param($wordToComplete, $commandAst, $cursorPosition)
178
- $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')
179
183
  $devSubcommands = @('on','off','status','restart','sync','update')
180
184
  $sessionSubcommands = @('save','load')
181
185
  $scopeFlags = @('--user','--global','--project','--local')
@@ -187,7 +191,7 @@ Register-ArgumentCompleter -Native -CommandName cf -ScriptBlock {
187
191
  } elseif ($words.Count -ge 2 -and $words[1].ToString() -eq 'session') {
188
192
  $sessionSubcommands | Where-Object { $_ -like "$wordToComplete*" } |
189
193
  ForEach-Object { [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) }
190
- } elseif ($words.Count -ge 2 -and ($words[1].ToString() -eq 'install' -or $words[1].ToString() -eq 'uninstall')) {
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')) {
191
195
  $scopeFlags | Where-Object { $_ -like "$wordToComplete*" } |
192
196
  ForEach-Object { [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) }
193
197
  } elseif ($words.Count -ge 2 -and $words[1].ToString() -eq 'update') {
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  run
3
- } from "./chunk-UFGNO6CW.js";
3
+ } from "./chunk-X5WEODUD.js";
4
4
  import {
5
5
  globalConfigPath,
6
6
  localConfigPath,
7
7
  readJson
8
- } from "./chunk-ZS7BLEYT.js";
8
+ } from "./chunk-RWUTFVRB.js";
9
9
  import {
10
10
  log
11
11
  } from "./chunk-W5CD7WTX.js";
@@ -33,26 +33,26 @@ async function askScope(label = "Save to:") {
33
33
  ]
34
34
  });
35
35
  }
36
- async function askPluginScope() {
36
+ async function askPluginScope(message = "Where should the plugin be installed?") {
37
37
  return select({
38
- message: "Where should the plugin be installed?",
38
+ message,
39
39
  choices: [
40
40
  {
41
41
  name: "User / Global \u2014 available in all projects",
42
42
  value: "user"
43
43
  },
44
44
  {
45
- name: "Project \u2014 shared with team via .claude/settings.json",
45
+ name: "Project \u2014 shared with team via <project>.claude/settings.json",
46
46
  value: "project"
47
47
  },
48
48
  {
49
- name: "Local \u2014 this machine only, not shared (gitignored)",
49
+ name: "Local \u2014 this machine only via <project>.claude/settings.local.json, not shared (gitignored)",
50
50
  value: "local"
51
51
  }
52
52
  ]
53
53
  });
54
54
  }
55
- async function resolveScope(opts) {
55
+ async function resolveScope(opts, message) {
56
56
  const flags = [
57
57
  { key: "user", scope: "user" },
58
58
  { key: "global", scope: "user" },
@@ -76,7 +76,7 @@ async function resolveScope(opts) {
76
76
  );
77
77
  process.exit(1);
78
78
  }
79
- return askPluginScope();
79
+ return askPluginScope(message);
80
80
  }
81
81
  function showConfigHint() {
82
82
  console.log(chalk.dim("Config files:"));
@@ -10,7 +10,7 @@ import {
10
10
  pluginCachePath,
11
11
  readJson,
12
12
  writeJson
13
- } from "./chunk-ZS7BLEYT.js";
13
+ } from "./chunk-RWUTFVRB.js";
14
14
 
15
15
  // src/lib/statusline.ts
16
16
  import { existsSync, readdirSync } from "fs";
@@ -15,6 +15,9 @@ function globalConfigPath() {
15
15
  function claudeSettingsPath() {
16
16
  return join(homedir(), ".claude", "settings.json");
17
17
  }
18
+ function claudeProjectSettingsPath() {
19
+ return resolve(process.cwd(), ".claude", "settings.json");
20
+ }
18
21
  function claudeLocalSettingsPath() {
19
22
  return resolve(process.cwd(), ".claude", "settings.local.json");
20
23
  }
@@ -96,6 +99,7 @@ export {
96
99
  localConfigPath,
97
100
  globalConfigPath,
98
101
  claudeSettingsPath,
102
+ claudeProjectSettingsPath,
99
103
  claudeLocalSettingsPath,
100
104
  installedPluginsPath,
101
105
  pluginCachePath,
@@ -11,6 +11,23 @@ function run(cmd, args = [], opts) {
11
11
  return null;
12
12
  }
13
13
  }
14
+ function runWithStderr(cmd, args = [], opts) {
15
+ try {
16
+ const stdout = execFileSync(cmd, args, {
17
+ encoding: "utf-8",
18
+ cwd: opts?.cwd,
19
+ stdio: ["pipe", "pipe", "pipe"]
20
+ }).trim();
21
+ return { stdout, stderr: "", exitCode: 0 };
22
+ } catch (err) {
23
+ const e = err;
24
+ return {
25
+ stdout: (e.stdout ?? "").toString().trim(),
26
+ stderr: (e.stderr ?? "").toString().trim(),
27
+ exitCode: e.status ?? 1
28
+ };
29
+ }
30
+ }
14
31
  function streamExec(cmd, args, opts) {
15
32
  return new Promise((resolve, reject) => {
16
33
  const child = spawn(cmd, args, {
@@ -30,6 +47,7 @@ function commandExists(cmd) {
30
47
 
31
48
  export {
32
49
  run,
50
+ runWithStderr,
33
51
  streamExec,
34
52
  sleepSync,
35
53
  commandExists
@@ -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
+ };
@@ -4,7 +4,16 @@ import {
4
4
  saveStatuslineConfig,
5
5
  selectStatuslineComponents,
6
6
  writeStatuslineSettings
7
- } from "./chunk-HYLS67T7.js";
7
+ } from "./chunk-QG6XYVJU.js";
8
+ import {
9
+ ALL_COMPONENT_IDS,
10
+ DEFAULT_CONFIG
11
+ } from "./chunk-PGLUEN7D.js";
12
+ import {
13
+ ensureShellCompletion,
14
+ hasShellCompletion,
15
+ removeShellCompletion
16
+ } from "./chunk-KJUGTLPQ.js";
8
17
  import {
9
18
  BACK,
10
19
  applyDocsDirChange,
@@ -14,26 +23,17 @@ import {
14
23
  getScopeLabel,
15
24
  injectBackChoice,
16
25
  showConfigHint
17
- } from "./chunk-GJLNN6X5.js";
18
- import {
19
- ensureShellCompletion,
20
- hasShellCompletion,
21
- removeShellCompletion
22
- } from "./chunk-4JL3SR5V.js";
23
- import {
24
- ALL_COMPONENT_IDS,
25
- DEFAULT_CONFIG
26
- } from "./chunk-PGLUEN7D.js";
26
+ } from "./chunk-PYRGNY5P.js";
27
27
  import {
28
28
  run
29
- } from "./chunk-UFGNO6CW.js";
29
+ } from "./chunk-X5WEODUD.js";
30
30
  import {
31
31
  globalConfigPath,
32
32
  localConfigPath,
33
33
  mergeJson,
34
34
  readJson,
35
35
  resolvePath
36
- } from "./chunk-ZS7BLEYT.js";
36
+ } from "./chunk-RWUTFVRB.js";
37
37
  import {
38
38
  log
39
39
  } from "./chunk-W5CD7WTX.js";
@@ -1,25 +1,25 @@
1
1
  import {
2
2
  isMarketplaceRegistered,
3
3
  isPluginInstalled
4
- } from "./chunk-E2XX5MIM.js";
4
+ } from "./chunk-ZOOFPF5I.js";
5
5
  import {
6
6
  ensureStatusline
7
- } from "./chunk-HYLS67T7.js";
7
+ } from "./chunk-QG6XYVJU.js";
8
+ import "./chunk-PGLUEN7D.js";
8
9
  import {
9
10
  ensureShellCompletion
10
- } from "./chunk-4JL3SR5V.js";
11
- import "./chunk-PGLUEN7D.js";
11
+ } from "./chunk-KJUGTLPQ.js";
12
12
  import {
13
13
  commandExists,
14
14
  run
15
- } from "./chunk-UFGNO6CW.js";
15
+ } from "./chunk-X5WEODUD.js";
16
16
  import {
17
17
  devStatePath,
18
18
  knownMarketplacesPath,
19
19
  pluginCachePath,
20
20
  readJson,
21
21
  writeJson
22
- } from "./chunk-ZS7BLEYT.js";
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-PYRGNY5P.js";
8
+ import "./chunk-X5WEODUD.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-PYRGNY5P.js";
8
+ import "./chunk-X5WEODUD.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-XIZJ64JK.js";
6
+ } from "./chunk-KB4JM2EB.js";
7
7
  import "./chunk-PGLUEN7D.js";
8
8
  import {
9
9
  run,
10
10
  streamExec
11
- } from "./chunk-UFGNO6CW.js";
12
- import "./chunk-ZS7BLEYT.js";
11
+ } from "./chunk-X5WEODUD.js";
12
+ import "./chunk-RWUTFVRB.js";
13
13
  import {
14
14
  log
15
15
  } from "./chunk-W5CD7WTX.js";
package/dist/index.js CHANGED
@@ -14,39 +14,47 @@ 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
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-FQTMSBGK.js");
17
+ const { installCommand } = await import("./install-5P2S6XVC.js");
18
18
  await installCommand(opts);
19
19
  });
20
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-A2LJR2OD.js");
21
+ const { uninstallCommand } = await import("./uninstall-7SX73XM5.js");
22
22
  await uninstallCommand(opts);
23
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-4CD623UW.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-QTUP4MMY.js");
30
+ await enableCommand(opts);
31
+ });
24
32
  program.command("init").description("Initialize coding-friend in current project").action(async () => {
25
- const { initCommand } = await import("./init-QRUDHFME.js");
33
+ const { initCommand } = await import("./init-SIZ5RXE7.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-GYJGDXGV.js");
37
+ const { configCommand } = await import("./config-F6QRCOYP.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-SWIWQRRL.js");
41
+ const { hostCommand } = await import("./host-D3GAQ4BW.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-H3K67N2P.js");
45
+ const { mcpCommand } = await import("./mcp-H42K6Y6T.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-DIJMCOZX.js");
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-H2WUKOJ6.js");
53
+ const { statuslineCommand } = await import("./statusline-5ZMM3RYY.js");
46
54
  await statuslineCommand();
47
55
  });
48
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) => {
49
- const { updateCommand } = await import("./update-RJSWHCCR.js");
57
+ const { updateCommand } = await import("./update-VZZ3SNCZ.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-2APBPDZF.js");
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-2APBPDZF.js");
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-GFFXRZJC.js");
92
+ const { devOnCommand } = await import("./dev-DIWT3AAU.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-GFFXRZJC.js");
96
+ const { devOffCommand } = await import("./dev-DIWT3AAU.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-GFFXRZJC.js");
100
+ const { devStatusCommand } = await import("./dev-DIWT3AAU.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-GFFXRZJC.js");
106
+ const { devSyncCommand } = await import("./dev-DIWT3AAU.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-GFFXRZJC.js");
113
+ const { devRestartCommand } = await import("./dev-DIWT3AAU.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-GFFXRZJC.js");
120
+ const { devUpdateCommand } = await import("./dev-DIWT3AAU.js");
113
121
  await devUpdateCommand(path);
114
122
  });
115
123
  program.parse();
@@ -3,14 +3,21 @@ import {
3
3
  buildLearnDirRules,
4
4
  getExistingRules,
5
5
  getMissingRules
6
- } from "./chunk-EL6BAAKL.js";
6
+ } from "./chunk-56U7US6J.js";
7
7
  import {
8
8
  findStatuslineHookPath,
9
9
  isStatuslineConfigured,
10
10
  saveStatuslineConfig,
11
11
  selectStatuslineComponents,
12
12
  writeStatuslineSettings
13
- } from "./chunk-HYLS67T7.js";
13
+ } from "./chunk-QG6XYVJU.js";
14
+ import {
15
+ DEFAULT_CONFIG
16
+ } from "./chunk-PGLUEN7D.js";
17
+ import {
18
+ ensureShellCompletion,
19
+ hasShellCompletion
20
+ } from "./chunk-KJUGTLPQ.js";
14
21
  import {
15
22
  BACK,
16
23
  applyDocsDirChange,
@@ -20,17 +27,10 @@ import {
20
27
  getScopeLabel,
21
28
  injectBackChoice,
22
29
  showConfigHint
23
- } from "./chunk-GJLNN6X5.js";
24
- import {
25
- ensureShellCompletion,
26
- hasShellCompletion
27
- } from "./chunk-4JL3SR5V.js";
28
- import {
29
- DEFAULT_CONFIG
30
- } from "./chunk-PGLUEN7D.js";
30
+ } from "./chunk-PYRGNY5P.js";
31
31
  import {
32
32
  run
33
- } from "./chunk-UFGNO6CW.js";
33
+ } from "./chunk-X5WEODUD.js";
34
34
  import {
35
35
  claudeSettingsPath,
36
36
  globalConfigPath,
@@ -38,7 +38,7 @@ import {
38
38
  mergeJson,
39
39
  readJson,
40
40
  resolvePath
41
- } from "./chunk-ZS7BLEYT.js";
41
+ } from "./chunk-RWUTFVRB.js";
42
42
  import {
43
43
  log
44
44
  } from "./chunk-W5CD7WTX.js";
@@ -1,27 +1,28 @@
1
1
  import {
2
2
  getLatestVersion,
3
3
  semverCompare
4
- } from "./chunk-RN5UYDIT.js";
4
+ } from "./chunk-E76PLDNS.js";
5
5
  import {
6
- isMarketplaceRegistered
7
- } from "./chunk-E2XX5MIM.js";
6
+ isMarketplaceRegistered,
7
+ isPluginDisabled
8
+ } from "./chunk-ZOOFPF5I.js";
8
9
  import {
9
10
  getInstalledVersion
10
- } from "./chunk-HYLS67T7.js";
11
- import {
12
- resolveScope
13
- } from "./chunk-GJLNN6X5.js";
11
+ } from "./chunk-QG6XYVJU.js";
12
+ import "./chunk-PGLUEN7D.js";
14
13
  import {
15
14
  ensureShellCompletion
16
- } from "./chunk-4JL3SR5V.js";
17
- import "./chunk-PGLUEN7D.js";
15
+ } from "./chunk-KJUGTLPQ.js";
16
+ import {
17
+ resolveScope
18
+ } from "./chunk-PYRGNY5P.js";
18
19
  import {
19
20
  commandExists,
20
21
  run
21
- } from "./chunk-UFGNO6CW.js";
22
+ } from "./chunk-X5WEODUD.js";
22
23
  import {
23
24
  devStatePath
24
- } from "./chunk-ZS7BLEYT.js";
25
+ } from "./chunk-RWUTFVRB.js";
25
26
  import {
26
27
  log
27
28
  } from "./chunk-W5CD7WTX.js";
@@ -85,6 +86,11 @@ async function installCommand(opts = {}) {
85
86
  log.success(
86
87
  `Plugin already installed (${chalk.green(`v${installedVersion}`)}).`
87
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
+ }
88
94
  const latestVersion = getLatestVersion();
89
95
  if (latestVersion) {
90
96
  const cmp = semverCompare(installedVersion, latestVersion);
@@ -3,12 +3,12 @@ import {
3
3
  } from "./chunk-RZRT7NGT.js";
4
4
  import {
5
5
  resolveDocsDir
6
- } from "./chunk-XIZJ64JK.js";
6
+ } from "./chunk-KB4JM2EB.js";
7
7
  import "./chunk-PGLUEN7D.js";
8
8
  import {
9
9
  run
10
- } from "./chunk-UFGNO6CW.js";
11
- import "./chunk-ZS7BLEYT.js";
10
+ } from "./chunk-X5WEODUD.js";
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-EL6BAAKL.js";
6
+ } from "./chunk-56U7US6J.js";
7
7
  import {
8
8
  claudeLocalSettingsPath
9
- } from "./chunk-ZS7BLEYT.js";
9
+ } from "./chunk-RWUTFVRB.js";
10
10
  import {
11
11
  log
12
12
  } from "./chunk-W5CD7WTX.js";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  ensureShellCompletion
4
- } from "./chunk-4JL3SR5V.js";
4
+ } from "./chunk-KJUGTLPQ.js";
5
5
  import "./chunk-W5CD7WTX.js";
6
6
 
7
7
  // src/postinstall.ts
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  loadConfig
3
- } from "./chunk-XIZJ64JK.js";
3
+ } from "./chunk-KB4JM2EB.js";
4
4
  import "./chunk-PGLUEN7D.js";
5
5
  import {
6
6
  claudeSessionDir,
@@ -8,7 +8,7 @@ import {
8
8
  readJson,
9
9
  resolvePath,
10
10
  writeJson
11
- } from "./chunk-ZS7BLEYT.js";
11
+ } from "./chunk-RWUTFVRB.js";
12
12
  import {
13
13
  log
14
14
  } from "./chunk-W5CD7WTX.js";
@@ -4,11 +4,11 @@ import {
4
4
  saveStatuslineConfig,
5
5
  selectStatuslineComponents,
6
6
  writeStatuslineSettings
7
- } from "./chunk-HYLS67T7.js";
7
+ } from "./chunk-QG6XYVJU.js";
8
8
  import {
9
9
  ALL_COMPONENT_IDS
10
10
  } from "./chunk-PGLUEN7D.js";
11
- import "./chunk-ZS7BLEYT.js";
11
+ import "./chunk-RWUTFVRB.js";
12
12
  import {
13
13
  log
14
14
  } from "./chunk-W5CD7WTX.js";
@@ -1,18 +1,18 @@
1
1
  import {
2
2
  isMarketplaceRegistered,
3
3
  isPluginInstalled
4
- } from "./chunk-E2XX5MIM.js";
5
- import {
6
- resolveScope
7
- } from "./chunk-GJLNN6X5.js";
4
+ } from "./chunk-ZOOFPF5I.js";
8
5
  import {
9
6
  hasShellCompletion,
10
7
  removeShellCompletion
11
- } from "./chunk-4JL3SR5V.js";
8
+ } from "./chunk-KJUGTLPQ.js";
9
+ import {
10
+ resolveScope
11
+ } from "./chunk-PYRGNY5P.js";
12
12
  import {
13
13
  commandExists,
14
14
  run
15
- } from "./chunk-UFGNO6CW.js";
15
+ } from "./chunk-X5WEODUD.js";
16
16
  import {
17
17
  claudeSettingsPath,
18
18
  devStatePath,
@@ -21,7 +21,7 @@ import {
21
21
  marketplaceClonePath,
22
22
  readJson,
23
23
  writeJson
24
- } from "./chunk-ZS7BLEYT.js";
24
+ } from "./chunk-RWUTFVRB.js";
25
25
  import {
26
26
  log
27
27
  } from "./chunk-W5CD7WTX.js";
@@ -130,7 +130,10 @@ async function uninstallCommand(opts = {}) {
130
130
  log.dim(`Run ${chalk.bold("cf dev off")} first, then try again.`);
131
131
  return;
132
132
  }
133
- const scope = await resolveScope(opts);
133
+ const scope = await resolveScope(
134
+ opts,
135
+ "Where should the plugin be uninstalled from?"
136
+ );
134
137
  if (scope === "project" || scope === "local") {
135
138
  await uninstallScoped(scope);
136
139
  return;
@@ -141,6 +144,15 @@ async function uninstallCommand(opts = {}) {
141
144
  return;
142
145
  }
143
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();
144
156
  const proceed = await confirm({
145
157
  message: "This will remove Coding Friend from Claude Code. Continue?",
146
158
  default: false
@@ -2,13 +2,13 @@ import {
2
2
  getLatestVersion,
3
3
  semverCompare,
4
4
  updateCommand
5
- } from "./chunk-RN5UYDIT.js";
6
- import "./chunk-HYLS67T7.js";
7
- import "./chunk-GJLNN6X5.js";
8
- import "./chunk-4JL3SR5V.js";
5
+ } from "./chunk-E76PLDNS.js";
6
+ import "./chunk-QG6XYVJU.js";
9
7
  import "./chunk-PGLUEN7D.js";
10
- import "./chunk-UFGNO6CW.js";
11
- import "./chunk-ZS7BLEYT.js";
8
+ import "./chunk-KJUGTLPQ.js";
9
+ import "./chunk-PYRGNY5P.js";
10
+ import "./chunk-X5WEODUD.js";
11
+ import "./chunk-RWUTFVRB.js";
12
12
  import "./chunk-W5CD7WTX.js";
13
13
  export {
14
14
  getLatestVersion,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "coding-friend-cli",
3
- "version": "1.11.0",
3
+ "version": "1.12.1",
4
4
  "description": "CLI for coding-friend — host learning docs, setup MCP server, initialize projects",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,25 +0,0 @@
1
- import {
2
- installedPluginsPath,
3
- knownMarketplacesPath,
4
- readJson
5
- } from "./chunk-ZS7BLEYT.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
- };