@staff0rd/assist 0.112.0 → 0.114.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 +7 -0
- package/assist.cli-reads +29 -0
- package/claude/settings.json +3 -0
- package/dist/index.js +516 -93
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -114,6 +114,13 @@ After installation, the `assist` command will be available globally. You can als
|
|
|
114
114
|
- `assist netframework in-sln <csproj>` - Check whether a .csproj is referenced by any .sln file
|
|
115
115
|
- `assist jira auth` - Authenticate with Jira via API token (saves site/email to ~/.assist/jira.json)
|
|
116
116
|
- `assist jira ac <issue-key>` - Print acceptance criteria for a Jira issue
|
|
117
|
+
- `assist ravendb auth` - Configure a named RavenDB connection (prompts for name, URL, database, op:// secret reference)
|
|
118
|
+
- `assist ravendb auth --list` - List configured RavenDB connections
|
|
119
|
+
- `assist ravendb auth --remove <name>` - Remove a configured connection
|
|
120
|
+
- `assist ravendb set-connection <name>` - Set the default connection for query/collections commands
|
|
121
|
+
- `assist ravendb query [connection] [collection]` - Query a RavenDB collection (outputs JSON to stdout)
|
|
122
|
+
- `assist ravendb query [connection] [collection] --page-size <n> --sort <field> --query <lucene> --limit <n>` - Query with options
|
|
123
|
+
- `assist ravendb collections [connection]` - List collections and document counts in a database
|
|
117
124
|
- `assist complexity <pattern>` - Analyze a file (all metrics if single match, maintainability if multiple)
|
|
118
125
|
- `assist complexity cyclomatic [pattern]` - Calculate cyclomatic complexity per function
|
|
119
126
|
- `assist complexity halstead [pattern]` - Calculate Halstead metrics per function
|
package/assist.cli-reads
CHANGED
|
@@ -127,6 +127,7 @@ az afd security-policy list
|
|
|
127
127
|
az afd security-policy show
|
|
128
128
|
az afd waf-log-analytic metric list
|
|
129
129
|
az afd waf-log-analytic ranking list
|
|
130
|
+
az afd waf-policy list
|
|
130
131
|
az aks approuting zone list
|
|
131
132
|
az aks browse
|
|
132
133
|
az aks connection list
|
|
@@ -1086,6 +1087,34 @@ az network express-route port link show
|
|
|
1086
1087
|
az network express-route port list
|
|
1087
1088
|
az network express-route port show
|
|
1088
1089
|
az network express-route show
|
|
1090
|
+
az network front-door backend-pool backend list
|
|
1091
|
+
az network front-door backend-pool list
|
|
1092
|
+
az network front-door backend-pool show
|
|
1093
|
+
az network front-door frontend-endpoint list
|
|
1094
|
+
az network front-door frontend-endpoint show
|
|
1095
|
+
az network front-door list
|
|
1096
|
+
az network front-door load-balancing list
|
|
1097
|
+
az network front-door load-balancing show
|
|
1098
|
+
az network front-door probe list
|
|
1099
|
+
az network front-door probe show
|
|
1100
|
+
az network front-door routing-rule list
|
|
1101
|
+
az network front-door routing-rule show
|
|
1102
|
+
az network front-door rules-engine list
|
|
1103
|
+
az network front-door rules-engine rule action list
|
|
1104
|
+
az network front-door rules-engine rule condition list
|
|
1105
|
+
az network front-door rules-engine rule list
|
|
1106
|
+
az network front-door rules-engine rule show
|
|
1107
|
+
az network front-door rules-engine show
|
|
1108
|
+
az network front-door show
|
|
1109
|
+
az network front-door waf-policy list
|
|
1110
|
+
az network front-door waf-policy managed-rule-definition list
|
|
1111
|
+
az network front-door waf-policy managed-rules exclusion list
|
|
1112
|
+
az network front-door waf-policy managed-rules list
|
|
1113
|
+
az network front-door waf-policy managed-rules override list
|
|
1114
|
+
az network front-door waf-policy rule list
|
|
1115
|
+
az network front-door waf-policy rule match-condition list
|
|
1116
|
+
az network front-door waf-policy rule show
|
|
1117
|
+
az network front-door waf-policy show
|
|
1089
1118
|
az network lb address-pool address list
|
|
1090
1119
|
az network lb address-pool address show
|
|
1091
1120
|
az network lb address-pool list
|
package/claude/settings.json
CHANGED
|
@@ -40,6 +40,9 @@
|
|
|
40
40
|
"Bash(assist jira auth:*)",
|
|
41
41
|
"Bash(assist jira ac:*)",
|
|
42
42
|
"Bash(assist netframework:*)",
|
|
43
|
+
"Bash(assist ravendb query:*)",
|
|
44
|
+
"Bash(assist ravendb collections:*)",
|
|
45
|
+
"Bash(assist ravendb auth --list:*)",
|
|
43
46
|
"Bash(head:*)",
|
|
44
47
|
"Bash(tail:*)",
|
|
45
48
|
"Bash(grep:*)",
|
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.114.0",
|
|
10
10
|
type: "module",
|
|
11
11
|
main: "dist/index.js",
|
|
12
12
|
bin: {
|
|
@@ -162,6 +162,17 @@ var assistConfigSchema = z.strictObject({
|
|
|
162
162
|
news: z.strictObject({
|
|
163
163
|
feeds: z.array(z.string()).default([])
|
|
164
164
|
}).default({ feeds: [] }),
|
|
165
|
+
ravendb: z.strictObject({
|
|
166
|
+
connections: z.array(
|
|
167
|
+
z.strictObject({
|
|
168
|
+
name: z.string(),
|
|
169
|
+
url: z.string(),
|
|
170
|
+
database: z.string(),
|
|
171
|
+
apiKeyRef: z.string()
|
|
172
|
+
})
|
|
173
|
+
).default([]),
|
|
174
|
+
defaultConnection: z.string().optional()
|
|
175
|
+
}).optional(),
|
|
165
176
|
voice: z.strictObject({
|
|
166
177
|
wakeWords: z.array(z.string()).default(DEFAULT_WAKE_WORDS),
|
|
167
178
|
mic: z.string().optional(),
|
|
@@ -3187,14 +3198,14 @@ async function discoverAt(cli, parentPath, depth, p) {
|
|
|
3187
3198
|
);
|
|
3188
3199
|
return results.flat();
|
|
3189
3200
|
}
|
|
3190
|
-
async function discoverAll(cli) {
|
|
3191
|
-
const topLevel = parseCommands(await runHelp([cli]));
|
|
3201
|
+
async function discoverAll(cli, prefixPath = []) {
|
|
3202
|
+
const topLevel = parseCommands(await runHelp([cli, ...prefixPath]));
|
|
3192
3203
|
const p = { done: 0, total: topLevel.length };
|
|
3193
3204
|
const results = await mapAsync(topLevel, CONCURRENCY, async (cmd) => {
|
|
3194
3205
|
showProgress(p, cmd.name);
|
|
3195
3206
|
const resolved = await resolveCommand(
|
|
3196
3207
|
cli,
|
|
3197
|
-
[cmd.name],
|
|
3208
|
+
[...prefixPath, cmd.name],
|
|
3198
3209
|
cmd.description,
|
|
3199
3210
|
1,
|
|
3200
3211
|
p
|
|
@@ -3342,20 +3353,23 @@ async function permitCliReads(cli, options2 = { noCache: false }) {
|
|
|
3342
3353
|
);
|
|
3343
3354
|
process.exit(1);
|
|
3344
3355
|
}
|
|
3356
|
+
const parts = cli.split(/\s+/);
|
|
3357
|
+
const binary = parts[0];
|
|
3358
|
+
const prefixPath = parts.slice(1);
|
|
3345
3359
|
if (!options2.noCache) {
|
|
3346
3360
|
const cached2 = readCache(cli);
|
|
3347
3361
|
if (cached2) {
|
|
3348
3362
|
console.log(colorize(cached2));
|
|
3349
|
-
updateSettings(
|
|
3363
|
+
updateSettings(binary, parseCached(binary, cached2));
|
|
3350
3364
|
return;
|
|
3351
3365
|
}
|
|
3352
3366
|
}
|
|
3353
3367
|
assertCliExists(cli);
|
|
3354
|
-
const commands = await discoverAll(
|
|
3355
|
-
const output = formatHuman(
|
|
3368
|
+
const commands = await discoverAll(binary, prefixPath);
|
|
3369
|
+
const output = formatHuman(binary, commands);
|
|
3356
3370
|
console.log(colorize(output));
|
|
3357
3371
|
writeCache(cli, output);
|
|
3358
|
-
updateSettings(
|
|
3372
|
+
updateSettings(binary, commands);
|
|
3359
3373
|
}
|
|
3360
3374
|
|
|
3361
3375
|
// src/commands/registerCliHook.ts
|
|
@@ -4543,13 +4557,13 @@ function saveJson(filename, data) {
|
|
|
4543
4557
|
// src/commands/jira/jiraAuth.ts
|
|
4544
4558
|
var CONFIG_FILE = "jira.json";
|
|
4545
4559
|
async function promptCredentials(config) {
|
|
4546
|
-
const { Input, Password } = Enquirer;
|
|
4547
|
-
const site = await new
|
|
4560
|
+
const { Input: Input2, Password } = Enquirer;
|
|
4561
|
+
const site = await new Input2({
|
|
4548
4562
|
name: "site",
|
|
4549
4563
|
message: "Jira site (e.g., mycompany.atlassian.net):",
|
|
4550
4564
|
initial: config.site
|
|
4551
4565
|
}).run();
|
|
4552
|
-
const email = await new
|
|
4566
|
+
const email = await new Input2({
|
|
4553
4567
|
name: "email",
|
|
4554
4568
|
message: "Email:",
|
|
4555
4569
|
initial: config.email
|
|
@@ -5631,12 +5645,420 @@ function registerPrs(program2) {
|
|
|
5631
5645
|
});
|
|
5632
5646
|
}
|
|
5633
5647
|
|
|
5648
|
+
// src/commands/ravendb/ravendbAuth.ts
|
|
5649
|
+
import chalk60 from "chalk";
|
|
5650
|
+
|
|
5651
|
+
// src/commands/ravendb/loadConnections.ts
|
|
5652
|
+
function loadConnections() {
|
|
5653
|
+
const raw = loadGlobalConfigRaw();
|
|
5654
|
+
const ravendb = raw.ravendb;
|
|
5655
|
+
return ravendb?.connections ?? [];
|
|
5656
|
+
}
|
|
5657
|
+
function saveConnections(connections) {
|
|
5658
|
+
const raw = loadGlobalConfigRaw();
|
|
5659
|
+
const ravendb = raw.ravendb ?? {};
|
|
5660
|
+
ravendb.connections = connections;
|
|
5661
|
+
raw.ravendb = ravendb;
|
|
5662
|
+
saveGlobalConfig(raw);
|
|
5663
|
+
}
|
|
5664
|
+
|
|
5665
|
+
// src/commands/ravendb/promptConnection.ts
|
|
5666
|
+
import chalk58 from "chalk";
|
|
5667
|
+
import Enquirer3 from "enquirer";
|
|
5668
|
+
|
|
5669
|
+
// src/commands/ravendb/selectOpSecret.ts
|
|
5670
|
+
import chalk57 from "chalk";
|
|
5671
|
+
import Enquirer2 from "enquirer";
|
|
5672
|
+
|
|
5673
|
+
// src/commands/ravendb/searchItems.ts
|
|
5674
|
+
import { execSync as execSync29 } from "child_process";
|
|
5675
|
+
import chalk56 from "chalk";
|
|
5676
|
+
function opExec(args) {
|
|
5677
|
+
return execSync29(`op ${args}`, {
|
|
5678
|
+
encoding: "utf-8",
|
|
5679
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
5680
|
+
}).trim();
|
|
5681
|
+
}
|
|
5682
|
+
function searchItems(search) {
|
|
5683
|
+
let items;
|
|
5684
|
+
try {
|
|
5685
|
+
items = JSON.parse(opExec("item list --format=json"));
|
|
5686
|
+
} catch {
|
|
5687
|
+
console.error(
|
|
5688
|
+
chalk56.red(
|
|
5689
|
+
"Failed to search 1Password. Ensure the CLI is installed and you are signed in."
|
|
5690
|
+
)
|
|
5691
|
+
);
|
|
5692
|
+
process.exit(1);
|
|
5693
|
+
}
|
|
5694
|
+
const lower = search.toLowerCase();
|
|
5695
|
+
return items.filter((i) => i.title.toLowerCase().includes(lower));
|
|
5696
|
+
}
|
|
5697
|
+
function getItemFields(itemId) {
|
|
5698
|
+
try {
|
|
5699
|
+
const item = JSON.parse(opExec(`item get "${itemId}" --format=json`));
|
|
5700
|
+
return item.fields.filter((f) => f.reference && f.label);
|
|
5701
|
+
} catch {
|
|
5702
|
+
console.error(chalk56.red("Failed to get item details from 1Password."));
|
|
5703
|
+
process.exit(1);
|
|
5704
|
+
}
|
|
5705
|
+
}
|
|
5706
|
+
|
|
5707
|
+
// src/commands/ravendb/selectOpSecret.ts
|
|
5708
|
+
var { Input, Select } = Enquirer2;
|
|
5709
|
+
async function selectOne(message, choices) {
|
|
5710
|
+
if (choices.length === 1) return choices[0].value;
|
|
5711
|
+
const selected = await new Select({ name: "choice", message, choices }).run();
|
|
5712
|
+
return choices.find((c) => c.name === selected)?.value ?? selected;
|
|
5713
|
+
}
|
|
5714
|
+
async function selectOpSecret(searchTerm) {
|
|
5715
|
+
const search = searchTerm ?? await new Input({
|
|
5716
|
+
name: "search",
|
|
5717
|
+
message: "Search 1Password for API key item:"
|
|
5718
|
+
}).run();
|
|
5719
|
+
const items = searchItems(search);
|
|
5720
|
+
if (items.length === 0) {
|
|
5721
|
+
console.error(chalk57.red(`No items found matching "${search}".`));
|
|
5722
|
+
process.exit(1);
|
|
5723
|
+
}
|
|
5724
|
+
const itemId = await selectOne(
|
|
5725
|
+
"Select item:",
|
|
5726
|
+
items.map((i) => ({ name: `${i.title} (${i.vault.name})`, value: i.id }))
|
|
5727
|
+
);
|
|
5728
|
+
const fields = getItemFields(itemId);
|
|
5729
|
+
if (fields.length === 0) {
|
|
5730
|
+
console.error(chalk57.red("No fields with references found on this item."));
|
|
5731
|
+
process.exit(1);
|
|
5732
|
+
}
|
|
5733
|
+
const ref = await selectOne(
|
|
5734
|
+
"Select field:",
|
|
5735
|
+
fields.map((f) => ({ name: f.label, value: f.reference }))
|
|
5736
|
+
);
|
|
5737
|
+
return ref;
|
|
5738
|
+
}
|
|
5739
|
+
|
|
5740
|
+
// src/commands/ravendb/promptConnection.ts
|
|
5741
|
+
async function promptConnection(existingNames) {
|
|
5742
|
+
const { Input: Input2 } = Enquirer3;
|
|
5743
|
+
const name = await new Input2({
|
|
5744
|
+
name: "name",
|
|
5745
|
+
message: "Connection name:"
|
|
5746
|
+
}).run();
|
|
5747
|
+
if (existingNames.includes(name)) {
|
|
5748
|
+
console.error(chalk58.red(`Connection "${name}" already exists.`));
|
|
5749
|
+
process.exit(1);
|
|
5750
|
+
}
|
|
5751
|
+
const url = await new Input2({
|
|
5752
|
+
name: "url",
|
|
5753
|
+
message: "RavenDB base URL (e.g. https://host.ravenhq.com):"
|
|
5754
|
+
}).run();
|
|
5755
|
+
const database = await new Input2({
|
|
5756
|
+
name: "database",
|
|
5757
|
+
message: "Database name:"
|
|
5758
|
+
}).run();
|
|
5759
|
+
if (!name || !url || !database) {
|
|
5760
|
+
console.error(chalk58.red("All fields are required."));
|
|
5761
|
+
process.exit(1);
|
|
5762
|
+
}
|
|
5763
|
+
const apiKeyRef = await selectOpSecret();
|
|
5764
|
+
console.log(chalk58.dim(`Using: ${apiKeyRef}`));
|
|
5765
|
+
return { name, url, database, apiKeyRef };
|
|
5766
|
+
}
|
|
5767
|
+
|
|
5768
|
+
// src/commands/ravendb/ravendbSetConnection.ts
|
|
5769
|
+
import chalk59 from "chalk";
|
|
5770
|
+
function ravendbSetConnection(name) {
|
|
5771
|
+
const raw = loadGlobalConfigRaw();
|
|
5772
|
+
const ravendb = raw.ravendb ?? {};
|
|
5773
|
+
const connections = ravendb.connections ?? [];
|
|
5774
|
+
if (!connections.some((c) => c.name === name)) {
|
|
5775
|
+
console.error(chalk59.red(`Connection "${name}" not found.`));
|
|
5776
|
+
console.error(
|
|
5777
|
+
`Available: ${connections.map((c) => c.name).join(", ") || "(none)"}`
|
|
5778
|
+
);
|
|
5779
|
+
process.exit(1);
|
|
5780
|
+
}
|
|
5781
|
+
ravendb.defaultConnection = name;
|
|
5782
|
+
raw.ravendb = ravendb;
|
|
5783
|
+
saveGlobalConfig(raw);
|
|
5784
|
+
console.log(`Default connection set to "${name}".`);
|
|
5785
|
+
}
|
|
5786
|
+
|
|
5787
|
+
// src/commands/ravendb/ravendbAuth.ts
|
|
5788
|
+
async function ravendbAuth(options2) {
|
|
5789
|
+
const connections = loadConnections();
|
|
5790
|
+
if (options2.list) {
|
|
5791
|
+
if (connections.length === 0) {
|
|
5792
|
+
console.log("No RavenDB connections configured.");
|
|
5793
|
+
return;
|
|
5794
|
+
}
|
|
5795
|
+
for (const c of connections) {
|
|
5796
|
+
console.log(
|
|
5797
|
+
`${chalk60.bold(c.name)} ${c.url} db=${c.database} key=${c.apiKeyRef}`
|
|
5798
|
+
);
|
|
5799
|
+
}
|
|
5800
|
+
return;
|
|
5801
|
+
}
|
|
5802
|
+
if (options2.remove) {
|
|
5803
|
+
const filtered = connections.filter((c) => c.name !== options2.remove);
|
|
5804
|
+
if (filtered.length === connections.length) {
|
|
5805
|
+
console.error(chalk60.red(`Connection "${options2.remove}" not found.`));
|
|
5806
|
+
process.exit(1);
|
|
5807
|
+
}
|
|
5808
|
+
saveConnections(filtered);
|
|
5809
|
+
console.log(`Removed connection "${options2.remove}".`);
|
|
5810
|
+
return;
|
|
5811
|
+
}
|
|
5812
|
+
const isFirst = connections.length === 0;
|
|
5813
|
+
const newConnection = await promptConnection(connections.map((c) => c.name));
|
|
5814
|
+
connections.push(newConnection);
|
|
5815
|
+
saveConnections(connections);
|
|
5816
|
+
if (isFirst) {
|
|
5817
|
+
ravendbSetConnection(newConnection.name);
|
|
5818
|
+
}
|
|
5819
|
+
console.log(`Connection "${newConnection.name}" saved.`);
|
|
5820
|
+
}
|
|
5821
|
+
|
|
5822
|
+
// src/commands/ravendb/ravendbCollections.ts
|
|
5823
|
+
import chalk64 from "chalk";
|
|
5824
|
+
|
|
5825
|
+
// src/commands/ravendb/ravenFetch.ts
|
|
5826
|
+
import chalk62 from "chalk";
|
|
5827
|
+
|
|
5828
|
+
// src/commands/ravendb/getAccessToken.ts
|
|
5829
|
+
var OAUTH_URL = "https://amazon-useast-1-oauth.ravenhq.com/ApiKeys/OAuth/AccessToken";
|
|
5830
|
+
var TOKEN_CACHE_MS = 50 * 60 * 1e3;
|
|
5831
|
+
var tokenCache = /* @__PURE__ */ new Map();
|
|
5832
|
+
function clearCachedToken(apiKey) {
|
|
5833
|
+
tokenCache.delete(apiKey);
|
|
5834
|
+
}
|
|
5835
|
+
async function getAccessToken(apiKey) {
|
|
5836
|
+
const now = Date.now();
|
|
5837
|
+
const cached2 = tokenCache.get(apiKey);
|
|
5838
|
+
if (cached2 && now < cached2.expiry) {
|
|
5839
|
+
return cached2.token;
|
|
5840
|
+
}
|
|
5841
|
+
const response = await fetch(OAUTH_URL, {
|
|
5842
|
+
method: "GET",
|
|
5843
|
+
headers: {
|
|
5844
|
+
"Api-Key": apiKey,
|
|
5845
|
+
grant_type: "client_credentials"
|
|
5846
|
+
}
|
|
5847
|
+
});
|
|
5848
|
+
if (!response.ok) {
|
|
5849
|
+
const errorText = await response.text();
|
|
5850
|
+
throw new Error(
|
|
5851
|
+
`Failed to get access token: ${response.status} ${response.statusText}
|
|
5852
|
+
${errorText}`
|
|
5853
|
+
);
|
|
5854
|
+
}
|
|
5855
|
+
const tokenData = await response.json();
|
|
5856
|
+
const token = JSON.stringify(tokenData);
|
|
5857
|
+
tokenCache.set(apiKey, { token, expiry: now + TOKEN_CACHE_MS });
|
|
5858
|
+
return token;
|
|
5859
|
+
}
|
|
5860
|
+
|
|
5861
|
+
// src/commands/ravendb/resolveOpSecret.ts
|
|
5862
|
+
import { execSync as execSync30 } from "child_process";
|
|
5863
|
+
import chalk61 from "chalk";
|
|
5864
|
+
function resolveOpSecret(reference) {
|
|
5865
|
+
if (!reference.startsWith("op://")) {
|
|
5866
|
+
console.error(chalk61.red(`Invalid secret reference: must start with op://`));
|
|
5867
|
+
process.exit(1);
|
|
5868
|
+
}
|
|
5869
|
+
try {
|
|
5870
|
+
return execSync30(`op read "${reference}"`, {
|
|
5871
|
+
encoding: "utf-8",
|
|
5872
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
5873
|
+
}).trim();
|
|
5874
|
+
} catch {
|
|
5875
|
+
console.error(
|
|
5876
|
+
chalk61.red(
|
|
5877
|
+
"Failed to resolve secret reference. Ensure 1Password CLI is installed and you are signed in."
|
|
5878
|
+
)
|
|
5879
|
+
);
|
|
5880
|
+
process.exit(1);
|
|
5881
|
+
}
|
|
5882
|
+
}
|
|
5883
|
+
|
|
5884
|
+
// src/commands/ravendb/ravenFetch.ts
|
|
5885
|
+
async function ravenFetch(connection, path42) {
|
|
5886
|
+
const apiKey = resolveOpSecret(connection.apiKeyRef);
|
|
5887
|
+
let accessToken = await getAccessToken(apiKey);
|
|
5888
|
+
const url = `${connection.url}${path42}`;
|
|
5889
|
+
const headers = {
|
|
5890
|
+
Authorization: `Bearer ${accessToken}`,
|
|
5891
|
+
"Content-Type": "application/json"
|
|
5892
|
+
};
|
|
5893
|
+
let response = await fetch(url, { headers });
|
|
5894
|
+
if (response.status === 401) {
|
|
5895
|
+
clearCachedToken(apiKey);
|
|
5896
|
+
accessToken = await getAccessToken(apiKey);
|
|
5897
|
+
headers.Authorization = `Bearer ${accessToken}`;
|
|
5898
|
+
response = await fetch(url, { headers });
|
|
5899
|
+
}
|
|
5900
|
+
if (!response.ok) {
|
|
5901
|
+
const body = await response.text();
|
|
5902
|
+
console.error(
|
|
5903
|
+
chalk62.red(`RavenDB error: ${response.status} ${response.statusText}`)
|
|
5904
|
+
);
|
|
5905
|
+
console.error(body.substring(0, 500));
|
|
5906
|
+
process.exit(1);
|
|
5907
|
+
}
|
|
5908
|
+
return response.json();
|
|
5909
|
+
}
|
|
5910
|
+
|
|
5911
|
+
// src/commands/ravendb/resolveConnection.ts
|
|
5912
|
+
import chalk63 from "chalk";
|
|
5913
|
+
function loadRavendb() {
|
|
5914
|
+
const raw = loadGlobalConfigRaw();
|
|
5915
|
+
const ravendb = raw.ravendb;
|
|
5916
|
+
return {
|
|
5917
|
+
connections: ravendb?.connections ?? [],
|
|
5918
|
+
defaultConnection: ravendb?.defaultConnection
|
|
5919
|
+
};
|
|
5920
|
+
}
|
|
5921
|
+
function resolveConnection(name) {
|
|
5922
|
+
const { connections, defaultConnection } = loadRavendb();
|
|
5923
|
+
const connectionName = name ?? defaultConnection;
|
|
5924
|
+
if (!connectionName) {
|
|
5925
|
+
console.error(
|
|
5926
|
+
chalk63.red(
|
|
5927
|
+
"No connection specified and no default set. Use assist ravendb set-connection <name> or pass a connection name."
|
|
5928
|
+
)
|
|
5929
|
+
);
|
|
5930
|
+
process.exit(1);
|
|
5931
|
+
}
|
|
5932
|
+
const connection = connections.find((c) => c.name === connectionName);
|
|
5933
|
+
if (!connection) {
|
|
5934
|
+
console.error(chalk63.red(`Connection "${connectionName}" not found.`));
|
|
5935
|
+
console.error(
|
|
5936
|
+
`Available: ${connections.map((c) => c.name).join(", ") || "(none)"}`
|
|
5937
|
+
);
|
|
5938
|
+
console.error("Run assist ravendb auth to add a connection.");
|
|
5939
|
+
process.exit(1);
|
|
5940
|
+
}
|
|
5941
|
+
return connection;
|
|
5942
|
+
}
|
|
5943
|
+
function resolveArgs(first, second) {
|
|
5944
|
+
const { connections } = loadRavendb();
|
|
5945
|
+
const isConnection = first && connections.some((c) => c.name === first);
|
|
5946
|
+
if (isConnection) {
|
|
5947
|
+
return { connection: resolveConnection(first), collection: second };
|
|
5948
|
+
}
|
|
5949
|
+
return { connection: resolveConnection(void 0), collection: first };
|
|
5950
|
+
}
|
|
5951
|
+
|
|
5952
|
+
// src/commands/ravendb/ravendbCollections.ts
|
|
5953
|
+
async function ravendbCollections(connectionName) {
|
|
5954
|
+
const connection = resolveConnection(connectionName);
|
|
5955
|
+
const data = await ravenFetch(
|
|
5956
|
+
connection,
|
|
5957
|
+
`/databases/${encodeURIComponent(connection.database)}/collections/stats`
|
|
5958
|
+
);
|
|
5959
|
+
const collections = data.Collections ?? [];
|
|
5960
|
+
if (collections.length === 0) {
|
|
5961
|
+
console.log("No collections found.");
|
|
5962
|
+
return;
|
|
5963
|
+
}
|
|
5964
|
+
for (const c of collections) {
|
|
5965
|
+
console.log(`${chalk64.bold(c.Name)} ${c.CountOfDocuments} docs`);
|
|
5966
|
+
}
|
|
5967
|
+
}
|
|
5968
|
+
|
|
5969
|
+
// src/commands/ravendb/ravendbQuery.ts
|
|
5970
|
+
import chalk66 from "chalk";
|
|
5971
|
+
|
|
5972
|
+
// src/commands/ravendb/fetchAllPages.ts
|
|
5973
|
+
import chalk65 from "chalk";
|
|
5974
|
+
|
|
5975
|
+
// src/commands/ravendb/buildQueryPath.ts
|
|
5976
|
+
function buildQueryPath(opts) {
|
|
5977
|
+
const db = encodeURIComponent(opts.db);
|
|
5978
|
+
let path42;
|
|
5979
|
+
if (opts.collection) {
|
|
5980
|
+
path42 = `/databases/${db}/indexes/dynamic/${encodeURIComponent(opts.collection)}?start=${opts.start}&pageSize=${opts.pageSize}&sort=${encodeURIComponent(opts.sort)}`;
|
|
5981
|
+
} else {
|
|
5982
|
+
path42 = `/databases/${db}/queries?start=${opts.start}&pageSize=${opts.pageSize}`;
|
|
5983
|
+
}
|
|
5984
|
+
if (opts.query) {
|
|
5985
|
+
path42 += `&query=${encodeURIComponent(opts.query)}`;
|
|
5986
|
+
}
|
|
5987
|
+
return path42;
|
|
5988
|
+
}
|
|
5989
|
+
|
|
5990
|
+
// src/commands/ravendb/fetchAllPages.ts
|
|
5991
|
+
async function fetchAllPages(connection, opts) {
|
|
5992
|
+
const allResults = [];
|
|
5993
|
+
let start3 = 0;
|
|
5994
|
+
while (true) {
|
|
5995
|
+
const effectivePageSize = opts.limit !== void 0 ? Math.min(opts.pageSize, opts.limit - allResults.length) : opts.pageSize;
|
|
5996
|
+
const path42 = buildQueryPath({
|
|
5997
|
+
db: connection.database,
|
|
5998
|
+
collection: opts.collection,
|
|
5999
|
+
start: start3,
|
|
6000
|
+
pageSize: effectivePageSize,
|
|
6001
|
+
sort: opts.sort,
|
|
6002
|
+
query: opts.query
|
|
6003
|
+
});
|
|
6004
|
+
const data = await ravenFetch(connection, path42);
|
|
6005
|
+
const results = data.Results ?? [];
|
|
6006
|
+
const totalResults = data.TotalResults ?? 0;
|
|
6007
|
+
if (results.length === 0) break;
|
|
6008
|
+
allResults.push(...results);
|
|
6009
|
+
start3 += results.length;
|
|
6010
|
+
process.stderr.write(
|
|
6011
|
+
`\r${chalk65.dim(`Fetched ${allResults.length}/${totalResults}`)}`
|
|
6012
|
+
);
|
|
6013
|
+
if (start3 >= totalResults) break;
|
|
6014
|
+
if (opts.limit !== void 0 && allResults.length >= opts.limit) break;
|
|
6015
|
+
}
|
|
6016
|
+
if (allResults.length > 0) {
|
|
6017
|
+
process.stderr.write("\n");
|
|
6018
|
+
}
|
|
6019
|
+
return allResults;
|
|
6020
|
+
}
|
|
6021
|
+
|
|
6022
|
+
// src/commands/ravendb/ravendbQuery.ts
|
|
6023
|
+
async function ravendbQuery(connectionName, collection, options2) {
|
|
6024
|
+
const resolved = resolveArgs(connectionName, collection);
|
|
6025
|
+
if (!resolved.collection && !options2.query) {
|
|
6026
|
+
console.error(chalk66.red("Provide a collection name or --query filter."));
|
|
6027
|
+
process.exit(1);
|
|
6028
|
+
}
|
|
6029
|
+
const { collection: col } = resolved;
|
|
6030
|
+
const connection = resolved.connection;
|
|
6031
|
+
const allResults = await fetchAllPages(connection, {
|
|
6032
|
+
collection: col,
|
|
6033
|
+
pageSize: Number.parseInt(options2.pageSize ?? "25", 10),
|
|
6034
|
+
sort: options2.sort ?? "-@metadata.Last-Modified",
|
|
6035
|
+
query: options2.query,
|
|
6036
|
+
limit: options2.limit ? Number.parseInt(options2.limit, 10) : void 0
|
|
6037
|
+
});
|
|
6038
|
+
console.log(JSON.stringify(allResults, null, 2));
|
|
6039
|
+
}
|
|
6040
|
+
|
|
6041
|
+
// src/commands/registerRavendb.ts
|
|
6042
|
+
function registerRavendb(program2) {
|
|
6043
|
+
const cmd = program2.command("ravendb").description("RavenDB query utilities");
|
|
6044
|
+
cmd.command("auth").description("Configure a named RavenDB connection").option("--list", "List configured connections").option("--remove <name>", "Remove a configured connection").action((options2) => ravendbAuth(options2));
|
|
6045
|
+
cmd.command("set-connection <name>").description("Set the default connection").action((name) => ravendbSetConnection(name));
|
|
6046
|
+
cmd.command("query [connection] [collection]").description("Query a RavenDB collection").option("--page-size <n>", "Documents per page", "25").option(
|
|
6047
|
+
"--sort <field>",
|
|
6048
|
+
"Sort field (prefix - for descending)",
|
|
6049
|
+
"-@metadata.Last-Modified"
|
|
6050
|
+
).option("--query <lucene>", "Lucene filter query").option("--limit <n>", "Max total documents to fetch").action(
|
|
6051
|
+
(connection, collection, options2) => ravendbQuery(connection, collection, options2)
|
|
6052
|
+
);
|
|
6053
|
+
cmd.command("collections [connection]").description("List collections in a RavenDB database").action((connection) => ravendbCollections(connection));
|
|
6054
|
+
}
|
|
6055
|
+
|
|
5634
6056
|
// src/commands/refactor/check/index.ts
|
|
5635
6057
|
import { spawn as spawn3 } from "child_process";
|
|
5636
6058
|
import * as path25 from "path";
|
|
5637
6059
|
|
|
5638
6060
|
// src/commands/refactor/logViolations.ts
|
|
5639
|
-
import
|
|
6061
|
+
import chalk67 from "chalk";
|
|
5640
6062
|
var DEFAULT_MAX_LINES = 100;
|
|
5641
6063
|
function logViolations(violations, maxLines = DEFAULT_MAX_LINES) {
|
|
5642
6064
|
if (violations.length === 0) {
|
|
@@ -5645,43 +6067,43 @@ function logViolations(violations, maxLines = DEFAULT_MAX_LINES) {
|
|
|
5645
6067
|
}
|
|
5646
6068
|
return;
|
|
5647
6069
|
}
|
|
5648
|
-
console.error(
|
|
6070
|
+
console.error(chalk67.red(`
|
|
5649
6071
|
Refactor check failed:
|
|
5650
6072
|
`));
|
|
5651
|
-
console.error(
|
|
6073
|
+
console.error(chalk67.red(` The following files exceed ${maxLines} lines:
|
|
5652
6074
|
`));
|
|
5653
6075
|
for (const violation of violations) {
|
|
5654
|
-
console.error(
|
|
6076
|
+
console.error(chalk67.red(` ${violation.file} (${violation.lines} lines)`));
|
|
5655
6077
|
}
|
|
5656
6078
|
console.error(
|
|
5657
|
-
|
|
6079
|
+
chalk67.yellow(
|
|
5658
6080
|
`
|
|
5659
6081
|
Each file needs to be sensibly refactored, or if there is no sensible
|
|
5660
6082
|
way to refactor it, ignore it with:
|
|
5661
6083
|
`
|
|
5662
6084
|
)
|
|
5663
6085
|
);
|
|
5664
|
-
console.error(
|
|
6086
|
+
console.error(chalk67.gray(` assist refactor ignore <file>
|
|
5665
6087
|
`));
|
|
5666
6088
|
if (process.env.CLAUDECODE) {
|
|
5667
|
-
console.error(
|
|
6089
|
+
console.error(chalk67.cyan(`
|
|
5668
6090
|
## Extracting Code to New Files
|
|
5669
6091
|
`));
|
|
5670
6092
|
console.error(
|
|
5671
|
-
|
|
6093
|
+
chalk67.cyan(
|
|
5672
6094
|
` When extracting logic from one file to another, consider where the extracted code belongs:
|
|
5673
6095
|
`
|
|
5674
6096
|
)
|
|
5675
6097
|
);
|
|
5676
6098
|
console.error(
|
|
5677
|
-
|
|
6099
|
+
chalk67.cyan(
|
|
5678
6100
|
` 1. Keep related logic together: If the extracted code is tightly coupled to the
|
|
5679
6101
|
original file's domain, create a new folder containing both the original and extracted files.
|
|
5680
6102
|
`
|
|
5681
6103
|
)
|
|
5682
6104
|
);
|
|
5683
6105
|
console.error(
|
|
5684
|
-
|
|
6106
|
+
chalk67.cyan(
|
|
5685
6107
|
` 2. Share common utilities: If the extracted code can be reused across multiple
|
|
5686
6108
|
domains, move it to a common/shared folder.
|
|
5687
6109
|
`
|
|
@@ -5691,7 +6113,7 @@ Refactor check failed:
|
|
|
5691
6113
|
}
|
|
5692
6114
|
|
|
5693
6115
|
// src/commands/refactor/check/getViolations/index.ts
|
|
5694
|
-
import { execSync as
|
|
6116
|
+
import { execSync as execSync31 } from "child_process";
|
|
5695
6117
|
import fs16 from "fs";
|
|
5696
6118
|
import { minimatch as minimatch4 } from "minimatch";
|
|
5697
6119
|
|
|
@@ -5741,7 +6163,7 @@ function getGitFiles(options2) {
|
|
|
5741
6163
|
}
|
|
5742
6164
|
const files = /* @__PURE__ */ new Set();
|
|
5743
6165
|
if (options2.staged || options2.modified) {
|
|
5744
|
-
const staged =
|
|
6166
|
+
const staged = execSync31("git diff --cached --name-only", {
|
|
5745
6167
|
encoding: "utf-8"
|
|
5746
6168
|
});
|
|
5747
6169
|
for (const file of staged.trim().split("\n").filter(Boolean)) {
|
|
@@ -5749,7 +6171,7 @@ function getGitFiles(options2) {
|
|
|
5749
6171
|
}
|
|
5750
6172
|
}
|
|
5751
6173
|
if (options2.unstaged || options2.modified) {
|
|
5752
|
-
const unstaged =
|
|
6174
|
+
const unstaged = execSync31("git diff --name-only", { encoding: "utf-8" });
|
|
5753
6175
|
for (const file of unstaged.trim().split("\n").filter(Boolean)) {
|
|
5754
6176
|
files.add(file);
|
|
5755
6177
|
}
|
|
@@ -5837,11 +6259,11 @@ async function check(pattern2, options2) {
|
|
|
5837
6259
|
|
|
5838
6260
|
// src/commands/refactor/ignore.ts
|
|
5839
6261
|
import fs17 from "fs";
|
|
5840
|
-
import
|
|
6262
|
+
import chalk68 from "chalk";
|
|
5841
6263
|
var REFACTOR_YML_PATH2 = "refactor.yml";
|
|
5842
6264
|
function ignore(file) {
|
|
5843
6265
|
if (!fs17.existsSync(file)) {
|
|
5844
|
-
console.error(
|
|
6266
|
+
console.error(chalk68.red(`Error: File does not exist: ${file}`));
|
|
5845
6267
|
process.exit(1);
|
|
5846
6268
|
}
|
|
5847
6269
|
const content = fs17.readFileSync(file, "utf-8");
|
|
@@ -5857,7 +6279,7 @@ function ignore(file) {
|
|
|
5857
6279
|
fs17.writeFileSync(REFACTOR_YML_PATH2, entry);
|
|
5858
6280
|
}
|
|
5859
6281
|
console.log(
|
|
5860
|
-
|
|
6282
|
+
chalk68.green(
|
|
5861
6283
|
`Added ${file} to refactor ignore list (max ${maxLines} lines)`
|
|
5862
6284
|
)
|
|
5863
6285
|
);
|
|
@@ -5865,7 +6287,7 @@ function ignore(file) {
|
|
|
5865
6287
|
|
|
5866
6288
|
// src/commands/refactor/rename/index.ts
|
|
5867
6289
|
import path26 from "path";
|
|
5868
|
-
import
|
|
6290
|
+
import chalk69 from "chalk";
|
|
5869
6291
|
import { Project as Project2 } from "ts-morph";
|
|
5870
6292
|
async function rename(source, destination, options2 = {}) {
|
|
5871
6293
|
const sourcePath = path26.resolve(source);
|
|
@@ -5878,22 +6300,22 @@ async function rename(source, destination, options2 = {}) {
|
|
|
5878
6300
|
});
|
|
5879
6301
|
const sourceFile = project.getSourceFile(sourcePath);
|
|
5880
6302
|
if (!sourceFile) {
|
|
5881
|
-
console.log(
|
|
6303
|
+
console.log(chalk69.red(`File not found in project: ${source}`));
|
|
5882
6304
|
process.exit(1);
|
|
5883
6305
|
}
|
|
5884
|
-
console.log(
|
|
6306
|
+
console.log(chalk69.bold(`Rename: ${relSource} \u2192 ${relDest}`));
|
|
5885
6307
|
if (options2.apply) {
|
|
5886
6308
|
sourceFile.move(destPath);
|
|
5887
6309
|
await project.save();
|
|
5888
|
-
console.log(
|
|
6310
|
+
console.log(chalk69.green("Done"));
|
|
5889
6311
|
} else {
|
|
5890
|
-
console.log(
|
|
6312
|
+
console.log(chalk69.dim("Dry run. Use --apply to execute."));
|
|
5891
6313
|
}
|
|
5892
6314
|
}
|
|
5893
6315
|
|
|
5894
6316
|
// src/commands/refactor/renameSymbol/index.ts
|
|
5895
6317
|
import path28 from "path";
|
|
5896
|
-
import
|
|
6318
|
+
import chalk70 from "chalk";
|
|
5897
6319
|
import { Project as Project3 } from "ts-morph";
|
|
5898
6320
|
|
|
5899
6321
|
// src/commands/refactor/renameSymbol/findSymbol.ts
|
|
@@ -5942,38 +6364,38 @@ async function renameSymbol(file, oldName, newName, options2 = {}) {
|
|
|
5942
6364
|
const project = new Project3({ tsConfigFilePath: tsConfigPath });
|
|
5943
6365
|
const sourceFile = project.getSourceFile(filePath);
|
|
5944
6366
|
if (!sourceFile) {
|
|
5945
|
-
console.log(
|
|
6367
|
+
console.log(chalk70.red(`File not found in project: ${file}`));
|
|
5946
6368
|
process.exit(1);
|
|
5947
6369
|
}
|
|
5948
6370
|
const symbol = findSymbol(sourceFile, oldName);
|
|
5949
6371
|
if (!symbol) {
|
|
5950
|
-
console.log(
|
|
6372
|
+
console.log(chalk70.red(`Symbol "${oldName}" not found in ${file}`));
|
|
5951
6373
|
process.exit(1);
|
|
5952
6374
|
}
|
|
5953
6375
|
const grouped = groupReferences(symbol, cwd);
|
|
5954
6376
|
const totalRefs = [...grouped.values()].reduce((s, l) => s + l.length, 0);
|
|
5955
6377
|
console.log(
|
|
5956
|
-
|
|
6378
|
+
chalk70.bold(`Rename: ${oldName} \u2192 ${newName} (${totalRefs} references)
|
|
5957
6379
|
`)
|
|
5958
6380
|
);
|
|
5959
6381
|
for (const [refFile, lines] of grouped) {
|
|
5960
6382
|
console.log(
|
|
5961
|
-
` ${
|
|
6383
|
+
` ${chalk70.dim(refFile)}: lines ${chalk70.cyan(lines.join(", "))}`
|
|
5962
6384
|
);
|
|
5963
6385
|
}
|
|
5964
6386
|
if (options2.apply) {
|
|
5965
6387
|
symbol.rename(newName);
|
|
5966
6388
|
await project.save();
|
|
5967
|
-
console.log(
|
|
6389
|
+
console.log(chalk70.green(`
|
|
5968
6390
|
Renamed ${oldName} \u2192 ${newName}`));
|
|
5969
6391
|
} else {
|
|
5970
|
-
console.log(
|
|
6392
|
+
console.log(chalk70.dim("\nDry run. Use --apply to execute."));
|
|
5971
6393
|
}
|
|
5972
6394
|
}
|
|
5973
6395
|
|
|
5974
6396
|
// src/commands/refactor/restructure/index.ts
|
|
5975
6397
|
import path37 from "path";
|
|
5976
|
-
import
|
|
6398
|
+
import chalk73 from "chalk";
|
|
5977
6399
|
|
|
5978
6400
|
// src/commands/refactor/restructure/buildImportGraph/index.ts
|
|
5979
6401
|
import path29 from "path";
|
|
@@ -6216,50 +6638,50 @@ function computeRewrites(moves, edges, allProjectFiles) {
|
|
|
6216
6638
|
|
|
6217
6639
|
// src/commands/refactor/restructure/displayPlan.ts
|
|
6218
6640
|
import path33 from "path";
|
|
6219
|
-
import
|
|
6641
|
+
import chalk71 from "chalk";
|
|
6220
6642
|
function relPath(filePath) {
|
|
6221
6643
|
return path33.relative(process.cwd(), filePath);
|
|
6222
6644
|
}
|
|
6223
6645
|
function displayMoves(plan) {
|
|
6224
6646
|
if (plan.moves.length === 0) return;
|
|
6225
|
-
console.log(
|
|
6647
|
+
console.log(chalk71.bold("\nFile moves:"));
|
|
6226
6648
|
for (const move of plan.moves) {
|
|
6227
6649
|
console.log(
|
|
6228
|
-
` ${
|
|
6650
|
+
` ${chalk71.red(relPath(move.from))} \u2192 ${chalk71.green(relPath(move.to))}`
|
|
6229
6651
|
);
|
|
6230
|
-
console.log(
|
|
6652
|
+
console.log(chalk71.dim(` ${move.reason}`));
|
|
6231
6653
|
}
|
|
6232
6654
|
}
|
|
6233
6655
|
function displayRewrites(rewrites) {
|
|
6234
6656
|
if (rewrites.length === 0) return;
|
|
6235
6657
|
const affectedFiles = new Set(rewrites.map((r) => r.file));
|
|
6236
|
-
console.log(
|
|
6658
|
+
console.log(chalk71.bold(`
|
|
6237
6659
|
Import rewrites (${affectedFiles.size} files):`));
|
|
6238
6660
|
for (const file of affectedFiles) {
|
|
6239
|
-
console.log(` ${
|
|
6661
|
+
console.log(` ${chalk71.cyan(relPath(file))}:`);
|
|
6240
6662
|
for (const { oldSpecifier, newSpecifier } of rewrites.filter(
|
|
6241
6663
|
(r) => r.file === file
|
|
6242
6664
|
)) {
|
|
6243
6665
|
console.log(
|
|
6244
|
-
` ${
|
|
6666
|
+
` ${chalk71.red(`"${oldSpecifier}"`)} \u2192 ${chalk71.green(`"${newSpecifier}"`)}`
|
|
6245
6667
|
);
|
|
6246
6668
|
}
|
|
6247
6669
|
}
|
|
6248
6670
|
}
|
|
6249
6671
|
function displayPlan(plan) {
|
|
6250
6672
|
if (plan.warnings.length > 0) {
|
|
6251
|
-
console.log(
|
|
6252
|
-
for (const w of plan.warnings) console.log(
|
|
6673
|
+
console.log(chalk71.yellow("\nWarnings:"));
|
|
6674
|
+
for (const w of plan.warnings) console.log(chalk71.yellow(` ${w}`));
|
|
6253
6675
|
}
|
|
6254
6676
|
if (plan.newDirectories.length > 0) {
|
|
6255
|
-
console.log(
|
|
6677
|
+
console.log(chalk71.bold("\nNew directories:"));
|
|
6256
6678
|
for (const dir of plan.newDirectories)
|
|
6257
|
-
console.log(
|
|
6679
|
+
console.log(chalk71.green(` ${dir}/`));
|
|
6258
6680
|
}
|
|
6259
6681
|
displayMoves(plan);
|
|
6260
6682
|
displayRewrites(plan.rewrites);
|
|
6261
6683
|
console.log(
|
|
6262
|
-
|
|
6684
|
+
chalk71.dim(
|
|
6263
6685
|
`
|
|
6264
6686
|
Summary: ${plan.moves.length} file(s) moved, ${plan.rewrites.length} imports rewritten`
|
|
6265
6687
|
)
|
|
@@ -6269,18 +6691,18 @@ Summary: ${plan.moves.length} file(s) moved, ${plan.rewrites.length} imports rew
|
|
|
6269
6691
|
// src/commands/refactor/restructure/executePlan.ts
|
|
6270
6692
|
import fs19 from "fs";
|
|
6271
6693
|
import path34 from "path";
|
|
6272
|
-
import
|
|
6694
|
+
import chalk72 from "chalk";
|
|
6273
6695
|
function executePlan(plan) {
|
|
6274
6696
|
const updatedContents = applyRewrites(plan.rewrites);
|
|
6275
6697
|
for (const [file, content] of updatedContents) {
|
|
6276
6698
|
fs19.writeFileSync(file, content, "utf-8");
|
|
6277
6699
|
console.log(
|
|
6278
|
-
|
|
6700
|
+
chalk72.cyan(` Rewrote imports in ${path34.relative(process.cwd(), file)}`)
|
|
6279
6701
|
);
|
|
6280
6702
|
}
|
|
6281
6703
|
for (const dir of plan.newDirectories) {
|
|
6282
6704
|
fs19.mkdirSync(dir, { recursive: true });
|
|
6283
|
-
console.log(
|
|
6705
|
+
console.log(chalk72.green(` Created ${path34.relative(process.cwd(), dir)}/`));
|
|
6284
6706
|
}
|
|
6285
6707
|
for (const move of plan.moves) {
|
|
6286
6708
|
const targetDir = path34.dirname(move.to);
|
|
@@ -6289,7 +6711,7 @@ function executePlan(plan) {
|
|
|
6289
6711
|
}
|
|
6290
6712
|
fs19.renameSync(move.from, move.to);
|
|
6291
6713
|
console.log(
|
|
6292
|
-
|
|
6714
|
+
chalk72.white(
|
|
6293
6715
|
` Moved ${path34.relative(process.cwd(), move.from)} \u2192 ${path34.relative(process.cwd(), move.to)}`
|
|
6294
6716
|
)
|
|
6295
6717
|
);
|
|
@@ -6304,7 +6726,7 @@ function removeEmptyDirectories(dirs) {
|
|
|
6304
6726
|
if (entries.length === 0) {
|
|
6305
6727
|
fs19.rmdirSync(dir);
|
|
6306
6728
|
console.log(
|
|
6307
|
-
|
|
6729
|
+
chalk72.dim(
|
|
6308
6730
|
` Removed empty directory ${path34.relative(process.cwd(), dir)}`
|
|
6309
6731
|
)
|
|
6310
6732
|
);
|
|
@@ -6437,22 +6859,22 @@ async function restructure(pattern2, options2 = {}) {
|
|
|
6437
6859
|
const targetPattern = pattern2 ?? "src";
|
|
6438
6860
|
const files = findSourceFiles2(targetPattern);
|
|
6439
6861
|
if (files.length === 0) {
|
|
6440
|
-
console.log(
|
|
6862
|
+
console.log(chalk73.yellow("No files found matching pattern"));
|
|
6441
6863
|
return;
|
|
6442
6864
|
}
|
|
6443
6865
|
const tsConfigPath = path37.resolve("tsconfig.json");
|
|
6444
6866
|
const plan = buildPlan(files, tsConfigPath);
|
|
6445
6867
|
if (plan.moves.length === 0) {
|
|
6446
|
-
console.log(
|
|
6868
|
+
console.log(chalk73.green("No restructuring needed"));
|
|
6447
6869
|
return;
|
|
6448
6870
|
}
|
|
6449
6871
|
displayPlan(plan);
|
|
6450
6872
|
if (options2.apply) {
|
|
6451
|
-
console.log(
|
|
6873
|
+
console.log(chalk73.bold("\nApplying changes..."));
|
|
6452
6874
|
executePlan(plan);
|
|
6453
|
-
console.log(
|
|
6875
|
+
console.log(chalk73.green("\nRestructuring complete"));
|
|
6454
6876
|
} else {
|
|
6455
|
-
console.log(
|
|
6877
|
+
console.log(chalk73.dim("\nDry run. Use --apply to execute."));
|
|
6456
6878
|
}
|
|
6457
6879
|
}
|
|
6458
6880
|
|
|
@@ -7000,14 +7422,14 @@ import {
|
|
|
7000
7422
|
import { dirname as dirname18, join as join26 } from "path";
|
|
7001
7423
|
|
|
7002
7424
|
// src/commands/transcript/summarise/processStagedFile/validateStagedContent.ts
|
|
7003
|
-
import
|
|
7425
|
+
import chalk74 from "chalk";
|
|
7004
7426
|
var FULL_TRANSCRIPT_REGEX = /^\[Full Transcript\]\(([^)]+)\)/;
|
|
7005
7427
|
function validateStagedContent(filename, content) {
|
|
7006
7428
|
const firstLine = content.split("\n")[0];
|
|
7007
7429
|
const match = firstLine.match(FULL_TRANSCRIPT_REGEX);
|
|
7008
7430
|
if (!match) {
|
|
7009
7431
|
console.error(
|
|
7010
|
-
|
|
7432
|
+
chalk74.red(
|
|
7011
7433
|
`Staged file ${filename} missing [Full Transcript](<path>) link on first line.`
|
|
7012
7434
|
)
|
|
7013
7435
|
);
|
|
@@ -7016,7 +7438,7 @@ function validateStagedContent(filename, content) {
|
|
|
7016
7438
|
const contentAfterLink = content.slice(firstLine.length).trim();
|
|
7017
7439
|
if (!contentAfterLink) {
|
|
7018
7440
|
console.error(
|
|
7019
|
-
|
|
7441
|
+
chalk74.red(
|
|
7020
7442
|
`Staged file ${filename} has no summary content after the transcript link.`
|
|
7021
7443
|
)
|
|
7022
7444
|
);
|
|
@@ -7216,7 +7638,7 @@ import { mkdirSync as mkdirSync10 } from "fs";
|
|
|
7216
7638
|
import { join as join31 } from "path";
|
|
7217
7639
|
|
|
7218
7640
|
// src/commands/voice/checkLockFile.ts
|
|
7219
|
-
import { execSync as
|
|
7641
|
+
import { execSync as execSync32 } from "child_process";
|
|
7220
7642
|
import { existsSync as existsSync31, mkdirSync as mkdirSync9, readFileSync as readFileSync25, writeFileSync as writeFileSync23 } from "fs";
|
|
7221
7643
|
import { join as join30 } from "path";
|
|
7222
7644
|
function isProcessAlive(pid) {
|
|
@@ -7245,7 +7667,7 @@ function bootstrapVenv() {
|
|
|
7245
7667
|
if (existsSync31(getVenvPython())) return;
|
|
7246
7668
|
console.log("Setting up Python environment...");
|
|
7247
7669
|
const pythonDir = getPythonDir();
|
|
7248
|
-
|
|
7670
|
+
execSync32(
|
|
7249
7671
|
`uv sync --project "${pythonDir}" --extra runtime --no-install-project`,
|
|
7250
7672
|
{
|
|
7251
7673
|
stdio: "inherit",
|
|
@@ -7409,14 +7831,14 @@ function registerVoice(program2) {
|
|
|
7409
7831
|
|
|
7410
7832
|
// src/commands/roam/auth.ts
|
|
7411
7833
|
import { randomBytes } from "crypto";
|
|
7412
|
-
import
|
|
7834
|
+
import chalk75 from "chalk";
|
|
7413
7835
|
|
|
7414
7836
|
// src/lib/openBrowser.ts
|
|
7415
|
-
import { execSync as
|
|
7837
|
+
import { execSync as execSync33 } from "child_process";
|
|
7416
7838
|
function tryExec(commands) {
|
|
7417
7839
|
for (const cmd of commands) {
|
|
7418
7840
|
try {
|
|
7419
|
-
|
|
7841
|
+
execSync33(cmd);
|
|
7420
7842
|
return true;
|
|
7421
7843
|
} catch {
|
|
7422
7844
|
}
|
|
@@ -7584,13 +8006,13 @@ async function auth() {
|
|
|
7584
8006
|
saveGlobalConfig(config);
|
|
7585
8007
|
const state = randomBytes(16).toString("hex");
|
|
7586
8008
|
console.log(
|
|
7587
|
-
|
|
8009
|
+
chalk75.yellow("\nEnsure this Redirect URI is set in your Roam OAuth app:")
|
|
7588
8010
|
);
|
|
7589
|
-
console.log(
|
|
7590
|
-
console.log(
|
|
7591
|
-
console.log(
|
|
8011
|
+
console.log(chalk75.white("http://localhost:14523/callback\n"));
|
|
8012
|
+
console.log(chalk75.blue("Opening browser for authorization..."));
|
|
8013
|
+
console.log(chalk75.dim("Waiting for authorization callback..."));
|
|
7592
8014
|
const { code, redirectUri } = await authorizeInBrowser(clientId, state);
|
|
7593
|
-
console.log(
|
|
8015
|
+
console.log(chalk75.dim("Exchanging code for tokens..."));
|
|
7594
8016
|
const tokens = await exchangeToken({
|
|
7595
8017
|
code,
|
|
7596
8018
|
clientId,
|
|
@@ -7606,7 +8028,7 @@ async function auth() {
|
|
|
7606
8028
|
};
|
|
7607
8029
|
saveGlobalConfig(config);
|
|
7608
8030
|
console.log(
|
|
7609
|
-
|
|
8031
|
+
chalk75.green("Roam credentials and tokens saved to ~/.assist.yml")
|
|
7610
8032
|
);
|
|
7611
8033
|
}
|
|
7612
8034
|
|
|
@@ -7794,14 +8216,14 @@ function run2(name, args) {
|
|
|
7794
8216
|
}
|
|
7795
8217
|
|
|
7796
8218
|
// src/commands/statusLine.ts
|
|
7797
|
-
import
|
|
8219
|
+
import chalk76 from "chalk";
|
|
7798
8220
|
function formatNumber(num) {
|
|
7799
8221
|
return num.toLocaleString("en-US");
|
|
7800
8222
|
}
|
|
7801
8223
|
function colorizePercent(pct) {
|
|
7802
8224
|
const label2 = `${pct}%`;
|
|
7803
|
-
if (pct > 80) return
|
|
7804
|
-
if (pct > 40) return
|
|
8225
|
+
if (pct > 80) return chalk76.red(label2);
|
|
8226
|
+
if (pct > 40) return chalk76.yellow(label2);
|
|
7805
8227
|
return label2;
|
|
7806
8228
|
}
|
|
7807
8229
|
async function statusLine() {
|
|
@@ -7827,7 +8249,7 @@ import { fileURLToPath as fileURLToPath7 } from "url";
|
|
|
7827
8249
|
// src/commands/sync/syncClaudeMd.ts
|
|
7828
8250
|
import * as fs22 from "fs";
|
|
7829
8251
|
import * as path38 from "path";
|
|
7830
|
-
import
|
|
8252
|
+
import chalk77 from "chalk";
|
|
7831
8253
|
async function syncClaudeMd(claudeDir, targetBase) {
|
|
7832
8254
|
const source = path38.join(claudeDir, "CLAUDE.md");
|
|
7833
8255
|
const target = path38.join(targetBase, "CLAUDE.md");
|
|
@@ -7836,12 +8258,12 @@ async function syncClaudeMd(claudeDir, targetBase) {
|
|
|
7836
8258
|
const targetContent = fs22.readFileSync(target, "utf-8");
|
|
7837
8259
|
if (sourceContent !== targetContent) {
|
|
7838
8260
|
console.log(
|
|
7839
|
-
|
|
8261
|
+
chalk77.yellow("\n\u26A0\uFE0F Warning: CLAUDE.md differs from existing file")
|
|
7840
8262
|
);
|
|
7841
8263
|
console.log();
|
|
7842
8264
|
printDiff(targetContent, sourceContent);
|
|
7843
8265
|
const confirm = await promptConfirm(
|
|
7844
|
-
|
|
8266
|
+
chalk77.red("Overwrite existing CLAUDE.md?"),
|
|
7845
8267
|
false
|
|
7846
8268
|
);
|
|
7847
8269
|
if (!confirm) {
|
|
@@ -7857,7 +8279,7 @@ async function syncClaudeMd(claudeDir, targetBase) {
|
|
|
7857
8279
|
// src/commands/sync/syncSettings.ts
|
|
7858
8280
|
import * as fs23 from "fs";
|
|
7859
8281
|
import * as path39 from "path";
|
|
7860
|
-
import
|
|
8282
|
+
import chalk78 from "chalk";
|
|
7861
8283
|
async function syncSettings(claudeDir, targetBase, options2) {
|
|
7862
8284
|
const source = path39.join(claudeDir, "settings.json");
|
|
7863
8285
|
const target = path39.join(targetBase, "settings.json");
|
|
@@ -7873,14 +8295,14 @@ async function syncSettings(claudeDir, targetBase, options2) {
|
|
|
7873
8295
|
if (mergedContent !== normalizedTarget) {
|
|
7874
8296
|
if (!options2?.yes) {
|
|
7875
8297
|
console.log(
|
|
7876
|
-
|
|
8298
|
+
chalk78.yellow(
|
|
7877
8299
|
"\n\u26A0\uFE0F Warning: settings.json differs from existing file"
|
|
7878
8300
|
)
|
|
7879
8301
|
);
|
|
7880
8302
|
console.log();
|
|
7881
8303
|
printDiff(targetContent, mergedContent);
|
|
7882
8304
|
const confirm = await promptConfirm(
|
|
7883
|
-
|
|
8305
|
+
chalk78.red("Overwrite existing settings.json?"),
|
|
7884
8306
|
false
|
|
7885
8307
|
);
|
|
7886
8308
|
if (!confirm) {
|
|
@@ -7917,7 +8339,7 @@ function syncCommands(claudeDir, targetBase) {
|
|
|
7917
8339
|
}
|
|
7918
8340
|
|
|
7919
8341
|
// src/commands/update.ts
|
|
7920
|
-
import { execSync as
|
|
8342
|
+
import { execSync as execSync34 } from "child_process";
|
|
7921
8343
|
import * as path41 from "path";
|
|
7922
8344
|
function isGlobalNpmInstall(dir) {
|
|
7923
8345
|
try {
|
|
@@ -7925,7 +8347,7 @@ function isGlobalNpmInstall(dir) {
|
|
|
7925
8347
|
if (resolved.split(path41.sep).includes("node_modules")) {
|
|
7926
8348
|
return true;
|
|
7927
8349
|
}
|
|
7928
|
-
const globalPrefix =
|
|
8350
|
+
const globalPrefix = execSync34("npm prefix -g", { stdio: "pipe" }).toString().trim();
|
|
7929
8351
|
return resolved.toLowerCase().startsWith(path41.resolve(globalPrefix).toLowerCase());
|
|
7930
8352
|
} catch {
|
|
7931
8353
|
return false;
|
|
@@ -7936,18 +8358,18 @@ async function update() {
|
|
|
7936
8358
|
console.log(`Assist is installed at: ${installDir}`);
|
|
7937
8359
|
if (isGitRepo(installDir)) {
|
|
7938
8360
|
console.log("Detected git repo installation, pulling latest...");
|
|
7939
|
-
|
|
8361
|
+
execSync34("git pull", { cwd: installDir, stdio: "inherit" });
|
|
7940
8362
|
console.log("Installing dependencies...");
|
|
7941
|
-
|
|
8363
|
+
execSync34("npm i", { cwd: installDir, stdio: "inherit" });
|
|
7942
8364
|
console.log("Building...");
|
|
7943
|
-
|
|
8365
|
+
execSync34("npm run build", { cwd: installDir, stdio: "inherit" });
|
|
7944
8366
|
console.log("Syncing commands...");
|
|
7945
|
-
|
|
8367
|
+
execSync34("assist sync", { stdio: "inherit" });
|
|
7946
8368
|
} else if (isGlobalNpmInstall(installDir)) {
|
|
7947
8369
|
console.log("Detected global npm installation, updating...");
|
|
7948
|
-
|
|
8370
|
+
execSync34("npm i -g @staff0rd/assist@latest", { stdio: "inherit" });
|
|
7949
8371
|
console.log("Syncing commands...");
|
|
7950
|
-
|
|
8372
|
+
execSync34("assist sync", { stdio: "inherit" });
|
|
7951
8373
|
} else {
|
|
7952
8374
|
console.error(
|
|
7953
8375
|
"Could not determine installation method. Expected a git repo or global npm install."
|
|
@@ -7996,6 +8418,7 @@ registerDeploy(program);
|
|
|
7996
8418
|
registerComplexity(program);
|
|
7997
8419
|
registerNetframework(program);
|
|
7998
8420
|
registerNews(program);
|
|
8421
|
+
registerRavendb(program);
|
|
7999
8422
|
registerTranscript(program);
|
|
8000
8423
|
registerVoice(program);
|
|
8001
8424
|
program.parse();
|