coding-friend-cli 1.9.1 → 1.11.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.
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  isMarketplaceRegistered,
3
3
  isPluginInstalled
4
- } from "./chunk-HFLBFX6J.js";
4
+ } from "./chunk-E2XX5MIM.js";
5
5
  import {
6
6
  ensureStatusline
7
- } from "./chunk-BPLN4LDL.js";
7
+ } from "./chunk-HYLS67T7.js";
8
8
  import {
9
9
  ensureShellCompletion
10
- } from "./chunk-7N64TDZ6.js";
10
+ } from "./chunk-4JL3SR5V.js";
11
11
  import "./chunk-PGLUEN7D.js";
12
12
  import {
13
13
  commandExists,
@@ -19,7 +19,7 @@ import {
19
19
  pluginCachePath,
20
20
  readJson,
21
21
  writeJson
22
- } from "./chunk-TPRZHSFS.js";
22
+ } from "./chunk-ZS7BLEYT.js";
23
23
  import {
24
24
  log
25
25
  } from "./chunk-W5CD7WTX.js";
@@ -3,13 +3,13 @@ import {
3
3
  } from "./chunk-RZRT7NGT.js";
4
4
  import {
5
5
  resolveDocsDir
6
- } from "./chunk-FYHHNX7K.js";
6
+ } from "./chunk-XIZJ64JK.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-TPRZHSFS.js";
12
+ import "./chunk-ZS7BLEYT.js";
13
13
  import {
14
14
  log
15
15
  } from "./chunk-W5CD7WTX.js";
package/dist/index.js CHANGED
@@ -13,36 +13,40 @@ 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-D4NW3OAA.js");
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-FQTMSBGK.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-SOHU5WGK.js");
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-A2LJR2OD.js");
22
+ await uninstallCommand(opts);
23
23
  });
24
24
  program.command("init").description("Initialize coding-friend in current project").action(async () => {
25
- const { initCommand } = await import("./init-CIEDOFNC.js");
25
+ const { initCommand } = await import("./init-QRUDHFME.js");
26
26
  await initCommand();
27
27
  });
28
28
  program.command("config").description("Manage Coding Friend configuration").action(async () => {
29
- const { configCommand } = await import("./config-VAML7F7K.js");
29
+ const { configCommand } = await import("./config-GYJGDXGV.js");
30
30
  await configCommand();
31
31
  });
32
32
  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-LOG5RPZ7.js");
33
+ const { hostCommand } = await import("./host-SWIWQRRL.js");
34
34
  await hostCommand(path, opts);
35
35
  });
36
36
  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-ORMYETXQ.js");
37
+ const { mcpCommand } = await import("./mcp-H3K67N2P.js");
38
38
  await mcpCommand(path);
39
39
  });
40
+ 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");
42
+ await permissionCommand(opts);
43
+ });
40
44
  program.command("statusline").description("Setup coding-friend statusline in Claude Code").action(async () => {
41
- const { statuslineCommand } = await import("./statusline-5HWRTSVL.js");
45
+ const { statuslineCommand } = await import("./statusline-H2WUKOJ6.js");
42
46
  await statuslineCommand();
43
47
  });
44
- 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) => {
45
- const { updateCommand } = await import("./update-LA4B3LN4.js");
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").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");
46
50
  await updateCommand(opts);
47
51
  });
48
52
  var session = program.command("session").description("Save and load Claude Code sessions across machines");
@@ -57,11 +61,11 @@ session.command("save").description("Save current Claude Code session to sync fo
57
61
  "-s, --session-id <id>",
58
62
  "session UUID to save (default: auto-detect newest)"
59
63
  ).option("-l, --label <label>", "label for this session").action(async (opts) => {
60
- const { sessionSaveCommand } = await import("./session-74F7L5LV.js");
64
+ const { sessionSaveCommand } = await import("./session-2APBPDZF.js");
61
65
  await sessionSaveCommand(opts);
62
66
  });
63
67
  session.command("load").description("Load a saved session from sync folder").action(async () => {
64
- const { sessionLoadCommand } = await import("./session-74F7L5LV.js");
68
+ const { sessionLoadCommand } = await import("./session-2APBPDZF.js");
65
69
  await sessionLoadCommand();
66
70
  });
