@staff0rd/assist 0.101.0 → 0.102.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
@@ -101,6 +101,8 @@ After installation, the `assist` command will be available globally. You can als
101
101
  - `assist deploy redirect` - Add trailing slash redirect script to index.html
102
102
  - `assist notify` - Show desktop notification from JSON stdin (supports macOS, Windows, WSL)
103
103
  - `assist status-line` - Format Claude Code status line from JSON stdin
104
+ - `assist netframework deps <csproj>` - Show .csproj project dependency tree and solution membership
105
+ - `assist netframework in-sln <csproj>` - Check whether a .csproj is referenced by any .sln file
104
106
  - `assist complexity <pattern>` - Analyze a file (all metrics if single match, maintainability if multiple)
105
107
  - `assist complexity cyclomatic [pattern]` - Calculate cyclomatic complexity per function
106
108
  - `assist complexity halstead [pattern]` - Calculate Halstead metrics per function
@@ -36,7 +36,7 @@
36
36
  "Bash(assist complexity:*)",
37
37
  "Bash(assist transcript format:*)",
38
38
  "Bash(assist voice:*)",
39
- "Bash(assist deps:*)",
39
+ "Bash(assist netframework:*)",
40
40
  "Bash(head:*)",
41
41
  "Bash(tail:*)",
42
42
  "Bash(grep:*)",
@@ -52,6 +52,7 @@
52
52
  "Bash(echo:*)",
53
53
  "Bash(printf:*)",
54
54
  "Bash(date:*)",
55
+ "Bash(jq:*)",
55
56
  "SlashCommand(/next-backlog-item)",
56
57
  "SlashCommand(/verify)",
57
58
  "SlashCommand(/commit)",
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ import { Command } from "commander";
6
6
  // package.json
7
7
  var package_default = {
8
8
  name: "@staff0rd/assist",
9
- version: "0.101.0",
9
+ version: "0.102.1",
10
10
  type: "module",
11
11
  main: "dist/index.js",
12
12
  bin: {
@@ -3712,216 +3712,25 @@ function registerDeploy(program2) {
3712
3712
  deployCommand.command("redirect").description("Add trailing slash redirect script to index.html").action(redirect);
3713
3713
  }
3714
3714
 
3715
- // src/commands/deps/deps.ts
3716
- import { existsSync as existsSync21 } from "fs";
3717
- import path20 from "path";
3718
- import chalk39 from "chalk";
3719
-
3720
- // src/commands/deps/buildTree.ts
3721
- import { readFileSync as readFileSync17 } from "fs";
3722
- import path17 from "path";
3723
- var PROJECT_REF_RE = /<ProjectReference\s+Include="([^"]+)"/g;
3724
- function getProjectRefs(csprojPath) {
3725
- const content = readFileSync17(csprojPath, "utf-8");
3726
- const refs = [];
3727
- for (const match of content.matchAll(PROJECT_REF_RE)) {
3728
- refs.push(match[1].replace(/\\/g, "/"));
3729
- }
3730
- return refs;
3731
- }
3732
- function buildTree(csprojPath, repoRoot, visited = /* @__PURE__ */ new Set()) {
3733
- const abs = path17.resolve(csprojPath);
3734
- const rel = path17.relative(repoRoot, abs);
3735
- const node = { path: abs, relativePath: rel, children: [] };
3736
- if (visited.has(abs)) return node;
3737
- visited.add(abs);
3738
- const dir = path17.dirname(abs);
3739
- for (const ref of getProjectRefs(abs)) {
3740
- const childAbs = path17.resolve(dir, ref);
3741
- try {
3742
- readFileSync17(childAbs);
3743
- node.children.push(buildTree(childAbs, repoRoot, visited));
3744
- } catch {
3745
- node.children.push({
3746
- path: childAbs,
3747
- relativePath: `[MISSING] ${ref}`,
3748
- children: []
3749
- });
3750
- }
3751
- }
3752
- return node;
3753
- }
3754
- function collectAllDeps(node) {
3755
- const result = /* @__PURE__ */ new Set();
3756
- function walk2(n) {
3757
- for (const child of n.children) {
3758
- result.add(child.path);
3759
- walk2(child);
3760
- }
3761
- }
3762
- walk2(node);
3763
- return result;
3764
- }
3765
-
3766
- // src/commands/deps/findContainingSolutions.ts
3767
- import { readdirSync, readFileSync as readFileSync18, statSync } from "fs";
3768
- import path18 from "path";
3769
- function findSlnFiles(dir, maxDepth, depth = 0) {
3770
- if (depth > maxDepth) return [];
3771
- const results = [];
3772
- let entries;
3773
- try {
3774
- entries = readdirSync(dir);
3775
- } catch {
3776
- return results;
3777
- }
3778
- for (const entry of entries) {
3779
- if (entry.startsWith(".") || entry === "node_modules" || entry === "packages")
3780
- continue;
3781
- const full = path18.join(dir, entry);
3782
- try {
3783
- const stat = statSync(full);
3784
- if (stat.isFile() && entry.endsWith(".sln")) {
3785
- results.push(full);
3786
- } else if (stat.isDirectory()) {
3787
- results.push(...findSlnFiles(full, maxDepth, depth + 1));
3788
- }
3789
- } catch {
3790
- }
3791
- }
3792
- return results;
3793
- }
3794
- function findContainingSolutions(csprojPath, repoRoot) {
3795
- const csprojAbs = path18.resolve(csprojPath);
3796
- const csprojBasename = path18.basename(csprojAbs);
3797
- const slnFiles = findSlnFiles(repoRoot, 3);
3798
- const matches = [];
3799
- const pattern2 = new RegExp(`[\\\\"/]${escapeRegex(csprojBasename)}"`);
3800
- for (const sln of slnFiles) {
3801
- try {
3802
- const content = readFileSync18(sln, "utf-8");
3803
- if (pattern2.test(content)) {
3804
- matches.push(path18.relative(repoRoot, sln));
3805
- }
3806
- } catch {
3807
- }
3808
- }
3809
- return matches;
3810
- }
3811
- function escapeRegex(s) {
3812
- return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
3813
- }
3814
-
3815
- // src/commands/deps/findRepoRoot.ts
3816
- import { existsSync as existsSync20 } from "fs";
3817
- import path19 from "path";
3818
- function findRepoRoot(dir) {
3819
- let current = dir;
3820
- while (current !== path19.dirname(current)) {
3821
- if (existsSync20(path19.join(current, ".git"))) {
3822
- return current;
3823
- }
3824
- current = path19.dirname(current);
3825
- }
3826
- return null;
3827
- }
3828
-
3829
- // src/commands/deps/printTree.ts
3830
- import chalk38 from "chalk";
3831
- function printNodes(nodes, prefix2) {
3832
- for (let i = 0; i < nodes.length; i++) {
3833
- const isLast = i === nodes.length - 1;
3834
- const connector = isLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
3835
- const childPrefix = isLast ? " " : "\u2502 ";
3836
- const isMissing = nodes[i].relativePath.startsWith("[MISSING]");
3837
- const label2 = isMissing ? chalk38.red(nodes[i].relativePath) : nodes[i].relativePath;
3838
- console.log(`${prefix2}${connector}${label2}`);
3839
- printNodes(nodes[i].children, prefix2 + childPrefix);
3840
- }
3841
- }
3842
- function printTree(tree, totalCount, solutions) {
3843
- console.log(chalk38.bold("\nProject Dependency Tree"));
3844
- console.log(chalk38.cyan(tree.relativePath));
3845
- printNodes(tree.children, "");
3846
- console.log(chalk38.dim(`
3847
- ${totalCount} projects total (including root)`));
3848
- console.log(chalk38.bold("\nSolution Membership"));
3849
- if (solutions.length === 0) {
3850
- console.log(chalk38.yellow(" Not found in any .sln"));
3851
- } else {
3852
- for (const sln of solutions) {
3853
- console.log(` ${chalk38.green(sln)}`);
3854
- }
3855
- }
3856
- console.log();
3857
- }
3858
- function nodesToJson(node) {
3859
- return node.children.map((child) => ({
3860
- project: child.relativePath,
3861
- dependencies: nodesToJson(child)
3862
- }));
3863
- }
3864
- function printJson(tree, totalCount, solutions) {
3865
- console.log(
3866
- JSON.stringify(
3867
- {
3868
- project: tree.relativePath,
3869
- totalProjects: totalCount,
3870
- dependencies: nodesToJson(tree),
3871
- solutions
3872
- },
3873
- null,
3874
- 2
3875
- )
3876
- );
3877
- }
3878
-
3879
- // src/commands/deps/deps.ts
3880
- async function deps(csprojPath, options2) {
3881
- const resolved = path20.resolve(csprojPath);
3882
- if (!existsSync21(resolved)) {
3883
- console.error(chalk39.red(`File not found: ${resolved}`));
3884
- process.exit(1);
3885
- }
3886
- const repoRoot = findRepoRoot(path20.dirname(resolved));
3887
- if (!repoRoot) {
3888
- console.error(chalk39.red("Could not find git repository root"));
3889
- process.exit(1);
3890
- }
3891
- const tree = buildTree(resolved, repoRoot);
3892
- const totalCount = collectAllDeps(tree).size + 1;
3893
- const solutions = findContainingSolutions(resolved, repoRoot);
3894
- if (options2.json) {
3895
- printJson(tree, totalCount, solutions);
3896
- } else {
3897
- printTree(tree, totalCount, solutions);
3898
- }
3899
- }
3900
-
3901
- // src/commands/registerDeps.ts
3902
- function registerDeps(program2) {
3903
- program2.command("deps").description("Show .csproj project dependency tree and solution membership").argument("<csproj>", "Path to a .csproj file").option("--json", "Output as JSON").action(deps);
3904
- }
3905
-
3906
3715
  // src/commands/devlog/list/index.ts
