@staff0rd/assist 0.205.1 → 0.206.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/index.js +111 -52
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -117,7 +117,7 @@ After installation, the `assist` command will be available globally. You can als
|
|
|
117
117
|
- `assist config list` - List all config values
|
|
118
118
|
- `assist verify` - Run all verify:* commands in parallel (from run configs in assist.yml and scripts in package.json)
|
|
119
119
|
- `assist verify all` - Run all checks, ignoring diff-based filters
|
|
120
|
-
- `assist verify init` - Add verify scripts to a project
|
|
120
|
+
- `assist verify init` - Add verify scripts to a project (writes to `assist.yml` by default; pass `--package-json` to write to `package.json` scripts instead)
|
|
121
121
|
- `assist verify hardcoded-colors` - Check for hardcoded hex colors in src/ (supports `hardcodedColors.ignore` globs in config)
|
|
122
122
|
- `assist lint [-f, --fix]` - Run lint checks for conventions not enforced by biomejs (use `-f` to auto-fix)
|
|
123
123
|
- `assist lint init` - Initialize Biome with standard linter config
|
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.206.1",
|
|
10
10
|
type: "module",
|
|
11
11
|
main: "dist/index.js",
|
|
12
12
|
bin: {
|
|
@@ -3192,10 +3192,7 @@ function detectExistingSetup(pkg) {
|
|
|
3192
3192
|
...buildToolStatuses(pkg, configScriptNames),
|
|
3193
3193
|
hasVite: hasDep(pkg, "vite"),
|
|
3194
3194
|
hasTypescript: !!pkg.devDependencies?.typescript,
|
|
3195
|
-
hasOpenColor: hasDep(pkg, "open-color")
|
|
3196
|
-
hasConfigScripts: [...configScriptNames].some(
|
|
3197
|
-
(n) => n.startsWith("verify:")
|
|
3198
|
-
)
|
|
3195
|
+
hasOpenColor: hasDep(pkg, "open-color")
|
|
3199
3196
|
};
|
|
3200
3197
|
}
|
|
3201
3198
|
|
|
@@ -3326,12 +3323,12 @@ async function promptForScripts(availableOptions) {
|
|
|
3326
3323
|
}
|
|
3327
3324
|
return selected;
|
|
3328
3325
|
}
|
|
3329
|
-
async function init2() {
|
|
3326
|
+
async function init2(options2 = {}) {
|
|
3330
3327
|
const { packageJsonPath, pkg } = requirePackageJson();
|
|
3331
3328
|
const setup2 = detectExistingSetup(pkg);
|
|
3332
3329
|
const selected = await promptForScripts(getAvailableOptions(setup2));
|
|
3333
3330
|
if (!selected) return;
|
|
3334
|
-
const writer =
|
|
3331
|
+
const writer = options2.packageJson ? (name, cmd) => setupVerifyScript(packageJsonPath, name, cmd) : setupVerifyRunEntry;
|
|
3335
3332
|
const handlers2 = getSetupHandlers(
|
|
3336
3333
|
setup2.hasVite,
|
|
3337
3334
|
setup2.hasTypescript,
|
|
@@ -5466,6 +5463,86 @@ import { basename as basename4 } from "path";
|
|
|
5466
5463
|
// src/shared/splitCompound.ts
|
|
5467
5464
|
import { parse } from "shell-quote";
|
|
5468
5465
|
|
|
5466
|
+
// src/shared/consumeRedirect.ts
|
|
5467
|
+
import { tmpdir as tmpdir2 } from "os";
|
|
5468
|
+
|
|
5469
|
+
// src/shared/isRedirectTargetAllowed.ts
|
|
5470
|
+
function isRedirectTargetAllowed(target, tmp) {
|
|
5471
|
+
if (/^[A-Za-z]:[\\/]/.test(tmp)) return isUnderWindowsTmp(target, tmp);
|
|
5472
|
+
return isUnderPosixTmp(target, tmp);
|
|
5473
|
+
}
|
|
5474
|
+
function isUnderWindowsTmp(target, tmp) {
|
|
5475
|
+
if (!/^[A-Za-z]:[\\/]/.test(target)) return false;
|
|
5476
|
+
const nTmp = normalizeWindowsPath(tmp);
|
|
5477
|
+
const nTarget = normalizeWindowsPath(target);
|
|
5478
|
+
return nTarget === nTmp || nTarget.startsWith(`${nTmp}\\`);
|
|
5479
|
+
}
|
|
5480
|
+
function normalizeWindowsPath(p) {
|
|
5481
|
+
return p.replace(/\//g, "\\").toLowerCase().replace(/\\+$/, "");
|
|
5482
|
+
}
|
|
5483
|
+
function isUnderPosixTmp(target, tmp) {
|
|
5484
|
+
if (!target.startsWith("/")) return false;
|
|
5485
|
+
const nTmp = tmp.replace(/\/+$/, "");
|
|
5486
|
+
return target === nTmp || target.startsWith(`${nTmp}/`);
|
|
5487
|
+
}
|
|
5488
|
+
|
|
5489
|
+
// src/shared/consumeRedirect.ts
|
|
5490
|
+
function consumeRedirect(tokens, opIndex, current) {
|
|
5491
|
+
const target = tokens[opIndex + 1];
|
|
5492
|
+
if (typeof target !== "string") {
|
|
5493
|
+
return { ok: false, error: "unable to parse" };
|
|
5494
|
+
}
|
|
5495
|
+
if (!isRedirectTargetAllowed(target, tmpdir2())) {
|
|
5496
|
+
return {
|
|
5497
|
+
ok: false,
|
|
5498
|
+
error: `redirect target '${target}' is outside the OS temp directory`
|
|
5499
|
+
};
|
|
5500
|
+
}
|
|
5501
|
+
if (current.length > 0 && /^\d$/.test(current[current.length - 1])) {
|
|
5502
|
+
current.pop();
|
|
5503
|
+
}
|
|
5504
|
+
return { ok: true, nextIndex: opIndex + 1 };
|
|
5505
|
+
}
|
|
5506
|
+
|
|
5507
|
+
// src/shared/groupByOperator.ts
|
|
5508
|
+
var SEPARATOR_OPS = /* @__PURE__ */ new Set(["|", "&&", "||", ";"]);
|
|
5509
|
+
var OUTPUT_REDIRECT_OPS = /* @__PURE__ */ new Set([">", ">>"]);
|
|
5510
|
+
var UNPARSEABLE = { ok: false, error: "unable to parse" };
|
|
5511
|
+
function groupByOperator(tokens) {
|
|
5512
|
+
const groups = [[]];
|
|
5513
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
5514
|
+
const step = handleToken(tokens, i, groups);
|
|
5515
|
+
if (!step.ok) return step;
|
|
5516
|
+
i = step.nextIndex;
|
|
5517
|
+
}
|
|
5518
|
+
return { ok: true, groups };
|
|
5519
|
+
}
|
|
5520
|
+
function handleToken(tokens, i, groups) {
|
|
5521
|
+
const token = tokens[i];
|
|
5522
|
+
const op = getOp(token);
|
|
5523
|
+
if (op === void 0) return appendWord(token, groups, i);
|
|
5524
|
+
if (op === "glob") {
|
|
5525
|
+
groups[groups.length - 1].push(token.pattern);
|
|
5526
|
+
return { ok: true, nextIndex: i };
|
|
5527
|
+
}
|
|
5528
|
+
if (SEPARATOR_OPS.has(op)) {
|
|
5529
|
+
groups.push([]);
|
|
5530
|
+
return { ok: true, nextIndex: i };
|
|
5531
|
+
}
|
|
5532
|
+
if (OUTPUT_REDIRECT_OPS.has(op)) {
|
|
5533
|
+
return consumeRedirect(tokens, i, groups[groups.length - 1]);
|
|
5534
|
+
}
|
|
5535
|
+
return UNPARSEABLE;
|
|
5536
|
+
}
|
|
5537
|
+
function appendWord(token, groups, i) {
|
|
5538
|
+
if (typeof token !== "string") return UNPARSEABLE;
|
|
5539
|
+
groups[groups.length - 1].push(token);
|
|
5540
|
+
return { ok: true, nextIndex: i };
|
|
5541
|
+
}
|
|
5542
|
+
function getOp(token) {
|
|
5543
|
+
return typeof token === "object" && token !== null && "op" in token ? token.op : void 0;
|
|
5544
|
+
}
|
|
5545
|
+
|
|
5469
5546
|
// src/shared/hasUnquotedBackticks.ts
|
|
5470
5547
|
var QUOTED_OR_BACKTICK_RE = /\\.|'[^']*'|"[^"]*"|(`)/g;
|
|
5471
5548
|
function hasUnquotedBackticks(command) {
|
|
@@ -5477,17 +5554,17 @@ function hasUnquotedBackticks(command) {
|
|
|
5477
5554
|
}
|
|
5478
5555
|
|
|
5479
5556
|
// src/shared/splitCompound.ts
|
|
5480
|
-
var SEPARATOR_OPS = /* @__PURE__ */ new Set(["|", "&&", "||", ";"]);
|
|
5481
|
-
var UNSAFE_OPS = /* @__PURE__ */ new Set(["(", ")", ">", ">>", "<", "<&", "|&", ">&"]);
|
|
5482
5557
|
var FD_REDIRECT_RE = /\d+>&\d+/g;
|
|
5483
5558
|
var FD_DEVNULL_RE = /\d*>(?:\/dev\/null|\$null)/g;
|
|
5559
|
+
var UNPARSEABLE2 = { ok: false, error: "unable to parse" };
|
|
5484
5560
|
function splitCompound(command) {
|
|
5485
5561
|
const tokens = tokenizeCommand(command);
|
|
5486
|
-
if (!tokens) return
|
|
5487
|
-
const
|
|
5488
|
-
if (!
|
|
5489
|
-
const
|
|
5490
|
-
|
|
5562
|
+
if (!tokens) return UNPARSEABLE2;
|
|
5563
|
+
const grouped = groupByOperator(tokens);
|
|
5564
|
+
if (!grouped.ok) return grouped;
|
|
5565
|
+
const parts = grouped.groups.map((g) => stripEnvPrefix(g).join(" ")).filter((cmd) => cmd !== "");
|
|
5566
|
+
if (parts.length === 0) return UNPARSEABLE2;
|
|
5567
|
+
return { ok: true, parts };
|
|
5491
5568
|
}
|
|
5492
5569
|
function tokenizeCommand(command) {
|
|
5493
5570
|
const trimmed = command.trim().replace(FD_DEVNULL_RE, "").replace(FD_REDIRECT_RE, "");
|
|
@@ -5499,28 +5576,6 @@ function tokenizeCommand(command) {
|
|
|
5499
5576
|
return void 0;
|
|
5500
5577
|
}
|
|
5501
5578
|
}
|
|
5502
|
-
function getOp(token) {
|
|
5503
|
-
return typeof token === "object" && token !== null && "op" in token ? token.op : void 0;
|
|
5504
|
-
}
|
|
5505
|
-
function groupByOperator(tokens) {
|
|
5506
|
-
const groups = [[]];
|
|
5507
|
-
for (const token of tokens) {
|
|
5508
|
-
const op = getOp(token);
|
|
5509
|
-
if (op === void 0) {
|
|
5510
|
-
if (typeof token !== "string") return void 0;
|
|
5511
|
-
groups[groups.length - 1].push(token);
|
|
5512
|
-
} else if (op === "glob") {
|
|
5513
|
-
groups[groups.length - 1].push(token.pattern);
|
|
5514
|
-
} else if (SEPARATOR_OPS.has(op)) {
|
|
5515
|
-
groups.push([]);
|
|
5516
|
-
} else if (UNSAFE_OPS.has(op)) {
|
|
5517
|
-
return void 0;
|
|
5518
|
-
} else {
|
|
5519
|
-
return void 0;
|
|
5520
|
-
}
|
|
5521
|
-
}
|
|
5522
|
-
return groups;
|
|
5523
|
-
}
|
|
5524
5579
|
function stripEnvPrefix(parts) {
|
|
5525
5580
|
let i = 0;
|
|
5526
5581
|
while (i < parts.length && /^[A-Za-z_]\w*=/.test(parts[i])) i++;
|
|
@@ -5898,8 +5953,8 @@ function tryParseInput(raw) {
|
|
|
5898
5953
|
}
|
|
5899
5954
|
}
|
|
5900
5955
|
function decide(toolName, rawCommand) {
|
|
5901
|
-
const
|
|
5902
|
-
if (
|
|
5956
|
+
const result = splitCompound(rawCommand);
|
|
5957
|
+
if (result.ok) return resolvePermission(toolName, result.parts);
|
|
5903
5958
|
return findDeny(toolName, [rawCommand]);
|
|
5904
5959
|
}
|
|
5905
5960
|
async function cliHook() {
|
|
@@ -5929,12 +5984,13 @@ async function cliHook() {
|
|
|
5929
5984
|
// src/commands/cliHook/cliHookCheck.ts
|
|
5930
5985
|
function cliHookCheck(command, toolName = "Bash") {
|
|
5931
5986
|
const trimmed = command.trim();
|
|
5932
|
-
const
|
|
5933
|
-
if (!
|
|
5934
|
-
console.log(
|
|
5987
|
+
const result = splitCompound(trimmed);
|
|
5988
|
+
if (!result.ok) {
|
|
5989
|
+
console.log(`not approved (${result.error})`);
|
|
5935
5990
|
process.exitCode = 1;
|
|
5936
5991
|
return;
|
|
5937
5992
|
}
|
|
5993
|
+
const parts = result.parts;
|
|
5938
5994
|
for (const part of parts) {
|
|
5939
5995
|
const configDeny = matchesConfigDeny(part);
|
|
5940
5996
|
if (configDeny) {
|
|
@@ -8063,7 +8119,7 @@ function parseInspectReport(json) {
|
|
|
8063
8119
|
// src/commands/dotnet/runInspectCode.ts
|
|
8064
8120
|
import { execSync as execSync22 } from "child_process";
|
|
8065
8121
|
import { existsSync as existsSync28, readFileSync as readFileSync25, unlinkSync as unlinkSync5 } from "fs";
|
|
8066
|
-
import { tmpdir as
|
|
8122
|
+
import { tmpdir as tmpdir3 } from "os";
|
|
8067
8123
|
import path29 from "path";
|
|
8068
8124
|
import chalk91 from "chalk";
|
|
8069
8125
|
function assertJbInstalled() {
|
|
@@ -8078,7 +8134,7 @@ function assertJbInstalled() {
|
|
|
8078
8134
|
}
|
|
8079
8135
|
}
|
|
8080
8136
|
function runInspectCode(slnPath, include, swea) {
|
|
8081
|
-
const reportPath = path29.join(
|
|
8137
|
+
const reportPath = path29.join(tmpdir3(), `inspect-${Date.now()}.xml`);
|
|
8082
8138
|
const includeFlag = include ? ` --include="${include}"` : "";
|
|
8083
8139
|
const sweaFlag = swea ? " --swea" : "";
|
|
8084
8140
|
try {
|
|
@@ -8718,7 +8774,7 @@ function registerPrompts(program2) {
|
|
|
8718
8774
|
// src/commands/prs/comment.ts
|
|
8719
8775
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
8720
8776
|
import { unlinkSync as unlinkSync6, writeFileSync as writeFileSync21 } from "fs";
|
|
8721
|
-
import { tmpdir as
|
|
8777
|
+
import { tmpdir as tmpdir4 } from "os";
|
|
8722
8778
|
import { join as join29 } from "path";
|
|
8723
8779
|
|
|
8724
8780
|
// src/commands/prs/shared.ts
|
|
@@ -8791,7 +8847,7 @@ function comment2(path53, line, body) {
|
|
|
8791
8847
|
validateLine(line);
|
|
8792
8848
|
try {
|
|
8793
8849
|
const prId = getCurrentPrNodeId();
|
|
8794
|
-
const queryFile = join29(
|
|
8850
|
+
const queryFile = join29(tmpdir4(), `gh-query-${Date.now()}.graphql`);
|
|
8795
8851
|
writeFileSync21(queryFile, MUTATION);
|
|
8796
8852
|
try {
|
|
8797
8853
|
const result = spawnSync2(
|
|
@@ -8835,7 +8891,7 @@ import { execSync as execSync28 } from "child_process";
|
|
|
8835
8891
|
// src/commands/prs/resolveCommentWithReply.ts
|
|
8836
8892
|
import { execSync as execSync27 } from "child_process";
|
|
8837
8893
|
import { unlinkSync as unlinkSync8, writeFileSync as writeFileSync22 } from "fs";
|
|
8838
|
-
import { tmpdir as
|
|
8894
|
+
import { tmpdir as tmpdir5 } from "os";
|
|
8839
8895
|
import { join as join31 } from "path";
|
|
8840
8896
|
|
|
8841
8897
|
// src/commands/prs/loadCommentsCache.ts
|
|
@@ -8870,7 +8926,7 @@ function replyToComment(org, repo, prNumber, commentId, message) {
|
|
|
8870
8926
|
}
|
|
8871
8927
|
function resolveThread(threadId) {
|
|
8872
8928
|
const mutation = `mutation($threadId: ID!) { resolveReviewThread(input: {threadId: $threadId}) { thread { isResolved } } }`;
|
|
8873
|
-
const queryFile = join31(
|
|
8929
|
+
const queryFile = join31(tmpdir5(), `gh-mutation-${Date.now()}.graphql`);
|
|
8874
8930
|
writeFileSync22(queryFile, mutation);
|
|
8875
8931
|
try {
|
|
8876
8932
|
execSync27(
|
|
@@ -8959,11 +9015,11 @@ import { stringify } from "yaml";
|
|
|
8959
9015
|
// src/commands/prs/fetchThreadIds.ts
|
|
8960
9016
|
import { execSync as execSync29 } from "child_process";
|
|
8961
9017
|
import { unlinkSync as unlinkSync9, writeFileSync as writeFileSync23 } from "fs";
|
|
8962
|
-
import { tmpdir as
|
|
9018
|
+
import { tmpdir as tmpdir6 } from "os";
|
|
8963
9019
|
import { join as join32 } from "path";
|
|
8964
9020
|
var THREAD_QUERY = `query($owner: String!, $repo: String!, $prNumber: Int!) { repository(owner: $owner, name: $repo) { pullRequest(number: $prNumber) { reviewThreads(first: 100) { nodes { id isResolved comments(first: 100) { nodes { databaseId } } } } } } }`;
|
|
8965
9021
|
function fetchThreadIds(org, repo, prNumber) {
|
|
8966
|
-
const queryFile = join32(
|
|
9022
|
+
const queryFile = join32(tmpdir6(), `gh-query-${Date.now()}.graphql`);
|
|
8967
9023
|
writeFileSync23(queryFile, THREAD_QUERY);
|
|
8968
9024
|
try {
|
|
8969
9025
|
const result = execSync29(
|
|
@@ -12210,7 +12266,10 @@ function registerVerify(program2) {
|
|
|
12210
12266
|
run2({ ...options2, all: scope === "all" });
|
|
12211
12267
|
});
|
|
12212
12268
|
verifyCommand.command("list").description("List configured verify commands").action(list);
|
|
12213
|
-
verifyCommand.command("init").description("Add verify scripts to a project").
|
|
12269
|
+
verifyCommand.command("init").description("Add verify scripts to a project").option(
|
|
12270
|
+
"--package-json",
|
|
12271
|
+
"Write scripts to package.json instead of assist.yml"
|
|
12272
|
+
).action(init2);
|
|
12214
12273
|
verifyCommand.command("hardcoded-colors").description("Check for hardcoded hex colors in src/").action(hardcodedColors);
|
|
12215
12274
|
verifyCommand.command("no-venv").description("Check that no venv folders exist in the repo").action(noVenv);
|
|
12216
12275
|
}
|
|
@@ -13067,7 +13126,7 @@ function registerRun(program2) {
|
|
|
13067
13126
|
// src/commands/screenshot/index.ts
|
|
13068
13127
|
import { execSync as execSync39 } from "child_process";
|
|
13069
13128
|
import { existsSync as existsSync43, mkdirSync as mkdirSync15, unlinkSync as unlinkSync12, writeFileSync as writeFileSync29 } from "fs";
|
|
13070
|
-
import { tmpdir as
|
|
13129
|
+
import { tmpdir as tmpdir7 } from "os";
|
|
13071
13130
|
import { join as join49, resolve as resolve11 } from "path";
|
|
13072
13131
|
import chalk133 from "chalk";
|
|
13073
13132
|
|
|
@@ -13205,7 +13264,7 @@ function buildOutputPath(outputDir, processName) {
|
|
|
13205
13264
|
return resolve11(outputDir, `${processName}-${timestamp}.png`);
|
|
13206
13265
|
}
|
|
13207
13266
|
function runPowerShellScript(processName, outputPath) {
|
|
13208
|
-
const scriptPath = join49(
|
|
13267
|
+
const scriptPath = join49(tmpdir7(), `assist-screenshot-${Date.now()}.ps1`);
|
|
13209
13268
|
writeFileSync29(scriptPath, captureWindowPs1, "utf-8");
|
|
13210
13269
|
try {
|
|
13211
13270
|
execSync39(
|