@staff0rd/assist 0.206.0 → 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.
Files changed (2) hide show
  1. package/dist/index.js +104 -45
  2. 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.206.0",
9
+ version: "0.206.1",
10
10
  type: "module",
11
11
  main: "dist/index.js",
12
12
  bin: {
@@ -5463,6 +5463,86 @@ import { basename as basename4 } from "path";
5463
5463
  // src/shared/splitCompound.ts
5464
5464
  import { parse } from "shell-quote";
5465
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
+
5466
5546
  // src/shared/hasUnquotedBackticks.ts
5467
5547
  var QUOTED_OR_BACKTICK_RE = /\\.|'[^']*'|"[^"]*"|(`)/g;
5468
5548
  function hasUnquotedBackticks(command) {
@@ -5474,17 +5554,17 @@ function hasUnquotedBackticks(command) {
5474
5554
  }
5475
5555
 
5476
5556
  // src/shared/splitCompound.ts
5477
- var SEPARATOR_OPS = /* @__PURE__ */ new Set(["|", "&&", "||", ";"]);
5478
- var UNSAFE_OPS = /* @__PURE__ */ new Set(["(", ")", ">", ">>", "<", "<&", "|&", ">&"]);
5479
5557
  var FD_REDIRECT_RE = /\d+>&\d+/g;
5480
5558
  var FD_DEVNULL_RE = /\d*>(?:\/dev\/null|\$null)/g;
5559
+ var UNPARSEABLE2 = { ok: false, error: "unable to parse" };
5481
5560
  function splitCompound(command) {
5482
5561
  const tokens = tokenizeCommand(command);
5483
- if (!tokens) return void 0;
5484
- const groups = groupByOperator(tokens);
5485
- if (!groups) return void 0;
5486
- const result = groups.map((parts) => stripEnvPrefix(parts).join(" ")).filter((cmd) => cmd !== "");
5487
- return result.length > 0 ? result : void 0;
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 };
5488
5568
  }
5489
5569
  function tokenizeCommand(command) {
5490
5570
  const trimmed = command.trim().replace(FD_DEVNULL_RE, "").replace(FD_REDIRECT_RE, "");
@@ -5496,28 +5576,6 @@ function tokenizeCommand(command) {
5496
5576
  return void 0;
5497
5577
  }
5498
5578
  }
5499
- function getOp(token) {
5500
- return typeof token === "object" && token !== null && "op" in token ? token.op : void 0;
5501
- }
5502
- function groupByOperator(tokens) {
5503
- const groups = [[]];
5504
- for (const token of tokens) {
5505
- const op = getOp(token);
5506
- if (op === void 0) {
5507
- if (typeof token !== "string") return void 0;
5508
- groups[groups.length - 1].push(token);
5509
- } else if (op === "glob") {
5510
- groups[groups.length - 1].push(token.pattern);
5511
- } else if (SEPARATOR_OPS.has(op)) {
5512
- groups.push([]);
5513
- } else if (UNSAFE_OPS.has(op)) {
5514
- return void 0;
5515
- } else {
5516
- return void 0;
5517
- }
5518
- }
5519
- return groups;
5520
- }
5521
5579
  function stripEnvPrefix(parts) {
5522
5580
  let i = 0;
5523
5581
  while (i < parts.length && /^[A-Za-z_]\w*=/.test(parts[i])) i++;
@@ -5895,8 +5953,8 @@ function tryParseInput(raw) {
5895
5953
  }
5896
5954
  }
5897
5955
  function decide(toolName, rawCommand) {
5898
- const parts = splitCompound(rawCommand);
5899
- if (parts) return resolvePermission(toolName, parts);
5956
+ const result = splitCompound(rawCommand);
5957
+ if (result.ok) return resolvePermission(toolName, result.parts);
5900
5958
  return findDeny(toolName, [rawCommand]);
5901
5959
  }
