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