@staff0rd/assist 0.138.0 → 0.139.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 +2 -0
- package/claude/CLAUDE.md +3 -1
- package/claude/commands/commit.md +1 -0
- package/dist/index.js +858 -259
- package/package.json +1 -1
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.139.0",
|
|
10
10
|
type: "module",
|
|
11
11
|
main: "dist/index.js",
|
|
12
12
|
bin: {
|
|
@@ -90,10 +90,10 @@ import { stringify as stringifyYaml } from "yaml";
|
|
|
90
90
|
// src/shared/loadRawYaml.ts
|
|
91
91
|
import { existsSync, readFileSync } from "fs";
|
|
92
92
|
import { parse as parseYaml } from "yaml";
|
|
93
|
-
function loadRawYaml(
|
|
94
|
-
if (!existsSync(
|
|
93
|
+
function loadRawYaml(path49) {
|
|
94
|
+
if (!existsSync(path49)) return {};
|
|
95
95
|
try {
|
|
96
|
-
const content = readFileSync(
|
|
96
|
+
const content = readFileSync(path49, "utf-8");
|
|
97
97
|
return parseYaml(content) || {};
|
|
98
98
|
} catch {
|
|
99
99
|
return {};
|
|
@@ -370,9 +370,9 @@ function isTraversable(value) {
|
|
|
370
370
|
function stepInto(current, key) {
|
|
371
371
|
return isTraversable(current) ? current[key] : void 0;
|
|
372
372
|
}
|
|
373
|
-
function getNestedValue(obj,
|
|
373
|
+
function getNestedValue(obj, path49) {
|
|
374
374
|
let current = obj;
|
|
375
|
-
for (const key of
|
|
375
|
+
for (const key of path49.split(".")) current = stepInto(current, key);
|
|
376
376
|
return current;
|
|
377
377
|
}
|
|
378
378
|
|
|
@@ -413,8 +413,8 @@ function stepIntoNested(container, key, nextKey) {
|
|
|
413
413
|
}
|
|
414
414
|
return ensureObject(container, resolved);
|
|
415
415
|
}
|
|
416
|
-
function setNestedValue(obj,
|
|
417
|
-
const keys =
|
|
416
|
+
function setNestedValue(obj, path49, value) {
|
|
417
|
+
const keys = path49.split(".");
|
|
418
418
|
const result = { ...obj };
|
|
419
419
|
let current = result;
|
|
420
420
|
for (let i = 0; i < keys.length - 1; i++) {
|
|
@@ -3222,12 +3222,12 @@ function getCliReadsPath() {
|
|
|
3222
3222
|
var cachedLines;
|
|
3223
3223
|
function getCliReadsLines() {
|
|
3224
3224
|
if (cachedLines) return cachedLines;
|
|
3225
|
-
const
|
|
3226
|
-
if (!existsSync18(
|
|
3225
|
+
const path49 = getCliReadsPath();
|
|
3226
|
+
if (!existsSync18(path49)) {
|
|
3227
3227
|
cachedLines = [];
|
|
3228
3228
|
return cachedLines;
|
|
3229
3229
|
}
|
|
3230
|
-
cachedLines = readFileSync13(
|
|
3230
|
+
cachedLines = readFileSync13(path49, "utf-8").split("\n").filter((line) => line.trim() !== "");
|
|
3231
3231
|
return cachedLines;
|
|
3232
3232
|
}
|
|
3233
3233
|
function loadCliReads() {
|
|
@@ -3582,14 +3582,14 @@ function showProgress(p, label2) {
|
|
|
3582
3582
|
const pct = Math.round(p.done / p.total * 100);
|
|
3583
3583
|
process.stderr.write(`\r\x1B[K[${pct}%] Scanning ${label2}...`);
|
|
3584
3584
|
}
|
|
3585
|
-
async function resolveCommand(cli,
|
|
3586
|
-
showProgress(p,
|
|
3587
|
-
const subHelp = await runHelp([cli, ...
|
|
3585
|
+
async function resolveCommand(cli, path49, description, depth, p) {
|
|
3586
|
+
showProgress(p, path49.join(" "));
|
|
3587
|
+
const subHelp = await runHelp([cli, ...path49]);
|
|
3588
3588
|
if (!subHelp || !hasSubcommands(subHelp)) {
|
|
3589
|
-
return [{ path:
|
|
3589
|
+
return [{ path: path49, description }];
|
|
3590
3590
|
}
|
|
3591
|
-
const children = await discoverAt(cli,
|
|
3592
|
-
return children.length > 0 ? children : [{ path:
|
|
3591
|
+
const children = await discoverAt(cli, path49, depth + 1, p);
|
|
3592
|
+
return children.length > 0 ? children : [{ path: path49, description }];
|
|
3593
3593
|
}
|
|
3594
3594
|
async function discoverAt(cli, parentPath, depth, p) {
|
|
3595
3595
|
if (depth > SAFETY_DEPTH) return [];
|
|
@@ -3737,9 +3737,9 @@ function logPath(cli) {
|
|
|
3737
3737
|
return join13(homedir4(), ".assist", `cli-discover-${safeName}.log`);
|
|
3738
3738
|
}
|
|
3739
3739
|
function readCache(cli) {
|
|
3740
|
-
const
|
|
3741
|
-
if (!existsSync20(
|
|
3742
|
-
return readFileSync15(
|
|
3740
|
+
const path49 = logPath(cli);
|
|
3741
|
+
if (!existsSync20(path49)) return void 0;
|
|
3742
|
+
return readFileSync15(path49, "utf-8");
|
|
3743
3743
|
}
|
|
3744
3744
|
function writeCache(cli, output) {
|
|
3745
3745
|
const dir = join13(homedir4(), ".assist");
|
|
@@ -5570,10 +5570,10 @@ function getStorePath(filename) {
|
|
|
5570
5570
|
return join19(getStoreDir(), filename);
|
|
5571
5571
|
}
|
|
5572
5572
|
function loadJson(filename) {
|
|
5573
|
-
const
|
|
5574
|
-
if (existsSync26(
|
|
5573
|
+
const path49 = getStorePath(filename);
|
|
5574
|
+
if (existsSync26(path49)) {
|
|
5575
5575
|
try {
|
|
5576
|
-
return JSON.parse(readFileSync21(
|
|
5576
|
+
return JSON.parse(readFileSync21(path49, "utf-8"));
|
|
5577
5577
|
} catch {
|
|
5578
5578
|
return {};
|
|
5579
5579
|
}
|
|
@@ -5966,7 +5966,7 @@ function validateLine(line) {
|
|
|
5966
5966
|
process.exit(1);
|
|
5967
5967
|
}
|
|
5968
5968
|
}
|
|
5969
|
-
function comment(
|
|
5969
|
+
function comment(path49, line, body) {
|
|
5970
5970
|
validateBody(body);
|
|
5971
5971
|
validateLine(line);
|
|
5972
5972
|
try {
|
|
@@ -5986,7 +5986,7 @@ function comment(path44, line, body) {
|
|
|
5986
5986
|
"-f",
|
|
5987
5987
|
`body=${body}`,
|
|
5988
5988
|
"-f",
|
|
5989
|
-
`path=${
|
|
5989
|
+
`path=${path49}`,
|
|
5990
5990
|
"-F",
|
|
5991
5991
|
`line=${line}`
|
|
5992
5992
|
],
|
|
@@ -5995,7 +5995,7 @@ function comment(path44, line, body) {
|
|
|
5995
5995
|
if (result.status !== 0) {
|
|
5996
5996
|
throw new Error(result.stderr || result.stdout);
|
|
5997
5997
|
}
|
|
5998
|
-
console.log(`Added review comment on ${
|
|
5998
|
+
console.log(`Added review comment on ${path49}:${line}`);
|
|
5999
5999
|
} finally {
|
|
6000
6000
|
unlinkSync5(queryFile);
|
|
6001
6001
|
}
|
|
@@ -6494,8 +6494,8 @@ function registerPrs(program2) {
|
|
|
6494
6494
|
prsCommand.command("wontfix <comment-id> <reason>").description("Reply with reason and resolve thread").action((commentId, reason) => {
|
|
6495
6495
|
wontfix(Number.parseInt(commentId, 10), reason);
|
|
6496
6496
|
});
|
|
6497
|
-
prsCommand.command("comment <path> <line> <body>").description("Add a line comment to the pending review").action((
|
|
6498
|
-
comment(
|
|
6497
|
+
prsCommand.command("comment <path> <line> <body>").description("Add a line comment to the pending review").action((path49, line, body) => {
|
|
6498
|
+
comment(path49, Number.parseInt(line, 10), body);
|
|
6499
6499
|
});
|
|
6500
6500
|
}
|
|
6501
6501
|
|
|
@@ -6747,10 +6747,10 @@ function resolveOpSecret(reference) {
|
|
|
6747
6747
|
}
|
|
6748
6748
|
|
|
6749
6749
|
// src/commands/ravendb/ravenFetch.ts
|
|
6750
|
-
async function ravenFetch(connection,
|
|
6750
|
+
async function ravenFetch(connection, path49) {
|
|
6751
6751
|
const apiKey = resolveOpSecret(connection.apiKeyRef);
|
|
6752
6752
|
let accessToken = await getAccessToken(apiKey);
|
|
6753
|
-
const url = `${connection.url}${
|
|
6753
|
+
const url = `${connection.url}${path49}`;
|
|
6754
6754
|
const headers = {
|
|
6755
6755
|
Authorization: `Bearer ${accessToken}`,
|
|
6756
6756
|
"Content-Type": "application/json"
|
|
@@ -6840,16 +6840,16 @@ import chalk82 from "chalk";
|
|
|
6840
6840
|
// src/commands/ravendb/buildQueryPath.ts
|
|
6841
6841
|
function buildQueryPath(opts) {
|
|
6842
6842
|
const db = encodeURIComponent(opts.db);
|
|
6843
|
-
let
|
|
6843
|
+
let path49;
|
|
6844
6844
|
if (opts.collection) {
|
|
6845
|
-
|
|
6845
|
+
path49 = `/databases/${db}/indexes/dynamic/${encodeURIComponent(opts.collection)}?start=${opts.start}&pageSize=${opts.pageSize}&sort=${encodeURIComponent(opts.sort)}`;
|
|
6846
6846
|
} else {
|
|
6847
|
-
|
|
6847
|
+
path49 = `/databases/${db}/queries?start=${opts.start}&pageSize=${opts.pageSize}`;
|
|
6848
6848
|
}
|
|
6849
6849
|
if (opts.query) {
|
|
6850
|
-
|
|
6850
|
+
path49 += `&query=${encodeURIComponent(opts.query)}`;
|
|
6851
6851
|
}
|
|
6852
|
-
return
|
|
6852
|
+
return path49;
|
|
6853
6853
|
}
|
|
6854
6854
|
|
|
6855
6855
|
// src/commands/ravendb/fetchAllPages.ts
|
|
@@ -6858,7 +6858,7 @@ async function fetchAllPages(connection, opts) {
|
|
|
6858
6858
|
let start3 = 0;
|
|
6859
6859
|
while (true) {
|
|
6860
6860
|
const effectivePageSize = opts.limit !== void 0 ? Math.min(opts.pageSize, opts.limit - allResults.length) : opts.pageSize;
|
|
6861
|
-
const
|
|
6861
|
+
const path49 = buildQueryPath({
|
|
6862
6862
|
db: connection.database,
|
|
6863
6863
|
collection: opts.collection,
|
|
6864
6864
|
start: start3,
|
|
@@ -6866,7 +6866,7 @@ async function fetchAllPages(connection, opts) {
|
|
|
6866
6866
|
sort: opts.sort,
|
|
6867
6867
|
query: opts.query
|
|
6868
6868
|
});
|
|
6869
|
-
const data = await ravenFetch(connection,
|
|
6869
|
+
const data = await ravenFetch(connection, path49);
|
|
6870
6870
|
const results = data.Results ?? [];
|
|
6871
6871
|
const totalResults = data.TotalResults ?? 0;
|
|
6872
6872
|
if (results.length === 0) break;
|
|
@@ -7125,98 +7125,685 @@ async function check(pattern2, options2) {
|
|
|
7125
7125
|
}
|
|
7126
7126
|
}
|
|
7127
7127
|
|
|
7128
|
-
// src/commands/refactor/
|
|
7129
|
-
import
|
|
7128
|
+
// src/commands/refactor/extract/index.ts
|
|
7129
|
+
import path32 from "path";
|
|
7130
|
+
import chalk87 from "chalk";
|
|
7131
|
+
|
|
7132
|
+
// src/commands/refactor/extract/applyExtraction.ts
|
|
7133
|
+
import { SyntaxKind as SyntaxKind3 } from "ts-morph";
|
|
7134
|
+
|
|
7135
|
+
// src/commands/refactor/extract/removeStaleImports.ts
|
|
7136
|
+
import { SyntaxKind as SyntaxKind2 } from "ts-morph";
|
|
7137
|
+
function collectReferencedNames(sourceFile) {
|
|
7138
|
+
const names = /* @__PURE__ */ new Set();
|
|
7139
|
+
for (const id of sourceFile.getDescendantsOfKind(SyntaxKind2.Identifier)) {
|
|
7140
|
+
names.add(id.getText());
|
|
7141
|
+
}
|
|
7142
|
+
return names;
|
|
7143
|
+
}
|
|
7144
|
+
function isImportEmpty(importDecl, usedNames) {
|
|
7145
|
+
if (importDecl.getNamedImports().length > 0) return false;
|
|
7146
|
+
const def = importDecl.getDefaultImport();
|
|
7147
|
+
if (def && usedNames.has(def.getText())) return false;
|
|
7148
|
+
const ns = importDecl.getNamespaceImport();
|
|
7149
|
+
if (ns && usedNames.has(ns.getText())) return false;
|
|
7150
|
+
return true;
|
|
7151
|
+
}
|
|
7152
|
+
function removeStaleImports(sourceFile) {
|
|
7153
|
+
const usedNames = collectReferencedNames(sourceFile);
|
|
7154
|
+
for (const importDecl of sourceFile.getImportDeclarations()) {
|
|
7155
|
+
for (const ni of importDecl.getNamedImports()) {
|
|
7156
|
+
const name = ni.getAliasNode()?.getText() ?? ni.getName();
|
|
7157
|
+
if (!usedNames.has(name)) ni.remove();
|
|
7158
|
+
}
|
|
7159
|
+
if (isImportEmpty(importDecl, usedNames)) {
|
|
7160
|
+
importDecl.remove();
|
|
7161
|
+
}
|
|
7162
|
+
}
|
|
7163
|
+
}
|
|
7164
|
+
|
|
7165
|
+
// src/commands/refactor/extract/updateImporters.ts
|
|
7166
|
+
function updateImporters(functionName, sourceFile, importers) {
|
|
7167
|
+
for (const { file: importerFile, relPath: relPath2 } of importers) {
|
|
7168
|
+
let alias;
|
|
7169
|
+
for (const importDecl of importerFile.getImportDeclarations()) {
|
|
7170
|
+
if (importDecl.getModuleSpecifierSourceFile() !== sourceFile) continue;
|
|
7171
|
+
for (const ni of importDecl.getNamedImports()) {
|
|
7172
|
+
if (ni.getName() === functionName) {
|
|
7173
|
+
alias = ni.getAliasNode()?.getText();
|
|
7174
|
+
ni.remove();
|
|
7175
|
+
break;
|
|
7176
|
+
}
|
|
7177
|
+
}
|
|
7178
|
+
if (importDecl.getNamedImports().length === 0 && !importDecl.getDefaultImport() && !importDecl.getNamespaceImport()) {
|
|
7179
|
+
importDecl.remove();
|
|
7180
|
+
}
|
|
7181
|
+
}
|
|
7182
|
+
importerFile.addImportDeclaration({
|
|
7183
|
+
moduleSpecifier: relPath2,
|
|
7184
|
+
namedImports: [alias ? { name: functionName, alias } : functionName]
|
|
7185
|
+
});
|
|
7186
|
+
}
|
|
7187
|
+
}
|
|
7188
|
+
|
|
7189
|
+
// src/commands/refactor/extract/applyExtraction.ts
|
|
7190
|
+
function isNameReferencedInSource(sourceFile, name) {
|
|
7191
|
+
return sourceFile.getDescendantsOfKind(SyntaxKind3.Identifier).some((id) => id.getText() === name);
|
|
7192
|
+
}
|
|
7193
|
+
async function applyExtraction(functionName, sourceFile, destPath, plan2, project) {
|
|
7194
|
+
project.createSourceFile(destPath, plan2.destContent, { overwrite: false });
|
|
7195
|
+
for (const fn of [plan2.target, ...plan2.dependencies]) {
|
|
7196
|
+
fn.remove();
|
|
7197
|
+
}
|
|
7198
|
+
for (const stmt of plan2.statementsToRemove) {
|
|
7199
|
+
stmt.remove();
|
|
7200
|
+
}
|
|
7201
|
+
removeStaleImports(sourceFile);
|
|
7202
|
+
if (isNameReferencedInSource(sourceFile, functionName)) {
|
|
7203
|
+
sourceFile.addImportDeclaration({
|
|
7204
|
+
moduleSpecifier: plan2.destRelPath,
|
|
7205
|
+
namedImports: [functionName]
|
|
7206
|
+
});
|
|
7207
|
+
}
|
|
7208
|
+
updateImporters(functionName, sourceFile, plan2.importersToUpdate);
|
|
7209
|
+
if (plan2.barrel) {
|
|
7210
|
+
plan2.barrel.addExportDeclaration({
|
|
7211
|
+
moduleSpecifier: plan2.barrelRelPath,
|
|
7212
|
+
namedExports: [functionName]
|
|
7213
|
+
});
|
|
7214
|
+
}
|
|
7215
|
+
await project.save();
|
|
7216
|
+
}
|
|
7217
|
+
|
|
7218
|
+
// src/commands/refactor/extract/buildPlan.ts
|
|
7219
|
+
import path29 from "path";
|
|
7220
|
+
|
|
7221
|
+
// src/commands/refactor/extract/collectDependencies.ts
|
|
7222
|
+
import {
|
|
7223
|
+
SyntaxKind as SyntaxKind5
|
|
7224
|
+
} from "ts-morph";
|
|
7225
|
+
|
|
7226
|
+
// src/commands/refactor/extract/collectPrivateFunctions.ts
|
|
7227
|
+
import { SyntaxKind as SyntaxKind4 } from "ts-morph";
|
|
7228
|
+
function isPrivate(fn) {
|
|
7229
|
+
return !fn.isExported() && !fn.isDefaultExport();
|
|
7230
|
+
}
|
|
7231
|
+
function getCalledFunctionNames(fn) {
|
|
7232
|
+
const names = /* @__PURE__ */ new Set();
|
|
7233
|
+
for (const call of fn.getDescendantsOfKind(SyntaxKind4.CallExpression)) {
|
|
7234
|
+
const expr = call.getExpression();
|
|
7235
|
+
if (expr.getKind() === SyntaxKind4.Identifier) {
|
|
7236
|
+
names.add(expr.getText());
|
|
7237
|
+
}
|
|
7238
|
+
}
|
|
7239
|
+
return names;
|
|
7240
|
+
}
|
|
7241
|
+
function collectPrivateFunctions(target, fnMap) {
|
|
7242
|
+
const collected = /* @__PURE__ */ new Set();
|
|
7243
|
+
const queue = [target];
|
|
7244
|
+
let current = queue.pop();
|
|
7245
|
+
while (current) {
|
|
7246
|
+
for (const name of getCalledFunctionNames(current)) {
|
|
7247
|
+
if (collected.has(name)) continue;
|
|
7248
|
+
const fn = fnMap.get(name);
|
|
7249
|
+
if (fn && isPrivate(fn)) {
|
|
7250
|
+
collected.add(name);
|
|
7251
|
+
queue.push(fn);
|
|
7252
|
+
}
|
|
7253
|
+
}
|
|
7254
|
+
current = queue.pop();
|
|
7255
|
+
}
|
|
7256
|
+
return [...collected].flatMap((name) => {
|
|
7257
|
+
const fn = fnMap.get(name);
|
|
7258
|
+
return fn ? [fn] : [];
|
|
7259
|
+
});
|
|
7260
|
+
}
|
|
7261
|
+
|
|
7262
|
+
// src/commands/refactor/extract/getPrivateStatementMap.ts
|
|
7263
|
+
function getPrivateStatementMap(sourceFile) {
|
|
7264
|
+
const map = /* @__PURE__ */ new Map();
|
|
7265
|
+
for (const stmt of sourceFile.getVariableStatements()) {
|
|
7266
|
+
if (stmt.isExported()) continue;
|
|
7267
|
+
for (const decl of stmt.getDeclarations()) map.set(decl.getName(), stmt);
|
|
7268
|
+
}
|
|
7269
|
+
for (const alias of sourceFile.getTypeAliases()) {
|
|
7270
|
+
if (!alias.isExported()) map.set(alias.getName(), alias);
|
|
7271
|
+
}
|
|
7272
|
+
for (const iface of sourceFile.getInterfaces()) {
|
|
7273
|
+
if (!iface.isExported()) map.set(iface.getName(), iface);
|
|
7274
|
+
}
|
|
7275
|
+
return map;
|
|
7276
|
+
}
|
|
7277
|
+
|
|
7278
|
+
// src/commands/refactor/extract/collectDependencies.ts
|
|
7279
|
+
function getReferencedIdentifiers(fn) {
|
|
7280
|
+
const names = /* @__PURE__ */ new Set();
|
|
7281
|
+
for (const id of fn.getDescendantsOfKind(SyntaxKind5.Identifier)) {
|
|
7282
|
+
names.add(id.getText());
|
|
7283
|
+
}
|
|
7284
|
+
return names;
|
|
7285
|
+
}
|
|
7286
|
+
function getFunctionMap(sourceFile) {
|
|
7287
|
+
const map = /* @__PURE__ */ new Map();
|
|
7288
|
+
for (const fn of sourceFile.getDescendantsOfKind(
|
|
7289
|
+
SyntaxKind5.FunctionDeclaration
|
|
7290
|
+
)) {
|
|
7291
|
+
const name = fn.getName();
|
|
7292
|
+
if (name) map.set(name, fn);
|
|
7293
|
+
}
|
|
7294
|
+
return map;
|
|
7295
|
+
}
|
|
7296
|
+
function collectPrivateStatements(functions, stmtMap) {
|
|
7297
|
+
const seen = /* @__PURE__ */ new Set();
|
|
7298
|
+
for (const fn of functions) {
|
|
7299
|
+
for (const name of getReferencedIdentifiers(fn)) {
|
|
7300
|
+
const stmt = stmtMap.get(name);
|
|
7301
|
+
if (stmt) seen.add(stmt);
|
|
7302
|
+
}
|
|
7303
|
+
}
|
|
7304
|
+
return [...seen];
|
|
7305
|
+
}
|
|
7306
|
+
function getRemainingFunctions(sourceFile, extracted) {
|
|
7307
|
+
return sourceFile.getDescendantsOfKind(SyntaxKind5.FunctionDeclaration).filter((fn) => !extracted.has(fn));
|
|
7308
|
+
}
|
|
7309
|
+
function collectDependencies(target, sourceFile) {
|
|
7310
|
+
const fnMap = getFunctionMap(sourceFile);
|
|
7311
|
+
const depFunctions = collectPrivateFunctions(target, fnMap);
|
|
7312
|
+
const allExtracted = [target, ...depFunctions];
|
|
7313
|
+
const stmtMap = getPrivateStatementMap(sourceFile);
|
|
7314
|
+
const toCopy = collectPrivateStatements(allExtracted, stmtMap);
|
|
7315
|
+
const extractedSet = new Set(allExtracted);
|
|
7316
|
+
const remaining = getRemainingFunctions(sourceFile, extractedSet);
|
|
7317
|
+
const usedByRemaining = new Set(collectPrivateStatements(remaining, stmtMap));
|
|
7318
|
+
const toRemove = toCopy.filter((s) => !usedByRemaining.has(s));
|
|
7319
|
+
return {
|
|
7320
|
+
functions: depFunctions,
|
|
7321
|
+
statements: { toCopy, toRemove }
|
|
7322
|
+
};
|
|
7323
|
+
}
|
|
7324
|
+
|
|
7325
|
+
// src/commands/refactor/extract/findFunction.ts
|
|
7326
|
+
import {
|
|
7327
|
+
SyntaxKind as SyntaxKind6
|
|
7328
|
+
} from "ts-morph";
|
|
7329
|
+
function findFunction(sourceFile, functionName) {
|
|
7330
|
+
return sourceFile.getDescendantsOfKind(SyntaxKind6.FunctionDeclaration).find((fn) => fn.getName() === functionName);
|
|
7331
|
+
}
|
|
7332
|
+
|
|
7333
|
+
// src/commands/refactor/extract/getExportedDependencyNames.ts
|
|
7334
|
+
import { SyntaxKind as SyntaxKind7 } from "ts-morph";
|
|
7335
|
+
function getExportedDependencyNames(target, sourceFile) {
|
|
7336
|
+
const calledNames = /* @__PURE__ */ new Set();
|
|
7337
|
+
for (const call of target.getDescendantsOfKind(SyntaxKind7.CallExpression)) {
|
|
7338
|
+
const expr = call.getExpression();
|
|
7339
|
+
if (expr.getKind() === SyntaxKind7.Identifier) {
|
|
7340
|
+
calledNames.add(expr.getText());
|
|
7341
|
+
}
|
|
7342
|
+
}
|
|
7343
|
+
const exported = [];
|
|
7344
|
+
for (const fn of sourceFile.getDescendantsOfKind(
|
|
7345
|
+
SyntaxKind7.FunctionDeclaration
|
|
7346
|
+
)) {
|
|
7347
|
+
const name = fn.getName();
|
|
7348
|
+
if (name && calledNames.has(name) && fn.isExported()) {
|
|
7349
|
+
exported.push(name);
|
|
7350
|
+
}
|
|
7351
|
+
}
|
|
7352
|
+
return exported;
|
|
7353
|
+
}
|
|
7354
|
+
|
|
7355
|
+
// src/commands/refactor/extract/getStatementNames.ts
|
|
7356
|
+
import { SyntaxKind as SyntaxKind8 } from "ts-morph";
|
|
7357
|
+
function getStatementNames(node) {
|
|
7358
|
+
if (node.getKind() === SyntaxKind8.VariableStatement) {
|
|
7359
|
+
const stmt = node;
|
|
7360
|
+
return stmt.getDeclarations().map((d) => d.getName());
|
|
7361
|
+
}
|
|
7362
|
+
const named = node;
|
|
7363
|
+
return named.getName ? [named.getName()] : [];
|
|
7364
|
+
}
|
|
7365
|
+
|
|
7366
|
+
// src/commands/refactor/extract/resolveImports.ts
|
|
7367
|
+
import {
|
|
7368
|
+
SyntaxKind as SyntaxKind9
|
|
7369
|
+
} from "ts-morph";
|
|
7370
|
+
|
|
7371
|
+
// src/commands/refactor/extract/matchImport.ts
|
|
7372
|
+
function matchNamedImports(importDecl, neededNames) {
|
|
7373
|
+
const matched = [];
|
|
7374
|
+
for (const specifier of importDecl.getNamedImports()) {
|
|
7375
|
+
const name = specifier.getAliasNode()?.getText() ?? specifier.getName();
|
|
7376
|
+
if (!neededNames.has(name)) continue;
|
|
7377
|
+
const original = specifier.getName();
|
|
7378
|
+
const alias = specifier.getAliasNode()?.getText();
|
|
7379
|
+
matched.push(alias ? `${original} as ${alias}` : original);
|
|
7380
|
+
}
|
|
7381
|
+
return matched;
|
|
7382
|
+
}
|
|
7383
|
+
function matchOptionalImport(node, neededNames) {
|
|
7384
|
+
return node && neededNames.has(node.getText()) ? node.getText() : void 0;
|
|
7385
|
+
}
|
|
7386
|
+
function matchImport(importDecl, neededNames) {
|
|
7387
|
+
const namedImports = matchNamedImports(importDecl, neededNames);
|
|
7388
|
+
const defaultImport = matchOptionalImport(
|
|
7389
|
+
importDecl.getDefaultImport(),
|
|
7390
|
+
neededNames
|
|
7391
|
+
);
|
|
7392
|
+
const namespaceImport = matchOptionalImport(
|
|
7393
|
+
importDecl.getNamespaceImport(),
|
|
7394
|
+
neededNames
|
|
7395
|
+
);
|
|
7396
|
+
if (namedImports.length === 0 && !defaultImport && !namespaceImport) {
|
|
7397
|
+
return void 0;
|
|
7398
|
+
}
|
|
7399
|
+
return {
|
|
7400
|
+
moduleSpecifier: importDecl.getModuleSpecifierValue(),
|
|
7401
|
+
namedImports,
|
|
7402
|
+
defaultImport,
|
|
7403
|
+
namespaceImport,
|
|
7404
|
+
isTypeOnly: importDecl.isTypeOnly()
|
|
7405
|
+
};
|
|
7406
|
+
}
|
|
7407
|
+
|
|
7408
|
+
// src/commands/refactor/extract/resolveImports.ts
|
|
7409
|
+
function getReferencedNames(nodes) {
|
|
7410
|
+
const names = /* @__PURE__ */ new Set();
|
|
7411
|
+
for (const node of nodes) {
|
|
7412
|
+
for (const id of node.getDescendantsOfKind(SyntaxKind9.Identifier)) {
|
|
7413
|
+
names.add(id.getText());
|
|
7414
|
+
}
|
|
7415
|
+
}
|
|
7416
|
+
return names;
|
|
7417
|
+
}
|
|
7418
|
+
function getLocallyDeclaredNames(functions) {
|
|
7419
|
+
const names = /* @__PURE__ */ new Set();
|
|
7420
|
+
for (const fn of functions) {
|
|
7421
|
+
const name = fn.getName();
|
|
7422
|
+
if (name) names.add(name);
|
|
7423
|
+
for (const param of fn.getParameters()) {
|
|
7424
|
+
names.add(param.getName());
|
|
7425
|
+
}
|
|
7426
|
+
for (const varDecl of fn.getDescendantsOfKind(
|
|
7427
|
+
SyntaxKind9.VariableDeclaration
|
|
7428
|
+
)) {
|
|
7429
|
+
names.add(varDecl.getName());
|
|
7430
|
+
}
|
|
7431
|
+
}
|
|
7432
|
+
return names;
|
|
7433
|
+
}
|
|
7434
|
+
function resolveImports(target, dependencies, sourceFile, statements = []) {
|
|
7435
|
+
const allFunctions = [target, ...dependencies];
|
|
7436
|
+
const allNodes = [...allFunctions, ...statements];
|
|
7437
|
+
const referencedNames = getReferencedNames(allNodes);
|
|
7438
|
+
const localNames = getLocallyDeclaredNames(allFunctions);
|
|
7439
|
+
const externalNames = /* @__PURE__ */ new Set();
|
|
7440
|
+
for (const name of referencedNames) {
|
|
7441
|
+
if (!localNames.has(name)) externalNames.add(name);
|
|
7442
|
+
}
|
|
7443
|
+
const result = [];
|
|
7444
|
+
for (const importDecl of sourceFile.getImportDeclarations()) {
|
|
7445
|
+
const matched = matchImport(importDecl, externalNames);
|
|
7446
|
+
if (matched) result.push(matched);
|
|
7447
|
+
}
|
|
7448
|
+
return result;
|
|
7449
|
+
}
|
|
7450
|
+
|
|
7451
|
+
// src/commands/refactor/extract/analyseTarget.ts
|
|
7452
|
+
function extractTexts(target, allFunctions, statements) {
|
|
7453
|
+
const stmtTexts = statements.map((v) => v.getFullText().trim());
|
|
7454
|
+
const fnTexts = allFunctions.map((fn) => {
|
|
7455
|
+
const text = fn.getFullText().trim();
|
|
7456
|
+
if (fn === target && !text.startsWith("export ")) return `export ${text}`;
|
|
7457
|
+
return text;
|
|
7458
|
+
});
|
|
7459
|
+
return [...stmtTexts, ...fnTexts];
|
|
7460
|
+
}
|
|
7461
|
+
function analyseTarget(sourceFile, functionName) {
|
|
7462
|
+
const target = findFunction(sourceFile, functionName);
|
|
7463
|
+
if (!target) throw new Error(`Function "${functionName}" not found`);
|
|
7464
|
+
const { functions: dependencies, statements } = collectDependencies(
|
|
7465
|
+
target,
|
|
7466
|
+
sourceFile
|
|
7467
|
+
);
|
|
7468
|
+
const all = [target, ...dependencies];
|
|
7469
|
+
return {
|
|
7470
|
+
target,
|
|
7471
|
+
dependencies,
|
|
7472
|
+
statementsToCopy: statements.toCopy,
|
|
7473
|
+
statementsToRemove: statements.toRemove,
|
|
7474
|
+
imports: resolveImports(
|
|
7475
|
+
target,
|
|
7476
|
+
dependencies,
|
|
7477
|
+
sourceFile,
|
|
7478
|
+
statements.toCopy
|
|
7479
|
+
),
|
|
7480
|
+
exportedDeps: getExportedDependencyNames(target, sourceFile),
|
|
7481
|
+
extractedNames: [
|
|
7482
|
+
...statements.toRemove.flatMap(getStatementNames),
|
|
7483
|
+
...all.map((fn) => fn.getName()).filter(Boolean)
|
|
7484
|
+
],
|
|
7485
|
+
functionTexts: extractTexts(target, all, statements.toCopy)
|
|
7486
|
+
};
|
|
7487
|
+
}
|
|
7488
|
+
|
|
7489
|
+
// src/commands/refactor/extract/formatImportLine.ts
|
|
7490
|
+
function formatImportLine(imp) {
|
|
7491
|
+
const parts = [];
|
|
7492
|
+
if (imp.isTypeOnly) parts.push("type ");
|
|
7493
|
+
if (imp.defaultImport) parts.push(imp.defaultImport);
|
|
7494
|
+
if (imp.namespaceImport) parts.push(`* as ${imp.namespaceImport}`);
|
|
7495
|
+
if (imp.namedImports.length > 0) {
|
|
7496
|
+
if (imp.defaultImport) parts.push(", ");
|
|
7497
|
+
parts.push(`{ ${imp.namedImports.join(", ")} }`);
|
|
7498
|
+
}
|
|
7499
|
+
return `import ${parts.join("")} from "${imp.moduleSpecifier}";`;
|
|
7500
|
+
}
|
|
7501
|
+
|
|
7502
|
+
// src/commands/refactor/extract/buildDestinationContent.ts
|
|
7503
|
+
function buildDestinationContent(functionTexts, imports, sourceRelativePath, sourceImportNames) {
|
|
7504
|
+
const lines = [];
|
|
7505
|
+
for (const imp of imports) {
|
|
7506
|
+
lines.push(formatImportLine(imp));
|
|
7507
|
+
}
|
|
7508
|
+
if (sourceImportNames.length > 0) {
|
|
7509
|
+
lines.push(
|
|
7510
|
+
`import { ${sourceImportNames.join(", ")} } from "${sourceRelativePath}";`
|
|
7511
|
+
);
|
|
7512
|
+
}
|
|
7513
|
+
if (lines.length > 0) lines.push("");
|
|
7514
|
+
for (let i = 0; i < functionTexts.length; i++) {
|
|
7515
|
+
if (i > 0) lines.push("");
|
|
7516
|
+
lines.push(functionTexts[i]);
|
|
7517
|
+
}
|
|
7518
|
+
lines.push("");
|
|
7519
|
+
return lines.join("\n");
|
|
7520
|
+
}
|
|
7521
|
+
|
|
7522
|
+
// src/commands/refactor/extract/getRelativeImportPath.ts
|
|
7523
|
+
import path28 from "path";
|
|
7524
|
+
function getRelativeImportPath(from, to) {
|
|
7525
|
+
let rel = path28.relative(path28.dirname(from), to).replace(/\.tsx?$/, "").replace(/\\/g, "/");
|
|
7526
|
+
if (!rel.startsWith(".")) rel = `./${rel}`;
|
|
7527
|
+
return rel;
|
|
7528
|
+
}
|
|
7529
|
+
|
|
7530
|
+
// src/commands/refactor/extract/findImporters.ts
|
|
7531
|
+
function findImporters(functionName, sourceFile, destPath, project) {
|
|
7532
|
+
const result = [];
|
|
7533
|
+
for (const sf of project.getSourceFiles()) {
|
|
7534
|
+
if (sf === sourceFile) continue;
|
|
7535
|
+
for (const importDecl of sf.getImportDeclarations()) {
|
|
7536
|
+
if (importDecl.getModuleSpecifierSourceFile() !== sourceFile) continue;
|
|
7537
|
+
if (importDecl.getNamedImports().some((ni) => ni.getName() === functionName)) {
|
|
7538
|
+
result.push({
|
|
7539
|
+
file: sf,
|
|
7540
|
+
relPath: getRelativeImportPath(sf.getFilePath(), destPath)
|
|
7541
|
+
});
|
|
7542
|
+
}
|
|
7543
|
+
}
|
|
7544
|
+
}
|
|
7545
|
+
return result;
|
|
7546
|
+
}
|
|
7547
|
+
|
|
7548
|
+
// src/commands/refactor/extract/sourceReferencesName.ts
|
|
7549
|
+
import { SyntaxKind as SyntaxKind10 } from "ts-morph";
|
|
7550
|
+
var DECLARATION_KINDS = /* @__PURE__ */ new Set([
|
|
7551
|
+
SyntaxKind10.FunctionDeclaration,
|
|
7552
|
+
SyntaxKind10.ImportSpecifier,
|
|
7553
|
+
SyntaxKind10.ExportSpecifier
|
|
7554
|
+
]);
|
|
7555
|
+
function isInsideExtractedFunction(node, extracted) {
|
|
7556
|
+
let current = node;
|
|
7557
|
+
while (current) {
|
|
7558
|
+
if (current.getKind() !== SyntaxKind10.FunctionDeclaration) {
|
|
7559
|
+
current = current.getParent();
|
|
7560
|
+
continue;
|
|
7561
|
+
}
|
|
7562
|
+
const name = current.getName?.();
|
|
7563
|
+
if (name && extracted.has(name)) return true;
|
|
7564
|
+
current = current.getParent();
|
|
7565
|
+
}
|
|
7566
|
+
return false;
|
|
7567
|
+
}
|
|
7568
|
+
function sourceReferencesName(sourceFile, functionName, extractedNames) {
|
|
7569
|
+
const extracted = new Set(extractedNames);
|
|
7570
|
+
for (const id of sourceFile.getDescendantsOfKind(SyntaxKind10.Identifier)) {
|
|
7571
|
+
if (id.getText() !== functionName) continue;
|
|
7572
|
+
const parent = id.getParent();
|
|
7573
|
+
if (!parent || DECLARATION_KINDS.has(parent.getKind())) continue;
|
|
7574
|
+
if (!isInsideExtractedFunction(parent, extracted)) return true;
|
|
7575
|
+
}
|
|
7576
|
+
return false;
|
|
7577
|
+
}
|
|
7578
|
+
|
|
7579
|
+
// src/commands/refactor/extract/buildPlan.ts
|
|
7580
|
+
function resolveBarrel(destPath, project) {
|
|
7581
|
+
const indexPath = path29.join(path29.dirname(destPath), "index.ts");
|
|
7582
|
+
return {
|
|
7583
|
+
barrel: project.getSourceFile(indexPath),
|
|
7584
|
+
barrelRelPath: getRelativeImportPath(indexPath, destPath)
|
|
7585
|
+
};
|
|
7586
|
+
}
|
|
7587
|
+
function buildPlan(functionName, sourceFile, sourcePath, destPath, project) {
|
|
7588
|
+
const analysis = analyseTarget(sourceFile, functionName);
|
|
7589
|
+
const sourceRelPath = getRelativeImportPath(destPath, sourcePath);
|
|
7590
|
+
const { functionTexts: _, ...planFields } = analysis;
|
|
7591
|
+
return {
|
|
7592
|
+
...planFields,
|
|
7593
|
+
destContent: buildDestinationContent(
|
|
7594
|
+
analysis.functionTexts,
|
|
7595
|
+
analysis.imports,
|
|
7596
|
+
sourceRelPath,
|
|
7597
|
+
analysis.exportedDeps
|
|
7598
|
+
),
|
|
7599
|
+
destRelPath: getRelativeImportPath(sourcePath, destPath),
|
|
7600
|
+
sourceRelPath,
|
|
7601
|
+
sourceNeedsReimport: sourceReferencesName(
|
|
7602
|
+
sourceFile,
|
|
7603
|
+
functionName,
|
|
7604
|
+
analysis.extractedNames
|
|
7605
|
+
),
|
|
7606
|
+
importersToUpdate: analysis.target.isExported() ? findImporters(functionName, sourceFile, destPath, project) : [],
|
|
7607
|
+
...resolveBarrel(destPath, project)
|
|
7608
|
+
};
|
|
7609
|
+
}
|
|
7610
|
+
|
|
7611
|
+
// src/commands/refactor/extract/displayPlan.ts
|
|
7612
|
+
import path30 from "path";
|
|
7130
7613
|
import chalk85 from "chalk";
|
|
7614
|
+
function section(title) {
|
|
7615
|
+
return `
|
|
7616
|
+
${chalk85.cyan(title)}`;
|
|
7617
|
+
}
|
|
7618
|
+
function displayImporters(plan2, cwd) {
|
|
7619
|
+
if (plan2.importersToUpdate.length === 0) return;
|
|
7620
|
+
console.log(section("Update importers:"));
|
|
7621
|
+
for (const imp of plan2.importersToUpdate) {
|
|
7622
|
+
const rel = path30.relative(cwd, imp.file.getFilePath());
|
|
7623
|
+
console.log(` ${chalk85.dim(rel)}: \u2192 import from "${imp.relPath}"`);
|
|
7624
|
+
}
|
|
7625
|
+
}
|
|
7626
|
+
function displayPlan(functionName, relDest, plan2, cwd) {
|
|
7627
|
+
console.log(chalk85.bold(`Extract: ${functionName} \u2192 ${relDest}
|
|
7628
|
+
`));
|
|
7629
|
+
console.log(` ${chalk85.cyan("Functions to move:")}`);
|
|
7630
|
+
for (const name of plan2.extractedNames) {
|
|
7631
|
+
console.log(` ${name}`);
|
|
7632
|
+
}
|
|
7633
|
+
if (plan2.imports.length > 0) {
|
|
7634
|
+
console.log(section("Imports to copy:"));
|
|
7635
|
+
for (const imp of plan2.imports) {
|
|
7636
|
+
console.log(` ${formatImportLine(imp)}`);
|
|
7637
|
+
}
|
|
7638
|
+
}
|
|
7639
|
+
if (plan2.exportedDeps.length > 0) {
|
|
7640
|
+
console.log(section("New imports from source:"));
|
|
7641
|
+
console.log(
|
|
7642
|
+
` import { ${plan2.exportedDeps.join(", ")} } from "${plan2.sourceRelPath}";`
|
|
7643
|
+
);
|
|
7644
|
+
}
|
|
7645
|
+
console.log(section("Source file changes:"));
|
|
7646
|
+
console.log(` Remove: ${plan2.extractedNames.join(", ")}`);
|
|
7647
|
+
if (plan2.sourceNeedsReimport) {
|
|
7648
|
+
console.log(
|
|
7649
|
+
` Add: import { ${functionName} } from "${plan2.destRelPath}";`
|
|
7650
|
+
);
|
|
7651
|
+
}
|
|
7652
|
+
displayImporters(plan2, cwd);
|
|
7653
|
+
if (plan2.barrel) {
|
|
7654
|
+
console.log(section("Barrel export:"));
|
|
7655
|
+
console.log(
|
|
7656
|
+
` Add: export { ${functionName} } from "${plan2.barrelRelPath}";`
|
|
7657
|
+
);
|
|
7658
|
+
}
|
|
7659
|
+
}
|
|
7660
|
+
|
|
7661
|
+
// src/commands/refactor/extract/loadProjectFile.ts
|
|
7662
|
+
import fs17 from "fs";
|
|
7663
|
+
import path31 from "path";
|
|
7664
|
+
import chalk86 from "chalk";
|
|
7665
|
+
import { Project as Project2 } from "ts-morph";
|
|
7666
|
+
function findTsConfig(sourcePath) {
|
|
7667
|
+
const rootConfig = path31.resolve("tsconfig.json");
|
|
7668
|
+
if (!fs17.existsSync(rootConfig)) return rootConfig;
|
|
7669
|
+
const raw = fs17.readFileSync(rootConfig, "utf-8");
|
|
7670
|
+
const stripped = raw.replace(/\/\/.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "");
|
|
7671
|
+
let parsed;
|
|
7672
|
+
try {
|
|
7673
|
+
parsed = JSON.parse(stripped);
|
|
7674
|
+
} catch {
|
|
7675
|
+
return rootConfig;
|
|
7676
|
+
}
|
|
7677
|
+
if (!parsed.references?.length) return rootConfig;
|
|
7678
|
+
for (const ref of parsed.references) {
|
|
7679
|
+
const refPath = path31.resolve(ref.path);
|
|
7680
|
+
const configPath = fs17.statSync(refPath, { throwIfNoEntry: false })?.isDirectory() ? path31.join(refPath, "tsconfig.json") : refPath;
|
|
7681
|
+
if (!fs17.existsSync(configPath)) continue;
|
|
7682
|
+
const project = new Project2({ tsConfigFilePath: configPath });
|
|
7683
|
+
if (project.getSourceFile(sourcePath)) return configPath;
|
|
7684
|
+
}
|
|
7685
|
+
return rootConfig;
|
|
7686
|
+
}
|
|
7687
|
+
function loadProjectFile(file) {
|
|
7688
|
+
const sourcePath = path31.resolve(file);
|
|
7689
|
+
const tsConfigPath = findTsConfig(sourcePath);
|
|
7690
|
+
const project = new Project2({
|
|
7691
|
+
tsConfigFilePath: tsConfigPath
|
|
7692
|
+
});
|
|
7693
|
+
const sourceFile = project.getSourceFile(sourcePath);
|
|
7694
|
+
if (!sourceFile) {
|
|
7695
|
+
console.log(chalk86.red(`File not found in project: ${file}`));
|
|
7696
|
+
process.exit(1);
|
|
7697
|
+
}
|
|
7698
|
+
return { project, sourceFile };
|
|
7699
|
+
}
|
|
7700
|
+
|
|
7701
|
+
// src/commands/refactor/extract/index.ts
|
|
7702
|
+
async function extract(file, functionName, destination, options2 = {}) {
|
|
7703
|
+
const sourcePath = path32.resolve(file);
|
|
7704
|
+
const destPath = path32.resolve(destination);
|
|
7705
|
+
const cwd = process.cwd();
|
|
7706
|
+
const relDest = path32.relative(cwd, destPath);
|
|
7707
|
+
const { project, sourceFile } = loadProjectFile(file);
|
|
7708
|
+
const plan2 = buildPlan(
|
|
7709
|
+
functionName,
|
|
7710
|
+
sourceFile,
|
|
7711
|
+
sourcePath,
|
|
7712
|
+
destPath,
|
|
7713
|
+
project
|
|
7714
|
+
);
|
|
7715
|
+
displayPlan(functionName, relDest, plan2, cwd);
|
|
7716
|
+
if (options2.apply) {
|
|
7717
|
+
await applyExtraction(functionName, sourceFile, destPath, plan2, project);
|
|
7718
|
+
console.log(chalk87.green("\nExtraction complete"));
|
|
7719
|
+
} else {
|
|
7720
|
+
console.log(chalk87.dim("\nDry run. Use --apply to execute."));
|
|
7721
|
+
}
|
|
7722
|
+
}
|
|
7723
|
+
|
|
7724
|
+
// src/commands/refactor/ignore.ts
|
|
7725
|
+
import fs18 from "fs";
|
|
7726
|
+
import chalk88 from "chalk";
|
|
7131
7727
|
var REFACTOR_YML_PATH2 = "refactor.yml";
|
|
7132
7728
|
function ignore(file) {
|
|
7133
|
-
if (!
|
|
7134
|
-
console.error(
|
|
7729
|
+
if (!fs18.existsSync(file)) {
|
|
7730
|
+
console.error(chalk88.red(`Error: File does not exist: ${file}`));
|
|
7135
7731
|
process.exit(1);
|
|
7136
7732
|
}
|
|
7137
|
-
const content =
|
|
7733
|
+
const content = fs18.readFileSync(file, "utf-8");
|
|
7138
7734
|
const lineCount = content.split("\n").length;
|
|
7139
7735
|
const maxLines = lineCount + 10;
|
|
7140
7736
|
const entry = `- file: ${file}
|
|
7141
7737
|
maxLines: ${maxLines}
|
|
7142
7738
|
`;
|
|
7143
|
-
if (
|
|
7144
|
-
const existing =
|
|
7145
|
-
|
|
7739
|
+
if (fs18.existsSync(REFACTOR_YML_PATH2)) {
|
|
7740
|
+
const existing = fs18.readFileSync(REFACTOR_YML_PATH2, "utf-8");
|
|
7741
|
+
fs18.writeFileSync(REFACTOR_YML_PATH2, existing + entry);
|
|
7146
7742
|
} else {
|
|
7147
|
-
|
|
7743
|
+
fs18.writeFileSync(REFACTOR_YML_PATH2, entry);
|
|
7148
7744
|
}
|
|
7149
7745
|
console.log(
|
|
7150
|
-
|
|
7746
|
+
chalk88.green(
|
|
7151
7747
|
`Added ${file} to refactor ignore list (max ${maxLines} lines)`
|
|
7152
7748
|
)
|
|
7153
7749
|
);
|
|
7154
7750
|
}
|
|
7155
7751
|
|
|
7156
7752
|
// src/commands/refactor/rename/index.ts
|
|
7157
|
-
import
|
|
7158
|
-
import
|
|
7159
|
-
import { Project as Project2 } from "ts-morph";
|
|
7753
|
+
import path33 from "path";
|
|
7754
|
+
import chalk89 from "chalk";
|
|
7160
7755
|
async function rename(source, destination, options2 = {}) {
|
|
7161
|
-
const
|
|
7162
|
-
const destPath = path28.resolve(destination);
|
|
7756
|
+
const destPath = path33.resolve(destination);
|
|
7163
7757
|
const cwd = process.cwd();
|
|
7164
|
-
const relSource =
|
|
7165
|
-
const relDest =
|
|
7166
|
-
const project =
|
|
7167
|
-
|
|
7168
|
-
});
|
|
7169
|
-
const sourceFile = project.getSourceFile(sourcePath);
|
|
7170
|
-
if (!sourceFile) {
|
|
7171
|
-
console.log(chalk86.red(`File not found in project: ${source}`));
|
|
7172
|
-
process.exit(1);
|
|
7173
|
-
}
|
|
7174
|
-
console.log(chalk86.bold(`Rename: ${relSource} \u2192 ${relDest}`));
|
|
7758
|
+
const relSource = path33.relative(cwd, path33.resolve(source));
|
|
7759
|
+
const relDest = path33.relative(cwd, destPath);
|
|
7760
|
+
const { project, sourceFile } = loadProjectFile(source);
|
|
7761
|
+
console.log(chalk89.bold(`Rename: ${relSource} \u2192 ${relDest}`));
|
|
7175
7762
|
if (options2.apply) {
|
|
7176
7763
|
sourceFile.move(destPath);
|
|
7177
7764
|
await project.save();
|
|
7178
|
-
console.log(
|
|
7765
|
+
console.log(chalk89.green("Done"));
|
|
7179
7766
|
} else {
|
|
7180
|
-
console.log(
|
|
7767
|
+
console.log(chalk89.dim("Dry run. Use --apply to execute."));
|
|
7181
7768
|
}
|
|
7182
7769
|
}
|
|
7183
7770
|
|
|
7184
7771
|
// src/commands/refactor/renameSymbol/index.ts
|
|
7185
|
-
import
|
|
7186
|
-
import
|
|
7772
|
+
import path35 from "path";
|
|
7773
|
+
import chalk90 from "chalk";
|
|
7187
7774
|
import { Project as Project3 } from "ts-morph";
|
|
7188
7775
|
|
|
7189
7776
|
// src/commands/refactor/renameSymbol/findSymbol.ts
|
|
7190
|
-
import { SyntaxKind as
|
|
7777
|
+
import { SyntaxKind as SyntaxKind11 } from "ts-morph";
|
|
7191
7778
|
var declarationKinds = [
|
|
7192
|
-
|
|
7193
|
-
|
|
7194
|
-
|
|
7195
|
-
|
|
7196
|
-
|
|
7197
|
-
|
|
7198
|
-
|
|
7199
|
-
|
|
7200
|
-
|
|
7779
|
+
SyntaxKind11.VariableDeclaration,
|
|
7780
|
+
SyntaxKind11.FunctionDeclaration,
|
|
7781
|
+
SyntaxKind11.ClassDeclaration,
|
|
7782
|
+
SyntaxKind11.InterfaceDeclaration,
|
|
7783
|
+
SyntaxKind11.TypeAliasDeclaration,
|
|
7784
|
+
SyntaxKind11.EnumDeclaration,
|
|
7785
|
+
SyntaxKind11.PropertyDeclaration,
|
|
7786
|
+
SyntaxKind11.MethodDeclaration,
|
|
7787
|
+
SyntaxKind11.Parameter
|
|
7201
7788
|
];
|
|
7202
7789
|
function isDeclaration(identifier) {
|
|
7203
7790
|
const parent = identifier.getParent();
|
|
7204
7791
|
return parent !== void 0 && declarationKinds.includes(parent.getKind());
|
|
7205
7792
|
}
|
|
7206
7793
|
function findSymbol(sourceFile, symbolName) {
|
|
7207
|
-
for (const id of sourceFile.getDescendantsOfKind(
|
|
7794
|
+
for (const id of sourceFile.getDescendantsOfKind(SyntaxKind11.Identifier)) {
|
|
7208
7795
|
if (id.getText() === symbolName && isDeclaration(id)) return id;
|
|
7209
7796
|
}
|
|
7210
7797
|
return void 0;
|
|
7211
7798
|
}
|
|
7212
7799
|
|
|
7213
7800
|
// src/commands/refactor/renameSymbol/groupReferences.ts
|
|
7214
|
-
import
|
|
7801
|
+
import path34 from "path";
|
|
7215
7802
|
function groupReferences(symbol, cwd) {
|
|
7216
7803
|
const refs = symbol.findReferencesAsNodes();
|
|
7217
7804
|
const grouped = /* @__PURE__ */ new Map();
|
|
7218
7805
|
for (const ref of refs) {
|
|
7219
|
-
const refFile =
|
|
7806
|
+
const refFile = path34.relative(cwd, ref.getSourceFile().getFilePath());
|
|
7220
7807
|
const lines = grouped.get(refFile) ?? [];
|
|
7221
7808
|
if (!grouped.has(refFile)) grouped.set(refFile, lines);
|
|
7222
7809
|
lines.push(ref.getStartLineNumber());
|
|
@@ -7226,47 +7813,47 @@ function groupReferences(symbol, cwd) {
|
|
|
7226
7813
|
|
|
7227
7814
|
// src/commands/refactor/renameSymbol/index.ts
|
|
7228
7815
|
async function renameSymbol(file, oldName, newName, options2 = {}) {
|
|
7229
|
-
const filePath =
|
|
7230
|
-
const tsConfigPath =
|
|
7816
|
+
const filePath = path35.resolve(file);
|
|
7817
|
+
const tsConfigPath = path35.resolve("tsconfig.json");
|
|
7231
7818
|
const cwd = process.cwd();
|
|
7232
7819
|
const project = new Project3({ tsConfigFilePath: tsConfigPath });
|
|
7233
7820
|
const sourceFile = project.getSourceFile(filePath);
|
|
7234
7821
|
if (!sourceFile) {
|
|
7235
|
-
console.log(
|
|
7822
|
+
console.log(chalk90.red(`File not found in project: ${file}`));
|
|
7236
7823
|
process.exit(1);
|
|
7237
7824
|
}
|
|
7238
7825
|
const symbol = findSymbol(sourceFile, oldName);
|
|
7239
7826
|
if (!symbol) {
|
|
7240
|
-
console.log(
|
|
7827
|
+
console.log(chalk90.red(`Symbol "${oldName}" not found in ${file}`));
|
|
7241
7828
|
process.exit(1);
|
|
7242
7829
|
}
|
|
7243
7830
|
const grouped = groupReferences(symbol, cwd);
|
|
7244
7831
|
const totalRefs = [...grouped.values()].reduce((s, l) => s + l.length, 0);
|
|
7245
7832
|
console.log(
|
|
7246
|
-
|
|
7833
|
+
chalk90.bold(`Rename: ${oldName} \u2192 ${newName} (${totalRefs} references)
|
|
7247
7834
|
`)
|
|
7248
7835
|
);
|
|
7249
7836
|
for (const [refFile, lines] of grouped) {
|
|
7250
7837
|
console.log(
|
|
7251
|
-
` ${
|
|
7838
|
+
` ${chalk90.dim(refFile)}: lines ${chalk90.cyan(lines.join(", "))}`
|
|
7252
7839
|
);
|
|
7253
7840
|
}
|
|
7254
7841
|
if (options2.apply) {
|
|
7255
7842
|
symbol.rename(newName);
|
|
7256
7843
|
await project.save();
|
|
7257
|
-
console.log(
|
|
7844
|
+
console.log(chalk90.green(`
|
|
7258
7845
|
Renamed ${oldName} \u2192 ${newName}`));
|
|
7259
7846
|
} else {
|
|
7260
|
-
console.log(
|
|
7847
|
+
console.log(chalk90.dim("\nDry run. Use --apply to execute."));
|
|
7261
7848
|
}
|
|
7262
7849
|
}
|
|
7263
7850
|
|
|
7264
7851
|
// src/commands/refactor/restructure/index.ts
|
|
7265
|
-
import
|
|
7266
|
-
import
|
|
7852
|
+
import path44 from "path";
|
|
7853
|
+
import chalk93 from "chalk";
|
|
7267
7854
|
|
|
7268
7855
|
// src/commands/refactor/restructure/buildImportGraph/index.ts
|
|
7269
|
-
import
|
|
7856
|
+
import path36 from "path";
|
|
7270
7857
|
import ts7 from "typescript";
|
|
7271
7858
|
|
|
7272
7859
|
// src/commands/refactor/restructure/buildImportGraph/getImportSpecifiers.ts
|
|
@@ -7293,7 +7880,7 @@ function loadParsedConfig(tsConfigPath) {
|
|
|
7293
7880
|
return ts7.parseJsonConfigFileContent(
|
|
7294
7881
|
configFile.config,
|
|
7295
7882
|
ts7.sys,
|
|
7296
|
-
|
|
7883
|
+
path36.dirname(tsConfigPath)
|
|
7297
7884
|
);
|
|
7298
7885
|
}
|
|
7299
7886
|
function addToSetMap(map, key, value) {
|
|
@@ -7309,7 +7896,7 @@ function resolveImport(specifier, filePath, options2) {
|
|
|
7309
7896
|
const resolved = ts7.resolveModuleName(specifier, filePath, options2, ts7.sys);
|
|
7310
7897
|
const resolvedPath = resolved.resolvedModule?.resolvedFileName;
|
|
7311
7898
|
if (!resolvedPath || resolvedPath.includes("node_modules")) return null;
|
|
7312
|
-
return
|
|
7899
|
+
return path36.resolve(resolvedPath);
|
|
7313
7900
|
}
|
|
7314
7901
|
function buildImportGraph(candidateFiles, tsConfigPath) {
|
|
7315
7902
|
const parsed = loadParsedConfig(tsConfigPath);
|
|
@@ -7318,7 +7905,7 @@ function buildImportGraph(candidateFiles, tsConfigPath) {
|
|
|
7318
7905
|
const importedBy = /* @__PURE__ */ new Map();
|
|
7319
7906
|
const imports = /* @__PURE__ */ new Map();
|
|
7320
7907
|
for (const sourceFile of program2.getSourceFiles()) {
|
|
7321
|
-
const filePath =
|
|
7908
|
+
const filePath = path36.resolve(sourceFile.fileName);
|
|
7322
7909
|
if (filePath.includes("node_modules")) continue;
|
|
7323
7910
|
for (const specifier of getImportSpecifiers(sourceFile)) {
|
|
7324
7911
|
const absTarget = resolveImport(specifier, filePath, parsed.options);
|
|
@@ -7332,12 +7919,12 @@ function buildImportGraph(candidateFiles, tsConfigPath) {
|
|
|
7332
7919
|
}
|
|
7333
7920
|
|
|
7334
7921
|
// src/commands/refactor/restructure/clusterDirectories.ts
|
|
7335
|
-
import
|
|
7922
|
+
import path37 from "path";
|
|
7336
7923
|
function clusterDirectories(graph) {
|
|
7337
7924
|
const dirImportedBy = /* @__PURE__ */ new Map();
|
|
7338
7925
|
for (const edge of graph.edges) {
|
|
7339
|
-
const sourceDir =
|
|
7340
|
-
const targetDir =
|
|
7926
|
+
const sourceDir = path37.dirname(edge.source);
|
|
7927
|
+
const targetDir = path37.dirname(edge.target);
|
|
7341
7928
|
if (sourceDir === targetDir) continue;
|
|
7342
7929
|
if (!graph.files.has(edge.target)) continue;
|
|
7343
7930
|
const existing = dirImportedBy.get(targetDir) ?? /* @__PURE__ */ new Set();
|
|
@@ -7365,20 +7952,20 @@ function clusterDirectories(graph) {
|
|
|
7365
7952
|
return clusters;
|
|
7366
7953
|
}
|
|
7367
7954
|
function isAncestor(ancestor, descendant) {
|
|
7368
|
-
const rel =
|
|
7955
|
+
const rel = path37.relative(ancestor, descendant);
|
|
7369
7956
|
return !rel.startsWith("..") && rel !== "";
|
|
7370
7957
|
}
|
|
7371
7958
|
|
|
7372
7959
|
// src/commands/refactor/restructure/clusterFiles.ts
|
|
7373
|
-
import
|
|
7960
|
+
import path38 from "path";
|
|
7374
7961
|
function findRootParent(file, importedBy, visited) {
|
|
7375
7962
|
const importers = importedBy.get(file);
|
|
7376
7963
|
if (!importers || importers.size !== 1) return file;
|
|
7377
7964
|
const parent = [...importers][0];
|
|
7378
|
-
const parentDir =
|
|
7379
|
-
const fileDir =
|
|
7965
|
+
const parentDir = path38.dirname(parent);
|
|
7966
|
+
const fileDir = path38.dirname(file);
|
|
7380
7967
|
if (parentDir !== fileDir) return file;
|
|
7381
|
-
if (
|
|
7968
|
+
if (path38.basename(parent, path38.extname(parent)) === "index") return file;
|
|
7382
7969
|
if (visited.has(parent)) return file;
|
|
7383
7970
|
visited.add(parent);
|
|
7384
7971
|
return findRootParent(parent, importedBy, visited);
|
|
@@ -7386,16 +7973,16 @@ function findRootParent(file, importedBy, visited) {
|
|
|
7386
7973
|
function clusterFiles(graph) {
|
|
7387
7974
|
const clusters = /* @__PURE__ */ new Map();
|
|
7388
7975
|
for (const file of graph.files) {
|
|
7389
|
-
const basename7 =
|
|
7976
|
+
const basename7 = path38.basename(file, path38.extname(file));
|
|
7390
7977
|
if (basename7 === "index") continue;
|
|
7391
7978
|
const importers = graph.importedBy.get(file);
|
|
7392
7979
|
if (!importers || importers.size !== 1) continue;
|
|
7393
7980
|
const parent = [...importers][0];
|
|
7394
7981
|
if (!graph.files.has(parent)) continue;
|
|
7395
|
-
const parentDir =
|
|
7396
|
-
const fileDir =
|
|
7982
|
+
const parentDir = path38.dirname(parent);
|
|
7983
|
+
const fileDir = path38.dirname(file);
|
|
7397
7984
|
if (parentDir !== fileDir) continue;
|
|
7398
|
-
const parentBasename =
|
|
7985
|
+
const parentBasename = path38.basename(parent, path38.extname(parent));
|
|
7399
7986
|
if (parentBasename === "index") continue;
|
|
7400
7987
|
const root = findRootParent(parent, graph.importedBy, /* @__PURE__ */ new Set([file]));
|
|
7401
7988
|
if (!root || root === file) continue;
|
|
@@ -7407,10 +7994,10 @@ function clusterFiles(graph) {
|
|
|
7407
7994
|
}
|
|
7408
7995
|
|
|
7409
7996
|
// src/commands/refactor/restructure/computeRewrites/index.ts
|
|
7410
|
-
import
|
|
7997
|
+
import path39 from "path";
|
|
7411
7998
|
|
|
7412
7999
|
// src/commands/refactor/restructure/computeRewrites/applyRewrites.ts
|
|
7413
|
-
import
|
|
8000
|
+
import fs19 from "fs";
|
|
7414
8001
|
function getOrCreateList(map, key) {
|
|
7415
8002
|
const list4 = map.get(key) ?? [];
|
|
7416
8003
|
if (!map.has(key)) map.set(key, list4);
|
|
@@ -7429,7 +8016,7 @@ function rewriteSpecifier(content, oldSpecifier, newSpecifier) {
|
|
|
7429
8016
|
return content.replace(pattern2, `$1${newSpecifier}$2`);
|
|
7430
8017
|
}
|
|
7431
8018
|
function applyFileRewrites(file, fileRewrites) {
|
|
7432
|
-
let content =
|
|
8019
|
+
let content = fs19.readFileSync(file, "utf-8");
|
|
7433
8020
|
for (const { oldSpecifier, newSpecifier } of fileRewrites) {
|
|
7434
8021
|
content = rewriteSpecifier(content, oldSpecifier, newSpecifier);
|
|
7435
8022
|
}
|
|
@@ -7461,7 +8048,7 @@ function normalizeSpecifier(rel) {
|
|
|
7461
8048
|
);
|
|
7462
8049
|
}
|
|
7463
8050
|
function computeSpecifier(fromFile, toFile) {
|
|
7464
|
-
return normalizeSpecifier(
|
|
8051
|
+
return normalizeSpecifier(path39.relative(path39.dirname(fromFile), toFile));
|
|
7465
8052
|
}
|
|
7466
8053
|
function isAffected(edge, moveMap) {
|
|
7467
8054
|
return moveMap.has(edge.target) || moveMap.has(edge.source);
|
|
@@ -7505,51 +8092,51 @@ function computeRewrites(moves, edges, allProjectFiles) {
|
|
|
7505
8092
|
}
|
|
7506
8093
|
|
|
7507
8094
|
// src/commands/refactor/restructure/displayPlan.ts
|
|
7508
|
-
import
|
|
7509
|
-
import
|
|
8095
|
+
import path40 from "path";
|
|
8096
|
+
import chalk91 from "chalk";
|
|
7510
8097
|
function relPath(filePath) {
|
|
7511
|
-
return
|
|
8098
|
+
return path40.relative(process.cwd(), filePath);
|
|
7512
8099
|
}
|
|
7513
8100
|
function displayMoves(plan2) {
|
|
7514
8101
|
if (plan2.moves.length === 0) return;
|
|
7515
|
-
console.log(
|
|
8102
|
+
console.log(chalk91.bold("\nFile moves:"));
|
|
7516
8103
|
for (const move of plan2.moves) {
|
|
7517
8104
|
console.log(
|
|
7518
|
-
` ${
|
|
8105
|
+
` ${chalk91.red(relPath(move.from))} \u2192 ${chalk91.green(relPath(move.to))}`
|
|
7519
8106
|
);
|
|
7520
|
-
console.log(
|
|
8107
|
+
console.log(chalk91.dim(` ${move.reason}`));
|
|
7521
8108
|
}
|
|
7522
8109
|
}
|
|
7523
8110
|
function displayRewrites(rewrites) {
|
|
7524
8111
|
if (rewrites.length === 0) return;
|
|
7525
8112
|
const affectedFiles = new Set(rewrites.map((r) => r.file));
|
|
7526
|
-
console.log(
|
|
8113
|
+
console.log(chalk91.bold(`
|
|
7527
8114
|
Import rewrites (${affectedFiles.size} files):`));
|
|
7528
8115
|
for (const file of affectedFiles) {
|
|
7529
|
-
console.log(` ${
|
|
8116
|
+
console.log(` ${chalk91.cyan(relPath(file))}:`);
|
|
7530
8117
|
for (const { oldSpecifier, newSpecifier } of rewrites.filter(
|
|
7531
8118
|
(r) => r.file === file
|
|
7532
8119
|
)) {
|
|
7533
8120
|
console.log(
|
|
7534
|
-
` ${
|
|
8121
|
+
` ${chalk91.red(`"${oldSpecifier}"`)} \u2192 ${chalk91.green(`"${newSpecifier}"`)}`
|
|
7535
8122
|
);
|
|
7536
8123
|
}
|
|
7537
8124
|
}
|
|
7538
8125
|
}
|
|
7539
|
-
function
|
|
8126
|
+
function displayPlan2(plan2) {
|
|
7540
8127
|
if (plan2.warnings.length > 0) {
|
|
7541
|
-
console.log(
|
|
7542
|
-
for (const w of plan2.warnings) console.log(
|
|
8128
|
+
console.log(chalk91.yellow("\nWarnings:"));
|
|
8129
|
+
for (const w of plan2.warnings) console.log(chalk91.yellow(` ${w}`));
|
|
7543
8130
|
}
|
|
7544
8131
|
if (plan2.newDirectories.length > 0) {
|
|
7545
|
-
console.log(
|
|
8132
|
+
console.log(chalk91.bold("\nNew directories:"));
|
|
7546
8133
|
for (const dir of plan2.newDirectories)
|
|
7547
|
-
console.log(
|
|
8134
|
+
console.log(chalk91.green(` ${dir}/`));
|
|
7548
8135
|
}
|
|
7549
8136
|
displayMoves(plan2);
|
|
7550
8137
|
displayRewrites(plan2.rewrites);
|
|
7551
8138
|
console.log(
|
|
7552
|
-
|
|
8139
|
+
chalk91.dim(
|
|
7553
8140
|
`
|
|
7554
8141
|
Summary: ${plan2.moves.length} file(s) moved, ${plan2.rewrites.length} imports rewritten`
|
|
7555
8142
|
)
|
|
@@ -7557,45 +8144,45 @@ Summary: ${plan2.moves.length} file(s) moved, ${plan2.rewrites.length} imports r
|
|
|
7557
8144
|
}
|
|
7558
8145
|
|
|
7559
8146
|
// src/commands/refactor/restructure/executePlan.ts
|
|
7560
|
-
import
|
|
7561
|
-
import
|
|
7562
|
-
import
|
|
8147
|
+
import fs20 from "fs";
|
|
8148
|
+
import path41 from "path";
|
|
8149
|
+
import chalk92 from "chalk";
|
|
7563
8150
|
function executePlan(plan2) {
|
|
7564
8151
|
const updatedContents = applyRewrites(plan2.rewrites);
|
|
7565
8152
|
for (const [file, content] of updatedContents) {
|
|
7566
|
-
|
|
8153
|
+
fs20.writeFileSync(file, content, "utf-8");
|
|
7567
8154
|
console.log(
|
|
7568
|
-
|
|
8155
|
+
chalk92.cyan(` Rewrote imports in ${path41.relative(process.cwd(), file)}`)
|
|
7569
8156
|
);
|
|
7570
8157
|
}
|
|
7571
8158
|
for (const dir of plan2.newDirectories) {
|
|
7572
|
-
|
|
7573
|
-
console.log(
|
|
8159
|
+
fs20.mkdirSync(dir, { recursive: true });
|
|
8160
|
+
console.log(chalk92.green(` Created ${path41.relative(process.cwd(), dir)}/`));
|
|
7574
8161
|
}
|
|
7575
8162
|
for (const move of plan2.moves) {
|
|
7576
|
-
const targetDir =
|
|
7577
|
-
if (!
|
|
7578
|
-
|
|
8163
|
+
const targetDir = path41.dirname(move.to);
|
|
8164
|
+
if (!fs20.existsSync(targetDir)) {
|
|
8165
|
+
fs20.mkdirSync(targetDir, { recursive: true });
|
|
7579
8166
|
}
|
|
7580
|
-
|
|
8167
|
+
fs20.renameSync(move.from, move.to);
|
|
7581
8168
|
console.log(
|
|
7582
|
-
|
|
7583
|
-
` Moved ${
|
|
8169
|
+
chalk92.white(
|
|
8170
|
+
` Moved ${path41.relative(process.cwd(), move.from)} \u2192 ${path41.relative(process.cwd(), move.to)}`
|
|
7584
8171
|
)
|
|
7585
8172
|
);
|
|
7586
8173
|
}
|
|
7587
|
-
removeEmptyDirectories(plan2.moves.map((m) =>
|
|
8174
|
+
removeEmptyDirectories(plan2.moves.map((m) => path41.dirname(m.from)));
|
|
7588
8175
|
}
|
|
7589
8176
|
function removeEmptyDirectories(dirs) {
|
|
7590
8177
|
const unique = [...new Set(dirs)];
|
|
7591
8178
|
for (const dir of unique) {
|
|
7592
|
-
if (!
|
|
7593
|
-
const entries =
|
|
8179
|
+
if (!fs20.existsSync(dir)) continue;
|
|
8180
|
+
const entries = fs20.readdirSync(dir);
|
|
7594
8181
|
if (entries.length === 0) {
|
|
7595
|
-
|
|
8182
|
+
fs20.rmdirSync(dir);
|
|
7596
8183
|
console.log(
|
|
7597
|
-
|
|
7598
|
-
` Removed empty directory ${
|
|
8184
|
+
chalk92.dim(
|
|
8185
|
+
` Removed empty directory ${path41.relative(process.cwd(), dir)}`
|
|
7599
8186
|
)
|
|
7600
8187
|
);
|
|
7601
8188
|
}
|
|
@@ -7603,46 +8190,46 @@ function removeEmptyDirectories(dirs) {
|
|
|
7603
8190
|
}
|
|
7604
8191
|
|
|
7605
8192
|
// src/commands/refactor/restructure/planFileMoves/index.ts
|
|
7606
|
-
import
|
|
8193
|
+
import path43 from "path";
|
|
7607
8194
|
|
|
7608
8195
|
// src/commands/refactor/restructure/planFileMoves/shared.ts
|
|
7609
|
-
import
|
|
8196
|
+
import fs21 from "fs";
|
|
7610
8197
|
function emptyResult() {
|
|
7611
8198
|
return { moves: [], directories: [], warnings: [] };
|
|
7612
8199
|
}
|
|
7613
8200
|
function checkDirConflict(result, label2, dir) {
|
|
7614
|
-
if (!
|
|
8201
|
+
if (!fs21.existsSync(dir)) return false;
|
|
7615
8202
|
result.warnings.push(`Skipping ${label2}: directory ${dir} already exists`);
|
|
7616
8203
|
return true;
|
|
7617
8204
|
}
|
|
7618
8205
|
|
|
7619
8206
|
// src/commands/refactor/restructure/planFileMoves/planDirectoryMoves.ts
|
|
7620
|
-
import
|
|
7621
|
-
import
|
|
8207
|
+
import fs22 from "fs";
|
|
8208
|
+
import path42 from "path";
|
|
7622
8209
|
function collectEntry(results, dir, entry) {
|
|
7623
|
-
const full =
|
|
8210
|
+
const full = path42.join(dir, entry.name);
|
|
7624
8211
|
const items = entry.isDirectory() ? listFilesRecursive(full) : [full];
|
|
7625
8212
|
results.push(...items);
|
|
7626
8213
|
}
|
|
7627
8214
|
function listFilesRecursive(dir) {
|
|
7628
|
-
if (!
|
|
8215
|
+
if (!fs22.existsSync(dir)) return [];
|
|
7629
8216
|
const results = [];
|
|
7630
|
-
for (const entry of
|
|
8217
|
+
for (const entry of fs22.readdirSync(dir, { withFileTypes: true })) {
|
|
7631
8218
|
collectEntry(results, dir, entry);
|
|
7632
8219
|
}
|
|
7633
8220
|
return results;
|
|
7634
8221
|
}
|
|
7635
8222
|
function addDirectoryFileMoves(moves, childDir, newLocation, reason) {
|
|
7636
8223
|
for (const file of listFilesRecursive(childDir)) {
|
|
7637
|
-
const rel =
|
|
7638
|
-
moves.push({ from: file, to:
|
|
8224
|
+
const rel = path42.relative(childDir, file);
|
|
8225
|
+
moves.push({ from: file, to: path42.join(newLocation, rel), reason });
|
|
7639
8226
|
}
|
|
7640
8227
|
}
|
|
7641
8228
|
function resolveChildDest(parentDir, childDir) {
|
|
7642
|
-
return
|
|
8229
|
+
return path42.join(parentDir, path42.basename(childDir));
|
|
7643
8230
|
}
|
|
7644
8231
|
function childMoveReason(parentDir) {
|
|
7645
|
-
return `Directory only imported from ${
|
|
8232
|
+
return `Directory only imported from ${path42.basename(parentDir)}/`;
|
|
7646
8233
|
}
|
|
7647
8234
|
function registerDirectoryMove(result, childDir, dest, parentDir) {
|
|
7648
8235
|
result.directories.push(dest);
|
|
@@ -7667,7 +8254,7 @@ function planDirectoryMoves(clusters) {
|
|
|
7667
8254
|
|
|
7668
8255
|
// src/commands/refactor/restructure/planFileMoves/index.ts
|
|
7669
8256
|
function childMoveData(child, newDir, parentBase) {
|
|
7670
|
-
const to =
|
|
8257
|
+
const to = path43.join(newDir, path43.basename(child));
|
|
7671
8258
|
return { from: child, to, reason: `Only imported by ${parentBase}` };
|
|
7672
8259
|
}
|
|
7673
8260
|
function addChildMoves(moves, children, newDir, parentBase) {
|
|
@@ -7675,15 +8262,15 @@ function addChildMoves(moves, children, newDir, parentBase) {
|
|
|
7675
8262
|
moves.push(childMoveData(child, newDir, parentBase));
|
|
7676
8263
|
}
|
|
7677
8264
|
function getBaseName(filePath) {
|
|
7678
|
-
return
|
|
8265
|
+
return path43.basename(filePath, path43.extname(filePath));
|
|
7679
8266
|
}
|
|
7680
8267
|
function resolveClusterDir(parent) {
|
|
7681
|
-
return
|
|
8268
|
+
return path43.join(path43.dirname(parent), getBaseName(parent));
|
|
7682
8269
|
}
|
|
7683
8270
|
function createParentMove(parent, newDir) {
|
|
7684
8271
|
return {
|
|
7685
8272
|
from: parent,
|
|
7686
|
-
to:
|
|
8273
|
+
to: path43.join(newDir, `index${path43.extname(parent)}`),
|
|
7687
8274
|
reason: `Main module of new ${getBaseName(parent)}/ directory`
|
|
7688
8275
|
};
|
|
7689
8276
|
}
|
|
@@ -7706,8 +8293,8 @@ function planFileMoves(clusters) {
|
|
|
7706
8293
|
}
|
|
7707
8294
|
|
|
7708
8295
|
// src/commands/refactor/restructure/index.ts
|
|
7709
|
-
function
|
|
7710
|
-
const candidates = new Set(candidateFiles.map((f) =>
|
|
8296
|
+
function buildPlan2(candidateFiles, tsConfigPath) {
|
|
8297
|
+
const candidates = new Set(candidateFiles.map((f) => path44.resolve(f)));
|
|
7711
8298
|
const graph = buildImportGraph(candidates, tsConfigPath);
|
|
7712
8299
|
const allProjectFiles = /* @__PURE__ */ new Set([
|
|
7713
8300
|
...graph.importedBy.keys(),
|
|
@@ -7727,40 +8314,42 @@ async function restructure(pattern2, options2 = {}) {
|
|
|
7727
8314
|
const targetPattern = pattern2 ?? "src";
|
|
7728
8315
|
const files = findSourceFiles2(targetPattern);
|
|
7729
8316
|
if (files.length === 0) {
|
|
7730
|
-
console.log(
|
|
8317
|
+
console.log(chalk93.yellow("No files found matching pattern"));
|
|
7731
8318
|
return;
|
|
7732
8319
|
}
|
|
7733
|
-
const tsConfigPath =
|
|
7734
|
-
const plan2 =
|
|
8320
|
+
const tsConfigPath = path44.resolve("tsconfig.json");
|
|
8321
|
+
const plan2 = buildPlan2(files, tsConfigPath);
|
|
7735
8322
|
if (plan2.moves.length === 0) {
|
|
7736
|
-
console.log(
|
|
8323
|
+
console.log(chalk93.green("No restructuring needed"));
|
|
7737
8324
|
return;
|
|
7738
8325
|
}
|
|
7739
|
-
|
|
8326
|
+
displayPlan2(plan2);
|
|
7740
8327
|
if (options2.apply) {
|
|
7741
|
-
console.log(
|
|
8328
|
+
console.log(chalk93.bold("\nApplying changes..."));
|
|
7742
8329
|
executePlan(plan2);
|
|
7743
|
-
console.log(
|
|
8330
|
+
console.log(chalk93.green("\nRestructuring complete"));
|
|
7744
8331
|
} else {
|
|
7745
|
-
console.log(
|
|
8332
|
+
console.log(chalk93.dim("\nDry run. Use --apply to execute."));
|
|
7746
8333
|
}
|
|
7747
8334
|
}
|
|
7748
8335
|
|
|
7749
8336
|
// src/commands/registerRefactor.ts
|
|
7750
|
-
function
|
|
7751
|
-
|
|
7752
|
-
refactorCommand.command("check [pattern]").description("Check for files that exceed the maximum line count").option("--modified", "Check only staged and unstaged files").option("--staged", "Check only staged files").option("--unstaged", "Check only unstaged files").option(
|
|
8337
|
+
function registerCheck(parent) {
|
|
8338
|
+
parent.command("check [pattern]").description("Check for files that exceed the maximum line count").option("--modified", "Check only staged and unstaged files").option("--staged", "Check only staged files").option("--unstaged", "Check only unstaged files").option(
|
|
7753
8339
|
"--max-lines <number>",
|
|
7754
8340
|
"Maximum lines allowed per file (default: 100)",
|
|
7755
8341
|
Number.parseInt
|
|
7756
8342
|
).action(check);
|
|
7757
|
-
|
|
7758
|
-
|
|
8343
|
+
}
|
|
8344
|
+
function registerRename(parent) {
|
|
8345
|
+
const renameCommand = parent.command("rename").description("Rename files or symbols with automatic import updates");
|
|
7759
8346
|
renameCommand.command("file <source> <destination>").description("Rename/move a TypeScript file and update all imports").option("--apply", "Execute the rename (default: dry-run)").action(rename);
|
|
7760
8347
|
renameCommand.command("symbol <file> <oldName> <newName>").description(
|
|
7761
8348
|
"Rename a variable, function, class, or type across the project"
|
|
7762
8349
|
).option("--apply", "Execute the rename (default: dry-run)").action(renameSymbol);
|
|
7763
|
-
|
|
8350
|
+
}
|
|
8351
|
+
function registerRestructure(parent) {
|
|
8352
|
+
parent.command("restructure [pattern]").description(
|
|
7764
8353
|
"Analyze import graph and restructure tightly-coupled files into nested directories"
|
|
7765
8354
|
).option("--apply", "Execute the restructuring (default: dry-run)").option(
|
|
7766
8355
|
"--max-depth <number>",
|
|
@@ -7768,9 +8357,19 @@ function registerRefactor(program2) {
|
|
|
7768
8357
|
Number.parseInt
|
|
7769
8358
|
).action(restructure);
|
|
7770
8359
|
}
|
|
8360
|
+
function registerRefactor(program2) {
|
|
8361
|
+
const refactorCommand = program2.command("refactor").description("Run refactoring checks for code quality");
|
|
8362
|
+
registerCheck(refactorCommand);
|
|
8363
|
+
refactorCommand.command("extract <file> <functionName> <destination>").description(
|
|
8364
|
+
"Extract a function and its private dependencies to a new file"
|
|
8365
|
+
).option("--apply", "Execute the extraction (default: dry-run)").action(extract);
|
|
8366
|
+
refactorCommand.command("ignore <file>").description("Add a file to the refactor ignore list").action(ignore);
|
|
8367
|
+
registerRename(refactorCommand);
|
|
8368
|
+
registerRestructure(refactorCommand);
|
|
8369
|
+
}
|
|
7771
8370
|
|
|
7772
8371
|
// src/commands/seq/seqAuth.ts
|
|
7773
|
-
import
|
|
8372
|
+
import chalk95 from "chalk";
|
|
7774
8373
|
|
|
7775
8374
|
// src/commands/seq/loadConnections.ts
|
|
7776
8375
|
function loadConnections2() {
|
|
@@ -7799,11 +8398,11 @@ function setDefaultConnection(name) {
|
|
|
7799
8398
|
}
|
|
7800
8399
|
|
|
7801
8400
|
// src/commands/seq/promptConnection.ts
|
|
7802
|
-
import
|
|
8401
|
+
import chalk94 from "chalk";
|
|
7803
8402
|
async function promptConnection2(existingNames) {
|
|
7804
8403
|
const name = await promptInput("name", "Connection name:", "default");
|
|
7805
8404
|
if (existingNames.includes(name)) {
|
|
7806
|
-
console.error(
|
|
8405
|
+
console.error(chalk94.red(`Connection "${name}" already exists.`));
|
|
7807
8406
|
process.exit(1);
|
|
7808
8407
|
}
|
|
7809
8408
|
const url = await promptInput("url", "Seq URL:", "http://localhost:5341");
|
|
@@ -7815,32 +8414,32 @@ async function promptConnection2(existingNames) {
|
|
|
7815
8414
|
var seqAuth = createConnectionAuth({
|
|
7816
8415
|
load: loadConnections2,
|
|
7817
8416
|
save: saveConnections2,
|
|
7818
|
-
format: (c) => `${
|
|
8417
|
+
format: (c) => `${chalk95.bold(c.name)} ${c.url}`,
|
|
7819
8418
|
promptNew: promptConnection2,
|
|
7820
8419
|
onFirst: (c) => setDefaultConnection(c.name)
|
|
7821
8420
|
});
|
|
7822
8421
|
|
|
7823
8422
|
// src/commands/seq/seqQuery.ts
|
|
7824
|
-
import
|
|
8423
|
+
import chalk98 from "chalk";
|
|
7825
8424
|
|
|
7826
8425
|
// src/commands/seq/formatEvent.ts
|
|
7827
|
-
import
|
|
8426
|
+
import chalk96 from "chalk";
|
|
7828
8427
|
function levelColor(level) {
|
|
7829
8428
|
switch (level) {
|
|
7830
8429
|
case "Fatal":
|
|
7831
|
-
return
|
|
8430
|
+
return chalk96.bgRed.white;
|
|
7832
8431
|
case "Error":
|
|
7833
|
-
return
|
|
8432
|
+
return chalk96.red;
|
|
7834
8433
|
case "Warning":
|
|
7835
|
-
return
|
|
8434
|
+
return chalk96.yellow;
|
|
7836
8435
|
case "Information":
|
|
7837
|
-
return
|
|
8436
|
+
return chalk96.cyan;
|
|
7838
8437
|
case "Debug":
|
|
7839
|
-
return
|
|
8438
|
+
return chalk96.gray;
|
|
7840
8439
|
case "Verbose":
|
|
7841
|
-
return
|
|
8440
|
+
return chalk96.dim;
|
|
7842
8441
|
default:
|
|
7843
|
-
return
|
|
8442
|
+
return chalk96.white;
|
|
7844
8443
|
}
|
|
7845
8444
|
}
|
|
7846
8445
|
function levelAbbrev(level) {
|
|
@@ -7881,31 +8480,31 @@ function formatTimestamp(iso) {
|
|
|
7881
8480
|
function formatEvent(event) {
|
|
7882
8481
|
const color = levelColor(event.Level);
|
|
7883
8482
|
const abbrev = levelAbbrev(event.Level);
|
|
7884
|
-
const ts8 =
|
|
8483
|
+
const ts8 = chalk96.dim(formatTimestamp(event.Timestamp));
|
|
7885
8484
|
const msg = renderMessage(event);
|
|
7886
8485
|
const lines = [`${ts8} ${color(`[${abbrev}]`)} ${msg}`];
|
|
7887
8486
|
if (event.Exception) {
|
|
7888
8487
|
for (const line of event.Exception.split("\n")) {
|
|
7889
|
-
lines.push(
|
|
8488
|
+
lines.push(chalk96.red(` ${line}`));
|
|
7890
8489
|
}
|
|
7891
8490
|
}
|
|
7892
8491
|
return lines.join("\n");
|
|
7893
8492
|
}
|
|
7894
8493
|
|
|
7895
8494
|
// src/commands/seq/resolveConnection.ts
|
|
7896
|
-
import
|
|
8495
|
+
import chalk97 from "chalk";
|
|
7897
8496
|
function resolveConnection2(name) {
|
|
7898
8497
|
const connections = loadConnections2();
|
|
7899
8498
|
if (connections.length === 0) {
|
|
7900
8499
|
console.error(
|
|
7901
|
-
|
|
8500
|
+
chalk97.red("No Seq connections configured. Run 'assist seq auth' first.")
|
|
7902
8501
|
);
|
|
7903
8502
|
process.exit(1);
|
|
7904
8503
|
}
|
|
7905
8504
|
const target = name ?? getDefaultConnection() ?? connections[0].name;
|
|
7906
8505
|
const connection = connections.find((c) => c.name === target);
|
|
7907
8506
|
if (!connection) {
|
|
7908
|
-
console.error(
|
|
8507
|
+
console.error(chalk97.red(`Seq connection "${target}" not found.`));
|
|
7909
8508
|
process.exit(1);
|
|
7910
8509
|
}
|
|
7911
8510
|
return connection;
|
|
@@ -7925,12 +8524,12 @@ async function seqQuery(filter, options2) {
|
|
|
7925
8524
|
});
|
|
7926
8525
|
if (!response.ok) {
|
|
7927
8526
|
const body = await response.text();
|
|
7928
|
-
console.error(
|
|
8527
|
+
console.error(chalk98.red(`Seq returned ${response.status}: ${body}`));
|
|
7929
8528
|
process.exit(1);
|
|
7930
8529
|
}
|
|
7931
8530
|
const events = await response.json();
|
|
7932
8531
|
if (events.length === 0) {
|
|
7933
|
-
console.log(
|
|
8532
|
+
console.log(chalk98.yellow("No events found."));
|
|
7934
8533
|
return;
|
|
7935
8534
|
}
|
|
7936
8535
|
if (options2.json) {
|
|
@@ -7941,11 +8540,11 @@ async function seqQuery(filter, options2) {
|
|
|
7941
8540
|
for (const event of chronological) {
|
|
7942
8541
|
console.log(formatEvent(event));
|
|
7943
8542
|
}
|
|
7944
|
-
console.log(
|
|
8543
|
+
console.log(chalk98.dim(`
|
|
7945
8544
|
${events.length} events`));
|
|
7946
8545
|
if (events.length >= count) {
|
|
7947
8546
|
console.log(
|
|
7948
|
-
|
|
8547
|
+
chalk98.yellow(
|
|
7949
8548
|
`Results limited to ${count}. Use --count to retrieve more.`
|
|
7950
8549
|
)
|
|
7951
8550
|
);
|
|
@@ -7953,11 +8552,11 @@ ${events.length} events`));
|
|
|
7953
8552
|
}
|
|
7954
8553
|
|
|
7955
8554
|
// src/commands/seq/seqSetConnection.ts
|
|
7956
|
-
import
|
|
8555
|
+
import chalk99 from "chalk";
|
|
7957
8556
|
function seqSetConnection(name) {
|
|
7958
8557
|
const connections = loadConnections2();
|
|
7959
8558
|
if (!connections.find((c) => c.name === name)) {
|
|
7960
|
-
console.error(
|
|
8559
|
+
console.error(chalk99.red(`Connection "${name}" not found.`));
|
|
7961
8560
|
process.exit(1);
|
|
7962
8561
|
}
|
|
7963
8562
|
setDefaultConnection(name);
|
|
@@ -8496,14 +9095,14 @@ import {
|
|
|
8496
9095
|
import { dirname as dirname20, join as join29 } from "path";
|
|
8497
9096
|
|
|
8498
9097
|
// src/commands/transcript/summarise/processStagedFile/validateStagedContent.ts
|
|
8499
|
-
import
|
|
9098
|
+
import chalk100 from "chalk";
|
|
8500
9099
|
var FULL_TRANSCRIPT_REGEX = /^\[Full Transcript\]\(([^)]+)\)/;
|
|
8501
9100
|
function validateStagedContent(filename, content) {
|
|
8502
9101
|
const firstLine = content.split("\n")[0];
|
|
8503
9102
|
const match = firstLine.match(FULL_TRANSCRIPT_REGEX);
|
|
8504
9103
|
if (!match) {
|
|
8505
9104
|
console.error(
|
|
8506
|
-
|
|
9105
|
+
chalk100.red(
|
|
8507
9106
|
`Staged file ${filename} missing [Full Transcript](<path>) link on first line.`
|
|
8508
9107
|
)
|
|
8509
9108
|
);
|
|
@@ -8512,7 +9111,7 @@ function validateStagedContent(filename, content) {
|
|
|
8512
9111
|
const contentAfterLink = content.slice(firstLine.length).trim();
|
|
8513
9112
|
if (!contentAfterLink) {
|
|
8514
9113
|
console.error(
|
|
8515
|
-
|
|
9114
|
+
chalk100.red(
|
|
8516
9115
|
`Staged file ${filename} has no summary content after the transcript link.`
|
|
8517
9116
|
)
|
|
8518
9117
|
);
|
|
@@ -8905,7 +9504,7 @@ function registerVoice(program2) {
|
|
|
8905
9504
|
|
|
8906
9505
|
// src/commands/roam/auth.ts
|
|
8907
9506
|
import { randomBytes } from "crypto";
|
|
8908
|
-
import
|
|
9507
|
+
import chalk101 from "chalk";
|
|
8909
9508
|
|
|
8910
9509
|
// src/lib/openBrowser.ts
|
|
8911
9510
|
import { execSync as execSync36 } from "child_process";
|
|
@@ -9080,13 +9679,13 @@ async function auth() {
|
|
|
9080
9679
|
saveGlobalConfig(config);
|
|
9081
9680
|
const state = randomBytes(16).toString("hex");
|
|
9082
9681
|
console.log(
|
|
9083
|
-
|
|
9682
|
+
chalk101.yellow("\nEnsure this Redirect URI is set in your Roam OAuth app:")
|
|
9084
9683
|
);
|
|
9085
|
-
console.log(
|
|
9086
|
-
console.log(
|
|
9087
|
-
console.log(
|
|
9684
|
+
console.log(chalk101.white("http://localhost:14523/callback\n"));
|
|
9685
|
+
console.log(chalk101.blue("Opening browser for authorization..."));
|
|
9686
|
+
console.log(chalk101.dim("Waiting for authorization callback..."));
|
|
9088
9687
|
const { code, redirectUri } = await authorizeInBrowser(clientId, state);
|
|
9089
|
-
console.log(
|
|
9688
|
+
console.log(chalk101.dim("Exchanging code for tokens..."));
|
|
9090
9689
|
const tokens = await exchangeToken({
|
|
9091
9690
|
code,
|
|
9092
9691
|
clientId,
|
|
@@ -9102,7 +9701,7 @@ async function auth() {
|
|
|
9102
9701
|
};
|
|
9103
9702
|
saveGlobalConfig(config);
|
|
9104
9703
|
console.log(
|
|
9105
|
-
|
|
9704
|
+
chalk101.green("Roam credentials and tokens saved to ~/.assist.yml")
|
|
9106
9705
|
);
|
|
9107
9706
|
}
|
|
9108
9707
|
|
|
@@ -9323,7 +9922,7 @@ import { execSync as execSync38 } from "child_process";
|
|
|
9323
9922
|
import { existsSync as existsSync38, mkdirSync as mkdirSync13, unlinkSync as unlinkSync10, writeFileSync as writeFileSync27 } from "fs";
|
|
9324
9923
|
import { tmpdir as tmpdir6 } from "os";
|
|
9325
9924
|
import { join as join38, resolve as resolve5 } from "path";
|
|
9326
|
-
import
|
|
9925
|
+
import chalk102 from "chalk";
|
|
9327
9926
|
|
|
9328
9927
|
// src/commands/screenshot/captureWindowPs1.ts
|
|
9329
9928
|
var captureWindowPs1 = `
|
|
@@ -9474,22 +10073,22 @@ function screenshot(processName) {
|
|
|
9474
10073
|
const config = loadConfig();
|
|
9475
10074
|
const outputDir = resolve5(config.screenshot.outputDir);
|
|
9476
10075
|
const outputPath = buildOutputPath(outputDir, processName);
|
|
9477
|
-
console.log(
|
|
10076
|
+
console.log(chalk102.gray(`Capturing window for process "${processName}" ...`));
|
|
9478
10077
|
try {
|
|
9479
10078
|
runPowerShellScript(processName, outputPath);
|
|
9480
|
-
console.log(
|
|
10079
|
+
console.log(chalk102.green(`Screenshot saved: ${outputPath}`));
|
|
9481
10080
|
} catch (error) {
|
|
9482
10081
|
const msg = error instanceof Error ? error.message : String(error);
|
|
9483
|
-
console.error(
|
|
10082
|
+
console.error(chalk102.red(`Failed to capture screenshot: ${msg}`));
|
|
9484
10083
|
process.exit(1);
|
|
9485
10084
|
}
|
|
9486
10085
|
}
|
|
9487
10086
|
|
|
9488
10087
|
// src/commands/statusLine.ts
|
|
9489
|
-
import
|
|
10088
|
+
import chalk104 from "chalk";
|
|
9490
10089
|
|
|
9491
10090
|
// src/commands/buildLimitsSegment.ts
|
|
9492
|
-
import
|
|
10091
|
+
import chalk103 from "chalk";
|
|
9493
10092
|
var FIVE_HOUR_SECONDS = 5 * 3600;
|
|
9494
10093
|
var SEVEN_DAY_SECONDS = 7 * 86400;
|
|
9495
10094
|
function formatTimeLeft(resetsAt) {
|
|
@@ -9512,10 +10111,10 @@ function projectUsage(pct, resetsAt, windowSeconds) {
|
|
|
9512
10111
|
function colorizeRateLimit(pct, resetsAt, windowSeconds) {
|
|
9513
10112
|
const label2 = `${Math.round(pct)}%`;
|
|
9514
10113
|
const projected = projectUsage(pct, resetsAt, windowSeconds);
|
|
9515
|
-
if (projected == null) return
|
|
9516
|
-
if (projected > 100) return
|
|
9517
|
-
if (projected > 75) return
|
|
9518
|
-
return
|
|
10114
|
+
if (projected == null) return chalk103.green(label2);
|
|
10115
|
+
if (projected > 100) return chalk103.red(label2);
|
|
10116
|
+
if (projected > 75) return chalk103.yellow(label2);
|
|
10117
|
+
return chalk103.green(label2);
|
|
9519
10118
|
}
|
|
9520
10119
|
function formatLimit(pct, resetsAt, windowSeconds, fallbackLabel) {
|
|
9521
10120
|
const timeLabel = resetsAt ? formatTimeLeft(resetsAt) : fallbackLabel;
|
|
@@ -9541,14 +10140,14 @@ function buildLimitsSegment(rateLimits) {
|
|
|
9541
10140
|
}
|
|
9542
10141
|
|
|
9543
10142
|
// src/commands/statusLine.ts
|
|
9544
|
-
|
|
10143
|
+
chalk104.level = 3;
|
|
9545
10144
|
function formatNumber(num) {
|
|
9546
10145
|
return num.toLocaleString("en-US");
|
|
9547
10146
|
}
|
|
9548
10147
|
function colorizePercent(pct) {
|
|
9549
10148
|
const label2 = `${Math.round(pct)}%`;
|
|
9550
|
-
if (pct > 80) return
|
|
9551
|
-
if (pct > 40) return
|
|
10149
|
+
if (pct > 80) return chalk104.red(label2);
|
|
10150
|
+
if (pct > 40) return chalk104.yellow(label2);
|
|
9552
10151
|
return label2;
|
|
9553
10152
|
}
|
|
9554
10153
|
async function statusLine() {
|
|
@@ -9563,29 +10162,29 @@ async function statusLine() {
|
|
|
9563
10162
|
}
|
|
9564
10163
|
|
|
9565
10164
|
// src/commands/sync.ts
|
|
9566
|
-
import * as
|
|
10165
|
+
import * as fs25 from "fs";
|
|
9567
10166
|
import * as os from "os";
|
|
9568
|
-
import * as
|
|
10167
|
+
import * as path47 from "path";
|
|
9569
10168
|
import { fileURLToPath as fileURLToPath7 } from "url";
|
|
9570
10169
|
|
|
9571
10170
|
// src/commands/sync/syncClaudeMd.ts
|
|
9572
|
-
import * as
|
|
9573
|
-
import * as
|
|
9574
|
-
import
|
|
10171
|
+
import * as fs23 from "fs";
|
|
10172
|
+
import * as path45 from "path";
|
|
10173
|
+
import chalk105 from "chalk";
|
|
9575
10174
|
async function syncClaudeMd(claudeDir, targetBase) {
|
|
9576
|
-
const source =
|
|
9577
|
-
const target =
|
|
9578
|
-
const sourceContent =
|
|
9579
|
-
if (
|
|
9580
|
-
const targetContent =
|
|
10175
|
+
const source = path45.join(claudeDir, "CLAUDE.md");
|
|
10176
|
+
const target = path45.join(targetBase, "CLAUDE.md");
|
|
10177
|
+
const sourceContent = fs23.readFileSync(source, "utf-8");
|
|
10178
|
+
if (fs23.existsSync(target)) {
|
|
10179
|
+
const targetContent = fs23.readFileSync(target, "utf-8");
|
|
9581
10180
|
if (sourceContent !== targetContent) {
|
|
9582
10181
|
console.log(
|
|
9583
|
-
|
|
10182
|
+
chalk105.yellow("\n\u26A0\uFE0F Warning: CLAUDE.md differs from existing file")
|
|
9584
10183
|
);
|
|
9585
10184
|
console.log();
|
|
9586
10185
|
printDiff(targetContent, sourceContent);
|
|
9587
10186
|
const confirm = await promptConfirm(
|
|
9588
|
-
|
|
10187
|
+
chalk105.red("Overwrite existing CLAUDE.md?"),
|
|
9589
10188
|
false
|
|
9590
10189
|
);
|
|
9591
10190
|
if (!confirm) {
|
|
@@ -9594,21 +10193,21 @@ async function syncClaudeMd(claudeDir, targetBase) {
|
|
|
9594
10193
|
}
|
|
9595
10194
|
}
|
|
9596
10195
|
}
|
|
9597
|
-
|
|
10196
|
+
fs23.copyFileSync(source, target);
|
|
9598
10197
|
console.log("Copied CLAUDE.md to ~/.claude/CLAUDE.md");
|
|
9599
10198
|
}
|
|
9600
10199
|
|
|
9601
10200
|
// src/commands/sync/syncSettings.ts
|
|
9602
|
-
import * as
|
|
9603
|
-
import * as
|
|
9604
|
-
import
|
|
10201
|
+
import * as fs24 from "fs";
|
|
10202
|
+
import * as path46 from "path";
|
|
10203
|
+
import chalk106 from "chalk";
|
|
9605
10204
|
async function syncSettings(claudeDir, targetBase, options2) {
|
|
9606
|
-
const source =
|
|
9607
|
-
const target =
|
|
9608
|
-
const sourceContent =
|
|
10205
|
+
const source = path46.join(claudeDir, "settings.json");
|
|
10206
|
+
const target = path46.join(targetBase, "settings.json");
|
|
10207
|
+
const sourceContent = fs24.readFileSync(source, "utf-8");
|
|
9609
10208
|
const mergedContent = JSON.stringify(JSON.parse(sourceContent), null, " ");
|
|
9610
|
-
if (
|
|
9611
|
-
const targetContent =
|
|
10209
|
+
if (fs24.existsSync(target)) {
|
|
10210
|
+
const targetContent = fs24.readFileSync(target, "utf-8");
|
|
9612
10211
|
const normalizedTarget = JSON.stringify(
|
|
9613
10212
|
JSON.parse(targetContent),
|
|
9614
10213
|
null,
|
|
@@ -9617,14 +10216,14 @@ async function syncSettings(claudeDir, targetBase, options2) {
|
|
|
9617
10216
|
if (mergedContent !== normalizedTarget) {
|
|
9618
10217
|
if (!options2?.yes) {
|
|
9619
10218
|
console.log(
|
|
9620
|
-
|
|
10219
|
+
chalk106.yellow(
|
|
9621
10220
|
"\n\u26A0\uFE0F Warning: settings.json differs from existing file"
|
|
9622
10221
|
)
|
|
9623
10222
|
);
|
|
9624
10223
|
console.log();
|
|
9625
10224
|
printDiff(targetContent, mergedContent);
|
|
9626
10225
|
const confirm = await promptConfirm(
|
|
9627
|
-
|
|
10226
|
+
chalk106.red("Overwrite existing settings.json?"),
|
|
9628
10227
|
false
|
|
9629
10228
|
);
|
|
9630
10229
|
if (!confirm) {
|
|
@@ -9634,27 +10233,27 @@ async function syncSettings(claudeDir, targetBase, options2) {
|
|
|
9634
10233
|
}
|
|
9635
10234
|
}
|
|
9636
10235
|
}
|
|
9637
|
-
|
|
10236
|
+
fs24.writeFileSync(target, mergedContent);
|
|
9638
10237
|
console.log("Copied settings.json to ~/.claude/settings.json");
|
|
9639
10238
|
}
|
|
9640
10239
|
|
|
9641
10240
|
// src/commands/sync.ts
|
|
9642
10241
|
var __filename4 = fileURLToPath7(import.meta.url);
|
|
9643
|
-
var __dirname7 =
|
|
10242
|
+
var __dirname7 = path47.dirname(__filename4);
|
|
9644
10243
|
async function sync(options2) {
|
|
9645
|
-
const claudeDir =
|
|
9646
|
-
const targetBase =
|
|
10244
|
+
const claudeDir = path47.join(__dirname7, "..", "claude");
|
|
10245
|
+
const targetBase = path47.join(os.homedir(), ".claude");
|
|
9647
10246
|
syncCommands(claudeDir, targetBase);
|
|
9648
10247
|
await syncSettings(claudeDir, targetBase, { yes: options2?.yes });
|
|
9649
10248
|
await syncClaudeMd(claudeDir, targetBase);
|
|
9650
10249
|
}
|
|
9651
10250
|
function syncCommands(claudeDir, targetBase) {
|
|
9652
|
-
const sourceDir =
|
|
9653
|
-
const targetDir =
|
|
9654
|
-
|
|
9655
|
-
const files =
|
|
10251
|
+
const sourceDir = path47.join(claudeDir, "commands");
|
|
10252
|
+
const targetDir = path47.join(targetBase, "commands");
|
|
10253
|
+
fs25.mkdirSync(targetDir, { recursive: true });
|
|
10254
|
+
const files = fs25.readdirSync(sourceDir);
|
|
9656
10255
|
for (const file of files) {
|
|
9657
|
-
|
|
10256
|
+
fs25.copyFileSync(path47.join(sourceDir, file), path47.join(targetDir, file));
|
|
9658
10257
|
console.log(`Copied ${file} to ${targetDir}`);
|
|
9659
10258
|
}
|
|
9660
10259
|
console.log(`Synced ${files.length} command(s) to ~/.claude/commands`);
|
|
@@ -9662,15 +10261,15 @@ function syncCommands(claudeDir, targetBase) {
|
|
|
9662
10261
|
|
|
9663
10262
|
// src/commands/update.ts
|
|
9664
10263
|
import { execSync as execSync39 } from "child_process";
|
|
9665
|
-
import * as
|
|
10264
|
+
import * as path48 from "path";
|
|
9666
10265
|
function isGlobalNpmInstall(dir) {
|
|
9667
10266
|
try {
|
|
9668
|
-
const resolved =
|
|
9669
|
-
if (resolved.split(
|
|
10267
|
+
const resolved = path48.resolve(dir);
|
|
10268
|
+
if (resolved.split(path48.sep).includes("node_modules")) {
|
|
9670
10269
|
return true;
|
|
9671
10270
|
}
|
|
9672
10271
|
const globalPrefix = execSync39("npm prefix -g", { stdio: "pipe" }).toString().trim();
|
|
9673
|
-
return resolved.toLowerCase().startsWith(
|
|
10272
|
+
return resolved.toLowerCase().startsWith(path48.resolve(globalPrefix).toLowerCase());
|
|
9674
10273
|
} catch {
|
|
9675
10274
|
return false;
|
|
9676
10275
|
}
|