@staff0rd/assist 0.103.0 → 0.105.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/index.js +257 -146
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -90,6 +90,7 @@ After installation, the `assist` command will be available globally. You can als
|
|
|
90
90
|
- `assist refactor restructure [pattern]` - Analyze import graph and restructure tightly-coupled files into nested directories
|
|
91
91
|
- `assist devlog list` - Group git commits by date
|
|
92
92
|
- `assist devlog next` - Show commits for the day after the last versioned entry
|
|
93
|
+
- `assist devlog repos` - Show which github.com/staff0rd repos are missing devlog entries
|
|
93
94
|
- `assist devlog skip <date>` - Add a date to the skip list
|
|
94
95
|
- `assist devlog version` - Show current repo name and version info
|
|
95
96
|
- `assist cli-hook` - PreToolUse hook for auto-approving read-only CLI commands (reads from `assist.cli-reads`, also auto-approves read-only `gh api` calls). Supports compound commands (`|`, `&&`, `||`, `;`) by checking each sub-command independently
|
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.105.0",
|
|
10
10
|
type: "module",
|
|
11
11
|
main: "dist/index.js",
|
|
12
12
|
bin: {
|
|
@@ -2720,6 +2720,7 @@ import { parse } from "shell-quote";
|
|
|
2720
2720
|
var SEPARATOR_OPS = /* @__PURE__ */ new Set(["|", "&&", "||", ";"]);
|
|
2721
2721
|
var UNSAFE_OPS = /* @__PURE__ */ new Set(["(", ")", ">", ">>", "<", "<&", "|&", ">&"]);
|
|
2722
2722
|
var FD_REDIRECT_RE = /\d+>&\d+/g;
|
|
2723
|
+
var FD_DEVNULL_RE = /\d*>\/dev\/null/g;
|
|
2723
2724
|
function splitCompound(command) {
|
|
2724
2725
|
const tokens = tokenizeCommand(command);
|
|
2725
2726
|
if (!tokens) return void 0;
|
|
@@ -2729,7 +2730,7 @@ function splitCompound(command) {
|
|
|
2729
2730
|
return result.length > 0 ? result : void 0;
|
|
2730
2731
|
}
|
|
2731
2732
|
function tokenizeCommand(command) {
|
|
2732
|
-
const trimmed = command.trim().replace(FD_REDIRECT_RE, "");
|
|
2733
|
+
const trimmed = command.trim().replace(FD_DEVNULL_RE, "").replace(FD_REDIRECT_RE, "");
|
|
2733
2734
|
if (!trimmed) return void 0;
|
|
2734
2735
|
try {
|
|
2735
2736
|
const tokens = parse(trimmed);
|
|
@@ -3725,38 +3726,65 @@ import { readdirSync, readFileSync as readFileSync17 } from "fs";
|
|
|
3725
3726
|
import { homedir as homedir5 } from "os";
|
|
3726
3727
|
import { join as join13 } from "path";
|
|
3727
3728
|
var DEVLOG_DIR = join13(homedir5(), "git/blog/src/content/devlog");
|
|
3728
|
-
function
|
|
3729
|
-
const
|
|
3729
|
+
function extractFrontmatter(content) {
|
|
3730
|
+
const fm = content.match(/^---\n([\s\S]*?)\n---/);
|
|
3731
|
+
return fm?.[1] ?? null;
|
|
3732
|
+
}
|
|
3733
|
+
function matchField(frontmatter, pattern2) {
|
|
3734
|
+
return frontmatter.match(pattern2)?.[1]?.trim() ?? null;
|
|
3735
|
+
}
|
|
3736
|
+
function parseFrontmatter(content, filename) {
|
|
3737
|
+
const frontmatter = extractFrontmatter(content);
|
|
3738
|
+
if (!frontmatter) return null;
|
|
3739
|
+
const date = matchField(frontmatter, /date:\s*"?(\d{4}-\d{2}-\d{2})"?/);
|
|
3740
|
+
const tagsRaw = matchField(frontmatter, /tags:\s*\[([^\]]*)\]/);
|
|
3741
|
+
if (!date || !tagsRaw) return null;
|
|
3742
|
+
const repoTag = tagsRaw.split(",")[0]?.trim();
|
|
3743
|
+
if (!repoTag) return null;
|
|
3744
|
+
return {
|
|
3745
|
+
date,
|
|
3746
|
+
repoTag,
|
|
3747
|
+
version: matchField(frontmatter, /version:\s*(.+)/),
|
|
3748
|
+
title: matchField(frontmatter, /title:\s*(.+)/),
|
|
3749
|
+
filename
|
|
3750
|
+
};
|
|
3751
|
+
}
|
|
3752
|
+
function readDevlogFiles(callback) {
|
|
3730
3753
|
try {
|
|
3731
3754
|
const files = readdirSync(DEVLOG_DIR).filter((f) => f.endsWith(".md"));
|
|
3732
3755
|
for (const file of files) {
|
|
3733
3756
|
const content = readFileSync17(join13(DEVLOG_DIR, file), "utf-8");
|
|
3734
|
-
const
|
|
3735
|
-
if (
|
|
3736
|
-
const frontmatter = frontmatterMatch[1];
|
|
3737
|
-
const dateMatch = frontmatter.match(/date:\s*"?(\d{4}-\d{2}-\d{2})"?/);
|
|
3738
|
-
const versionMatch = frontmatter.match(/version:\s*(.+)/);
|
|
3739
|
-
const titleMatch = frontmatter.match(/title:\s*(.+)/);
|
|
3740
|
-
const tagsMatch = frontmatter.match(/tags:\s*\[([^\]]*)\]/);
|
|
3741
|
-
if (dateMatch && versionMatch && titleMatch && tagsMatch) {
|
|
3742
|
-
const tags = tagsMatch[1].split(",").map((t) => t.trim());
|
|
3743
|
-
const firstTag = tags[0];
|
|
3744
|
-
if (firstTag !== repoName) {
|
|
3745
|
-
continue;
|
|
3746
|
-
}
|
|
3747
|
-
const date = dateMatch[1];
|
|
3748
|
-
const version2 = versionMatch[1].trim();
|
|
3749
|
-
const title = titleMatch[1].trim();
|
|
3750
|
-
const existing = entries.get(date) || [];
|
|
3751
|
-
existing.push({ version: version2, title, filename: file });
|
|
3752
|
-
entries.set(date, existing);
|
|
3753
|
-
}
|
|
3754
|
-
}
|
|
3757
|
+
const parsed = parseFrontmatter(content, file);
|
|
3758
|
+
if (parsed) callback(parsed);
|
|
3755
3759
|
}
|
|
3756
3760
|
} catch {
|
|
3757
3761
|
}
|
|
3762
|
+
}
|
|
3763
|
+
function loadDevlogEntries(repoName) {
|
|
3764
|
+
const entries = /* @__PURE__ */ new Map();
|
|
3765
|
+
readDevlogFiles((parsed) => {
|
|
3766
|
+
if (parsed.repoTag !== repoName) return;
|
|
3767
|
+
if (!parsed.version || !parsed.title) return;
|
|
3768
|
+
const existing = entries.get(parsed.date) || [];
|
|
3769
|
+
existing.push({
|
|
3770
|
+
version: parsed.version,
|
|
3771
|
+
title: parsed.title,
|
|
3772
|
+
filename: parsed.filename
|
|
3773
|
+
});
|
|
3774
|
+
entries.set(parsed.date, existing);
|
|
3775
|
+
});
|
|
3758
3776
|
return entries;
|
|
3759
3777
|
}
|
|
3778
|
+
function loadAllDevlogLatestDates() {
|
|
3779
|
+
const latest = /* @__PURE__ */ new Map();
|
|
3780
|
+
readDevlogFiles((parsed) => {
|
|
3781
|
+
const existing = latest.get(parsed.repoTag);
|
|
3782
|
+
if (!existing || parsed.date > existing) {
|
|
3783
|
+
latest.set(parsed.repoTag, parsed.date);
|
|
3784
|
+
}
|
|
3785
|
+
});
|
|
3786
|
+
return latest;
|
|
3787
|
+
}
|
|
3760
3788
|
|
|
3761
3789
|
// src/commands/devlog/shared.ts
|
|
3762
3790
|
function getCommitFiles(hash) {
|
|
@@ -4028,11 +4056,89 @@ function next(options2) {
|
|
|
4028
4056
|
showResult(ctx, fetchNextCommits(ctx));
|
|
4029
4057
|
}
|
|
4030
4058
|
|
|
4031
|
-
// src/commands/devlog/
|
|
4059
|
+
// src/commands/devlog/repos/index.ts
|
|
4060
|
+
import { execSync as execSync19 } from "child_process";
|
|
4061
|
+
|
|
4062
|
+
// src/commands/devlog/repos/printReposTable.ts
|
|
4032
4063
|
import chalk42 from "chalk";
|
|
4064
|
+
function colorStatus(status2) {
|
|
4065
|
+
if (status2 === "missing") return chalk42.red(status2);
|
|
4066
|
+
if (status2 === "outdated") return chalk42.yellow(status2);
|
|
4067
|
+
return chalk42.green(status2);
|
|
4068
|
+
}
|
|
4069
|
+
function formatRow(row, nameWidth) {
|
|
4070
|
+
const devlog = (row.lastDevlog ?? "-").padEnd(11);
|
|
4071
|
+
return `${row.name.padEnd(nameWidth)} ${row.lastPush} ${devlog} ${colorStatus(row.status)}`;
|
|
4072
|
+
}
|
|
4073
|
+
function printReposTable(rows) {
|
|
4074
|
+
const nameWidth = Math.max(4, ...rows.map((r) => r.name.length));
|
|
4075
|
+
const header = [
|
|
4076
|
+
"Repo".padEnd(nameWidth),
|
|
4077
|
+
"Last Push".padEnd(10),
|
|
4078
|
+
"Last Devlog".padEnd(11),
|
|
4079
|
+
"Status"
|
|
4080
|
+
].join(" ");
|
|
4081
|
+
console.log(chalk42.dim(header));
|
|
4082
|
+
console.log(chalk42.dim("-".repeat(header.length)));
|
|
4083
|
+
for (const row of rows) {
|
|
4084
|
+
console.log(formatRow(row, nameWidth));
|
|
4085
|
+
}
|
|
4086
|
+
}
|
|
4087
|
+
|
|
4088
|
+
// src/commands/devlog/repos/index.ts
|
|
4089
|
+
var statusOrder = { missing: 0, outdated: 1, ok: 2 };
|
|
4090
|
+
function getStatus(lastPush, lastDevlog) {
|
|
4091
|
+
if (!lastDevlog) return "missing";
|
|
4092
|
+
return lastDevlog < lastPush ? "outdated" : "ok";
|
|
4093
|
+
}
|
|
4094
|
+
function fetchRepos(days, all) {
|
|
4095
|
+
const json = execSync19(
|
|
4096
|
+
"gh repo list staff0rd --json name,pushedAt,isArchived --limit 200",
|
|
4097
|
+
{ encoding: "utf-8" }
|
|
4098
|
+
);
|
|
4099
|
+
const allRepos = JSON.parse(json);
|
|
4100
|
+
const cutoff = /* @__PURE__ */ new Date();
|
|
4101
|
+
cutoff.setDate(cutoff.getDate() - days);
|
|
4102
|
+
const cutoffStr = cutoff.toISOString().slice(0, 10);
|
|
4103
|
+
return allRepos.filter((r) => {
|
|
4104
|
+
if (r.isArchived) return false;
|
|
4105
|
+
if (all) return true;
|
|
4106
|
+
return r.pushedAt.slice(0, 10) >= cutoffStr;
|
|
4107
|
+
});
|
|
4108
|
+
}
|
|
4109
|
+
function toRow(repo, devlogDates) {
|
|
4110
|
+
const lastPush = repo.pushedAt.slice(0, 10);
|
|
4111
|
+
const lastDevlog = devlogDates.get(repo.name) ?? null;
|
|
4112
|
+
return {
|
|
4113
|
+
name: repo.name,
|
|
4114
|
+
lastPush,
|
|
4115
|
+
lastDevlog,
|
|
4116
|
+
status: getStatus(lastPush, lastDevlog)
|
|
4117
|
+
};
|
|
4118
|
+
}
|
|
4119
|
+
function sortRows(rows) {
|
|
4120
|
+
return rows.sort((a, b) => {
|
|
4121
|
+
const s = statusOrder[a.status] - statusOrder[b.status];
|
|
4122
|
+
if (s !== 0) return s;
|
|
4123
|
+
return b.lastPush.localeCompare(a.lastPush);
|
|
4124
|
+
});
|
|
4125
|
+
}
|
|
4126
|
+
function repos(options2) {
|
|
4127
|
+
const ghRepos = fetchRepos(options2.days ?? 30, options2.all ?? false);
|
|
4128
|
+
if (ghRepos.length === 0) {
|
|
4129
|
+
console.log("No repos with recent activity found.");
|
|
4130
|
+
return;
|
|
4131
|
+
}
|
|
4132
|
+
const devlogDates = loadAllDevlogLatestDates();
|
|
4133
|
+
const rows = ghRepos.map((repo) => toRow(repo, devlogDates));
|
|
4134
|
+
printReposTable(sortRows(rows));
|
|
4135
|
+
}
|
|
4136
|
+
|
|
4137
|
+
// src/commands/devlog/skip.ts
|
|
4138
|
+
import chalk43 from "chalk";
|
|
4033
4139
|
function skip(date) {
|
|
4034
4140
|
if (!/^\d{4}-\d{2}-\d{2}$/.test(date)) {
|
|
4035
|
-
console.log(
|
|
4141
|
+
console.log(chalk43.red("Invalid date format. Use YYYY-MM-DD"));
|
|
4036
4142
|
process.exit(1);
|
|
4037
4143
|
}
|
|
4038
4144
|
const config = loadProjectConfig();
|
|
@@ -4040,7 +4146,7 @@ function skip(date) {
|
|
|
4040
4146
|
const skip2 = devlog.skip ?? {};
|
|
4041
4147
|
const skipDays = skip2.days ?? [];
|
|
4042
4148
|
if (skipDays.includes(date)) {
|
|
4043
|
-
console.log(
|
|
4149
|
+
console.log(chalk43.yellow(`${date} is already in skip list`));
|
|
4044
4150
|
return;
|
|
4045
4151
|
}
|
|
4046
4152
|
skipDays.push(date);
|
|
@@ -4049,20 +4155,20 @@ function skip(date) {
|
|
|
4049
4155
|
devlog.skip = skip2;
|
|
4050
4156
|
config.devlog = devlog;
|
|
4051
4157
|
saveConfig(config);
|
|
4052
|
-
console.log(
|
|
4158
|
+
console.log(chalk43.green(`Added ${date} to skip list`));
|
|
4053
4159
|
}
|
|
4054
4160
|
|
|
4055
4161
|
// src/commands/devlog/version.ts
|
|
4056
|
-
import
|
|
4162
|
+
import chalk44 from "chalk";
|
|
4057
4163
|
function version() {
|
|
4058
4164
|
const config = loadConfig();
|
|
4059
4165
|
const name = getRepoName();
|
|
4060
4166
|
const lastInfo = getLastVersionInfo(name, config);
|
|
4061
4167
|
const lastVersion = lastInfo?.version ?? null;
|
|
4062
4168
|
const nextVersion = lastVersion ? bumpVersion(lastVersion, "patch") : null;
|
|
4063
|
-
console.log(`${
|
|
4064
|
-
console.log(`${
|
|
4065
|
-
console.log(`${
|
|
4169
|
+
console.log(`${chalk44.bold("name:")} ${name}`);
|
|
4170
|
+
console.log(`${chalk44.bold("last:")} ${lastVersion ?? chalk44.dim("none")}`);
|
|
4171
|
+
console.log(`${chalk44.bold("next:")} ${nextVersion ?? chalk44.dim("none")}`);
|
|
4066
4172
|
}
|
|
4067
4173
|
|
|
4068
4174
|
// src/commands/registerDevlog.ts
|
|
@@ -4076,6 +4182,11 @@ function registerDevlog(program2) {
|
|
|
4076
4182
|
devlogCommand.command("version").description("Show current repo name and version info").action(version);
|
|
4077
4183
|
devlogCommand.command("next").description("Show commits for the day after the last versioned entry").option("-v, --verbose", "Show file names for each commit").action(next);
|
|
4078
4184
|
devlogCommand.command("skip <date>").description("Add a date (YYYY-MM-DD) to the skip list").action(skip);
|
|
4185
|
+
devlogCommand.command("repos").description("Show repos missing devlog entries").option(
|
|
4186
|
+
"--days <number>",
|
|
4187
|
+
"Only show repos pushed within N days (default: 30)",
|
|
4188
|
+
Number.parseInt
|
|
4189
|
+
).option("--all", "Show all non-archived repos regardless of push date").action(repos);
|
|
4079
4190
|
}
|
|
4080
4191
|
|
|
4081
4192
|
// src/commands/netframework/buildTree.ts
|
|
@@ -4174,30 +4285,30 @@ function escapeRegex(s) {
|
|
|
4174
4285
|
}
|
|
4175
4286
|
|
|
4176
4287
|
// src/commands/netframework/printTree.ts
|
|
4177
|
-
import
|
|
4288
|
+
import chalk45 from "chalk";
|
|
4178
4289
|
function printNodes(nodes, prefix2) {
|
|
4179
4290
|
for (let i = 0; i < nodes.length; i++) {
|
|
4180
4291
|
const isLast = i === nodes.length - 1;
|
|
4181
4292
|
const connector = isLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
|
|
4182
4293
|
const childPrefix = isLast ? " " : "\u2502 ";
|
|
4183
4294
|
const isMissing = nodes[i].relativePath.startsWith("[MISSING]");
|
|
4184
|
-
const label2 = isMissing ?
|
|
4295
|
+
const label2 = isMissing ? chalk45.red(nodes[i].relativePath) : nodes[i].relativePath;
|
|
4185
4296
|
console.log(`${prefix2}${connector}${label2}`);
|
|
4186
4297
|
printNodes(nodes[i].children, prefix2 + childPrefix);
|
|
4187
4298
|
}
|
|
4188
4299
|
}
|
|
4189
4300
|
function printTree(tree, totalCount, solutions) {
|
|
4190
|
-
console.log(
|
|
4191
|
-
console.log(
|
|
4301
|
+
console.log(chalk45.bold("\nProject Dependency Tree"));
|
|
4302
|
+
console.log(chalk45.cyan(tree.relativePath));
|
|
4192
4303
|
printNodes(tree.children, "");
|
|
4193
|
-
console.log(
|
|
4304
|
+
console.log(chalk45.dim(`
|
|
4194
4305
|
${totalCount} projects total (including root)`));
|
|
4195
|
-
console.log(
|
|
4306
|
+
console.log(chalk45.bold("\nSolution Membership"));
|
|
4196
4307
|
if (solutions.length === 0) {
|
|
4197
|
-
console.log(
|
|
4308
|
+
console.log(chalk45.yellow(" Not found in any .sln"));
|
|
4198
4309
|
} else {
|
|
4199
4310
|
for (const sln of solutions) {
|
|
4200
|
-
console.log(` ${
|
|
4311
|
+
console.log(` ${chalk45.green(sln)}`);
|
|
4201
4312
|
}
|
|
4202
4313
|
}
|
|
4203
4314
|
console.log();
|
|
@@ -4226,7 +4337,7 @@ function printJson(tree, totalCount, solutions) {
|
|
|
4226
4337
|
// src/commands/netframework/resolveCsproj.ts
|
|
4227
4338
|
import { existsSync as existsSync21 } from "fs";
|
|
4228
4339
|
import path20 from "path";
|
|
4229
|
-
import
|
|
4340
|
+
import chalk46 from "chalk";
|
|
4230
4341
|
|
|
4231
4342
|
// src/commands/netframework/findRepoRoot.ts
|
|
4232
4343
|
import { existsSync as existsSync20 } from "fs";
|
|
@@ -4246,12 +4357,12 @@ function findRepoRoot(dir) {
|
|
|
4246
4357
|
function resolveCsproj(csprojPath) {
|
|
4247
4358
|
const resolved = path20.resolve(csprojPath);
|
|
4248
4359
|
if (!existsSync21(resolved)) {
|
|
4249
|
-
console.error(
|
|
4360
|
+
console.error(chalk46.red(`File not found: ${resolved}`));
|
|
4250
4361
|
process.exit(1);
|
|
4251
4362
|
}
|
|
4252
4363
|
const repoRoot = findRepoRoot(path20.dirname(resolved));
|
|
4253
4364
|
if (!repoRoot) {
|
|
4254
|
-
console.error(
|
|
4365
|
+
console.error(chalk46.red("Could not find git repository root"));
|
|
4255
4366
|
process.exit(1);
|
|
4256
4367
|
}
|
|
4257
4368
|
return { resolved, repoRoot };
|
|
@@ -4271,12 +4382,12 @@ async function deps(csprojPath, options2) {
|
|
|
4271
4382
|
}
|
|
4272
4383
|
|
|
4273
4384
|
// src/commands/netframework/inSln.ts
|
|
4274
|
-
import
|
|
4385
|
+
import chalk47 from "chalk";
|
|
4275
4386
|
async function inSln(csprojPath) {
|
|
4276
4387
|
const { resolved, repoRoot } = resolveCsproj(csprojPath);
|
|
4277
4388
|
const solutions = findContainingSolutions(resolved, repoRoot);
|
|
4278
4389
|
if (solutions.length === 0) {
|
|
4279
|
-
console.log(
|
|
4390
|
+
console.log(chalk47.yellow("Not found in any .sln file"));
|
|
4280
4391
|
process.exit(1);
|
|
4281
4392
|
}
|
|
4282
4393
|
for (const sln of solutions) {
|
|
@@ -4298,7 +4409,7 @@ import { tmpdir as tmpdir2 } from "os";
|
|
|
4298
4409
|
import { join as join14 } from "path";
|
|
4299
4410
|
|
|
4300
4411
|
// src/commands/prs/shared.ts
|
|
4301
|
-
import { execSync as
|
|
4412
|
+
import { execSync as execSync20 } from "child_process";
|
|
4302
4413
|
function isGhNotInstalled(error) {
|
|
4303
4414
|
if (error instanceof Error) {
|
|
4304
4415
|
const msg = error.message.toLowerCase();
|
|
@@ -4314,14 +4425,14 @@ function isNotFound(error) {
|
|
|
4314
4425
|
}
|
|
4315
4426
|
function getRepoInfo() {
|
|
4316
4427
|
const repoInfo = JSON.parse(
|
|
4317
|
-
|
|
4428
|
+
execSync20("gh repo view --json owner,name", { encoding: "utf-8" })
|
|
4318
4429
|
);
|
|
4319
4430
|
return { org: repoInfo.owner.login, repo: repoInfo.name };
|
|
4320
4431
|
}
|
|
4321
4432
|
function getCurrentPrNumber() {
|
|
4322
4433
|
try {
|
|
4323
4434
|
const prInfo = JSON.parse(
|
|
4324
|
-
|
|
4435
|
+
execSync20("gh pr view --json number", { encoding: "utf-8" })
|
|
4325
4436
|
);
|
|
4326
4437
|
return prInfo.number;
|
|
4327
4438
|
} catch (error) {
|
|
@@ -4335,7 +4446,7 @@ function getCurrentPrNumber() {
|
|
|
4335
4446
|
function getCurrentPrNodeId() {
|
|
4336
4447
|
try {
|
|
4337
4448
|
const prInfo = JSON.parse(
|
|
4338
|
-
|
|
4449
|
+
execSync20("gh pr view --json id", { encoding: "utf-8" })
|
|
4339
4450
|
);
|
|
4340
4451
|
return prInfo.id;
|
|
4341
4452
|
} catch (error) {
|
|
@@ -4406,10 +4517,10 @@ function comment(path35, line, body) {
|
|
|
4406
4517
|
}
|
|
4407
4518
|
|
|
4408
4519
|
// src/commands/prs/fixed.ts
|
|
4409
|
-
import { execSync as
|
|
4520
|
+
import { execSync as execSync22 } from "child_process";
|
|
4410
4521
|
|
|
4411
4522
|
// src/commands/prs/resolveCommentWithReply.ts
|
|
4412
|
-
import { execSync as
|
|
4523
|
+
import { execSync as execSync21 } from "child_process";
|
|
4413
4524
|
import { unlinkSync as unlinkSync5, writeFileSync as writeFileSync16 } from "fs";
|
|
4414
4525
|
import { tmpdir as tmpdir3 } from "os";
|
|
4415
4526
|
import { join as join16 } from "path";
|
|
@@ -4439,7 +4550,7 @@ function deleteCommentsCache(prNumber) {
|
|
|
4439
4550
|
|
|
4440
4551
|
// src/commands/prs/resolveCommentWithReply.ts
|
|
4441
4552
|
function replyToComment(org, repo, prNumber, commentId, message) {
|
|
4442
|
-
|
|
4553
|
+
execSync21(
|
|
4443
4554
|
`gh api repos/${org}/${repo}/pulls/${prNumber}/comments -f body="${message.replace(/"/g, '\\"')}" -F in_reply_to=${commentId}`,
|
|
4444
4555
|
{ stdio: "inherit" }
|
|
4445
4556
|
);
|
|
@@ -4449,7 +4560,7 @@ function resolveThread(threadId) {
|
|
|
4449
4560
|
const queryFile = join16(tmpdir3(), `gh-mutation-${Date.now()}.graphql`);
|
|
4450
4561
|
writeFileSync16(queryFile, mutation);
|
|
4451
4562
|
try {
|
|
4452
|
-
|
|
4563
|
+
execSync21(
|
|
4453
4564
|
`gh api graphql -F query=@${queryFile} -f threadId="${threadId}"`,
|
|
4454
4565
|
{ stdio: "inherit" }
|
|
4455
4566
|
);
|
|
@@ -4501,7 +4612,7 @@ function resolveCommentWithReply(commentId, message) {
|
|
|
4501
4612
|
// src/commands/prs/fixed.ts
|
|
4502
4613
|
function verifySha(sha) {
|
|
4503
4614
|
try {
|
|
4504
|
-
return
|
|
4615
|
+
return execSync22(`git rev-parse --verify ${sha}`, {
|
|
4505
4616
|
encoding: "utf-8"
|
|
4506
4617
|
}).trim();
|
|
4507
4618
|
} catch {
|
|
@@ -4532,7 +4643,7 @@ import { join as join18 } from "path";
|
|
|
4532
4643
|
import { stringify } from "yaml";
|
|
4533
4644
|
|
|
4534
4645
|
// src/commands/prs/fetchThreadIds.ts
|
|
4535
|
-
import { execSync as
|
|
4646
|
+
import { execSync as execSync23 } from "child_process";
|
|
4536
4647
|
import { unlinkSync as unlinkSync6, writeFileSync as writeFileSync17 } from "fs";
|
|
4537
4648
|
import { tmpdir as tmpdir4 } from "os";
|
|
4538
4649
|
import { join as join17 } from "path";
|
|
@@ -4541,7 +4652,7 @@ function fetchThreadIds(org, repo, prNumber) {
|
|
|
4541
4652
|
const queryFile = join17(tmpdir4(), `gh-query-${Date.now()}.graphql`);
|
|
4542
4653
|
writeFileSync17(queryFile, THREAD_QUERY);
|
|
4543
4654
|
try {
|
|
4544
|
-
const result =
|
|
4655
|
+
const result = execSync23(
|
|
4545
4656
|
`gh api graphql -F query=@${queryFile} -F owner="${org}" -F repo="${repo}" -F prNumber=${prNumber}`,
|
|
4546
4657
|
{ encoding: "utf-8" }
|
|
4547
4658
|
);
|
|
@@ -4563,9 +4674,9 @@ function fetchThreadIds(org, repo, prNumber) {
|
|
|
4563
4674
|
}
|
|
4564
4675
|
|
|
4565
4676
|
// src/commands/prs/listComments/fetchReviewComments.ts
|
|
4566
|
-
import { execSync as
|
|
4677
|
+
import { execSync as execSync24 } from "child_process";
|
|
4567
4678
|
function fetchJson(endpoint) {
|
|
4568
|
-
const result =
|
|
4679
|
+
const result = execSync24(`gh api --paginate ${endpoint}`, {
|
|
4569
4680
|
encoding: "utf-8"
|
|
4570
4681
|
});
|
|
4571
4682
|
if (!result.trim()) return [];
|
|
@@ -4607,20 +4718,20 @@ function fetchLineComments(org, repo, prNumber, threadInfo) {
|
|
|
4607
4718
|
}
|
|
4608
4719
|
|
|
4609
4720
|
// src/commands/prs/listComments/printComments.ts
|
|
4610
|
-
import
|
|
4721
|
+
import chalk48 from "chalk";
|
|
4611
4722
|
function formatForHuman(comment2) {
|
|
4612
4723
|
if (comment2.type === "review") {
|
|
4613
|
-
const stateColor = comment2.state === "APPROVED" ?
|
|
4724
|
+
const stateColor = comment2.state === "APPROVED" ? chalk48.green : comment2.state === "CHANGES_REQUESTED" ? chalk48.red : chalk48.yellow;
|
|
4614
4725
|
return [
|
|
4615
|
-
`${
|
|
4726
|
+
`${chalk48.cyan("Review")} by ${chalk48.bold(comment2.user)} ${stateColor(`[${comment2.state}]`)}`,
|
|
4616
4727
|
comment2.body,
|
|
4617
4728
|
""
|
|
4618
4729
|
].join("\n");
|
|
4619
4730
|
}
|
|
4620
4731
|
const location = comment2.line ? `:${comment2.line}` : "";
|
|
4621
4732
|
return [
|
|
4622
|
-
`${
|
|
4623
|
-
|
|
4733
|
+
`${chalk48.cyan("Line comment")} by ${chalk48.bold(comment2.user)} on ${chalk48.dim(`${comment2.path}${location}`)}`,
|
|
4734
|
+
chalk48.dim(comment2.diff_hunk.split("\n").slice(-3).join("\n")),
|
|
4624
4735
|
comment2.body,
|
|
4625
4736
|
""
|
|
4626
4737
|
].join("\n");
|
|
@@ -4704,37 +4815,37 @@ async function listComments() {
|
|
|
4704
4815
|
}
|
|
4705
4816
|
|
|
4706
4817
|
// src/commands/prs/prs/index.ts
|
|
4707
|
-
import { execSync as
|
|
4818
|
+
import { execSync as execSync25 } from "child_process";
|
|
4708
4819
|
|
|
4709
4820
|
// src/commands/prs/prs/displayPaginated/index.ts
|
|
4710
4821
|
import enquirer5 from "enquirer";
|
|
4711
4822
|
|
|
4712
4823
|
// src/commands/prs/prs/displayPaginated/printPr.ts
|
|
4713
|
-
import
|
|
4824
|
+
import chalk49 from "chalk";
|
|
4714
4825
|
var STATUS_MAP = {
|
|
4715
|
-
MERGED: (pr) => pr.mergedAt ? { label:
|
|
4716
|
-
CLOSED: (pr) => pr.closedAt ? { label:
|
|
4826
|
+
MERGED: (pr) => pr.mergedAt ? { label: chalk49.magenta("merged"), date: pr.mergedAt } : null,
|
|
4827
|
+
CLOSED: (pr) => pr.closedAt ? { label: chalk49.red("closed"), date: pr.closedAt } : null
|
|
4717
4828
|
};
|
|
4718
4829
|
function defaultStatus(pr) {
|
|
4719
|
-
return { label:
|
|
4830
|
+
return { label: chalk49.green("opened"), date: pr.createdAt };
|
|
4720
4831
|
}
|
|
4721
|
-
function
|
|
4832
|
+
function getStatus2(pr) {
|
|
4722
4833
|
return STATUS_MAP[pr.state]?.(pr) ?? defaultStatus(pr);
|
|
4723
4834
|
}
|
|
4724
4835
|
function formatDate(dateStr) {
|
|
4725
4836
|
return new Date(dateStr).toISOString().split("T")[0];
|
|
4726
4837
|
}
|
|
4727
4838
|
function formatPrHeader(pr, status2) {
|
|
4728
|
-
return `${
|
|
4839
|
+
return `${chalk49.cyan(`#${pr.number}`)} ${pr.title} ${chalk49.dim(`(${pr.author.login},`)} ${status2.label} ${chalk49.dim(`${formatDate(status2.date)})`)}`;
|
|
4729
4840
|
}
|
|
4730
4841
|
function logPrDetails(pr) {
|
|
4731
4842
|
console.log(
|
|
4732
|
-
|
|
4843
|
+
chalk49.dim(` ${pr.changedFiles.toLocaleString()} files | ${pr.url}`)
|
|
4733
4844
|
);
|
|
4734
4845
|
console.log();
|
|
4735
4846
|
}
|
|
4736
4847
|
function printPr(pr) {
|
|
4737
|
-
console.log(formatPrHeader(pr,
|
|
4848
|
+
console.log(formatPrHeader(pr, getStatus2(pr)));
|
|
4738
4849
|
logPrDetails(pr);
|
|
4739
4850
|
}
|
|
4740
4851
|
|
|
@@ -4810,7 +4921,7 @@ async function displayPaginated(pullRequests) {
|
|
|
4810
4921
|
async function prs(options2) {
|
|
4811
4922
|
const state = options2.open ? "open" : options2.closed ? "closed" : "all";
|
|
4812
4923
|
try {
|
|
4813
|
-
const result =
|
|
4924
|
+
const result = execSync25(
|
|
4814
4925
|
`gh pr list --state ${state} --json number,title,url,author,createdAt,mergedAt,closedAt,state,changedFiles --limit 100`,
|
|
4815
4926
|
{ encoding: "utf-8" }
|
|
4816
4927
|
);
|
|
@@ -4833,7 +4944,7 @@ async function prs(options2) {
|
|
|
4833
4944
|
}
|
|
4834
4945
|
|
|
4835
4946
|
// src/commands/prs/wontfix.ts
|
|
4836
|
-
import { execSync as
|
|
4947
|
+
import { execSync as execSync26 } from "child_process";
|
|
4837
4948
|
function validateReason(reason) {
|
|
4838
4949
|
const lowerReason = reason.toLowerCase();
|
|
4839
4950
|
if (lowerReason.includes("claude") || lowerReason.includes("opus")) {
|
|
@@ -4850,7 +4961,7 @@ function validateShaReferences(reason) {
|
|
|
4850
4961
|
const invalidShas = [];
|
|
4851
4962
|
for (const sha of shas) {
|
|
4852
4963
|
try {
|
|
4853
|
-
|
|
4964
|
+
execSync26(`git cat-file -t ${sha}`, { stdio: "pipe" });
|
|
4854
4965
|
} catch {
|
|
4855
4966
|
invalidShas.push(sha);
|
|
4856
4967
|
}
|
|
@@ -4899,7 +5010,7 @@ import { spawn as spawn3 } from "child_process";
|
|
|
4899
5010
|
import * as path21 from "path";
|
|
4900
5011
|
|
|
4901
5012
|
// src/commands/refactor/logViolations.ts
|
|
4902
|
-
import
|
|
5013
|
+
import chalk50 from "chalk";
|
|
4903
5014
|
var DEFAULT_MAX_LINES = 100;
|
|
4904
5015
|
function logViolations(violations, maxLines = DEFAULT_MAX_LINES) {
|
|
4905
5016
|
if (violations.length === 0) {
|
|
@@ -4908,43 +5019,43 @@ function logViolations(violations, maxLines = DEFAULT_MAX_LINES) {
|
|
|
4908
5019
|
}
|
|
4909
5020
|
return;
|
|
4910
5021
|
}
|
|
4911
|
-
console.error(
|
|
5022
|
+
console.error(chalk50.red(`
|
|
4912
5023
|
Refactor check failed:
|
|
4913
5024
|
`));
|
|
4914
|
-
console.error(
|
|
5025
|
+
console.error(chalk50.red(` The following files exceed ${maxLines} lines:
|
|
4915
5026
|
`));
|
|
4916
5027
|
for (const violation of violations) {
|
|
4917
|
-
console.error(
|
|
5028
|
+
console.error(chalk50.red(` ${violation.file} (${violation.lines} lines)`));
|
|
4918
5029
|
}
|
|
4919
5030
|
console.error(
|
|
4920
|
-
|
|
5031
|
+
chalk50.yellow(
|
|
4921
5032
|
`
|
|
4922
5033
|
Each file needs to be sensibly refactored, or if there is no sensible
|
|
4923
5034
|
way to refactor it, ignore it with:
|
|
4924
5035
|
`
|
|
4925
5036
|
)
|
|
4926
5037
|
);
|
|
4927
|
-
console.error(
|
|
5038
|
+
console.error(chalk50.gray(` assist refactor ignore <file>
|
|
4928
5039
|
`));
|
|
4929
5040
|
if (process.env.CLAUDECODE) {
|
|
4930
|
-
console.error(
|
|
5041
|
+
console.error(chalk50.cyan(`
|
|
4931
5042
|
## Extracting Code to New Files
|
|
4932
5043
|
`));
|
|
4933
5044
|
console.error(
|
|
4934
|
-
|
|
5045
|
+
chalk50.cyan(
|
|
4935
5046
|
` When extracting logic from one file to another, consider where the extracted code belongs:
|
|
4936
5047
|
`
|
|
4937
5048
|
)
|
|
4938
5049
|
);
|
|
4939
5050
|
console.error(
|
|
4940
|
-
|
|
5051
|
+
chalk50.cyan(
|
|
4941
5052
|
` 1. Keep related logic together: If the extracted code is tightly coupled to the
|
|
4942
5053
|
original file's domain, create a new folder containing both the original and extracted files.
|
|
4943
5054
|
`
|
|
4944
5055
|
)
|
|
4945
5056
|
);
|
|
4946
5057
|
console.error(
|
|
4947
|
-
|
|
5058
|
+
chalk50.cyan(
|
|
4948
5059
|
` 2. Share common utilities: If the extracted code can be reused across multiple
|
|
4949
5060
|
domains, move it to a common/shared folder.
|
|
4950
5061
|
`
|
|
@@ -4954,7 +5065,7 @@ Refactor check failed:
|
|
|
4954
5065
|
}
|
|
4955
5066
|
|
|
4956
5067
|
// src/commands/refactor/check/getViolations/index.ts
|
|
4957
|
-
import { execSync as
|
|
5068
|
+
import { execSync as execSync27 } from "child_process";
|
|
4958
5069
|
import fs15 from "fs";
|
|
4959
5070
|
import { minimatch as minimatch4 } from "minimatch";
|
|
4960
5071
|
|
|
@@ -5004,7 +5115,7 @@ function getGitFiles(options2) {
|
|
|
5004
5115
|
}
|
|
5005
5116
|
const files = /* @__PURE__ */ new Set();
|
|
5006
5117
|
if (options2.staged || options2.modified) {
|
|
5007
|
-
const staged =
|
|
5118
|
+
const staged = execSync27("git diff --cached --name-only", {
|
|
5008
5119
|
encoding: "utf-8"
|
|
5009
5120
|
});
|
|
5010
5121
|
for (const file of staged.trim().split("\n").filter(Boolean)) {
|
|
@@ -5012,7 +5123,7 @@ function getGitFiles(options2) {
|
|
|
5012
5123
|
}
|
|
5013
5124
|
}
|
|
5014
5125
|
if (options2.unstaged || options2.modified) {
|
|
5015
|
-
const unstaged =
|
|
5126
|
+
const unstaged = execSync27("git diff --name-only", { encoding: "utf-8" });
|
|
5016
5127
|
for (const file of unstaged.trim().split("\n").filter(Boolean)) {
|
|
5017
5128
|
files.add(file);
|
|
5018
5129
|
}
|
|
@@ -5100,11 +5211,11 @@ async function check(pattern2, options2) {
|
|
|
5100
5211
|
|
|
5101
5212
|
// src/commands/refactor/ignore.ts
|
|
5102
5213
|
import fs16 from "fs";
|
|
5103
|
-
import
|
|
5214
|
+
import chalk51 from "chalk";
|
|
5104
5215
|
var REFACTOR_YML_PATH2 = "refactor.yml";
|
|
5105
5216
|
function ignore(file) {
|
|
5106
5217
|
if (!fs16.existsSync(file)) {
|
|
5107
|
-
console.error(
|
|
5218
|
+
console.error(chalk51.red(`Error: File does not exist: ${file}`));
|
|
5108
5219
|
process.exit(1);
|
|
5109
5220
|
}
|
|
5110
5221
|
const content = fs16.readFileSync(file, "utf-8");
|
|
@@ -5120,7 +5231,7 @@ function ignore(file) {
|
|
|
5120
5231
|
fs16.writeFileSync(REFACTOR_YML_PATH2, entry);
|
|
5121
5232
|
}
|
|
5122
5233
|
console.log(
|
|
5123
|
-
|
|
5234
|
+
chalk51.green(
|
|
5124
5235
|
`Added ${file} to refactor ignore list (max ${maxLines} lines)`
|
|
5125
5236
|
)
|
|
5126
5237
|
);
|
|
@@ -5128,7 +5239,7 @@ function ignore(file) {
|
|
|
5128
5239
|
|
|
5129
5240
|
// src/commands/refactor/restructure/index.ts
|
|
5130
5241
|
import path30 from "path";
|
|
5131
|
-
import
|
|
5242
|
+
import chalk54 from "chalk";
|
|
5132
5243
|
|
|
5133
5244
|
// src/commands/refactor/restructure/buildImportGraph/index.ts
|
|
5134
5245
|
import path22 from "path";
|
|
@@ -5371,50 +5482,50 @@ function computeRewrites(moves, edges, allProjectFiles) {
|
|
|
5371
5482
|
|
|
5372
5483
|
// src/commands/refactor/restructure/displayPlan.ts
|
|
5373
5484
|
import path26 from "path";
|
|
5374
|
-
import
|
|
5485
|
+
import chalk52 from "chalk";
|
|
5375
5486
|
function relPath(filePath) {
|
|
5376
5487
|
return path26.relative(process.cwd(), filePath);
|
|
5377
5488
|
}
|
|
5378
5489
|
function displayMoves(plan) {
|
|
5379
5490
|
if (plan.moves.length === 0) return;
|
|
5380
|
-
console.log(
|
|
5491
|
+
console.log(chalk52.bold("\nFile moves:"));
|
|
5381
5492
|
for (const move of plan.moves) {
|
|
5382
5493
|
console.log(
|
|
5383
|
-
` ${
|
|
5494
|
+
` ${chalk52.red(relPath(move.from))} \u2192 ${chalk52.green(relPath(move.to))}`
|
|
5384
5495
|
);
|
|
5385
|
-
console.log(
|
|
5496
|
+
console.log(chalk52.dim(` ${move.reason}`));
|
|
5386
5497
|
}
|
|
5387
5498
|
}
|
|
5388
5499
|
function displayRewrites(rewrites) {
|
|
5389
5500
|
if (rewrites.length === 0) return;
|
|
5390
5501
|
const affectedFiles = new Set(rewrites.map((r) => r.file));
|
|
5391
|
-
console.log(
|
|
5502
|
+
console.log(chalk52.bold(`
|
|
5392
5503
|
Import rewrites (${affectedFiles.size} files):`));
|
|
5393
5504
|
for (const file of affectedFiles) {
|
|
5394
|
-
console.log(` ${
|
|
5505
|
+
console.log(` ${chalk52.cyan(relPath(file))}:`);
|
|
5395
5506
|
for (const { oldSpecifier, newSpecifier } of rewrites.filter(
|
|
5396
5507
|
(r) => r.file === file
|
|
5397
5508
|
)) {
|
|
5398
5509
|
console.log(
|
|
5399
|
-
` ${
|
|
5510
|
+
` ${chalk52.red(`"${oldSpecifier}"`)} \u2192 ${chalk52.green(`"${newSpecifier}"`)}`
|
|
5400
5511
|
);
|
|
5401
5512
|
}
|
|
5402
5513
|
}
|
|
5403
5514
|
}
|
|
5404
5515
|
function displayPlan(plan) {
|
|
5405
5516
|
if (plan.warnings.length > 0) {
|
|
5406
|
-
console.log(
|
|
5407
|
-
for (const w of plan.warnings) console.log(
|
|
5517
|
+
console.log(chalk52.yellow("\nWarnings:"));
|
|
5518
|
+
for (const w of plan.warnings) console.log(chalk52.yellow(` ${w}`));
|
|
5408
5519
|
}
|
|
5409
5520
|
if (plan.newDirectories.length > 0) {
|
|
5410
|
-
console.log(
|
|
5521
|
+
console.log(chalk52.bold("\nNew directories:"));
|
|
5411
5522
|
for (const dir of plan.newDirectories)
|
|
5412
|
-
console.log(
|
|
5523
|
+
console.log(chalk52.green(` ${dir}/`));
|
|
5413
5524
|
}
|
|
5414
5525
|
displayMoves(plan);
|
|
5415
5526
|
displayRewrites(plan.rewrites);
|
|
5416
5527
|
console.log(
|
|
5417
|
-
|
|
5528
|
+
chalk52.dim(
|
|
5418
5529
|
`
|
|
5419
5530
|
Summary: ${plan.moves.length} file(s) moved, ${plan.rewrites.length} imports rewritten`
|
|
5420
5531
|
)
|
|
@@ -5424,18 +5535,18 @@ Summary: ${plan.moves.length} file(s) moved, ${plan.rewrites.length} imports rew
|
|
|
5424
5535
|
// src/commands/refactor/restructure/executePlan.ts
|
|
5425
5536
|
import fs18 from "fs";
|
|
5426
5537
|
import path27 from "path";
|
|
5427
|
-
import
|
|
5538
|
+
import chalk53 from "chalk";
|
|
5428
5539
|
function executePlan(plan) {
|
|
5429
5540
|
const updatedContents = applyRewrites(plan.rewrites);
|
|
5430
5541
|
for (const [file, content] of updatedContents) {
|
|
5431
5542
|
fs18.writeFileSync(file, content, "utf-8");
|
|
5432
5543
|
console.log(
|
|
5433
|
-
|
|
5544
|
+
chalk53.cyan(` Rewrote imports in ${path27.relative(process.cwd(), file)}`)
|
|
5434
5545
|
);
|
|
5435
5546
|
}
|
|
5436
5547
|
for (const dir of plan.newDirectories) {
|
|
5437
5548
|
fs18.mkdirSync(dir, { recursive: true });
|
|
5438
|
-
console.log(
|
|
5549
|
+
console.log(chalk53.green(` Created ${path27.relative(process.cwd(), dir)}/`));
|
|
5439
5550
|
}
|
|
5440
5551
|
for (const move of plan.moves) {
|
|
5441
5552
|
const targetDir = path27.dirname(move.to);
|
|
@@ -5444,7 +5555,7 @@ function executePlan(plan) {
|
|
|
5444
5555
|
}
|
|
5445
5556
|
fs18.renameSync(move.from, move.to);
|
|
5446
5557
|
console.log(
|
|
5447
|
-
|
|
5558
|
+
chalk53.white(
|
|
5448
5559
|
` Moved ${path27.relative(process.cwd(), move.from)} \u2192 ${path27.relative(process.cwd(), move.to)}`
|
|
5449
5560
|
)
|
|
5450
5561
|
);
|
|
@@ -5459,7 +5570,7 @@ function removeEmptyDirectories(dirs) {
|
|
|
5459
5570
|
if (entries.length === 0) {
|
|
5460
5571
|
fs18.rmdirSync(dir);
|
|
5461
5572
|
console.log(
|
|
5462
|
-
|
|
5573
|
+
chalk53.dim(
|
|
5463
5574
|
` Removed empty directory ${path27.relative(process.cwd(), dir)}`
|
|
5464
5575
|
)
|
|
5465
5576
|
);
|
|
@@ -5590,22 +5701,22 @@ async function restructure(pattern2, options2 = {}) {
|
|
|
5590
5701
|
const targetPattern = pattern2 ?? "src";
|
|
5591
5702
|
const files = findSourceFiles2(targetPattern);
|
|
5592
5703
|
if (files.length === 0) {
|
|
5593
|
-
console.log(
|
|
5704
|
+
console.log(chalk54.yellow("No files found matching pattern"));
|
|
5594
5705
|
return;
|
|
5595
5706
|
}
|
|
5596
5707
|
const tsConfigPath = path30.resolve("tsconfig.json");
|
|
5597
5708
|
const plan = buildPlan(files, tsConfigPath);
|
|
5598
5709
|
if (plan.moves.length === 0) {
|
|
5599
|
-
console.log(
|
|
5710
|
+
console.log(chalk54.green("No restructuring needed"));
|
|
5600
5711
|
return;
|
|
5601
5712
|
}
|
|
5602
5713
|
displayPlan(plan);
|
|
5603
5714
|
if (options2.apply) {
|
|
5604
|
-
console.log(
|
|
5715
|
+
console.log(chalk54.bold("\nApplying changes..."));
|
|
5605
5716
|
executePlan(plan);
|
|
5606
|
-
console.log(
|
|
5717
|
+
console.log(chalk54.green("\nRestructuring complete"));
|
|
5607
5718
|
} else {
|
|
5608
|
-
console.log(
|
|
5719
|
+
console.log(chalk54.dim("\nDry run. Use --apply to execute."));
|
|
5609
5720
|
}
|
|
5610
5721
|
}
|
|
5611
5722
|
|
|
@@ -6148,14 +6259,14 @@ import {
|
|
|
6148
6259
|
import { dirname as dirname17, join as join23 } from "path";
|
|
6149
6260
|
|
|
6150
6261
|
// src/commands/transcript/summarise/processStagedFile/validateStagedContent.ts
|
|
6151
|
-
import
|
|
6262
|
+
import chalk55 from "chalk";
|
|
6152
6263
|
var FULL_TRANSCRIPT_REGEX = /^\[Full Transcript\]\(([^)]+)\)/;
|
|
6153
6264
|
function validateStagedContent(filename, content) {
|
|
6154
6265
|
const firstLine = content.split("\n")[0];
|
|
6155
6266
|
const match = firstLine.match(FULL_TRANSCRIPT_REGEX);
|
|
6156
6267
|
if (!match) {
|
|
6157
6268
|
console.error(
|
|
6158
|
-
|
|
6269
|
+
chalk55.red(
|
|
6159
6270
|
`Staged file ${filename} missing [Full Transcript](<path>) link on first line.`
|
|
6160
6271
|
)
|
|
6161
6272
|
);
|
|
@@ -6164,7 +6275,7 @@ function validateStagedContent(filename, content) {
|
|
|
6164
6275
|
const contentAfterLink = content.slice(firstLine.length).trim();
|
|
6165
6276
|
if (!contentAfterLink) {
|
|
6166
6277
|
console.error(
|
|
6167
|
-
|
|
6278
|
+
chalk55.red(
|
|
6168
6279
|
`Staged file ${filename} has no summary content after the transcript link.`
|
|
6169
6280
|
)
|
|
6170
6281
|
);
|
|
@@ -6364,7 +6475,7 @@ import { mkdirSync as mkdirSync9 } from "fs";
|
|
|
6364
6475
|
import { join as join28 } from "path";
|
|
6365
6476
|
|
|
6366
6477
|
// src/commands/voice/checkLockFile.ts
|
|
6367
|
-
import { execSync as
|
|
6478
|
+
import { execSync as execSync28 } from "child_process";
|
|
6368
6479
|
import { existsSync as existsSync30, mkdirSync as mkdirSync8, readFileSync as readFileSync24, writeFileSync as writeFileSync20 } from "fs";
|
|
6369
6480
|
import { join as join27 } from "path";
|
|
6370
6481
|
function isProcessAlive(pid) {
|
|
@@ -6393,7 +6504,7 @@ function bootstrapVenv() {
|
|
|
6393
6504
|
if (existsSync30(getVenvPython())) return;
|
|
6394
6505
|
console.log("Setting up Python environment...");
|
|
6395
6506
|
const pythonDir = getPythonDir();
|
|
6396
|
-
|
|
6507
|
+
execSync28(
|
|
6397
6508
|
`uv sync --project "${pythonDir}" --extra runtime --no-install-project`,
|
|
6398
6509
|
{
|
|
6399
6510
|
stdio: "inherit",
|
|
@@ -6557,14 +6668,14 @@ function registerVoice(program2) {
|
|
|
6557
6668
|
|
|
6558
6669
|
// src/commands/roam/auth.ts
|
|
6559
6670
|
import { randomBytes } from "crypto";
|
|
6560
|
-
import
|
|
6671
|
+
import chalk56 from "chalk";
|
|
6561
6672
|
|
|
6562
6673
|
// src/lib/openBrowser.ts
|
|
6563
|
-
import { execSync as
|
|
6674
|
+
import { execSync as execSync29 } from "child_process";
|
|
6564
6675
|
function tryExec(commands) {
|
|
6565
6676
|
for (const cmd of commands) {
|
|
6566
6677
|
try {
|
|
6567
|
-
|
|
6678
|
+
execSync29(cmd);
|
|
6568
6679
|
return true;
|
|
6569
6680
|
} catch {
|
|
6570
6681
|
}
|
|
@@ -6732,13 +6843,13 @@ async function auth() {
|
|
|
6732
6843
|
saveGlobalConfig(config);
|
|
6733
6844
|
const state = randomBytes(16).toString("hex");
|
|
6734
6845
|
console.log(
|
|
6735
|
-
|
|
6846
|
+
chalk56.yellow("\nEnsure this Redirect URI is set in your Roam OAuth app:")
|
|
6736
6847
|
);
|
|
6737
|
-
console.log(
|
|
6738
|
-
console.log(
|
|
6739
|
-
console.log(
|
|
6848
|
+
console.log(chalk56.white("http://localhost:14523/callback\n"));
|
|
6849
|
+
console.log(chalk56.blue("Opening browser for authorization..."));
|
|
6850
|
+
console.log(chalk56.dim("Waiting for authorization callback..."));
|
|
6740
6851
|
const { code, redirectUri } = await authorizeInBrowser(clientId, state);
|
|
6741
|
-
console.log(
|
|
6852
|
+
console.log(chalk56.dim("Exchanging code for tokens..."));
|
|
6742
6853
|
const tokens = await exchangeToken({
|
|
6743
6854
|
code,
|
|
6744
6855
|
clientId,
|
|
@@ -6754,7 +6865,7 @@ async function auth() {
|
|
|
6754
6865
|
};
|
|
6755
6866
|
saveGlobalConfig(config);
|
|
6756
6867
|
console.log(
|
|
6757
|
-
|
|
6868
|
+
chalk56.green("Roam credentials and tokens saved to ~/.assist.yml")
|
|
6758
6869
|
);
|
|
6759
6870
|
}
|
|
6760
6871
|
|
|
@@ -6942,14 +7053,14 @@ function run2(name, args) {
|
|
|
6942
7053
|
}
|
|
6943
7054
|
|
|
6944
7055
|
// src/commands/statusLine.ts
|
|
6945
|
-
import
|
|
7056
|
+
import chalk57 from "chalk";
|
|
6946
7057
|
function formatNumber(num) {
|
|
6947
7058
|
return num.toLocaleString("en-US");
|
|
6948
7059
|
}
|
|
6949
7060
|
function colorizePercent(pct) {
|
|
6950
7061
|
const label2 = `${pct}%`;
|
|
6951
|
-
if (pct > 80) return
|
|
6952
|
-
if (pct > 40) return
|
|
7062
|
+
if (pct > 80) return chalk57.red(label2);
|
|
7063
|
+
if (pct > 40) return chalk57.yellow(label2);
|
|
6953
7064
|
return label2;
|
|
6954
7065
|
}
|
|
6955
7066
|
async function statusLine() {
|
|
@@ -6975,7 +7086,7 @@ import { fileURLToPath as fileURLToPath7 } from "url";
|
|
|
6975
7086
|
// src/commands/sync/syncClaudeMd.ts
|
|
6976
7087
|
import * as fs21 from "fs";
|
|
6977
7088
|
import * as path31 from "path";
|
|
6978
|
-
import
|
|
7089
|
+
import chalk58 from "chalk";
|
|
6979
7090
|
async function syncClaudeMd(claudeDir, targetBase) {
|
|
6980
7091
|
const source = path31.join(claudeDir, "CLAUDE.md");
|
|
6981
7092
|
const target = path31.join(targetBase, "CLAUDE.md");
|
|
@@ -6984,12 +7095,12 @@ async function syncClaudeMd(claudeDir, targetBase) {
|
|
|
6984
7095
|
const targetContent = fs21.readFileSync(target, "utf-8");
|
|
6985
7096
|
if (sourceContent !== targetContent) {
|
|
6986
7097
|
console.log(
|
|
6987
|
-
|
|
7098
|
+
chalk58.yellow("\n\u26A0\uFE0F Warning: CLAUDE.md differs from existing file")
|
|
6988
7099
|
);
|
|
6989
7100
|
console.log();
|
|
6990
7101
|
printDiff(targetContent, sourceContent);
|
|
6991
7102
|
const confirm = await promptConfirm(
|
|
6992
|
-
|
|
7103
|
+
chalk58.red("Overwrite existing CLAUDE.md?"),
|
|
6993
7104
|
false
|
|
6994
7105
|
);
|
|
6995
7106
|
if (!confirm) {
|
|
@@ -7005,7 +7116,7 @@ async function syncClaudeMd(claudeDir, targetBase) {
|
|
|
7005
7116
|
// src/commands/sync/syncSettings.ts
|
|
7006
7117
|
import * as fs22 from "fs";
|
|
7007
7118
|
import * as path32 from "path";
|
|
7008
|
-
import
|
|
7119
|
+
import chalk59 from "chalk";
|
|
7009
7120
|
async function syncSettings(claudeDir, targetBase, options2) {
|
|
7010
7121
|
const source = path32.join(claudeDir, "settings.json");
|
|
7011
7122
|
const target = path32.join(targetBase, "settings.json");
|
|
@@ -7021,14 +7132,14 @@ async function syncSettings(claudeDir, targetBase, options2) {
|
|
|
7021
7132
|
if (mergedContent !== normalizedTarget) {
|
|
7022
7133
|
if (!options2?.yes) {
|
|
7023
7134
|
console.log(
|
|
7024
|
-
|
|
7135
|
+
chalk59.yellow(
|
|
7025
7136
|
"\n\u26A0\uFE0F Warning: settings.json differs from existing file"
|
|
7026
7137
|
)
|
|
7027
7138
|
);
|
|
7028
7139
|
console.log();
|
|
7029
7140
|
printDiff(targetContent, mergedContent);
|
|
7030
7141
|
const confirm = await promptConfirm(
|
|
7031
|
-
|
|
7142
|
+
chalk59.red("Overwrite existing settings.json?"),
|
|
7032
7143
|
false
|
|
7033
7144
|
);
|
|
7034
7145
|
if (!confirm) {
|
|
@@ -7065,7 +7176,7 @@ function syncCommands(claudeDir, targetBase) {
|
|
|
7065
7176
|
}
|
|
7066
7177
|
|
|
7067
7178
|
// src/commands/update.ts
|
|
7068
|
-
import { execSync as
|
|
7179
|
+
import { execSync as execSync30 } from "child_process";
|
|
7069
7180
|
import * as path34 from "path";
|
|
7070
7181
|
function isGlobalNpmInstall(dir) {
|
|
7071
7182
|
try {
|
|
@@ -7073,7 +7184,7 @@ function isGlobalNpmInstall(dir) {
|
|
|
7073
7184
|
if (resolved.split(path34.sep).includes("node_modules")) {
|
|
7074
7185
|
return true;
|
|
7075
7186
|
}
|
|
7076
|
-
const globalPrefix =
|
|
7187
|
+
const globalPrefix = execSync30("npm prefix -g", { stdio: "pipe" }).toString().trim();
|
|
7077
7188
|
return resolved.toLowerCase().startsWith(path34.resolve(globalPrefix).toLowerCase());
|
|
7078
7189
|
} catch {
|
|
7079
7190
|
return false;
|
|
@@ -7084,18 +7195,18 @@ async function update() {
|
|
|
7084
7195
|
console.log(`Assist is installed at: ${installDir}`);
|
|
7085
7196
|
if (isGitRepo(installDir)) {
|
|
7086
7197
|
console.log("Detected git repo installation, pulling latest...");
|
|
7087
|
-
|
|
7198
|
+
execSync30("git pull", { cwd: installDir, stdio: "inherit" });
|
|
7088
7199
|
console.log("Installing dependencies...");
|
|
7089
|
-
|
|
7200
|
+
execSync30("npm i", { cwd: installDir, stdio: "inherit" });
|
|
7090
7201
|
console.log("Building...");
|
|
7091
|
-
|
|
7202
|
+
execSync30("npm run build", { cwd: installDir, stdio: "inherit" });
|
|
7092
7203
|
console.log("Syncing commands...");
|
|
7093
|
-
|
|
7204
|
+
execSync30("assist sync", { stdio: "inherit" });
|
|
7094
7205
|
} else if (isGlobalNpmInstall(installDir)) {
|
|
7095
7206
|
console.log("Detected global npm installation, updating...");
|
|
7096
|
-
|
|
7207
|
+
execSync30("npm i -g @staff0rd/assist@latest", { stdio: "inherit" });
|
|
7097
7208
|
console.log("Syncing commands...");
|
|
7098
|
-
|
|
7209
|
+
execSync30("assist sync", { stdio: "inherit" });
|
|
7099
7210
|
} else {
|
|
7100
7211
|
console.error(
|
|
7101
7212
|
"Could not determine installation method. Expected a git repo or global npm install."
|