5902
5960
  async function cliHook() {
@@ -5926,12 +5984,13 @@ async function cliHook() {
5926
5984
  // src/commands/cliHook/cliHookCheck.ts
5927
5985
  function cliHookCheck(command, toolName = "Bash") {
5928
5986
  const trimmed = command.trim();
5929
- const parts = splitCompound(trimmed);
5930
- if (!parts) {
5931
- console.log("not approved (unable to parse)");
5987
+ const result = splitCompound(trimmed);
5988
+ if (!result.ok) {
5989
+ console.log(`not approved (${result.error})`);
5932
5990
  process.exitCode = 1;
5933
5991
  return;
5934
5992
  }
5993
+ const parts = result.parts;
5935
5994
  for (const part of parts) {
5936
5995
  const configDeny = matchesConfigDeny(part);
5937
5996
  if (configDeny) {
@@ -8060,7 +8119,7 @@ function parseInspectReport(json) {
8060
8119
  // src/commands/dotnet/runInspectCode.ts
8061
8120
  import { execSync as execSync22 } from "child_process";
8062
8121
  import { existsSync as existsSync28, readFileSync as readFileSync25, unlinkSync as unlinkSync5 } from "fs";
8063
- import { tmpdir as tmpdir2 } from "os";
8122
+ import { tmpdir as tmpdir3 } from "os";
8064
8123
  import path29 from "path";
8065
8124
  import chalk91 from "chalk";
8066
8125
  function assertJbInstalled() {
@@ -8075,7 +8134,7 @@ function assertJbInstalled() {
8075
8134
  }
8076
8135
  }
8077
8136
  function runInspectCode(slnPath, include, swea) {
8078
- const reportPath = path29.join(tmpdir2(), `inspect-${Date.now()}.xml`);
8137
+ const reportPath = path29.join(tmpdir3(), `inspect-${Date.now()}.xml`);
8079
8138
  const includeFlag = include ? ` --include="${include}"` : "";
8080
8139
  const sweaFlag = swea ? " --swea" : "";
8081
8140
  try {
@@ -8715,7 +8774,7 @@ function registerPrompts(program2) {
8715
8774
  // src/commands/prs/comment.ts
8716
8775
  import { spawnSync as spawnSync2 } from "child_process";
8717
8776
  import { unlinkSync as unlinkSync6, writeFileSync as writeFileSync21 } from "fs";
8718
- import { tmpdir as tmpdir3 } from "os";
8777
+ import { tmpdir as tmpdir4 } from "os";
8719
8778
  import { join as join29 } from "path";
8720
8779
 
8721
8780
  // src/commands/prs/shared.ts
@@ -8788,7 +8847,7 @@ function comment2(path53, line, body) {
8788
8847
  validateLine(line);
8789
8848
  try {
8790
8849
  const prId = getCurrentPrNodeId();
8791
- const queryFile = join29(tmpdir3(), `gh-query-${Date.now()}.graphql`);
8850
+ const queryFile = join29(tmpdir4(), `gh-query-${Date.now()}.graphql`);
8792
8851
  writeFileSync21(queryFile, MUTATION);
8793
8852
  try {
8794
8853
  const result = spawnSync2(
@@ -8832,7 +8891,7 @@ import { execSync as execSync28 } from "child_process";
8832
8891
  // src/commands/prs/resolveCommentWithReply.ts
8833
8892
  import { execSync as execSync27 } from "child_process";
8834
8893
  import { unlinkSync as unlinkSync8, writeFileSync as writeFileSync22 } from "fs";
8835
- import { tmpdir as tmpdir4 } from "os";
8894
+ import { tmpdir as tmpdir5 } from "os";
8836
8895
  import { join as join31 } from "path";
8837
8896
 
8838
8897
  // src/commands/prs/loadCommentsCache.ts
@@ -8867,7 +8926,7 @@ function replyToComment(org, repo, prNumber, commentId, message) {
8867
8926
  }
8868
8927
  function resolveThread(threadId) {
8869
8928
  const mutation = `mutation($threadId: ID!) { resolveReviewThread(input: {threadId: $threadId}) { thread { isResolved } } }`;
8870
- const queryFile = join31(tmpdir4(), `gh-mutation-${Date.now()}.graphql`);
8929
+ const queryFile = join31(tmpdir5(), `gh-mutation-${Date.now()}.graphql`);
8871
8930
  writeFileSync22(queryFile, mutation);
8872
8931
  try {
8873
8932
  execSync27(
@@ -8956,11 +9015,11 @@ import { stringify } from "yaml";
8956
9015
  // src/commands/prs/fetchThreadIds.ts
8957
9016
  import { execSync as execSync29 } from "child_process";
8958
9017
  import { unlinkSync as unlinkSync9, writeFileSync as writeFileSync23 } from "fs";
8959
- import { tmpdir as tmpdir5 } from "os";
9018
+ import { tmpdir as tmpdir6 } from "os";
8960
9019
  import { join as join32 } from "path";
8961
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 } } } } } } }`;
8962
9021
  function fetchThreadIds(org, repo, prNumber) {
8963
- const queryFile = join32(tmpdir5(), `gh-query-${Date.now()}.graphql`);
9022
+ const queryFile = join32(tmpdir6(), `gh-query-${Date.now()}.graphql`);
8964
9023
  writeFileSync23(queryFile, THREAD_QUERY);
8965
9024
  try {
8966
9025
  const result = execSync29(
@@ -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 tmpdir6 } from "os";
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(tmpdir6(), `assist-screenshot-${Date.now()}.ps1`);
13267
+ const scriptPath = join49(tmpdir7(), `assist-screenshot-${Date.now()}.ps1`);
13209
13268
  writeFileSync29(scriptPath, captureWindowPs1, "utf-8");
13210
13269
  try {
13211
13270
  execSync39(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@staff0rd/assist",
3
- "version": "0.206.0",
3
+ "version": "0.206.1",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "bin": {