3907
3716
  import { execSync as execSync16 } from "child_process";
3908
3717
  import { basename as basename3 } from "path";
3909
3718
 
3910
3719
  // src/commands/devlog/shared.ts
3911
3720
  import { execSync as execSync15 } from "child_process";
3912
- import chalk40 from "chalk";
3721
+ import chalk38 from "chalk";
3913
3722
 
3914
3723
  // src/commands/devlog/loadDevlogEntries.ts
3915
- import { readdirSync as readdirSync2, readFileSync as readFileSync19 } from "fs";
3724
+ import { readdirSync, readFileSync as readFileSync17 } from "fs";
3916
3725
  import { homedir as homedir5 } from "os";
3917
3726
  import { join as join13 } from "path";
3918
3727
  var DEVLOG_DIR = join13(homedir5(), "git/blog/src/content/devlog");
3919
3728
  function loadDevlogEntries(repoName) {
3920
3729
  const entries = /* @__PURE__ */ new Map();
3921
3730
  try {
3922
- const files = readdirSync2(DEVLOG_DIR).filter((f) => f.endsWith(".md"));
3731
+ const files = readdirSync(DEVLOG_DIR).filter((f) => f.endsWith(".md"));
3923
3732
  for (const file of files) {
3924
- const content = readFileSync19(join13(DEVLOG_DIR, file), "utf-8");
3733
+ const content = readFileSync17(join13(DEVLOG_DIR, file), "utf-8");
3925
3734
  const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
3926
3735
  if (frontmatterMatch) {
3927
3736
  const frontmatter = frontmatterMatch[1];
@@ -3970,13 +3779,13 @@ function shouldIgnoreCommit(files, ignorePaths) {
3970
3779
  }
3971
3780
  function printCommitsWithFiles(commits, ignore2, verbose) {
3972
3781
  for (const commit2 of commits) {
3973
- console.log(` ${chalk40.yellow(commit2.hash)} ${commit2.message}`);
3782
+ console.log(` ${chalk38.yellow(commit2.hash)} ${commit2.message}`);
3974
3783
  if (verbose) {
3975
3784
  const visibleFiles = commit2.files.filter(
3976
3785
  (file) => !ignore2.some((p) => file.startsWith(p))
3977
3786
  );
3978
3787
  for (const file of visibleFiles) {
3979
- console.log(` ${chalk40.dim(file)}`);
3788
+ console.log(` ${chalk38.dim(file)}`);
3980
3789
  }
3981
3790
  }
3982
3791
  }
@@ -4001,15 +3810,15 @@ function parseGitLogCommits(output, ignore2, afterDate) {
4001
3810
  }
4002
3811
 
4003
3812
  // src/commands/devlog/list/printDateHeader.ts
4004
- import chalk41 from "chalk";
3813
+ import chalk39 from "chalk";
4005
3814
  function printDateHeader(date, isSkipped, entries) {
4006
3815
  if (isSkipped) {
4007
- console.log(`${chalk41.bold.blue(date)} ${chalk41.dim("skipped")}`);
3816
+ console.log(`${chalk39.bold.blue(date)} ${chalk39.dim("skipped")}`);
4008
3817
  } else if (entries && entries.length > 0) {
4009
- const entryInfo = entries.map((e) => `${chalk41.green(e.version)} ${e.title}`).join(" | ");
4010
- console.log(`${chalk41.bold.blue(date)} ${entryInfo}`);
3818
+ const entryInfo = entries.map((e) => `${chalk39.green(e.version)} ${e.title}`).join(" | ");
3819
+ console.log(`${chalk39.bold.blue(date)} ${entryInfo}`);
4011
3820
  } else {
4012
- console.log(`${chalk41.bold.blue(date)} ${chalk41.red("\u26A0 devlog missing")}`);
3821
+ console.log(`${chalk39.bold.blue(date)} ${chalk39.red("\u26A0 devlog missing")}`);
4013
3822
  }
4014
3823
  }
4015
3824
 
@@ -4112,24 +3921,24 @@ function bumpVersion(version2, type) {
4112
3921
 
4113
3922
  // src/commands/devlog/next/displayNextEntry/index.ts
4114
3923
  import { execSync as execSync18 } from "child_process";
4115
- import chalk43 from "chalk";
3924
+ import chalk41 from "chalk";
4116
3925
 
4117
3926
  // src/commands/devlog/next/displayNextEntry/displayVersion.ts
4118
- import chalk42 from "chalk";
3927
+ import chalk40 from "chalk";
4119
3928
  function displayVersion(conventional, firstHash, patchVersion, minorVersion) {
4120
3929
  if (conventional && firstHash) {
4121
3930
  const version2 = getVersionAtCommit(firstHash);
4122
3931
  if (version2) {
4123
- console.log(`${chalk42.bold("version:")} ${stripToMinor(version2)}`);
3932
+ console.log(`${chalk40.bold("version:")} ${stripToMinor(version2)}`);
4124
3933
  } else {
4125
- console.log(`${chalk42.bold("version:")} ${chalk42.red("unknown")}`);
3934
+ console.log(`${chalk40.bold("version:")} ${chalk40.red("unknown")}`);
4126
3935
  }
4127
3936
  } else if (patchVersion && minorVersion) {
4128
3937
  console.log(
4129
- `${chalk42.bold("version:")} ${patchVersion} (patch) or ${minorVersion} (minor)`
3938
+ `${chalk40.bold("version:")} ${patchVersion} (patch) or ${minorVersion} (minor)`
4130
3939
  );
4131
3940
  } else {
4132
- console.log(`${chalk42.bold("version:")} v0.1 (initial)`);
3941
+ console.log(`${chalk40.bold("version:")} v0.1 (initial)`);
4133
3942
  }
4134
3943
  }
4135
3944
 
@@ -4176,16 +3985,16 @@ function noCommitsMessage(hasLastInfo) {
4176
3985
  return hasLastInfo ? "No commits after last versioned entry" : "No commits found";
4177
3986
  }
4178
3987
  function logName(repoName) {
4179
- console.log(`${chalk43.bold("name:")} ${repoName}`);
3988
+ console.log(`${chalk41.bold("name:")} ${repoName}`);
4180
3989
  }
4181
3990
  function displayNextEntry(ctx, targetDate, commits) {
4182
3991
  logName(ctx.repoName);
4183
3992
  printVersionInfo(ctx.config, ctx.lastInfo, commits[0]?.hash);
4184
- console.log(chalk43.bold.blue(targetDate));
3993
+ console.log(chalk41.bold.blue(targetDate));
4185
3994
  printCommitsWithFiles(commits, ctx.ignore, ctx.verbose);
4186
3995
  }
4187
3996
  function logNoCommits(lastInfo) {
4188
- console.log(chalk43.dim(noCommitsMessage(!!lastInfo)));
3997
+ console.log(chalk41.dim(noCommitsMessage(!!lastInfo)));
4189
3998
  }
4190
3999
 
4191
4000
  // src/commands/devlog/next/index.ts
@@ -4220,10 +4029,10 @@ function next(options2) {
4220
4029
  }
4221
4030
 
4222
4031
  // src/commands/devlog/skip.ts
4223
- import chalk44 from "chalk";
4032
+ import chalk42 from "chalk";
4224
4033
  function skip(date) {
4225
4034
  if (!/^\d{4}-\d{2}-\d{2}$/.test(date)) {
4226
- console.log(chalk44.red("Invalid date format. Use YYYY-MM-DD"));
4035
+ console.log(chalk42.red("Invalid date format. Use YYYY-MM-DD"));
4227
4036
  process.exit(1);
4228
4037
  }
4229
4038
  const config = loadProjectConfig();
@@ -4231,7 +4040,7 @@ function skip(date) {
4231
4040
  const skip2 = devlog.skip ?? {};
4232
4041
  const skipDays = skip2.days ?? [];
4233
4042
  if (skipDays.includes(date)) {
4234
- console.log(chalk44.yellow(`${date} is already in skip list`));
4043
+ console.log(chalk42.yellow(`${date} is already in skip list`));
4235
4044
  return;
4236
4045
  }
4237
4046
  skipDays.push(date);
@@ -4240,20 +4049,20 @@ function skip(date) {
4240
4049
  devlog.skip = skip2;
4241
4050
  config.devlog = devlog;
4242
4051
  saveConfig(config);
4243
- console.log(chalk44.green(`Added ${date} to skip list`));
4052
+ console.log(chalk42.green(`Added ${date} to skip list`));
4244
4053
  }
4245
4054
 
4246
4055
  // src/commands/devlog/version.ts
4247
- import chalk45 from "chalk";
4056
+ import chalk43 from "chalk";
4248
4057
  function version() {
4249
4058
  const config = loadConfig();
4250
4059
  const name = getRepoName();
4251
4060
  const lastInfo = getLastVersionInfo(name, config);
4252
4061
  const lastVersion = lastInfo?.version ?? null;
4253
4062
  const nextVersion = lastVersion ? bumpVersion(lastVersion, "patch") : null;
4254
- console.log(`${chalk45.bold("name:")} ${name}`);
4255
- console.log(`${chalk45.bold("last:")} ${lastVersion ?? chalk45.dim("none")}`);
4256
- console.log(`${chalk45.bold("next:")} ${nextVersion ?? chalk45.dim("none")}`);
4063
+ console.log(`${chalk43.bold("name:")} ${name}`);
4064
+ console.log(`${chalk43.bold("last:")} ${lastVersion ?? chalk43.dim("none")}`);
4065
+ console.log(`${chalk43.bold("next:")} ${nextVersion ?? chalk43.dim("none")}`);
4257
4066
  }
4258
4067
 
4259
4068
  // src/commands/registerDevlog.ts
@@ -4269,6 +4078,219 @@ function registerDevlog(program2) {
4269
4078
  devlogCommand.command("skip <date>").description("Add a date (YYYY-MM-DD) to the skip list").action(skip);
4270
4079
  }
4271
4080
 
4081
+ // src/commands/netframework/buildTree.ts
4082
+ import { readFileSync as readFileSync18 } from "fs";
4083
+ import path17 from "path";
4084
+ var PROJECT_REF_RE = /<ProjectReference\s+Include="([^"]+)"/g;
4085
+ function getProjectRefs(csprojPath) {
4086
+ const content = readFileSync18(csprojPath, "utf-8");
4087
+ const refs = [];
4088
+ for (const match of content.matchAll(PROJECT_REF_RE)) {
4089
+ refs.push(match[1].replace(/\\/g, "/"));
4090
+ }
4091
+ return refs;
4092
+ }
4093
+ function buildTree(csprojPath, repoRoot, visited = /* @__PURE__ */ new Set()) {
4094
+ const abs = path17.resolve(csprojPath);
4095
+ const rel = path17.relative(repoRoot, abs);
4096
+ const node = { path: abs, relativePath: rel, children: [] };
4097
+ if (visited.has(abs)) return node;
4098
+ visited.add(abs);
4099
+ const dir = path17.dirname(abs);
4100
+ for (const ref of getProjectRefs(abs)) {
4101
+ const childAbs = path17.resolve(dir, ref);
4102
+ try {
4103
+ readFileSync18(childAbs);
4104
+ node.children.push(buildTree(childAbs, repoRoot, visited));
4105
+ } catch {
4106
+ node.children.push({
4107
+ path: childAbs,
4108
+ relativePath: `[MISSING] ${ref}`,
4109
+ children: []
4110
+ });
4111
+ }
4112
+ }
4113
+ return node;
4114
+ }
4115
+ function collectAllDeps(node) {
4116
+ const result = /* @__PURE__ */ new Set();
4117
+ function walk2(n) {
4118
+ for (const child of n.children) {
4119
+ result.add(child.path);
4120
+ walk2(child);
4121
+ }
4122
+ }
4123
+ walk2(node);
4124
+ return result;
4125
+ }
4126
+
4127
+ // src/commands/netframework/findContainingSolutions.ts
4128
+ import { readdirSync as readdirSync2, readFileSync as readFileSync19, statSync } from "fs";
4129
+ import path18 from "path";
4130
+ function findSlnFiles(dir, maxDepth, depth = 0) {
4131
+ if (depth > maxDepth) return [];
4132
+ const results = [];
4133
+ let entries;
4134
+ try {
4135
+ entries = readdirSync2(dir);
4136
+ } catch {
4137
+ return results;
4138
+ }
4139
+ for (const entry of entries) {
4140
+ if (entry.startsWith(".") || entry === "node_modules" || entry === "packages")
4141
+ continue;
4142
+ const full = path18.join(dir, entry);
4143
+ try {
4144
+ const stat = statSync(full);
4145
+ if (stat.isFile() && entry.endsWith(".sln")) {
4146
+ results.push(full);
4147
+ } else if (stat.isDirectory()) {
4148
+ results.push(...findSlnFiles(full, maxDepth, depth + 1));
4149
+ }
4150
+ } catch {
4151
+ }
4152
+ }
4153
+ return results;
4154
+ }
4155
+ function findContainingSolutions(csprojPath, repoRoot) {
4156
+ const csprojAbs = path18.resolve(csprojPath);
4157
+ const csprojBasename = path18.basename(csprojAbs);
4158
+ const slnFiles = findSlnFiles(repoRoot, 3);
4159
+ const matches = [];
4160
+ const pattern2 = new RegExp(`[\\\\"/]${escapeRegex(csprojBasename)}"`);
4161
+ for (const sln of slnFiles) {
4162
+ try {
4163
+ const content = readFileSync19(sln, "utf-8");
4164
+ if (pattern2.test(content)) {
4165
+ matches.push(path18.relative(repoRoot, sln));
4166
+ }
4167
+ } catch {
4168
+ }
4169
+ }
4170
+ return matches;
4171
+ }
4172
+ function escapeRegex(s) {
4173
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
4174
+ }
4175
+
4176
+ // src/commands/netframework/printTree.ts
4177
+ import chalk44 from "chalk";
4178
+ function printNodes(nodes, prefix2) {
4179
+ for (let i = 0; i < nodes.length; i++) {
4180
+ const isLast = i === nodes.length - 1;
4181
+ const connector = isLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
4182
+ const childPrefix = isLast ? " " : "\u2502 ";
4183
+ const isMissing = nodes[i].relativePath.startsWith("[MISSING]");
4184
+ const label2 = isMissing ? chalk44.red(nodes[i].relativePath) : nodes[i].relativePath;
4185
+ console.log(`${prefix2}${connector}${label2}`);
4186
+ printNodes(nodes[i].children, prefix2 + childPrefix);
4187
+ }
4188
+ }
4189
+ function printTree(tree, totalCount, solutions) {
4190
+ console.log(chalk44.bold("\nProject Dependency Tree"));
4191
+ console.log(chalk44.cyan(tree.relativePath));
4192
+ printNodes(tree.children, "");
4193
+ console.log(chalk44.dim(`
4194
+ ${totalCount} projects total (including root)`));
4195
+ console.log(chalk44.bold("\nSolution Membership"));
4196
+ if (solutions.length === 0) {
4197
+ console.log(chalk44.yellow(" Not found in any .sln"));
4198
+ } else {
4199
+ for (const sln of solutions) {
4200
+ console.log(` ${chalk44.green(sln)}`);
4201
+ }
4202
+ }
4203
+ console.log();
4204
+ }
4205
+ function nodesToJson(node) {
4206
+ return node.children.map((child) => ({
4207
+ project: child.relativePath,
4208
+ dependencies: nodesToJson(child)
4209
+ }));
4210
+ }
4211
+ function printJson(tree, totalCount, solutions) {
4212
+ console.log(
4213
+ JSON.stringify(
4214
+ {
4215
+ project: tree.relativePath,
4216
+ totalProjects: totalCount,
4217
+ dependencies: nodesToJson(tree),
4218
+ solutions
4219
+ },
4220
+ null,
4221
+ 2
4222
+ )
4223
+ );
4224
+ }
4225
+
4226
+ // src/commands/netframework/resolveCsproj.ts
4227
+ import { existsSync as existsSync21 } from "fs";
4228
+ import path20 from "path";
4229
+ import chalk45 from "chalk";
4230
+
4231
+ // src/commands/netframework/findRepoRoot.ts
4232
+ import { existsSync as existsSync20 } from "fs";
4233
+ import path19 from "path";
4234
+ function findRepoRoot(dir) {
4235
+ let current = dir;
4236
+ while (current !== path19.dirname(current)) {
4237
+ if (existsSync20(path19.join(current, ".git"))) {
4238
+ return current;
4239
+ }
4240
+ current = path19.dirname(current);
4241
+ }
4242
+ return null;
4243
+ }
4244
+
4245
+ // src/commands/netframework/resolveCsproj.ts
4246
+ function resolveCsproj(csprojPath) {
4247
+ const resolved = path20.resolve(csprojPath);
4248
+ if (!existsSync21(resolved)) {
4249
+ console.error(chalk45.red(`File not found: ${resolved}`));
4250
+ process.exit(1);
4251
+ }
4252
+ const repoRoot = findRepoRoot(path20.dirname(resolved));
4253
+ if (!repoRoot) {
4254
+ console.error(chalk45.red("Could not find git repository root"));
4255
+ process.exit(1);
4256
+ }
4257
+ return { resolved, repoRoot };
4258
+ }
4259
+
4260
+ // src/commands/netframework/deps.ts
4261
+ async function deps(csprojPath, options2) {
4262
+ const { resolved, repoRoot } = resolveCsproj(csprojPath);
4263
+ const tree = buildTree(resolved, repoRoot);
4264
+ const totalCount = collectAllDeps(tree).size + 1;
4265
+ const solutions = findContainingSolutions(resolved, repoRoot);
4266
+ if (options2.json) {
4267
+ printJson(tree, totalCount, solutions);
4268
+ } else {
4269
+ printTree(tree, totalCount, solutions);
4270
+ }
4271
+ }
4272
+
4273
+ // src/commands/netframework/inSln.ts
4274
+ import chalk46 from "chalk";
4275
+ async function inSln(csprojPath) {
4276
+ const { resolved, repoRoot } = resolveCsproj(csprojPath);
4277
+ const solutions = findContainingSolutions(resolved, repoRoot);
4278
+ if (solutions.length === 0) {
4279
+ console.log(chalk46.yellow("Not found in any .sln file"));
4280
+ process.exit(1);
4281
+ }
4282
+ for (const sln of solutions) {
4283
+ console.log(sln);
4284
+ }
4285
+ }
4286
+
4287
+ // src/commands/registerNetframework.ts
4288
+ function registerNetframework(program2) {
4289
+ const cmd = program2.command("netframework").description(".NET Framework project utilities");
4290
+ cmd.command("deps").description("Show .csproj project dependency tree and solution membership").argument("<csproj>", "Path to a .csproj file").option("--json", "Output as JSON").action(deps);
4291
+ cmd.command("in-sln").description("Check whether a .csproj is referenced by any .sln file").argument("<csproj>", "Path to a .csproj file").action(inSln);
4292
+ }
4293
+
4272
4294
  // src/commands/prs/comment.ts
4273
4295
  import { spawnSync as spawnSync2 } from "child_process";
4274
4296
  import { unlinkSync as unlinkSync3, writeFileSync as writeFileSync15 } from "fs";
@@ -4585,20 +4607,20 @@ function fetchLineComments(org, repo, prNumber, threadInfo) {
4585
4607
  }
4586
4608
 
4587
4609
  // src/commands/prs/listComments/formatForHuman.ts
4588
- import chalk46 from "chalk";
4610
+ import chalk47 from "chalk";
4589
4611
  function formatForHuman(comment2) {
4590
4612
  if (comment2.type === "review") {
4591
- const stateColor = comment2.state === "APPROVED" ? chalk46.green : comment2.state === "CHANGES_REQUESTED" ? chalk46.red : chalk46.yellow;
4613
+ const stateColor = comment2.state === "APPROVED" ? chalk47.green : comment2.state === "CHANGES_REQUESTED" ? chalk47.red : chalk47.yellow;
4592
4614
  return [
4593
- `${chalk46.cyan("Review")} by ${chalk46.bold(comment2.user)} ${stateColor(`[${comment2.state}]`)}`,
4615
+ `${chalk47.cyan("Review")} by ${chalk47.bold(comment2.user)} ${stateColor(`[${comment2.state}]`)}`,
4594
4616
  comment2.body,
4595
4617
  ""
4596
4618
  ].join("\n");
4597
4619
  }
4598
4620
  const location = comment2.line ? `:${comment2.line}` : "";
4599
4621
  return [
4600
- `${chalk46.cyan("Line comment")} by ${chalk46.bold(comment2.user)} on ${chalk46.dim(`${comment2.path}${location}`)}`,
4601
- chalk46.dim(comment2.diff_hunk.split("\n").slice(-3).join("\n")),
4622
+ `${chalk47.cyan("Line comment")} by ${chalk47.bold(comment2.user)} on ${chalk47.dim(`${comment2.path}${location}`)}`,
4623
+ chalk47.dim(comment2.diff_hunk.split("\n").slice(-3).join("\n")),
4602
4624
  comment2.body,
4603
4625
  ""
4604
4626
  ].join("\n");
@@ -4677,13 +4699,13 @@ import { execSync as execSync24 } from "child_process";
4677
4699
  import enquirer5 from "enquirer";
4678
4700
 
4679
4701
  // src/commands/prs/prs/displayPaginated/printPr.ts
4680
- import chalk47 from "chalk";
4702
+ import chalk48 from "chalk";
4681
4703
  var STATUS_MAP = {
4682
- MERGED: (pr) => pr.mergedAt ? { label: chalk47.magenta("merged"), date: pr.mergedAt } : null,
4683
- CLOSED: (pr) => pr.closedAt ? { label: chalk47.red("closed"), date: pr.closedAt } : null
4704
+ MERGED: (pr) => pr.mergedAt ? { label: chalk48.magenta("merged"), date: pr.mergedAt } : null,
4705
+ CLOSED: (pr) => pr.closedAt ? { label: chalk48.red("closed"), date: pr.closedAt } : null
4684
4706
  };
4685
4707
  function defaultStatus(pr) {
4686
- return { label: chalk47.green("opened"), date: pr.createdAt };
4708
+ return { label: chalk48.green("opened"), date: pr.createdAt };
4687
4709
  }
4688
4710
  function getStatus(pr) {
4689
4711
  return STATUS_MAP[pr.state]?.(pr) ?? defaultStatus(pr);
@@ -4692,11 +4714,11 @@ function formatDate(dateStr) {
4692
4714
  return new Date(dateStr).toISOString().split("T")[0];
4693
4715
  }
4694
4716
  function formatPrHeader(pr, status2) {
4695
- return `${chalk47.cyan(`#${pr.number}`)} ${pr.title} ${chalk47.dim(`(${pr.author.login},`)} ${status2.label} ${chalk47.dim(`${formatDate(status2.date)})`)}`;
4717
+ return `${chalk48.cyan(`#${pr.number}`)} ${pr.title} ${chalk48.dim(`(${pr.author.login},`)} ${status2.label} ${chalk48.dim(`${formatDate(status2.date)})`)}`;
4696
4718
  }
4697
4719
  function logPrDetails(pr) {
4698
4720
  console.log(
4699
- chalk47.dim(` ${pr.changedFiles.toLocaleString()} files | ${pr.url}`)
4721
+ chalk48.dim(` ${pr.changedFiles.toLocaleString()} files | ${pr.url}`)
4700
4722
  );
4701
4723
  console.log();
4702
4724
  }
@@ -4866,7 +4888,7 @@ import { spawn as spawn3 } from "child_process";
4866
4888
  import * as path21 from "path";
4867
4889
 
4868
4890
  // src/commands/refactor/logViolations.ts
4869
- import chalk48 from "chalk";
4891
+ import chalk49 from "chalk";
4870
4892
  var DEFAULT_MAX_LINES = 100;
4871
4893
  function logViolations(violations, maxLines = DEFAULT_MAX_LINES) {
4872
4894
  if (violations.length === 0) {
@@ -4875,43 +4897,43 @@ function logViolations(violations, maxLines = DEFAULT_MAX_LINES) {
4875
4897
  }
4876
4898
  return;
4877
4899
  }
4878
- console.error(chalk48.red(`
4900
+ console.error(chalk49.red(`
4879
4901
  Refactor check failed:
4880
4902
  `));
4881
- console.error(chalk48.red(` The following files exceed ${maxLines} lines:
4903
+ console.error(chalk49.red(` The following files exceed ${maxLines} lines:
4882
4904
  `));
4883
4905
  for (const violation of violations) {
4884
- console.error(chalk48.red(` ${violation.file} (${violation.lines} lines)`));
4906
+ console.error(chalk49.red(` ${violation.file} (${violation.lines} lines)`));
4885
4907
  }
4886
4908
  console.error(
4887
- chalk48.yellow(
4909
+ chalk49.yellow(
4888
4910
  `
4889
4911
  Each file needs to be sensibly refactored, or if there is no sensible
4890
4912
  way to refactor it, ignore it with:
4891
4913
  `
4892
4914
  )
4893
4915
  );
4894
- console.error(chalk48.gray(` assist refactor ignore <file>
4916
+ console.error(chalk49.gray(` assist refactor ignore <file>
4895
4917
  `));
4896
4918
  if (process.env.CLAUDECODE) {
4897
- console.error(chalk48.cyan(`
4919
+ console.error(chalk49.cyan(`
4898
4920
  ## Extracting Code to New Files
4899
4921
  `));
4900
4922
  console.error(
4901
- chalk48.cyan(
4923
+ chalk49.cyan(
4902
4924
  ` When extracting logic from one file to another, consider where the extracted code belongs:
4903
4925
  `
4904
4926
  )
4905
4927
  );
4906
4928
  console.error(
4907
- chalk48.cyan(
4929
+ chalk49.cyan(
4908
4930
  ` 1. Keep related logic together: If the extracted code is tightly coupled to the
4909
4931
  original file's domain, create a new folder containing both the original and extracted files.
4910
4932
  `
4911
4933
  )
4912
4934
  );
4913
4935
  console.error(
4914
- chalk48.cyan(
4936
+ chalk49.cyan(
4915
4937
  ` 2. Share common utilities: If the extracted code can be reused across multiple
4916
4938
  domains, move it to a common/shared folder.
4917
4939
  `
@@ -5067,11 +5089,11 @@ async function check(pattern2, options2) {
5067
5089
 
5068
5090
  // src/commands/refactor/ignore.ts
5069
5091
  import fs16 from "fs";
5070
- import chalk49 from "chalk";
5092
+ import chalk50 from "chalk";
5071
5093
  var REFACTOR_YML_PATH2 = "refactor.yml";
5072
5094
  function ignore(file) {
5073
5095
  if (!fs16.existsSync(file)) {
5074
- console.error(chalk49.red(`Error: File does not exist: ${file}`));
5096
+ console.error(chalk50.red(`Error: File does not exist: ${file}`));
5075
5097
  process.exit(1);
5076
5098
  }
5077
5099
  const content = fs16.readFileSync(file, "utf-8");
@@ -5087,7 +5109,7 @@ function ignore(file) {
5087
5109
  fs16.writeFileSync(REFACTOR_YML_PATH2, entry);
5088
5110
  }
5089
5111
  console.log(
5090
- chalk49.green(
5112
+ chalk50.green(
5091
5113
  `Added ${file} to refactor ignore list (max ${maxLines} lines)`
5092
5114
  )
5093
5115
  );
@@ -5095,7 +5117,7 @@ function ignore(file) {
5095
5117
 
5096
5118
  // src/commands/refactor/restructure/index.ts
5097
5119
  import path30 from "path";
5098
- import chalk52 from "chalk";
5120
+ import chalk53 from "chalk";
5099
5121
 
5100
5122
  // src/commands/refactor/restructure/buildImportGraph/index.ts
5101
5123
  import path22 from "path";
@@ -5338,50 +5360,50 @@ function computeRewrites(moves, edges, allProjectFiles) {
5338
5360
 
5339
5361
  // src/commands/refactor/restructure/displayPlan.ts
5340
5362
  import path26 from "path";
5341
- import chalk50 from "chalk";
5363
+ import chalk51 from "chalk";
5342
5364
  function relPath(filePath) {
5343
5365
  return path26.relative(process.cwd(), filePath);
5344
5366
  }
5345
5367
  function displayMoves(plan) {
5346
5368
  if (plan.moves.length === 0) return;
5347
- console.log(chalk50.bold("\nFile moves:"));
5369
+ console.log(chalk51.bold("\nFile moves:"));
5348
5370
  for (const move of plan.moves) {
5349
5371
  console.log(
5350
- ` ${chalk50.red(relPath(move.from))} \u2192 ${chalk50.green(relPath(move.to))}`
5372
+ ` ${chalk51.red(relPath(move.from))} \u2192 ${chalk51.green(relPath(move.to))}`
5351
5373
  );
5352
- console.log(chalk50.dim(` ${move.reason}`));
5374
+ console.log(chalk51.dim(` ${move.reason}`));
5353
5375
  }
5354
5376
  }
5355
5377
  function displayRewrites(rewrites) {
5356
5378
  if (rewrites.length === 0) return;
5357
5379
  const affectedFiles = new Set(rewrites.map((r) => r.file));
5358
- console.log(chalk50.bold(`
5380
+ console.log(chalk51.bold(`
5359
5381
  Import rewrites (${affectedFiles.size} files):`));
5360
5382
  for (const file of affectedFiles) {
5361
- console.log(` ${chalk50.cyan(relPath(file))}:`);
5383
+ console.log(` ${chalk51.cyan(relPath(file))}:`);
5362
5384
  for (const { oldSpecifier, newSpecifier } of rewrites.filter(
5363
5385
  (r) => r.file === file
5364
5386
  )) {
5365
5387
  console.log(
5366
- ` ${chalk50.red(`"${oldSpecifier}"`)} \u2192 ${chalk50.green(`"${newSpecifier}"`)}`
5388
+ ` ${chalk51.red(`"${oldSpecifier}"`)} \u2192 ${chalk51.green(`"${newSpecifier}"`)}`
5367
5389
  );
5368
5390
  }
5369
5391
  }
5370
5392
  }
5371
5393
  function displayPlan(plan) {
5372
5394
  if (plan.warnings.length > 0) {
5373
- console.log(chalk50.yellow("\nWarnings:"));
5374
- for (const w of plan.warnings) console.log(chalk50.yellow(` ${w}`));
5395
+ console.log(chalk51.yellow("\nWarnings:"));
5396
+ for (const w of plan.warnings) console.log(chalk51.yellow(` ${w}`));
5375
5397
  }
5376
5398
  if (plan.newDirectories.length > 0) {
5377
- console.log(chalk50.bold("\nNew directories:"));
5399
+ console.log(chalk51.bold("\nNew directories:"));
5378
5400
  for (const dir of plan.newDirectories)
5379
- console.log(chalk50.green(` ${dir}/`));
5401
+ console.log(chalk51.green(` ${dir}/`));
5380
5402
  }
5381
5403
  displayMoves(plan);
5382
5404
  displayRewrites(plan.rewrites);
5383
5405
  console.log(
5384
- chalk50.dim(
5406
+ chalk51.dim(
5385
5407
  `
5386
5408
  Summary: ${plan.moves.length} file(s) moved, ${plan.rewrites.length} imports rewritten`
5387
5409
  )
@@ -5391,18 +5413,18 @@ Summary: ${plan.moves.length} file(s) moved, ${plan.rewrites.length} imports rew
5391
5413
  // src/commands/refactor/restructure/executePlan.ts
5392
5414
  import fs18 from "fs";
5393
5415
  import path27 from "path";
5394
- import chalk51 from "chalk";
5416
+ import chalk52 from "chalk";
5395
5417
  function executePlan(plan) {
5396
5418
  const updatedContents = applyRewrites(plan.rewrites);
5397
5419
  for (const [file, content] of updatedContents) {
5398
5420
  fs18.writeFileSync(file, content, "utf-8");
5399
5421
  console.log(
5400
- chalk51.cyan(` Rewrote imports in ${path27.relative(process.cwd(), file)}`)
5422
+ chalk52.cyan(` Rewrote imports in ${path27.relative(process.cwd(), file)}`)
5401
5423
  );
5402
5424
  }
5403
5425
  for (const dir of plan.newDirectories) {
5404
5426
  fs18.mkdirSync(dir, { recursive: true });
5405
- console.log(chalk51.green(` Created ${path27.relative(process.cwd(), dir)}/`));
5427
+ console.log(chalk52.green(` Created ${path27.relative(process.cwd(), dir)}/`));
5406
5428
  }
5407
5429
  for (const move of plan.moves) {
5408
5430
  const targetDir = path27.dirname(move.to);
@@ -5411,7 +5433,7 @@ function executePlan(plan) {
5411
5433
  }
5412
5434
  fs18.renameSync(move.from, move.to);
5413
5435
  console.log(
5414
- chalk51.white(
5436
+ chalk52.white(
5415
5437
  ` Moved ${path27.relative(process.cwd(), move.from)} \u2192 ${path27.relative(process.cwd(), move.to)}`
5416
5438
  )
5417
5439
  );
@@ -5426,7 +5448,7 @@ function removeEmptyDirectories(dirs) {
5426
5448
  if (entries.length === 0) {
5427
5449
  fs18.rmdirSync(dir);
5428
5450
  console.log(
5429
- chalk51.dim(
5451
+ chalk52.dim(
5430
5452
  ` Removed empty directory ${path27.relative(process.cwd(), dir)}`
5431
5453
  )
5432
5454
  );
@@ -5557,22 +5579,22 @@ async function restructure(pattern2, options2 = {}) {
5557
5579
  const targetPattern = pattern2 ?? "src";
5558
5580
  const files = findSourceFiles2(targetPattern);
5559
5581
  if (files.length === 0) {
5560
- console.log(chalk52.yellow("No files found matching pattern"));
5582
+ console.log(chalk53.yellow("No files found matching pattern"));
5561
5583
  return;
5562
5584
  }
5563
5585
  const tsConfigPath = path30.resolve("tsconfig.json");
5564
5586
  const plan = buildPlan(files, tsConfigPath);
5565
5587
  if (plan.moves.length === 0) {
5566
- console.log(chalk52.green("No restructuring needed"));
5588
+ console.log(chalk53.green("No restructuring needed"));
5567
5589
  return;
5568
5590
  }
5569
5591
  displayPlan(plan);
5570
5592
  if (options2.apply) {
5571
- console.log(chalk52.bold("\nApplying changes..."));
5593
+ console.log(chalk53.bold("\nApplying changes..."));
5572
5594
  executePlan(plan);
5573
- console.log(chalk52.green("\nRestructuring complete"));
5595
+ console.log(chalk53.green("\nRestructuring complete"));
5574
5596
  } else {
5575
- console.log(chalk52.dim("\nDry run. Use --apply to execute."));
5597
+ console.log(chalk53.dim("\nDry run. Use --apply to execute."));
5576
5598
  }
5577
5599
  }
5578
5600
 
@@ -6115,14 +6137,14 @@ import {
6115
6137
  import { dirname as dirname17, join as join23 } from "path";
6116
6138
 
6117
6139
  // src/commands/transcript/summarise/processStagedFile/validateStagedContent.ts
6118
- import chalk53 from "chalk";
6140
+ import chalk54 from "chalk";
6119
6141
  var FULL_TRANSCRIPT_REGEX = /^\[Full Transcript\]\(([^)]+)\)/;
6120
6142
  function validateStagedContent(filename, content) {
6121
6143
  const firstLine = content.split("\n")[0];
6122
6144
  const match = firstLine.match(FULL_TRANSCRIPT_REGEX);
6123
6145
  if (!match) {
6124
6146
  console.error(
6125
- chalk53.red(
6147
+ chalk54.red(
6126
6148
  `Staged file ${filename} missing [Full Transcript](<path>) link on first line.`
6127
6149
  )
6128
6150
  );
@@ -6131,7 +6153,7 @@ function validateStagedContent(filename, content) {
6131
6153
  const contentAfterLink = content.slice(firstLine.length).trim();
6132
6154
  if (!contentAfterLink) {
6133
6155
  console.error(
6134
- chalk53.red(
6156
+ chalk54.red(
6135
6157
  `Staged file ${filename} has no summary content after the transcript link.`
6136
6158
  )
6137
6159
  );
@@ -6524,7 +6546,7 @@ function registerVoice(program2) {
6524
6546
 
6525
6547
  // src/commands/roam/auth.ts
6526
6548
  import { randomBytes } from "crypto";
6527
- import chalk54 from "chalk";
6549
+ import chalk55 from "chalk";
6528
6550
 
6529
6551
  // src/lib/openBrowser.ts
6530
6552
  import { execSync as execSync28 } from "child_process";
@@ -6699,13 +6721,13 @@ async function auth() {
6699
6721
  saveGlobalConfig(config);
6700
6722
  const state = randomBytes(16).toString("hex");
6701
6723
  console.log(
6702
- chalk54.yellow("\nEnsure this Redirect URI is set in your Roam OAuth app:")
6724
+ chalk55.yellow("\nEnsure this Redirect URI is set in your Roam OAuth app:")
6703
6725
  );
6704
- console.log(chalk54.white("http://localhost:14523/callback\n"));
6705
- console.log(chalk54.blue("Opening browser for authorization..."));
6706
- console.log(chalk54.dim("Waiting for authorization callback..."));
6726
+ console.log(chalk55.white("http://localhost:14523/callback\n"));
6727
+ console.log(chalk55.blue("Opening browser for authorization..."));
6728
+ console.log(chalk55.dim("Waiting for authorization callback..."));
6707
6729
  const { code, redirectUri } = await authorizeInBrowser(clientId, state);
6708
- console.log(chalk54.dim("Exchanging code for tokens..."));
6730
+ console.log(chalk55.dim("Exchanging code for tokens..."));
6709
6731
  const tokens = await exchangeToken({
6710
6732
  code,
6711
6733
  clientId,
@@ -6721,7 +6743,7 @@ async function auth() {
6721
6743
  };
6722
6744
  saveGlobalConfig(config);
6723
6745
  console.log(
6724
- chalk54.green("Roam credentials and tokens saved to ~/.assist.yml")
6746
+ chalk55.green("Roam credentials and tokens saved to ~/.assist.yml")
6725
6747
  );
6726
6748
  }
6727
6749
 
@@ -6909,14 +6931,14 @@ function run2(name, args) {
6909
6931
  }
6910
6932
 
6911
6933
  // src/commands/statusLine.ts
6912
- import chalk55 from "chalk";
6934
+ import chalk56 from "chalk";
6913
6935
  function formatNumber(num) {
6914
6936
  return num.toLocaleString("en-US");
6915
6937
  }
6916
6938
  function colorizePercent(pct) {
6917
6939
  const label2 = `${pct}%`;
6918
- if (pct > 80) return chalk55.red(label2);
6919
- if (pct > 40) return chalk55.yellow(label2);
6940
+ if (pct > 80) return chalk56.red(label2);
6941
+ if (pct > 40) return chalk56.yellow(label2);
6920
6942
  return label2;
6921
6943
  }
6922
6944
  async function statusLine() {
@@ -6942,7 +6964,7 @@ import { fileURLToPath as fileURLToPath7 } from "url";
6942
6964
  // src/commands/sync/syncClaudeMd.ts
6943
6965
  import * as fs21 from "fs";
6944
6966
  import * as path31 from "path";
6945
- import chalk56 from "chalk";
6967
+ import chalk57 from "chalk";
6946
6968
  async function syncClaudeMd(claudeDir, targetBase) {
6947
6969
  const source = path31.join(claudeDir, "CLAUDE.md");
6948
6970
  const target = path31.join(targetBase, "CLAUDE.md");
@@ -6951,12 +6973,12 @@ async function syncClaudeMd(claudeDir, targetBase) {
6951
6973
  const targetContent = fs21.readFileSync(target, "utf-8");
6952
6974
  if (sourceContent !== targetContent) {
6953
6975
  console.log(
6954
- chalk56.yellow("\n\u26A0\uFE0F Warning: CLAUDE.md differs from existing file")
6976
+ chalk57.yellow("\n\u26A0\uFE0F Warning: CLAUDE.md differs from existing file")
6955
6977
  );
6956
6978
  console.log();
6957
6979
  printDiff(targetContent, sourceContent);
6958
6980
  const confirm = await promptConfirm(
6959
- chalk56.red("Overwrite existing CLAUDE.md?"),
6981
+ chalk57.red("Overwrite existing CLAUDE.md?"),
6960
6982
  false
6961
6983
  );
6962
6984
  if (!confirm) {
@@ -6972,7 +6994,7 @@ async function syncClaudeMd(claudeDir, targetBase) {
6972
6994
  // src/commands/sync/syncSettings.ts
6973
6995
  import * as fs22 from "fs";
6974
6996
  import * as path32 from "path";
6975
- import chalk57 from "chalk";
6997
+ import chalk58 from "chalk";
6976
6998
  async function syncSettings(claudeDir, targetBase, options2) {
6977
6999
  const source = path32.join(claudeDir, "settings.json");
6978
7000
  const target = path32.join(targetBase, "settings.json");
@@ -6988,14 +7010,14 @@ async function syncSettings(claudeDir, targetBase, options2) {
6988
7010
  if (mergedContent !== normalizedTarget) {
6989
7011
  if (!options2?.yes) {
6990
7012
  console.log(
6991
- chalk57.yellow(
7013
+ chalk58.yellow(
6992
7014
  "\n\u26A0\uFE0F Warning: settings.json differs from existing file"
6993
7015
  )
6994
7016
  );
6995
7017
  console.log();
6996
7018
  printDiff(targetContent, mergedContent);
6997
7019
  const confirm = await promptConfirm(
6998
- chalk57.red("Overwrite existing settings.json?"),
7020
+ chalk58.red("Overwrite existing settings.json?"),
6999
7021
  false
7000
7022
  );
7001
7023
  if (!confirm) {
@@ -7036,8 +7058,12 @@ import { execSync as execSync29 } from "child_process";
7036
7058
  import * as path34 from "path";
7037
7059
  function isGlobalNpmInstall(dir) {
7038
7060
  try {
7061
+ const resolved = path34.resolve(dir);
7062
+ if (resolved.split(path34.sep).includes("node_modules")) {
7063
+ return true;
7064
+ }
7039
7065
  const globalPrefix = execSync29("npm prefix -g", { stdio: "pipe" }).toString().trim();
7040
- return path34.resolve(dir).toLowerCase().startsWith(path34.resolve(globalPrefix).toLowerCase());
7066
+ return resolved.toLowerCase().startsWith(path34.resolve(globalPrefix).toLowerCase());
7041
7067
  } catch {
7042
7068
  return false;
7043
7069
  }
@@ -7104,7 +7130,7 @@ registerRefactor(program);
7104
7130
  registerDevlog(program);
7105
7131
  registerDeploy(program);
7106
7132
  registerComplexity(program);
7107
- registerDeps(program);
7133
+ registerNetframework(program);
7108
7134
  registerTranscript(program);
7109
7135
  registerVoice(program);
7110
7136
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@staff0rd/assist",
3
- "version": "0.101.0",
3
+ "version": "0.102.1",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "bin": {