67
71
  var dev = program.command("dev").description("Development mode commands");
@@ -77,35 +81,35 @@ Dev subcommands:
77
81
  dev update [path] Update local dev plugin to latest version`
78
82
  );
79
83
  dev.command("on").description("Switch to local plugin source").argument("[path]", "path to local coding-friend repo (default: cwd)").action(async (path) => {
80
- const { devOnCommand } = await import("./dev-2GBY3GKC.js");
84
+ const { devOnCommand } = await import("./dev-GFFXRZJC.js");
81
85
  await devOnCommand(path);
82
86
  });
83
87
  dev.command("off").description("Switch back to remote marketplace").action(async () => {
84
- const { devOffCommand } = await import("./dev-2GBY3GKC.js");
88
+ const { devOffCommand } = await import("./dev-GFFXRZJC.js");
85
89
  await devOffCommand();
86
90
  });
87
91
  dev.command("status").description("Show current dev mode").action(async () => {
88
- const { devStatusCommand } = await import("./dev-2GBY3GKC.js");
92
+ const { devStatusCommand } = await import("./dev-GFFXRZJC.js");
89
93
  await devStatusCommand();
90
94
  });
91
95
  dev.command("sync").description(
92
96
  "Copy local source files to plugin cache (no version bump needed)"
93
97
  ).action(async () => {
94
- const { devSyncCommand } = await import("./dev-2GBY3GKC.js");
98
+ const { devSyncCommand } = await import("./dev-GFFXRZJC.js");
95
99
  await devSyncCommand();
96
100
  });
97
101
  dev.command("restart").description("Reinstall local dev plugin (off + on)").argument(
98
102
  "[path]",
99
103
  "path to local coding-friend repo (default: saved path or cwd)"
100
104
  ).action(async (path) => {
101
- const { devRestartCommand } = await import("./dev-2GBY3GKC.js");
105
+ const { devRestartCommand } = await import("./dev-GFFXRZJC.js");
102
106
  await devRestartCommand(path);
103
107
  });
104
108
  dev.command("update").description("Update local dev plugin to latest version (off + on)").argument(
105
109
  "[path]",
106
110
  "path to local coding-friend repo (default: saved path or cwd)"
107
111
  ).action(async (path) => {
108
- const { devUpdateCommand } = await import("./dev-2GBY3GKC.js");
112
+ const { devUpdateCommand } = await import("./dev-GFFXRZJC.js");
109
113
  await devUpdateCommand(path);
110
114
  });
111
115
  program.parse();
@@ -1,3 +1,16 @@
1
+ import {
2
+ applyPermissions,
3
+ buildLearnDirRules,
4
+ getExistingRules,
5
+ getMissingRules
6
+ } from "./chunk-EL6BAAKL.js";
7
+ import {
8
+ findStatuslineHookPath,
9
+ isStatuslineConfigured,
10
+ saveStatuslineConfig,
11
+ selectStatuslineComponents,
12
+ writeStatuslineSettings
13
+ } from "./chunk-HYLS67T7.js";
1
14
  import {
2
15
  BACK,
3
16
  applyDocsDirChange,
@@ -7,18 +20,11 @@ import {
7
20
  getScopeLabel,
8
21
  injectBackChoice,
9
22
  showConfigHint
10
- } from "./chunk-QQ5SVZET.js";
11
- import {
12
- findStatuslineHookPath,
13
- isStatuslineConfigured,
14
- saveStatuslineConfig,
15
- selectStatuslineComponents,
16
- writeStatuslineSettings
17
- } from "./chunk-BPLN4LDL.js";
23
+ } from "./chunk-GJLNN6X5.js";
18
24
  import {
19
25
  ensureShellCompletion,
20
26
  hasShellCompletion
21
- } from "./chunk-7N64TDZ6.js";
27
+ } from "./chunk-4JL3SR5V.js";
22
28
  import {
23
29
  DEFAULT_CONFIG
24
30
  } from "./chunk-PGLUEN7D.js";
@@ -31,9 +37,8 @@ import {
31
37
  localConfigPath,
32
38
  mergeJson,
33
39
  readJson,
34
- resolvePath,
35
- writeJson
36
- } from "./chunk-TPRZHSFS.js";
40
+ resolvePath
41
+ } from "./chunk-ZS7BLEYT.js";
37
42
  import {
38
43
  log
39
44
  } from "./chunk-W5CD7WTX.js";
@@ -411,35 +416,23 @@ async function stepStatusline() {
411
416
  async function stepClaudePermissions(outputDir, autoCommit) {
412
417
  const resolved = resolvePath(outputDir);
413
418
  const homePath = resolved.startsWith(homedir()) ? resolved.replace(homedir(), "~") : resolved;
414
- const rules = [
415
- `Read(${homePath}/**)`,
416
- `Edit(${homePath}/**)`,
417
- `Write(${homePath}/**)`
418
- ];
419
- if (autoCommit) {
420
- rules.push(`Bash(cd ${homePath} && git add:*)`);
421
- rules.push(`Bash(cd ${homePath} && git commit:*)`);
422
- }
423
419
  const settingsPath = claudeSettingsPath();
424
- const settings = readJson(settingsPath);
425
- if (!settings) {
420
+ const existing = getExistingRules(settingsPath);
421
+ if (existing.length === 0 && !readJson(settingsPath)) {
426
422
  log.warn(
427
423
  "~/.claude/settings.json not found. Create it via Claude Code settings first."
428
424
  );
429
425
  return;
430
426
  }
431
- const permissions = settings.permissions ?? {};
432
- const existing = permissions.allow ?? [];
433
- const missing = rules.filter(
434
- (r) => !existing.some((e) => e === r || e.includes(homePath))
435
- );
427
+ const learnRules = buildLearnDirRules(homePath, autoCommit);
428
+ const missing = getMissingRules(existing, learnRules);
436
429
  if (missing.length === 0) {
437
430
  log.dim("All permission rules already configured.");
438
431
  return;
439
432
  }
440
433
  console.log("\nTo avoid repeated permission prompts, add these rules:");
441
434
  for (const r of missing) {
442
- console.log(` ${r}`);
435
+ console.log(` ${r.rule}`);
443
436
  }
444
437
  const ok = await confirm({
445
438
  message: "Add these to ~/.claude/settings.json?",
@@ -449,10 +442,13 @@ async function stepClaudePermissions(outputDir, autoCommit) {
449
442
  log.dim("Skipped. You'll get prompted each time.");
450
443
  return;
451
444
  }
452
- permissions.allow = [...existing, ...missing];
453
- settings.permissions = permissions;
454
- writeJson(settingsPath, settings);
445
+ applyPermissions(
446
+ settingsPath,
447
+ missing.map((r) => r.rule),
448
+ []
449
+ );
455
450
  log.success(`Added ${missing.length} permission rules.`);
451
+ log.dim("For all plugin permissions, run: `cf permission`");
456
452
  }
457
453
  async function initCommand() {
458
454
  _stepIndex = 0;
@@ -485,6 +481,12 @@ async function initCommand() {
485
481
  const docsDir = getDocsDir(updatedGlobal, updatedLocal);
486
482
  if (gitAvailable) {
487
483
  await stepGitignore(docsDir);
484
+ } else {
485
+ printStepHeader(
486
+ `Configure .gitignore ${chalk.dim("[skipped]")}`,
487
+ "Keeps AI-generated docs and config out of your git history."
488
+ );
489
+ log.dim("Skipped \u2014 not inside a git repo.");
488
490
  }
489
491
  await stepDocsLanguage(globalCfg, localCfg);
490
492
  const { outputDir, autoCommit, isExternal } = await stepLearnConfig(
@@ -500,6 +502,14 @@ async function initCommand() {
500
502
  "Grants Claude read/write access to your external learn folder without repeated prompts."
501
503
  );
502
504
  await stepClaudePermissions(outputDir, autoCommit);
505
+ } else {
506
+ printStepHeader(
507
+ `Configure Claude permissions ${chalk.dim("[skipped]")}`,
508
+ "Grants Claude read/write access to your external learn folder without repeated prompts."
509
+ );
510
+ log.dim(
511
+ "Skipped \u2014 learn directory is inside the project. Run `cf permission` for other permissions."
512
+ );
503
513
  }
504
514
  console.log();
505
515
  log.congrats("Setup complete!");
@@ -1,27 +1,35 @@
1
1
  import {
2
2
  getLatestVersion,
3
3
  semverCompare
4
- } from "./chunk-VYMXERKM.js";
4
+ } from "./chunk-RN5UYDIT.js";
5
5
  import {
6
6
  isMarketplaceRegistered
7
- } from "./chunk-HFLBFX6J.js";
7
+ } from "./chunk-E2XX5MIM.js";
8
8
  import {
9
9
  getInstalledVersion
10
- } from "./chunk-BPLN4LDL.js";
11
- import "./chunk-7N64TDZ6.js";
10
+ } from "./chunk-HYLS67T7.js";
11
+ import {
12
+ resolveScope
13
+ } from "./chunk-GJLNN6X5.js";
14
+ import {
15
+ ensureShellCompletion
16
+ } from "./chunk-4JL3SR5V.js";
12
17
  import "./chunk-PGLUEN7D.js";
13
18
  import {
14
19
  commandExists,
15
20
  run
16
21
  } from "./chunk-UFGNO6CW.js";
17
- import "./chunk-TPRZHSFS.js";
22
+ import {
23
+ devStatePath
24
+ } from "./chunk-ZS7BLEYT.js";
18
25
  import {
19
26
  log
20
27
  } from "./chunk-W5CD7WTX.js";
21
28
 
22
29
  // src/commands/install.ts
30
+ import { existsSync } from "fs";
23
31
  import chalk from "chalk";
24
- async function installCommand() {
32
+ async function installCommand(opts = {}) {
25
33
  console.log("=== \u{1F33F} Coding Friend Install \u{1F33F} ===");
26
34
  console.log();
27
35
  if (!commandExists("claude")) {
@@ -30,6 +38,14 @@ async function installCommand() {
30
38
  );
31
39
  process.exit(1);
32
40
  }
41
+ if (existsSync(devStatePath())) {
42
+ log.warn("Dev mode is currently active.");
43
+ log.dim(
44
+ `Run ${chalk.bold("cf dev off")} first, then install. Or use ${chalk.bold("cf dev sync")} to update the dev plugin.`
45
+ );
46
+ return;
47
+ }
48
+ const scope = await resolveScope(opts);
33
49
  if (isMarketplaceRegistered()) {
34
50
  log.success("Marketplace already registered.");
35
51
  } else {
@@ -49,12 +65,14 @@ async function installCommand() {
49
65
  log.success("Marketplace added.");
50
66
  }
51
67
  const installedVersion = getInstalledVersion();
52
- if (!installedVersion) {
53
- log.step("Installing plugin...");
68
+ if (!installedVersion || scope !== "user") {
69
+ log.step(`Installing plugin (${chalk.cyan(scope)} scope)...`);
54
70
  const result = run("claude", [
55
71
  "plugin",
56
72
  "install",
57
- "coding-friend@coding-friend-marketplace"
73
+ "coding-friend@coding-friend-marketplace",
74
+ "--scope",
75
+ scope
58
76
  ]);
59
77
  if (result === null) {
60
78
  log.error(
@@ -81,12 +99,15 @@ async function installCommand() {
81
99
  log.dim("Could not check for updates (no network or GitHub rate limit).");
82
100
  }
83
101
  }
102
+ ensureShellCompletion({ silent: false });
84
103
  console.log();
85
104
  log.info("Next steps:");
86
- log.dim(
105
+ console.log(
87
106
  ` ${chalk.cyan("cf init")} Initialize workspace (docs folders, config)`
88
107
  );
89
- log.dim(` ${chalk.cyan("cf statusline")} Setup statusline in Claude Code`);
108
+ console.log(
109
+ ` ${chalk.cyan("cf statusline")} Setup statusline in Claude Code to show more real-time info`
110
+ );
90
111
  console.log();
91
112
  log.dim("Restart Claude Code (or start a new session) to use the plugin.");
92
113
  }
@@ -3,12 +3,12 @@ import {
3
3
  } from "./chunk-RZRT7NGT.js";
4
4
  import {
5
5
  resolveDocsDir
6
- } from "./chunk-FYHHNX7K.js";
6
+ } from "./chunk-XIZJ64JK.js";
7
7
  import "./chunk-PGLUEN7D.js";
8
8
  import {
9
9
  run
10
10
  } from "./chunk-UFGNO6CW.js";
11
- import "./chunk-TPRZHSFS.js";
11
+ import "./chunk-ZS7BLEYT.js";
12
12
  import {
13
13
  log
14
14
  } from "./chunk-W5CD7WTX.js";
@@ -0,0 +1,168 @@
1
+ import {
2
+ PERMISSION_RULES,
3
+ applyPermissions,
4
+ getExistingRules,
5
+ groupByCategory
6
+ } from "./chunk-EL6BAAKL.js";
7
+ import {
8
+ claudeLocalSettingsPath
9
+ } from "./chunk-ZS7BLEYT.js";
10
+ import {
11
+ log
12
+ } from "./chunk-W5CD7WTX.js";
13
+
14
+ // src/commands/permission.ts
15
+ import { checkbox, confirm, select } from "@inquirer/prompts";
16
+ import chalk from "chalk";
17
+ import { homedir } from "os";
18
+ var TAG_COLORS = {
19
+ "[read-only]": chalk.green,
20
+ "[modify]": chalk.yellow,
21
+ "[write]": chalk.yellow,
22
+ "[remote]": chalk.red,
23
+ "[execute]": chalk.magenta,
24
+ "[network]": chalk.magenta
25
+ };
26
+ function colorDescription(desc) {
27
+ const parts = desc.split(" \xB7 ");
28
+ const main = parts[0];
29
+ const usedBy = parts.length > 1 ? chalk.dim("\xB7 " + parts.slice(1).join(" \xB7 ")) : "";
30
+ const tagMatch = main.match(/^(\[[^\]]+\])\s*(.*)/);
31
+ if (tagMatch) {
32
+ const colorFn = TAG_COLORS[tagMatch[1]] ?? chalk.cyan;
33
+ return `${colorFn(tagMatch[1])} ${tagMatch[2]} ${usedBy}`;
34
+ }
35
+ return `${main} ${usedBy}`;
36
+ }
37
+ async function interactiveFlow(allRules, existing) {
38
+ const groups = groupByCategory(allRules);
39
+ const allRuleStrings = allRules.map((r) => r.rule);
40
+ const managedExisting = existing.filter((r) => allRuleStrings.includes(r));
41
+ const enabled = new Set(managedExisting);
42
+ console.log(
43
+ chalk.dim(
44
+ "Full reference: https://cf.dinhanhthi.com/docs/reference/permissions/"
45
+ )
46
+ );
47
+ console.log();
48
+ let browsing = true;
49
+ while (browsing) {
50
+ const categoryChoices = [];
51
+ for (const [category, rules] of groups) {
52
+ const configured = rules.filter((r) => enabled.has(r.rule)).length;
53
+ const total = rules.length;
54
+ let suffix;
55
+ if (configured === total)
56
+ suffix = chalk.green(`${configured}/${total} \u2713`);
57
+ else if (configured > 0) suffix = chalk.yellow(`${configured}/${total}`);
58
+ else suffix = chalk.dim(`0/${total}`);
59
+ categoryChoices.push({
60
+ name: `${category} (${suffix})`,
61
+ value: category
62
+ });
63
+ }
64
+ categoryChoices.push({
65
+ name: chalk.green("\u2192 Apply changes"),
66
+ value: "__apply__"
67
+ });
68
+ const chosen = await select({
69
+ message: "Select a category to configure:",
70
+ choices: categoryChoices
71
+ });
72
+ if (chosen === "__apply__") {
73
+ browsing = false;
74
+ continue;
75
+ }
76
+ const categoryRules = groups.get(chosen);
77
+ const selected = await checkbox({
78
+ message: `${chosen} permissions:`,
79
+ choices: categoryRules.map((rule) => ({
80
+ name: rule.rule,
81
+ value: rule.rule,
82
+ checked: enabled.has(rule.rule),
83
+ description: colorDescription(rule.description)
84
+ }))
85
+ });
86
+ for (const rule of categoryRules) {
87
+ if (selected.includes(rule.rule)) {
88
+ enabled.add(rule.rule);
89
+ } else {
90
+ enabled.delete(rule.rule);
91
+ }
92
+ }
93
+ }
94
+ const toAdd = [...enabled].filter((r) => !existing.includes(r));
95
+ const toRemove = managedExisting.filter((r) => !enabled.has(r));
96
+ return { toAdd, toRemove };
97
+ }
98
+ async function permissionCommand(opts) {
99
+ console.log("=== \u{1F33F} Coding Friend Permissions \u{1F33F} ===");
100
+ console.log();
101
+ const settingsPath = claudeLocalSettingsPath();
102
+ const settingsLabel = settingsPath.replace(homedir(), "~");
103
+ const existing = getExistingRules(settingsPath);
104
+ const allRules = PERMISSION_RULES;
105
+ const allRuleStrings = allRules.map((r) => r.rule);
106
+ const managedExisting = existing.filter((r) => allRuleStrings.includes(r));
107
+ const unmanagedExisting = existing.filter((r) => !allRuleStrings.includes(r));
108
+ log.dim(`Settings: ${settingsLabel} (project-local)`);
109
+ log.dim(
110
+ `Current: ${managedExisting.length}/${allRules.length} Coding Friend rules configured`
111
+ );
112
+ if (unmanagedExisting.length > 0) {
113
+ log.dim(
114
+ `(${unmanagedExisting.length} other permission rules will not be touched)`
115
+ );
116
+ }
117
+ console.log();
118
+ if (opts.all) {
119
+ const recommended = allRules.filter((r) => r.recommended);
120
+ const toAdd2 = recommended.map((r) => r.rule).filter((r) => !existing.includes(r));
121
+ if (toAdd2.length === 0) {
122
+ log.success("All recommended permissions already configured.");
123
+ return;
124
+ }
125
+ console.log("Adding recommended permissions:");
126
+ for (const r of toAdd2) {
127
+ console.log(` ${chalk.green("+")} ${r}`);
128
+ }
129
+ console.log();
130
+ applyPermissions(settingsPath, toAdd2, []);
131
+ log.success(`Added ${toAdd2.length} permission rules.`);
132
+ return;
133
+ }
134
+ const { toAdd, toRemove } = await interactiveFlow(allRules, existing);
135
+ if (toAdd.length === 0 && toRemove.length === 0) {
136
+ log.dim("No changes.");
137
+ return;
138
+ }
139
+ console.log();
140
+ if (toAdd.length > 0) {
141
+ console.log(chalk.green(`Adding ${toAdd.length} rules:`));
142
+ for (const r of toAdd) {
143
+ console.log(` ${chalk.green("+")} ${r}`);
144
+ }
145
+ }
146
+ if (toRemove.length > 0) {
147
+ console.log(chalk.red(`Removing ${toRemove.length} rules:`));
148
+ for (const r of toRemove) {
149
+ console.log(` ${chalk.red("-")} ${r}`);
150
+ }
151
+ }
152
+ console.log();
153
+ const ok = await confirm({
154
+ message: `Apply changes to ${settingsLabel}?`,
155
+ default: true
156
+ });
157
+ if (!ok) {
158
+ log.dim("Skipped.");
159
+ return;
160
+ }
161
+ applyPermissions(settingsPath, toAdd, toRemove);
162
+ log.success(
163
+ `Done \u2014 added ${toAdd.length}, removed ${toRemove.length} rules.`
164
+ );
165
+ }
166
+ export {
167
+ permissionCommand
168
+ };
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  ensureShellCompletion
4
- } from "./chunk-7N64TDZ6.js";
4
+ } from "./chunk-4JL3SR5V.js";
5
5
  import "./chunk-W5CD7WTX.js";
6
6
 
7
7
  // src/postinstall.ts
@@ -1,13 +1,14 @@
1
1
  import {
2
2
  loadConfig
3
- } from "./chunk-FYHHNX7K.js";
3
+ } from "./chunk-XIZJ64JK.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-TPRZHSFS.js";
11
+ } from "./chunk-ZS7BLEYT.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-BPLN4LDL.js";
7
+ } from "./chunk-HYLS67T7.js";
8
8
  import {
9
9
  ALL_COMPONENT_IDS
10
10
  } from "./chunk-PGLUEN7D.js";
11
- import "./chunk-TPRZHSFS.js";
11
+ import "./chunk-ZS7BLEYT.js";
12
12
  import {
13
13
  log
14
14
  } from "./chunk-W5CD7WTX.js";