@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 +2 -0
- package/claude/settings.json +2 -1
- package/dist/index.js +314 -288
- package/package.json +1 -1
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
|
package/claude/settings.json
CHANGED
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"Bash(assist complexity:*)",
|
|
37
37
|
"Bash(assist transcript format:*)",
|
|
38
38
|
"Bash(assist voice:*)",
|
|
39
|
-
"Bash(assist
|
|
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.
|
|
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
|
|
3721
|
+
import chalk38 from "chalk";
|
|
3913
3722
|
|
|
3914
3723
|
// src/commands/devlog/loadDevlogEntries.ts
|
|
3915
|
-
import { readdirSync
|
|
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 =
|
|
3731
|
+
const files = readdirSync(DEVLOG_DIR).filter((f) => f.endsWith(".md"));
|
|
3923
3732
|
for (const file of files) {
|
|
3924
|
-
const content =
|
|
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(` ${
|
|
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(` ${
|
|
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
|
|
3813
|
+
import chalk39 from "chalk";
|
|
4005
3814
|
function printDateHeader(date, isSkipped, entries) {
|
|
4006
3815
|
if (isSkipped) {
|
|
4007
|
-
console.log(`${
|
|
3816
|
+
console.log(`${chalk39.bold.blue(date)} ${chalk39.dim("skipped")}`);
|
|
4008
3817
|
} else if (entries && entries.length > 0) {
|
|
4009
|
-
const entryInfo = entries.map((e) => `${
|
|
4010
|
-
console.log(`${
|
|
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(`${
|
|
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
|
|
3924
|
+
import chalk41 from "chalk";
|
|
4116
3925
|
|
|
4117
3926
|
// src/commands/devlog/next/displayNextEntry/displayVersion.ts
|
|
4118
|
-
import
|
|
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(`${
|
|
3932
|
+
console.log(`${chalk40.bold("version:")} ${stripToMinor(version2)}`);
|
|
4124
3933
|
} else {
|
|
4125
|
-
console.log(`${
|
|
3934
|
+
console.log(`${chalk40.bold("version:")} ${chalk40.red("unknown")}`);
|
|
4126
3935
|
}
|
|
4127
3936
|
} else if (patchVersion && minorVersion) {
|
|
4128
3937
|
console.log(
|
|
4129
|
-
`${
|
|
3938
|
+
`${chalk40.bold("version:")} ${patchVersion} (patch) or ${minorVersion} (minor)`
|
|
4130
3939
|
);
|
|
4131
3940
|
} else {
|
|
4132
|
-
console.log(`${
|
|
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(`${
|
|
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(
|
|
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(
|
|
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
|
|
4032
|
+
import chalk42 from "chalk";
|
|
4224
4033
|
function skip(date) {
|
|
4225
4034
|
if (!/^\d{4}-\d{2}-\d{2}$/.test(date)) {
|
|
4226
|
-
console.log(
|
|
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(
|
|
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(
|
|
4052
|
+
console.log(chalk42.green(`Added ${date} to skip list`));
|
|
4244
4053
|
}
|
|
4245
4054
|
|
|
4246
4055
|
// src/commands/devlog/version.ts
|
|
4247
|
-
import
|
|
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(`${
|
|
4255
|
-
console.log(`${
|
|
4256
|
-
console.log(`${
|
|
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
|
|
4610
|
+
import chalk47 from "chalk";
|
|
4589
4611
|
function formatForHuman(comment2) {
|
|
4590
4612
|
if (comment2.type === "review") {
|
|
4591
|
-
const stateColor = comment2.state === "APPROVED" ?
|
|
4613
|
+
const stateColor = comment2.state === "APPROVED" ? chalk47.green : comment2.state === "CHANGES_REQUESTED" ? chalk47.red : chalk47.yellow;
|
|
4592
4614
|
return [
|
|
4593
|
-
`${
|
|
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
|
-
`${
|
|
4601
|
-
|
|
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
|
|
4702
|
+
import chalk48 from "chalk";
|
|
4681
4703
|
var STATUS_MAP = {
|
|
4682
|
-
MERGED: (pr) => pr.mergedAt ? { label:
|
|
4683
|
-
CLOSED: (pr) => pr.closedAt ? { label:
|
|
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:
|
|
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 `${
|
|
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
|
-
|
|
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
|
|
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(
|
|
4900
|
+
console.error(chalk49.red(`
|
|
4879
4901
|
Refactor check failed:
|
|
4880
4902
|
`));
|
|
4881
|
-
console.error(
|
|
4903
|
+
console.error(chalk49.red(` The following files exceed ${maxLines} lines:
|
|
4882
4904
|
`));
|
|
4883
4905
|
for (const violation of violations) {
|
|
4884
|
-
console.error(
|
|
4906
|
+
console.error(chalk49.red(` ${violation.file} (${violation.lines} lines)`));
|
|
4885
4907
|
}
|
|
4886
4908
|
console.error(
|
|
4887
|
-
|
|
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(
|
|
4916
|
+
console.error(chalk49.gray(` assist refactor ignore <file>
|
|
4895
4917
|
`));
|
|
4896
4918
|
if (process.env.CLAUDECODE) {
|
|
4897
|
-
console.error(
|
|
4919
|
+
console.error(chalk49.cyan(`
|
|
4898
4920
|
## Extracting Code to New Files
|
|
4899
4921
|
`));
|
|
4900
4922
|
console.error(
|
|
4901
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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(
|
|
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
|
-
|
|
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
|
|
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
|
|
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(
|
|
5369
|
+
console.log(chalk51.bold("\nFile moves:"));
|
|
5348
5370
|
for (const move of plan.moves) {
|
|
5349
5371
|
console.log(
|
|
5350
|
-
` ${
|
|
5372
|
+
` ${chalk51.red(relPath(move.from))} \u2192 ${chalk51.green(relPath(move.to))}`
|
|
5351
5373
|
);
|
|
5352
|
-
console.log(
|
|
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(
|
|
5380
|
+
console.log(chalk51.bold(`
|
|
5359
5381
|
Import rewrites (${affectedFiles.size} files):`));
|
|
5360
5382
|
for (const file of affectedFiles) {
|
|
5361
|
-
console.log(` ${
|
|
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
|
-
` ${
|
|
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(
|
|
5374
|
-
for (const w of plan.warnings) console.log(
|
|
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(
|
|
5399
|
+
console.log(chalk51.bold("\nNew directories:"));
|
|
5378
5400
|
for (const dir of plan.newDirectories)
|
|
5379
|
-
console.log(
|
|
5401
|
+
console.log(chalk51.green(` ${dir}/`));
|
|
5380
5402
|
}
|
|
5381
5403
|
displayMoves(plan);
|
|
5382
5404
|
displayRewrites(plan.rewrites);
|
|
5383
5405
|
console.log(
|
|
5384
|
-
|
|
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
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
5593
|
+
console.log(chalk53.bold("\nApplying changes..."));
|
|
5572
5594
|
executePlan(plan);
|
|
5573
|
-
console.log(
|
|
5595
|
+
console.log(chalk53.green("\nRestructuring complete"));
|
|
5574
5596
|
} else {
|
|
5575
|
-
console.log(
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
6724
|
+
chalk55.yellow("\nEnsure this Redirect URI is set in your Roam OAuth app:")
|
|
6703
6725
|
);
|
|
6704
|
-
console.log(
|
|
6705
|
-
console.log(
|
|
6706
|
-
console.log(
|
|
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(
|
|
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
|
-
|
|
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
|
|
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
|
|
6919
|
-
if (pct > 40) return
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
7133
|
+
registerNetframework(program);
|
|
7108
7134
|
registerTranscript(program);
|
|
7109
7135
|
registerVoice(program);
|
|
7110
7136
|
program.parse();
|