@staff0rd/assist 0.181.0 → 0.182.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.
Files changed (2) hide show
  1. package/dist/index.js +284 -247
  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.181.0",
9
+ version: "0.182.0",
10
10
  type: "module",
11
11
  main: "dist/index.js",
12
12
  bin: {
@@ -407,7 +407,9 @@ import { join as join2 } from "path";
407
407
  var gitignoreEntries = [
408
408
  ".assist/backlog.db",
409
409
  ".assist/backlog.db-shm",
410
- ".assist/backlog.db-wal"
410
+ ".assist/backlog.db-wal",
411
+ ".assist-signal*.json",
412
+ ".assist-lock-*.json"
411
413
  ];
412
414
  function ensureGitignore(dir) {
413
415
  const gitignorePath = join2(dir, ".gitignore");
@@ -903,8 +905,8 @@ function spawnClaude(prompt, options2 = {}) {
903
905
  const child = spawn("claude", args, {
904
906
  stdio: "inherit"
905
907
  });
906
- const done2 = new Promise((resolve7, reject) => {
907
- child.on("close", (code) => resolve7(code ?? 0));
908
+ const done2 = new Promise((resolve8, reject) => {
909
+ child.on("close", (code) => resolve8(code ?? 0));
908
910
  child.on("error", reject);
909
911
  });
910
912
  return { child, done: done2 };
@@ -1358,12 +1360,12 @@ function getHtml() {
1358
1360
 
1359
1361
  // src/commands/backlog/web/parseItemBody.ts
1360
1362
  function readBody(req) {
1361
- return new Promise((resolve7, reject) => {
1363
+ return new Promise((resolve8, reject) => {
1362
1364
  let body = "";
1363
1365
  req.on("data", (chunk) => {
1364
1366
  body += chunk.toString();
1365
1367
  });
1366
- req.on("end", () => resolve7(body));
1368
+ req.on("end", () => resolve8(body));
1367
1369
  req.on("error", reject);
1368
1370
  });
1369
1371
  }
@@ -1542,9 +1544,9 @@ async function refine(id) {
1542
1544
  import { execSync } from "child_process";
1543
1545
 
1544
1546
  // src/shared/loadConfig.ts
1545
- import { existsSync as existsSync9, readFileSync as readFileSync8, writeFileSync as writeFileSync5 } from "fs";
1547
+ import { existsSync as existsSync9, writeFileSync as writeFileSync5 } from "fs";
1546
1548
  import { homedir } from "os";
1547
- import { basename, dirname as dirname2, join as join8 } from "path";
1549
+ import { dirname as dirname2, join as join8 } from "path";
1548
1550
  import chalk18 from "chalk";
1549
1551
  import { stringify as stringifyYaml } from "yaml";
1550
1552
 
@@ -1576,7 +1578,8 @@ var runConfigSchema = z2.strictObject({
1576
1578
  params: z2.array(runParamSchema).optional(),
1577
1579
  env: z2.record(z2.string(), z2.string()).optional(),
1578
1580
  filter: z2.string().optional(),
1579
- pre: z2.array(z2.string()).optional()
1581
+ pre: z2.array(z2.string()).optional(),
1582
+ cwd: z2.string().optional()
1580
1583
  });
1581
1584
  var transcriptConfigSchema = z2.strictObject({
1582
1585
  vttDir: z2.string(),
@@ -1703,6 +1706,9 @@ function getConfigPath() {
1703
1706
  function getGlobalConfigPath() {
1704
1707
  return join8(homedir(), ".assist.yml");
1705
1708
  }
1709
+ function getConfigDir() {
1710
+ return dirname2(getConfigPath());
1711
+ }
1706
1712
  function loadConfig() {
1707
1713
  const globalRaw = loadRawYaml(getGlobalConfigPath());
1708
1714
  const projectRaw = loadRawYaml(getConfigPath());
@@ -1722,24 +1728,6 @@ function saveConfig(config) {
1722
1728
  const configPath = getConfigPath();
1723
1729
  writeFileSync5(configPath, stringifyYaml(config, { lineWidth: 0 }));
1724
1730
  }
1725
- function getRepoName() {
1726
- const config = loadConfig();
1727
- if (config.devlog?.name) {
1728
- return config.devlog.name;
1729
- }
1730
- const packageJsonPath = join8(process.cwd(), "package.json");
1731
- if (existsSync9(packageJsonPath)) {
1732
- try {
1733
- const content = readFileSync8(packageJsonPath, "utf-8");
1734
- const pkg = JSON.parse(content);
1735
- if (pkg.name) {
1736
- return pkg.name;
1737
- }
1738
- } catch {
1739
- }
1740
- }
1741
- return basename(process.cwd());
1742
- }
1743
1731
  function getTranscriptConfig() {
1744
1732
  const config = loadConfig();
1745
1733
  if (!config.transcript) {
@@ -1955,11 +1943,12 @@ function setupVerifyScript(packageJsonPath, scriptName, command) {
1955
1943
  }
1956
1944
 
1957
1945
  // src/commands/run/buildRunEntry.ts
1958
- function buildRunEntry(name, command, args) {
1946
+ function buildRunEntry(name, command, args, options2) {
1959
1947
  const effectiveArgs = args.length === 0 && command.includes(" ") ? command.split(/\s+/).slice(1) : args;
1960
1948
  const effectiveCommand = args.length === 0 && command.includes(" ") ? command.split(/\s+/)[0] : command;
1961
1949
  const entry = { name, command: effectiveCommand };
1962
1950
  if (effectiveArgs.length > 0) entry.args = effectiveArgs;
1951
+ if (options2?.cwd) entry.cwd = options2.cwd;
1963
1952
  return entry;
1964
1953
  }
1965
1954
 
@@ -2030,12 +2019,12 @@ import * as path3 from "path";
2030
2019
  import chalk25 from "chalk";
2031
2020
 
2032
2021
  // src/commands/verify/addToKnipIgnoreBinaries.ts
2033
- import { existsSync as existsSync11, readFileSync as readFileSync10, writeFileSync as writeFileSync7 } from "fs";
2022
+ import { existsSync as existsSync11, readFileSync as readFileSync9, writeFileSync as writeFileSync7 } from "fs";
2034
2023
  import { join as join10 } from "path";
2035
2024
  import chalk24 from "chalk";
2036
2025
  function loadKnipConfig(knipJsonPath) {
2037
2026
  if (existsSync11(knipJsonPath)) {
2038
- return JSON.parse(readFileSync10(knipJsonPath, "utf-8"));
2027
+ return JSON.parse(readFileSync9(knipJsonPath, "utf-8"));
2039
2028
  }
2040
2029
  return { $schema: "https://unpkg.com/knip@5/schema.json" };
2041
2030
  }
@@ -2088,7 +2077,7 @@ import chalk29 from "chalk";
2088
2077
 
2089
2078
  // src/commands/lint/init.ts
2090
2079
  import { execSync as execSync5 } from "child_process";
2091
- import { existsSync as existsSync14, readFileSync as readFileSync12, writeFileSync as writeFileSync9 } from "fs";
2080
+ import { existsSync as existsSync14, readFileSync as readFileSync11, writeFileSync as writeFileSync9 } from "fs";
2092
2081
  import { dirname as dirname7, join as join11 } from "path";
2093
2082
  import { fileURLToPath as fileURLToPath2 } from "url";
2094
2083
  import chalk28 from "chalk";
@@ -2114,7 +2103,7 @@ async function promptConfirm(message, initial = true) {
2114
2103
 
2115
2104
  // src/shared/removeEslint/index.ts
2116
2105
  import { execSync as execSync4 } from "child_process";
2117
- import { existsSync as existsSync13, readFileSync as readFileSync11, writeFileSync as writeFileSync8 } from "fs";
2106
+ import { existsSync as existsSync13, readFileSync as readFileSync10, writeFileSync as writeFileSync8 } from "fs";
2118
2107
 
2119
2108
  // src/shared/removeEslint/removeEslintConfigFiles.ts
2120
2109
  import { existsSync as existsSync12, unlinkSync as unlinkSync3 } from "fs";
@@ -2158,7 +2147,7 @@ function removeEslintFromPackageJson(options2) {
2158
2147
  if (!existsSync13(packageJsonPath)) {
2159
2148
  return false;
2160
2149
  }
2161
- const packageJson = JSON.parse(readFileSync11(packageJsonPath, "utf-8"));
2150
+ const packageJson = JSON.parse(readFileSync10(packageJsonPath, "utf-8"));
2162
2151
  let modified = false;
2163
2152
  modified = removeEslintDeps(packageJson.dependencies) || modified;
2164
2153
  modified = removeEslintDeps(packageJson.devDependencies) || modified;
@@ -2237,8 +2226,8 @@ async function init() {
2237
2226
  return;
2238
2227
  }
2239
2228
  const linterConfigPath = join11(__dirname2, "commands/lint/biome.linter.json");
2240
- const linterConfig = JSON.parse(readFileSync12(linterConfigPath, "utf-8"));
2241
- const biomeConfig = JSON.parse(readFileSync12(biomeConfigPath, "utf-8"));
2229
+ const linterConfig = JSON.parse(readFileSync11(linterConfigPath, "utf-8"));
2230
+ const biomeConfig = JSON.parse(readFileSync11(biomeConfigPath, "utf-8"));
2242
2231
  const oldContent = `${JSON.stringify(biomeConfig, null, 2)}
2243
2232
  `;
2244
2233
  biomeConfig.linter = linterConfig.linter;
@@ -2985,7 +2974,7 @@ function lint(options2 = {}) {
2985
2974
 
2986
2975
  // src/commands/new/registerNew/newCli/index.ts
2987
2976
  import { execSync as execSync11 } from "child_process";
2988
- import { basename as basename2, resolve } from "path";
2977
+ import { basename, resolve } from "path";
2989
2978
 
2990
2979
  // src/commands/verify/hardcodedColors.ts
2991
2980
  import { execSync as execSync6 } from "child_process";
@@ -3214,14 +3203,14 @@ function flushIfFailed(exitCode, chunks) {
3214
3203
 
3215
3204
  // src/commands/verify/run/runAllEntries.ts
3216
3205
  function runEntry(entry, onComplete) {
3217
- return new Promise((resolve7) => {
3206
+ return new Promise((resolve8) => {
3218
3207
  const child = spawnCommand(entry.fullCommand, entry.cwd, entry.env);
3219
3208
  const chunks = collectOutput(child);
3220
3209
  child.on("close", (code) => {
3221
3210
  const exitCode = code ?? 1;
3222
3211
  flushIfFailed(exitCode, chunks);
3223
3212
  onComplete?.(exitCode);
3224
- resolve7({ script: entry.name, code: exitCode });
3213
+ resolve8({ script: entry.name, code: exitCode });
3225
3214
  });
3226
3215
  });
3227
3216
  }
@@ -3351,7 +3340,7 @@ program.parse();
3351
3340
 
3352
3341
  // src/commands/new/registerNew/newCli/index.ts
3353
3342
  async function newCli() {
3354
- const name = basename2(resolve("."));
3343
+ const name = basename(resolve("."));
3355
3344
  initGit();
3356
3345
  initPackageJson(name);
3357
3346
  console.log("Installing dependencies...");
@@ -3366,7 +3355,7 @@ async function newCli() {
3366
3355
 
3367
3356
  // src/commands/new/registerNew/newProject.ts
3368
3357
  import { execSync as execSync13 } from "child_process";
3369
- import { existsSync as existsSync18, readFileSync as readFileSync15, writeFileSync as writeFileSync14 } from "fs";
3358
+ import { existsSync as existsSync18, readFileSync as readFileSync14, writeFileSync as writeFileSync14 } from "fs";
3370
3359
 
3371
3360
  // src/commands/deploy/init/index.ts
3372
3361
  import { execSync as execSync12 } from "child_process";
@@ -3374,7 +3363,7 @@ import chalk40 from "chalk";
3374
3363
  import enquirer6 from "enquirer";
3375
3364
 
3376
3365
  // src/commands/deploy/init/updateWorkflow.ts
3377
- import { existsSync as existsSync17, mkdirSync as mkdirSync4, readFileSync as readFileSync14, writeFileSync as writeFileSync13 } from "fs";
3366
+ import { existsSync as existsSync17, mkdirSync as mkdirSync4, readFileSync as readFileSync13, writeFileSync as writeFileSync13 } from "fs";
3378
3367
  import { dirname as dirname13, join as join14 } from "path";
3379
3368
  import { fileURLToPath as fileURLToPath3 } from "url";
3380
3369
  import chalk39 from "chalk";
@@ -3384,13 +3373,13 @@ function getExistingSiteId() {
3384
3373
  if (!existsSync17(WORKFLOW_PATH)) {
3385
3374
  return null;
3386
3375
  }
3387
- const content = readFileSync14(WORKFLOW_PATH, "utf-8");
3376
+ const content = readFileSync13(WORKFLOW_PATH, "utf-8");
3388
3377
  const match = content.match(/-s\s+([a-f0-9-]{36})/);
3389
3378
  return match ? match[1] : null;
3390
3379
  }
3391
3380
  function getTemplateContent(siteId) {
3392
3381
  const templatePath = join14(__dirname3, "commands/deploy/build.yml");
3393
- const template = readFileSync14(templatePath, "utf-8");
3382
+ const template = readFileSync13(templatePath, "utf-8");
3394
3383
  return template.replace("{{NETLIFY_SITE_ID}}", siteId);
3395
3384
  }
3396
3385
  async function updateWorkflow(siteId) {
@@ -3400,7 +3389,7 @@ async function updateWorkflow(siteId) {
3400
3389
  mkdirSync4(workflowDir, { recursive: true });
3401
3390
  }
3402
3391
  if (existsSync17(WORKFLOW_PATH)) {
3403
- const oldContent = readFileSync14(WORKFLOW_PATH, "utf-8");
3392
+ const oldContent = readFileSync13(WORKFLOW_PATH, "utf-8");
3404
3393
  if (oldContent === newContent) {
3405
3394
  console.log(chalk39.green("build.yml is already up to date"));
3406
3395
  return;
@@ -3498,7 +3487,7 @@ function addViteBaseConfig() {
3498
3487
  console.log("No vite.config.ts found, skipping base config");
3499
3488
  return;
3500
3489
  }
3501
- const content = readFileSync15(viteConfigPath, "utf-8");
3490
+ const content = readFileSync14(viteConfigPath, "utf-8");
3502
3491
  if (content.includes("base:")) {
3503
3492
  console.log("vite.config.ts already has base config");
3504
3493
  return;
@@ -3803,7 +3792,7 @@ function commitBacklog(id, name) {
3803
3792
 
3804
3793
  // src/commands/backlog/add/shared.ts
3805
3794
  import { spawnSync } from "child_process";
3806
- import { mkdtempSync, readFileSync as readFileSync16, unlinkSync as unlinkSync4, writeFileSync as writeFileSync15 } from "fs";
3795
+ import { mkdtempSync, readFileSync as readFileSync15, unlinkSync as unlinkSync4, writeFileSync as writeFileSync15 } from "fs";
3807
3796
  import { tmpdir } from "os";
3808
3797
  import { join as join16 } from "path";
3809
3798
  import enquirer7 from "enquirer";
@@ -3853,7 +3842,7 @@ function openEditor() {
3853
3842
  unlinkSync4(filePath);
3854
3843
  return void 0;
3855
3844
  }
3856
- const content = readFileSync16(filePath, "utf-8").trim();
3845
+ const content = readFileSync15(filePath, "utf-8").trim();
3857
3846
  unlinkSync4(filePath);
3858
3847
  return content || void 0;
3859
3848
  }
@@ -4540,7 +4529,7 @@ function extractGraphqlQuery(args) {
4540
4529
  }
4541
4530
 
4542
4531
  // src/shared/loadCliReads.ts
4543
- import { existsSync as existsSync19, readFileSync as readFileSync17, writeFileSync as writeFileSync16 } from "fs";
4532
+ import { existsSync as existsSync19, readFileSync as readFileSync16, writeFileSync as writeFileSync16 } from "fs";
4544
4533
  import { dirname as dirname14, resolve as resolve2 } from "path";
4545
4534
  import { fileURLToPath as fileURLToPath4 } from "url";
4546
4535
  var __filename2 = fileURLToPath4(import.meta.url);
@@ -4550,7 +4539,7 @@ function packageRoot() {
4550
4539
  }
4551
4540
  function readLines(path50) {
4552
4541
  if (!existsSync19(path50)) return [];
4553
- return readFileSync17(path50, "utf-8").split("\n").filter((line) => line.trim() !== "");
4542
+ return readFileSync16(path50, "utf-8").split("\n").filter((line) => line.trim() !== "");
4554
4543
  }
4555
4544
  var cachedReads;
4556
4545
  var cachedWrites;
@@ -4596,7 +4585,7 @@ function findCliWrite(command) {
4596
4585
  }
4597
4586
 
4598
4587
  // src/shared/readSettingsPerms.ts
4599
- import { existsSync as existsSync20, readFileSync as readFileSync18 } from "fs";
4588
+ import { existsSync as existsSync20, readFileSync as readFileSync17 } from "fs";
4600
4589
  import { homedir as homedir3 } from "os";
4601
4590
  import { join as join17 } from "path";
4602
4591
  function readSettingsPerms(key) {
@@ -4614,7 +4603,7 @@ function readSettingsPerms(key) {
4614
4603
  function readPermissionArray(filePath, key) {
4615
4604
  if (!existsSync20(filePath)) return [];
4616
4605
  try {
4617
- const data = JSON.parse(readFileSync18(filePath, "utf-8"));
4606
+ const data = JSON.parse(readFileSync17(filePath, "utf-8"));
4618
4607
  const arr = data?.permissions?.[key];
4619
4608
  return Array.isArray(arr) ? arr.filter((e) => typeof e === "string") : [];
4620
4609
  } catch {
@@ -4864,53 +4853,8 @@ function cliHookCheck(command, toolName = "Bash") {
4864
4853
  ${reasons.join("\n")}`);
4865
4854
  }
4866
4855
 
4867
- // src/commands/deny/denyAdd.ts
4868
- import chalk61 from "chalk";
4869
- function denyAdd(pattern2, message) {
4870
- const config = loadProjectConfig();
4871
- const deny = config.deny ?? [];
4872
- if (deny.some((r) => r.pattern === pattern2)) {
4873
- console.log(chalk61.yellow(`Deny rule already exists for: ${pattern2}`));
4874
- return;
4875
- }
4876
- deny.push({ pattern: pattern2, message });
4877
- config.deny = deny;
4878
- saveConfig(config);
4879
- console.log(chalk61.green(`Added deny rule: ${pattern2} \u2192 ${message}`));
4880
- }
4881
-
4882
- // src/commands/deny/denyList.ts
4883
- import chalk62 from "chalk";
4884
- function denyList() {
4885
- const config = loadConfig();
4886
- const deny = config.deny;
4887
- if (!deny || deny.length === 0) {
4888
- console.log(chalk62.dim("No deny rules configured."));
4889
- return;
4890
- }
4891
- for (const rule of deny) {
4892
- console.log(`${chalk62.red(rule.pattern)} \u2192 ${rule.message}`);
4893
- }
4894
- }
4895
-
4896
- // src/commands/deny/denyRemove.ts
4897
- import chalk63 from "chalk";
4898
- function denyRemove(pattern2) {
4899
- const config = loadProjectConfig();
4900
- const deny = config.deny ?? [];
4901
- const index = deny.findIndex((r) => r.pattern === pattern2);
4902
- if (index === -1) {
4903
- console.log(chalk63.yellow(`No deny rule found for: ${pattern2}`));
4904
- return;
4905
- }
4906
- deny.splice(index, 1);
4907
- config.deny = deny.length > 0 ? deny : void 0;
4908
- saveConfig(config);
4909
- console.log(chalk63.green(`Removed deny rule: ${pattern2}`));
4910
- }
4911
-
4912
4856
  // src/commands/permitCliReads/index.ts
4913
- import { existsSync as existsSync21, mkdirSync as mkdirSync5, readFileSync as readFileSync19, writeFileSync as writeFileSync17 } from "fs";
4857
+ import { existsSync as existsSync21, mkdirSync as mkdirSync5, readFileSync as readFileSync18, writeFileSync as writeFileSync17 } from "fs";
4914
4858
  import { homedir as homedir4 } from "os";
4915
4859
  import { join as join18 } from "path";
4916
4860
 
@@ -4956,11 +4900,11 @@ function assertCliExists(cli) {
4956
4900
  }
4957
4901
 
4958
4902
  // src/commands/permitCliReads/colorize.ts
4959
- import chalk64 from "chalk";
4903
+ import chalk61 from "chalk";
4960
4904
  function colorize(plainOutput) {
4961
4905
  return plainOutput.split("\n").map((line) => {
4962
- if (line.startsWith(" R ")) return chalk64.green(line);
4963
- if (line.startsWith(" W ")) return chalk64.red(line);
4906
+ if (line.startsWith(" R ")) return chalk61.green(line);
4907
+ if (line.startsWith(" W ")) return chalk61.red(line);
4964
4908
  return line;
4965
4909
  }).join("\n");
4966
4910
  }
@@ -5042,12 +4986,12 @@ function hasSubcommands(helpText) {
5042
4986
  // src/commands/permitCliReads/runHelp.ts
5043
4987
  import { exec as exec2 } from "child_process";
5044
4988
  function runHelp(args) {
5045
- return new Promise((resolve7) => {
4989
+ return new Promise((resolve8) => {
5046
4990
  exec2(
5047
4991
  `${args.join(" ")} --help`,
5048
4992
  { encoding: "utf-8", timeout: 3e4 },
5049
4993
  (_err, stdout, stderr) => {
5050
- resolve7(stdout || stderr || "");
4994
+ resolve8(stdout || stderr || "");
5051
4995
  }
5052
4996
  );
5053
4997
  });
@@ -5219,7 +5163,7 @@ function logPath(cli) {
5219
5163
  function readCache(cli) {
5220
5164
  const path50 = logPath(cli);
5221
5165
  if (!existsSync21(path50)) return void 0;
5222
- return readFileSync19(path50, "utf-8");
5166
+ return readFileSync18(path50, "utf-8");
5223
5167
  }
5224
5168
  function writeCache(cli, output) {
5225
5169
  const dir = join18(homedir4(), ".assist");
@@ -5257,6 +5201,59 @@ async function permitCliReads(cli, options2 = { noCache: false }) {
5257
5201
  updateSettings(binary, commands);
5258
5202
  }
5259
5203
 
5204
+ // src/commands/deny/denyAdd.ts
5205
+ import chalk62 from "chalk";
5206
+ function denyAdd(pattern2, message) {
5207
+ const config = loadProjectConfig();
5208
+ const deny = config.deny ?? [];
5209
+ if (deny.some((r) => r.pattern === pattern2)) {
5210
+ console.log(chalk62.yellow(`Deny rule already exists for: ${pattern2}`));
5211
+ return;
5212
+ }
5213
+ deny.push({ pattern: pattern2, message });
5214
+ config.deny = deny;
5215
+ saveConfig(config);
5216
+ console.log(chalk62.green(`Added deny rule: ${pattern2} \u2192 ${message}`));
5217
+ }
5218
+
5219
+ // src/commands/deny/denyList.ts
5220
+ import chalk63 from "chalk";
5221
+ function denyList() {
5222
+ const config = loadConfig();
5223
+ const deny = config.deny;
5224
+ if (!deny || deny.length === 0) {
5225
+ console.log(chalk63.dim("No deny rules configured."));
5226
+ return;
5227
+ }
5228
+ for (const rule of deny) {
5229
+ console.log(`${chalk63.red(rule.pattern)} \u2192 ${rule.message}`);
5230
+ }
5231
+ }
5232
+
5233
+ // src/commands/deny/denyRemove.ts
5234
+ import chalk64 from "chalk";
5235
+ function denyRemove(pattern2) {
5236
+ const config = loadProjectConfig();
5237
+ const deny = config.deny ?? [];
5238
+ const index = deny.findIndex((r) => r.pattern === pattern2);
5239
+ if (index === -1) {
5240
+ console.log(chalk64.yellow(`No deny rule found for: ${pattern2}`));
5241
+ return;
5242
+ }
5243
+ deny.splice(index, 1);
5244
+ config.deny = deny.length > 0 ? deny : void 0;
5245
+ saveConfig(config);
5246
+ console.log(chalk64.green(`Removed deny rule: ${pattern2}`));
5247
+ }
5248
+
5249
+ // src/commands/registerDeny.ts
5250
+ function registerDeny(parent) {
5251
+ const denyCommand = parent.command("deny").description("Manage command deny rules").action(denyList);
5252
+ denyCommand.command("add").description("Add a deny rule for a command pattern").argument("<pattern>", "Command prefix to deny").argument("<message>", "Correction message shown to the agent").action(denyAdd);
5253
+ denyCommand.command("remove").description("Remove a deny rule by pattern").argument("<pattern>", "Command prefix to remove").action(denyRemove);
5254
+ denyCommand.command("list").description("List all deny rules").action(denyList);
5255
+ }
5256
+
5260
5257
  // src/commands/registerCliHook.ts
5261
5258
  function registerCliHook(program2) {
5262
5259
  const cmd = program2.command("cli-hook").description("PreToolUse hook for auto-approving read-only CLI commands").action(() => {
@@ -5271,10 +5268,7 @@ function registerCliHook(program2) {
5271
5268
  ).option("--no-cache", "Force fresh discovery, ignoring cached results").action((cli, options2) => {
5272
5269
  permitCliReads(cli.join(" "), { noCache: !options2.cache });
5273
5270
  });
5274
- const denyCommand = cmd.command("deny").description("Manage command deny rules").action(denyList);
5275
- denyCommand.command("add").description("Add a deny rule for a command pattern").argument("<pattern>", "Command prefix to deny").argument("<message>", "Correction message shown to the agent").action(denyAdd);
5276
- denyCommand.command("remove").description("Remove a deny rule by pattern").argument("<pattern>", "Command prefix to remove").action(denyRemove);
5277
- denyCommand.command("list").description("List all deny rules").action(denyList);
5271
+ registerDeny(cmd);
5278
5272
  }
5279
5273
 
5280
5274
  // src/commands/complexity/analyze.ts
@@ -5928,7 +5922,7 @@ function registerConfig(program2) {
5928
5922
  }
5929
5923
 
5930
5924
  // src/commands/deploy/redirect.ts
5931
- import { existsSync as existsSync22, readFileSync as readFileSync20, writeFileSync as writeFileSync18 } from "fs";
5925
+ import { existsSync as existsSync22, readFileSync as readFileSync19, writeFileSync as writeFileSync18 } from "fs";
5932
5926
  import chalk73 from "chalk";
5933
5927
  var TRAILING_SLASH_SCRIPT = ` <script>
5934
5928
  if (!window.location.pathname.endsWith('/')) {
@@ -5941,7 +5935,7 @@ function redirect() {
5941
5935
  console.log(chalk73.yellow("No index.html found"));
5942
5936
  return;
5943
5937
  }
5944
- const content = readFileSync20(indexPath, "utf-8");
5938
+ const content = readFileSync19(indexPath, "utf-8");
5945
5939
  if (content.includes("window.location.pathname.endsWith('/')")) {
5946
5940
  console.log(chalk73.dim("Trailing slash script already present"));
5947
5941
  return;
@@ -5982,10 +5976,32 @@ function loadBlogSkipDays(repoName) {
5982
5976
  import { execSync as execSync18 } from "child_process";
5983
5977
  import chalk74 from "chalk";
5984
5978
 
5979
+ // src/shared/getRepoName.ts
5980
+ import { existsSync as existsSync23, readFileSync as readFileSync20 } from "fs";
5981
+ import { basename as basename2, join as join20 } from "path";
5982
+ function getRepoName() {
5983
+ const config = loadConfig();
5984
+ if (config.devlog?.name) {
5985
+ return config.devlog.name;
5986
+ }
5987
+ const packageJsonPath = join20(process.cwd(), "package.json");
5988
+ if (existsSync23(packageJsonPath)) {
5989
+ try {
5990
+ const content = readFileSync20(packageJsonPath, "utf-8");
5991
+ const pkg = JSON.parse(content);
5992
+ if (pkg.name) {
5993
+ return pkg.name;
5994
+ }
5995
+ } catch {
5996
+ }
5997
+ }
5998
+ return basename2(process.cwd());
5999
+ }
6000
+
5985
6001
  // src/commands/devlog/loadDevlogEntries.ts
5986
6002
  import { readdirSync, readFileSync as readFileSync21 } from "fs";
5987
- import { join as join20 } from "path";
5988
- var DEVLOG_DIR = join20(BLOG_REPO_ROOT, "src/content/devlog");
6003
+ import { join as join21 } from "path";
6004
+ var DEVLOG_DIR = join21(BLOG_REPO_ROOT, "src/content/devlog");
5989
6005
  function extractFrontmatter(content) {
5990
6006
  const fm = content.match(/^---\n([\s\S]*?)\n---/);
5991
6007
  return fm?.[1] ?? null;
@@ -6013,7 +6029,7 @@ function readDevlogFiles(callback) {
6013
6029
  try {
6014
6030
  const files = readdirSync(DEVLOG_DIR).filter((f) => f.endsWith(".md"));
6015
6031
  for (const file of files) {
6016
- const content = readFileSync21(join20(DEVLOG_DIR, file), "utf-8");
6032
+ const content = readFileSync21(join21(DEVLOG_DIR, file), "utf-8");
6017
6033
  const parsed = parseFrontmatter(content, file);
6018
6034
  if (parsed) callback(parsed);
6019
6035
  }
@@ -6400,11 +6416,11 @@ function repos(options2) {
6400
6416
 
6401
6417
  // src/commands/devlog/skip.ts
6402
6418
  import { writeFileSync as writeFileSync19 } from "fs";
6403
- import { join as join21 } from "path";
6419
+ import { join as join22 } from "path";
6404
6420
  import chalk79 from "chalk";
6405
6421
  import { stringify as stringifyYaml3 } from "yaml";
6406
6422
  function getBlogConfigPath() {
6407
- return join21(BLOG_REPO_ROOT, "assist.yml");
6423
+ return join22(BLOG_REPO_ROOT, "assist.yml");
6408
6424
  }
6409
6425
  function skip(date) {
6410
6426
  if (!/^\d{4}-\d{2}-\d{2}$/.test(date)) {
@@ -6465,16 +6481,16 @@ function registerDevlog(program2) {
6465
6481
 
6466
6482
  // src/commands/dotnet/checkBuildLocks.ts
6467
6483
  import { closeSync, openSync, readdirSync as readdirSync2 } from "fs";
6468
- import { join as join22 } from "path";
6484
+ import { join as join23 } from "path";
6469
6485
  import chalk81 from "chalk";
6470
6486
 
6471
6487
  // src/shared/findRepoRoot.ts
6472
- import { existsSync as existsSync23 } from "fs";
6488
+ import { existsSync as existsSync24 } from "fs";
6473
6489
  import path21 from "path";
6474
6490
  function findRepoRoot(dir) {
6475
6491
  let current = dir;
6476
6492
  while (current !== path21.dirname(current)) {
6477
- if (existsSync23(path21.join(current, ".git"))) {
6493
+ if (existsSync24(path21.join(current, ".git"))) {
6478
6494
  return current;
6479
6495
  }
6480
6496
  current = path21.dirname(current);
@@ -6493,7 +6509,7 @@ function isLockedDll(debugDir) {
6493
6509
  }
6494
6510
  for (const file of files) {
6495
6511
  if (!file.toLowerCase().endsWith(".dll")) continue;
6496
- const dllPath = join22(debugDir, file);
6512
+ const dllPath = join23(debugDir, file);
6497
6513
  try {
6498
6514
  const fd = openSync(dllPath, "r+");
6499
6515
  closeSync(fd);
@@ -6511,13 +6527,13 @@ function findFirstLockedDll(dir) {
6511
6527
  return null;
6512
6528
  }
6513
6529
  if (entries.includes("bin")) {
6514
- const locked = isLockedDll(join22(dir, "bin", "Debug"));
6530
+ const locked = isLockedDll(join23(dir, "bin", "Debug"));
6515
6531
  if (locked) return locked;
6516
6532
  }
6517
6533
  for (const entry of entries) {
6518
6534
  if (SKIP_DIRS.has(entry) || entry === "bin" || entry.startsWith("."))
6519
6535
  continue;
6520
- const found = findFirstLockedDll(join22(dir, entry));
6536
+ const found = findFirstLockedDll(join23(dir, entry));
6521
6537
  if (found) return found;
6522
6538
  }
6523
6539
  return null;
@@ -6685,12 +6701,12 @@ function printJson(tree, totalCount, solutions) {
6685
6701
  }
6686
6702
 
6687
6703
  // src/commands/dotnet/resolveCsproj.ts
6688
- import { existsSync as existsSync24 } from "fs";
6704
+ import { existsSync as existsSync25 } from "fs";
6689
6705
  import path24 from "path";
6690
6706
  import chalk83 from "chalk";
6691
6707
  function resolveCsproj(csprojPath) {
6692
6708
  const resolved = path24.resolve(csprojPath);
6693
- if (!existsSync24(resolved)) {
6709
+ if (!existsSync25(resolved)) {
6694
6710
  console.error(chalk83.red(`File not found: ${resolved}`));
6695
6711
  process.exit(1);
6696
6712
  }
@@ -6858,17 +6874,17 @@ function filterIssues(issues, all, cliOnly, cliSuppress) {
6858
6874
  }
6859
6875
 
6860
6876
  // src/commands/dotnet/resolveSolution.ts
6861
- import { existsSync as existsSync25 } from "fs";
6877
+ import { existsSync as existsSync26 } from "fs";
6862
6878
  import path25 from "path";
6863
6879
  import chalk87 from "chalk";
6864
6880
 
6865
6881
  // src/commands/dotnet/findSolution.ts
6866
6882
  import { readdirSync as readdirSync4 } from "fs";
6867
- import { dirname as dirname16, join as join23 } from "path";
6883
+ import { dirname as dirname16, join as join24 } from "path";
6868
6884
  import chalk86 from "chalk";
6869
6885
  function findSlnInDir(dir) {
6870
6886
  try {
6871
- return readdirSync4(dir).filter((f) => f.endsWith(".sln")).map((f) => join23(dir, f));
6887
+ return readdirSync4(dir).filter((f) => f.endsWith(".sln")).map((f) => join24(dir, f));
6872
6888
  } catch {
6873
6889
  return [];
6874
6890
  }
@@ -6899,7 +6915,7 @@ function findSolution() {
6899
6915
  function resolveSolution(sln) {
6900
6916
  if (sln) {
6901
6917
  const resolved = path25.resolve(sln);
6902
- if (!existsSync25(resolved)) {
6918
+ if (!existsSync26(resolved)) {
6903
6919
  console.error(chalk87.red(`Solution file not found: ${resolved}`));
6904
6920
  process.exit(1);
6905
6921
  }
@@ -6939,7 +6955,7 @@ function parseInspectReport(json) {
6939
6955
 
6940
6956
  // src/commands/dotnet/runInspectCode.ts
6941
6957
  import { execSync as execSync24 } from "child_process";
6942
- import { existsSync as existsSync26, readFileSync as readFileSync24, unlinkSync as unlinkSync5 } from "fs";
6958
+ import { existsSync as existsSync27, readFileSync as readFileSync24, unlinkSync as unlinkSync5 } from "fs";
6943
6959
  import { tmpdir as tmpdir2 } from "os";
6944
6960
  import path26 from "path";
6945
6961
  import chalk88 from "chalk";
@@ -6970,7 +6986,7 @@ function runInspectCode(slnPath, include, swea) {
6970
6986
  console.error(chalk88.red("jb inspectcode failed"));
6971
6987
  process.exit(1);
6972
6988
  }
6973
- if (!existsSync26(reportPath)) {
6989
+ if (!existsSync27(reportPath)) {
6974
6990
  console.error(chalk88.red("Report file not generated"));
6975
6991
  process.exit(1);
6976
6992
  }
@@ -7202,18 +7218,18 @@ function acceptanceCriteria(issueKey) {
7202
7218
  import { execSync as execSync27 } from "child_process";
7203
7219
 
7204
7220
  // src/shared/loadJson.ts
7205
- import { existsSync as existsSync27, mkdirSync as mkdirSync6, readFileSync as readFileSync25, writeFileSync as writeFileSync20 } from "fs";
7221
+ import { existsSync as existsSync28, mkdirSync as mkdirSync6, readFileSync as readFileSync25, writeFileSync as writeFileSync20 } from "fs";
7206
7222
  import { homedir as homedir6 } from "os";
7207
- import { join as join24 } from "path";
7223
+ import { join as join25 } from "path";
7208
7224
  function getStoreDir() {
7209
- return join24(homedir6(), ".assist");
7225
+ return join25(homedir6(), ".assist");
7210
7226
  }
7211
7227
  function getStorePath(filename) {
7212
- return join24(getStoreDir(), filename);
7228
+ return join25(getStoreDir(), filename);
7213
7229
  }
7214
7230
  function loadJson(filename) {
7215
7231
  const path50 = getStorePath(filename);
7216
- if (existsSync27(path50)) {
7232
+ if (existsSync28(path50)) {
7217
7233
  try {
7218
7234
  return JSON.parse(readFileSync25(path50, "utf-8"));
7219
7235
  } catch {
@@ -7224,7 +7240,7 @@ function loadJson(filename) {
7224
7240
  }
7225
7241
  function saveJson(filename, data) {
7226
7242
  const dir = getStoreDir();
7227
- if (!existsSync27(dir)) {
7243
+ if (!existsSync28(dir)) {
7228
7244
  mkdirSync6(dir, { recursive: true });
7229
7245
  }
7230
7246
  writeFileSync20(getStorePath(filename), JSON.stringify(data, null, 2));
@@ -7541,7 +7557,7 @@ function registerNews(program2) {
7541
7557
  import { spawnSync as spawnSync2 } from "child_process";
7542
7558
  import { unlinkSync as unlinkSync6, writeFileSync as writeFileSync21 } from "fs";
7543
7559
  import { tmpdir as tmpdir3 } from "os";
7544
- import { join as join25 } from "path";
7560
+ import { join as join26 } from "path";
7545
7561
 
7546
7562
  // src/commands/prs/shared.ts
7547
7563
  import { execSync as execSync28 } from "child_process";
@@ -7613,7 +7629,7 @@ function comment2(path50, line, body) {
7613
7629
  validateLine(line);
7614
7630
  try {
7615
7631
  const prId = getCurrentPrNodeId();
7616
- const queryFile = join25(tmpdir3(), `gh-query-${Date.now()}.graphql`);
7632
+ const queryFile = join26(tmpdir3(), `gh-query-${Date.now()}.graphql`);
7617
7633
  writeFileSync21(queryFile, MUTATION);
7618
7634
  try {
7619
7635
  const result = spawnSync2(
@@ -7658,18 +7674,18 @@ import { execSync as execSync30 } from "child_process";
7658
7674
  import { execSync as execSync29 } from "child_process";
7659
7675
  import { unlinkSync as unlinkSync8, writeFileSync as writeFileSync22 } from "fs";
7660
7676
  import { tmpdir as tmpdir4 } from "os";
7661
- import { join as join27 } from "path";
7677
+ import { join as join28 } from "path";
7662
7678
 
7663
7679
  // src/commands/prs/loadCommentsCache.ts
7664
- import { existsSync as existsSync28, readFileSync as readFileSync26, unlinkSync as unlinkSync7 } from "fs";
7665
- import { join as join26 } from "path";
7680
+ import { existsSync as existsSync29, readFileSync as readFileSync26, unlinkSync as unlinkSync7 } from "fs";
7681
+ import { join as join27 } from "path";
7666
7682
  import { parse as parse2 } from "yaml";
7667
7683
  function getCachePath(prNumber) {
7668
- return join26(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`);
7684
+ return join27(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`);
7669
7685
  }
7670
7686
  function loadCommentsCache(prNumber) {
7671
7687
  const cachePath = getCachePath(prNumber);
7672
- if (!existsSync28(cachePath)) {
7688
+ if (!existsSync29(cachePath)) {
7673
7689
  return null;
7674
7690
  }
7675
7691
  const content = readFileSync26(cachePath, "utf-8");
@@ -7677,7 +7693,7 @@ function loadCommentsCache(prNumber) {
7677
7693
  }
7678
7694
  function deleteCommentsCache(prNumber) {
7679
7695
  const cachePath = getCachePath(prNumber);
7680
- if (existsSync28(cachePath)) {
7696
+ if (existsSync29(cachePath)) {
7681
7697
  unlinkSync7(cachePath);
7682
7698
  console.log("No more unresolved line comments. Cache dropped.");
7683
7699
  }
@@ -7692,7 +7708,7 @@ function replyToComment(org, repo, prNumber, commentId, message) {
7692
7708
  }
7693
7709
  function resolveThread(threadId) {
7694
7710
  const mutation = `mutation($threadId: ID!) { resolveReviewThread(input: {threadId: $threadId}) { thread { isResolved } } }`;
7695
- const queryFile = join27(tmpdir4(), `gh-mutation-${Date.now()}.graphql`);
7711
+ const queryFile = join28(tmpdir4(), `gh-mutation-${Date.now()}.graphql`);
7696
7712
  writeFileSync22(queryFile, mutation);
7697
7713
  try {
7698
7714
  execSync29(
@@ -7774,18 +7790,18 @@ function fixed(commentId, sha) {
7774
7790
  }
7775
7791
 
7776
7792
  // src/commands/prs/listComments/index.ts
7777
- import { existsSync as existsSync29, mkdirSync as mkdirSync7, writeFileSync as writeFileSync24 } from "fs";
7778
- import { join as join29 } from "path";
7793
+ import { existsSync as existsSync30, mkdirSync as mkdirSync7, writeFileSync as writeFileSync24 } from "fs";
7794
+ import { join as join30 } from "path";
7779
7795
  import { stringify } from "yaml";
7780
7796
 
7781
7797
  // src/commands/prs/fetchThreadIds.ts
7782
7798
  import { execSync as execSync31 } from "child_process";
7783
7799
  import { unlinkSync as unlinkSync9, writeFileSync as writeFileSync23 } from "fs";
7784
7800
  import { tmpdir as tmpdir5 } from "os";
7785
- import { join as join28 } from "path";
7801
+ import { join as join29 } from "path";
7786
7802
  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 } } } } } } }`;
7787
7803
  function fetchThreadIds(org, repo, prNumber) {
7788
- const queryFile = join28(tmpdir5(), `gh-query-${Date.now()}.graphql`);
7804
+ const queryFile = join29(tmpdir5(), `gh-query-${Date.now()}.graphql`);
7789
7805
  writeFileSync23(queryFile, THREAD_QUERY);
7790
7806
  try {
7791
7807
  const result = execSync31(
@@ -7899,8 +7915,8 @@ function printComments2(result) {
7899
7915
 
7900
7916
  // src/commands/prs/listComments/index.ts
7901
7917
  function writeCommentsCache(prNumber, comments2) {
7902
- const assistDir = join29(process.cwd(), ".assist");
7903
- if (!existsSync29(assistDir)) {
7918
+ const assistDir = join30(process.cwd(), ".assist");
7919
+ if (!existsSync30(assistDir)) {
7904
7920
  mkdirSync7(assistDir, { recursive: true });
7905
7921
  }
7906
7922
  const cacheData = {
@@ -7908,7 +7924,7 @@ function writeCommentsCache(prNumber, comments2) {
7908
7924
  fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
7909
7925
  comments: comments2
7910
7926
  };
7911
- const cachePath = join29(assistDir, `pr-${prNumber}-comments.yaml`);
7927
+ const cachePath = join30(assistDir, `pr-${prNumber}-comments.yaml`);
7912
7928
  writeFileSync24(cachePath, stringify(cacheData));
7913
7929
  }
7914
7930
  function handleKnownErrors(error) {
@@ -7941,7 +7957,7 @@ async function listComments() {
7941
7957
  ];
7942
7958
  updateCache(prNumber, allComments);
7943
7959
  const hasLineComments = allComments.some((c) => c.type === "line");
7944
- const cachePath = hasLineComments ? join29(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`) : null;
7960
+ const cachePath = hasLineComments ? join30(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`) : null;
7945
7961
  return { comments: allComments, cachePath };
7946
7962
  } catch (error) {
7947
7963
  const handled = handleKnownErrors(error);
@@ -8711,7 +8727,7 @@ function getViolations(pattern2, options2 = {}, maxLines = DEFAULT_MAX_LINES) {
8711
8727
 
8712
8728
  // src/commands/refactor/check/index.ts
8713
8729
  function runScript(script, cwd) {
8714
- return new Promise((resolve7) => {
8730
+ return new Promise((resolve8) => {
8715
8731
  const child = spawn4("npm", ["run", script], {
8716
8732
  stdio: "pipe",
8717
8733
  shell: true,
@@ -8725,7 +8741,7 @@ function runScript(script, cwd) {
8725
8741
  output += data.toString();
8726
8742
  });
8727
8743
  child.on("close", (code) => {
8728
- resolve7({ script, code: code ?? 1, output });
8744
+ resolve8({ script, code: code ?? 1, output });
8729
8745
  });
8730
8746
  });
8731
8747
  }
@@ -10335,8 +10351,8 @@ function registerSeq(program2) {
10335
10351
  }
10336
10352
 
10337
10353
  // src/commands/transcript/shared.ts
10338
- import { existsSync as existsSync30, readdirSync as readdirSync5, statSync as statSync4 } from "fs";
10339
- import { basename as basename4, join as join30, relative } from "path";
10354
+ import { existsSync as existsSync31, readdirSync as readdirSync5, statSync as statSync4 } from "fs";
10355
+ import { basename as basename4, join as join31, relative } from "path";
10340
10356
  import * as readline2 from "readline";
10341
10357
  var DATE_PREFIX_REGEX = /^\d{4}-\d{2}-\d{2}/;
10342
10358
  function getDatePrefix(daysOffset = 0) {
@@ -10351,10 +10367,10 @@ function isValidDatePrefix(filename) {
10351
10367
  return DATE_PREFIX_REGEX.test(filename);
10352
10368
  }
10353
10369
  function collectFiles(dir, extension) {
10354
- if (!existsSync30(dir)) return [];
10370
+ if (!existsSync31(dir)) return [];
10355
10371
  const results = [];
10356
10372
  for (const entry of readdirSync5(dir)) {
10357
- const fullPath = join30(dir, entry);
10373
+ const fullPath = join31(dir, entry);
10358
10374
  if (statSync4(fullPath).isDirectory()) {
10359
10375
  results.push(...collectFiles(fullPath, extension));
10360
10376
  } else if (entry.endsWith(extension)) {
@@ -10386,9 +10402,9 @@ function createReadlineInterface() {
10386
10402
  });
10387
10403
  }
10388
10404
  function askQuestion(rl, question) {
10389
- return new Promise((resolve7) => {
10405
+ return new Promise((resolve8) => {
10390
10406
  rl.question(question, (answer) => {
10391
- resolve7(answer.trim());
10407
+ resolve8(answer.trim());
10392
10408
  });
10393
10409
  });
10394
10410
  }
@@ -10448,14 +10464,14 @@ async function configure() {
10448
10464
  }
10449
10465
 
10450
10466
  // src/commands/transcript/format/index.ts
10451
- import { existsSync as existsSync32 } from "fs";
10467
+ import { existsSync as existsSync33 } from "fs";
10452
10468
 
10453
10469
  // src/commands/transcript/format/fixInvalidDatePrefixes/index.ts
10454
- import { dirname as dirname18, join as join32 } from "path";
10470
+ import { dirname as dirname18, join as join33 } from "path";
10455
10471
 
10456
10472
  // src/commands/transcript/format/fixInvalidDatePrefixes/promptForDateFix.ts
10457
10473
  import { renameSync as renameSync2 } from "fs";
10458
- import { join as join31 } from "path";
10474
+ import { join as join32 } from "path";
10459
10475
  async function resolveDate(rl, choice) {
10460
10476
  if (choice === "1") return getDatePrefix(0);
10461
10477
  if (choice === "2") return getDatePrefix(-1);
@@ -10470,7 +10486,7 @@ async function resolveDate(rl, choice) {
10470
10486
  }
10471
10487
  function renameWithPrefix(vttDir, vttFile, prefix2) {
10472
10488
  const newFilename = `${prefix2}.${vttFile}`;
10473
- renameSync2(join31(vttDir, vttFile), join31(vttDir, newFilename));
10489
+ renameSync2(join32(vttDir, vttFile), join32(vttDir, newFilename));
10474
10490
  console.log(`Renamed to: ${newFilename}`);
10475
10491
  return newFilename;
10476
10492
  }
@@ -10504,12 +10520,12 @@ async function fixInvalidDatePrefixes(vttFiles) {
10504
10520
  const vttFileDir = dirname18(vttFile.absolutePath);
10505
10521
  const newFilename = await promptForDateFix(vttFile.filename, vttFileDir);
10506
10522
  if (newFilename) {
10507
- const newRelativePath = join32(
10523
+ const newRelativePath = join33(
10508
10524
  dirname18(vttFile.relativePath),
10509
10525
  newFilename
10510
10526
  );
10511
10527
  vttFiles[i] = {
10512
- absolutePath: join32(vttFileDir, newFilename),
10528
+ absolutePath: join33(vttFileDir, newFilename),
10513
10529
  relativePath: newRelativePath,
10514
10530
  filename: newFilename
10515
10531
  };
@@ -10522,8 +10538,8 @@ async function fixInvalidDatePrefixes(vttFiles) {
10522
10538
  }
10523
10539
 
10524
10540
  // src/commands/transcript/format/processVttFile/index.ts
10525
- import { existsSync as existsSync31, mkdirSync as mkdirSync8, readFileSync as readFileSync27, writeFileSync as writeFileSync25 } from "fs";
10526
- import { basename as basename5, dirname as dirname19, join as join33 } from "path";
10541
+ import { existsSync as existsSync32, mkdirSync as mkdirSync8, readFileSync as readFileSync27, writeFileSync as writeFileSync25 } from "fs";
10542
+ import { basename as basename5, dirname as dirname19, join as join34 } from "path";
10527
10543
 
10528
10544
  // src/commands/transcript/cleanText.ts
10529
10545
  function cleanText(text) {
@@ -10733,21 +10749,21 @@ function toMdFilename(vttFilename) {
10733
10749
  return `${basename5(vttFilename, ".vtt").replace(/\s*Transcription\s*/g, " ").trim()}.md`;
10734
10750
  }
10735
10751
  function resolveOutputDir(relativeDir, transcriptsDir) {
10736
- return relativeDir === "." ? transcriptsDir : join33(transcriptsDir, relativeDir);
10752
+ return relativeDir === "." ? transcriptsDir : join34(transcriptsDir, relativeDir);
10737
10753
  }
10738
10754
  function buildOutputPaths(vttFile, transcriptsDir) {
10739
10755
  const mdFile = toMdFilename(vttFile.filename);
10740
10756
  const relativeDir = dirname19(vttFile.relativePath);
10741
10757
  const outputDir = resolveOutputDir(relativeDir, transcriptsDir);
10742
- const outputPath = join33(outputDir, mdFile);
10758
+ const outputPath = join34(outputDir, mdFile);
10743
10759
  return { outputDir, outputPath, mdFile, relativeDir };
10744
10760
  }
10745
10761
  function logSkipped(relativeDir, mdFile) {
10746
- console.log(`Skipping (already exists): ${join33(relativeDir, mdFile)}`);
10762
+ console.log(`Skipping (already exists): ${join34(relativeDir, mdFile)}`);
10747
10763
  return "skipped";
10748
10764
  }
10749
10765
  function ensureDirectory(dir, label2) {
10750
- if (!existsSync31(dir)) {
10766
+ if (!existsSync32(dir)) {
10751
10767
  mkdirSync8(dir, { recursive: true });
10752
10768
  console.log(`Created ${label2}: ${dir}`);
10753
10769
  }
@@ -10783,7 +10799,7 @@ function convertVttToMarkdown(inputPath, outputPath) {
10783
10799
  logReduction(cues.length, chatMessages.length);
10784
10800
  }
10785
10801
  function tryProcessVtt(vttFile, paths) {
10786
- if (existsSync31(paths.outputPath))
10802
+ if (existsSync32(paths.outputPath))
10787
10803
  return logSkipped(paths.relativeDir, paths.mdFile);
10788
10804
  convertVttToMarkdown(vttFile.absolutePath, paths.outputPath);
10789
10805
  return "processed";
@@ -10809,7 +10825,7 @@ function processAllFiles(vttFiles, transcriptsDir) {
10809
10825
  logSummary(counts);
10810
10826
  }
10811
10827
  function requireVttDir(vttDir) {
10812
- if (!existsSync32(vttDir)) {
10828
+ if (!existsSync33(vttDir)) {
10813
10829
  console.error(`VTT directory not found: ${vttDir}`);
10814
10830
  process.exit(1);
10815
10831
  }
@@ -10841,18 +10857,18 @@ async function format() {
10841
10857
  }
10842
10858
 
10843
10859
  // src/commands/transcript/summarise/index.ts
10844
- import { existsSync as existsSync34 } from "fs";
10845
- import { basename as basename6, dirname as dirname21, join as join35, relative as relative2 } from "path";
10860
+ import { existsSync as existsSync35 } from "fs";
10861
+ import { basename as basename6, dirname as dirname21, join as join36, relative as relative2 } from "path";
10846
10862
 
10847
10863
  // src/commands/transcript/summarise/processStagedFile/index.ts
10848
10864
  import {
10849
- existsSync as existsSync33,
10865
+ existsSync as existsSync34,
10850
10866
  mkdirSync as mkdirSync9,
10851
10867
  readFileSync as readFileSync28,
10852
10868
  renameSync as renameSync3,
10853
10869
  rmSync
10854
10870
  } from "fs";
10855
- import { dirname as dirname20, join as join34 } from "path";
10871
+ import { dirname as dirname20, join as join35 } from "path";
10856
10872
 
10857
10873
  // src/commands/transcript/summarise/processStagedFile/validateStagedContent.ts
10858
10874
  import chalk127 from "chalk";
@@ -10881,9 +10897,9 @@ function validateStagedContent(filename, content) {
10881
10897
  }
10882
10898
 
10883
10899
  // src/commands/transcript/summarise/processStagedFile/index.ts
10884
- var STAGING_DIR = join34(process.cwd(), ".assist", "transcript");
10900
+ var STAGING_DIR = join35(process.cwd(), ".assist", "transcript");
10885
10901
  function processStagedFile() {
10886
- if (!existsSync33(STAGING_DIR)) {
10902
+ if (!existsSync34(STAGING_DIR)) {
10887
10903
  return false;
10888
10904
  }
10889
10905
  const stagedFiles = findMdFilesRecursive(STAGING_DIR);
@@ -10905,9 +10921,9 @@ function processStagedFile() {
10905
10921
  );
10906
10922
  process.exit(1);
10907
10923
  }
10908
- const destPath = join34(summaryDir, matchingTranscript.relativePath);
10924
+ const destPath = join35(summaryDir, matchingTranscript.relativePath);
10909
10925
  const destDir = dirname20(destPath);
10910
- if (!existsSync33(destDir)) {
10926
+ if (!existsSync34(destDir)) {
10911
10927
  mkdirSync9(destDir, { recursive: true });
10912
10928
  }
10913
10929
  renameSync3(stagedFile.absolutePath, destPath);
@@ -10921,7 +10937,7 @@ function processStagedFile() {
10921
10937
  // src/commands/transcript/summarise/index.ts
10922
10938
  function buildRelativeKey(relativePath, baseName) {
10923
10939
  const relDir = dirname21(relativePath);
10924
- return relDir === "." ? baseName : join35(relDir, baseName);
10940
+ return relDir === "." ? baseName : join36(relDir, baseName);
10925
10941
  }
10926
10942
  function buildSummaryIndex(summaryDir) {
10927
10943
  const summaryFiles = findMdFilesRecursive(summaryDir);
@@ -10934,7 +10950,7 @@ function buildSummaryIndex(summaryDir) {
10934
10950
  function summarise2() {
10935
10951
  processStagedFile();
10936
10952
  const { transcriptsDir, summaryDir } = getTranscriptConfig();
10937
- if (!existsSync34(transcriptsDir)) {
10953
+ if (!existsSync35(transcriptsDir)) {
10938
10954
  console.log("No transcripts directory found.");
10939
10955
  return;
10940
10956
  }
@@ -10955,8 +10971,8 @@ function summarise2() {
10955
10971
  }
10956
10972
  const next3 = missing[0];
10957
10973
  const outputFilename = `${getTranscriptBaseName(next3.filename)}.md`;
10958
- const outputPath = join35(STAGING_DIR, outputFilename);
10959
- const summaryFileDir = join35(summaryDir, dirname21(next3.relativePath));
10974
+ const outputPath = join36(STAGING_DIR, outputFilename);
10975
+ const summaryFileDir = join36(summaryDir, dirname21(next3.relativePath));
10960
10976
  const relativeTranscriptPath = encodeURI(
10961
10977
  relative2(summaryFileDir, next3.absolutePath).replace(/\\/g, "/")
10962
10978
  );
@@ -11002,45 +11018,45 @@ function registerVerify(program2) {
11002
11018
 
11003
11019
  // src/commands/voice/devices.ts
11004
11020
  import { spawnSync as spawnSync3 } from "child_process";
11005
- import { join as join37 } from "path";
11021
+ import { join as join38 } from "path";
11006
11022
 
11007
11023
  // src/commands/voice/shared.ts
11008
11024
  import { homedir as homedir7 } from "os";
11009
- import { dirname as dirname22, join as join36 } from "path";
11025
+ import { dirname as dirname22, join as join37 } from "path";
11010
11026
  import { fileURLToPath as fileURLToPath6 } from "url";
11011
11027
  var __dirname6 = dirname22(fileURLToPath6(import.meta.url));
11012
- var VOICE_DIR = join36(homedir7(), ".assist", "voice");
11028
+ var VOICE_DIR = join37(homedir7(), ".assist", "voice");
11013
11029
  var voicePaths = {
11014
11030
  dir: VOICE_DIR,
11015
- pid: join36(VOICE_DIR, "voice.pid"),
11016
- log: join36(VOICE_DIR, "voice.log"),
11017
- venv: join36(VOICE_DIR, ".venv"),
11018
- lock: join36(VOICE_DIR, "voice.lock")
11031
+ pid: join37(VOICE_DIR, "voice.pid"),
11032
+ log: join37(VOICE_DIR, "voice.log"),
11033
+ venv: join37(VOICE_DIR, ".venv"),
11034
+ lock: join37(VOICE_DIR, "voice.lock")
11019
11035
  };
11020
11036
  function getPythonDir() {
11021
- return join36(__dirname6, "commands", "voice", "python");
11037
+ return join37(__dirname6, "commands", "voice", "python");
11022
11038
  }
11023
11039
  function getVenvPython() {
11024
- return process.platform === "win32" ? join36(voicePaths.venv, "Scripts", "python.exe") : join36(voicePaths.venv, "bin", "python");
11040
+ return process.platform === "win32" ? join37(voicePaths.venv, "Scripts", "python.exe") : join37(voicePaths.venv, "bin", "python");
11025
11041
  }
11026
11042
  function getLockDir() {
11027
11043
  const config = loadConfig();
11028
11044
  return config.voice?.lockDir ?? VOICE_DIR;
11029
11045
  }
11030
11046
  function getLockFile() {
11031
- return join36(getLockDir(), "voice.lock");
11047
+ return join37(getLockDir(), "voice.lock");
11032
11048
  }
11033
11049
 
11034
11050
  // src/commands/voice/devices.ts
11035
11051
  function devices() {
11036
- const script = join37(getPythonDir(), "list_devices.py");
11052
+ const script = join38(getPythonDir(), "list_devices.py");
11037
11053
  spawnSync3(getVenvPython(), [script], { stdio: "inherit" });
11038
11054
  }
11039
11055
 
11040
11056
  // src/commands/voice/logs.ts
11041
- import { existsSync as existsSync35, readFileSync as readFileSync29 } from "fs";
11057
+ import { existsSync as existsSync36, readFileSync as readFileSync29 } from "fs";
11042
11058
  function logs(options2) {
11043
- if (!existsSync35(voicePaths.log)) {
11059
+ if (!existsSync36(voicePaths.log)) {
11044
11060
  console.log("No voice log file found");
11045
11061
  return;
11046
11062
  }
@@ -11068,12 +11084,12 @@ function logs(options2) {
11068
11084
  // src/commands/voice/setup.ts
11069
11085
  import { spawnSync as spawnSync4 } from "child_process";
11070
11086
  import { mkdirSync as mkdirSync11 } from "fs";
11071
- import { join as join39 } from "path";
11087
+ import { join as join40 } from "path";
11072
11088
 
11073
11089
  // src/commands/voice/checkLockFile.ts
11074
11090
  import { execSync as execSync38 } from "child_process";
11075
- import { existsSync as existsSync36, mkdirSync as mkdirSync10, readFileSync as readFileSync30, writeFileSync as writeFileSync26 } from "fs";
11076
- import { join as join38 } from "path";
11091
+ import { existsSync as existsSync37, mkdirSync as mkdirSync10, readFileSync as readFileSync30, writeFileSync as writeFileSync26 } from "fs";
11092
+ import { join as join39 } from "path";
11077
11093
  function isProcessAlive2(pid) {
11078
11094
  try {
11079
11095
  process.kill(pid, 0);
@@ -11084,7 +11100,7 @@ function isProcessAlive2(pid) {
11084
11100
  }
11085
11101
  function checkLockFile() {
11086
11102
  const lockFile = getLockFile();
11087
- if (!existsSync36(lockFile)) return;
11103
+ if (!existsSync37(lockFile)) return;
11088
11104
  try {
11089
11105
  const lock = JSON.parse(readFileSync30(lockFile, "utf-8"));
11090
11106
  if (lock.pid && isProcessAlive2(lock.pid)) {
@@ -11097,7 +11113,7 @@ function checkLockFile() {
11097
11113
  }
11098
11114
  }
11099
11115
  function bootstrapVenv() {
11100
- if (existsSync36(getVenvPython())) return;
11116
+ if (existsSync37(getVenvPython())) return;
11101
11117
  console.log("Setting up Python environment...");
11102
11118
  const pythonDir = getPythonDir();
11103
11119
  execSync38(
@@ -11110,7 +11126,7 @@ function bootstrapVenv() {
11110
11126
  }
11111
11127
  function writeLockFile(pid) {
11112
11128
  const lockFile = getLockFile();
11113
- mkdirSync10(join38(lockFile, ".."), { recursive: true });
11129
+ mkdirSync10(join39(lockFile, ".."), { recursive: true });
11114
11130
  writeFileSync26(
11115
11131
  lockFile,
11116
11132
  JSON.stringify({
@@ -11126,7 +11142,7 @@ function setup() {
11126
11142
  mkdirSync11(voicePaths.dir, { recursive: true });
11127
11143
  bootstrapVenv();
11128
11144
  console.log("\nDownloading models...\n");
11129
- const script = join39(getPythonDir(), "setup_models.py");
11145
+ const script = join40(getPythonDir(), "setup_models.py");
11130
11146
  const result = spawnSync4(getVenvPython(), [script], {
11131
11147
  stdio: "inherit",
11132
11148
  env: { ...process.env, VOICE_LOG_FILE: voicePaths.log }
@@ -11140,7 +11156,7 @@ function setup() {
11140
11156
  // src/commands/voice/start.ts
11141
11157
  import { spawn as spawn5 } from "child_process";
11142
11158
  import { mkdirSync as mkdirSync12, writeFileSync as writeFileSync27 } from "fs";
11143
- import { join as join40 } from "path";
11159
+ import { join as join41 } from "path";
11144
11160
 
11145
11161
  // src/commands/voice/buildDaemonEnv.ts
11146
11162
  function buildDaemonEnv(options2) {
@@ -11178,7 +11194,7 @@ function start2(options2) {
11178
11194
  bootstrapVenv();
11179
11195
  const debug = options2.debug || options2.foreground || process.platform === "win32";
11180
11196
  const env = buildDaemonEnv({ debug });
11181
- const script = join40(getPythonDir(), "voice_daemon.py");
11197
+ const script = join41(getPythonDir(), "voice_daemon.py");
11182
11198
  const python = getVenvPython();
11183
11199
  if (options2.foreground) {
11184
11200
  spawnForeground(python, script, env);
@@ -11188,7 +11204,7 @@ function start2(options2) {
11188
11204
  }
11189
11205
 
11190
11206
  // src/commands/voice/status.ts
11191
- import { existsSync as existsSync37, readFileSync as readFileSync31 } from "fs";
11207
+ import { existsSync as existsSync38, readFileSync as readFileSync31 } from "fs";
11192
11208
  function isProcessAlive3(pid) {
11193
11209
  try {
11194
11210
  process.kill(pid, 0);
@@ -11198,12 +11214,12 @@ function isProcessAlive3(pid) {
11198
11214
  }
11199
11215
  }
11200
11216
  function readRecentLogs(count) {
11201
- if (!existsSync37(voicePaths.log)) return [];
11217
+ if (!existsSync38(voicePaths.log)) return [];
11202
11218
  const lines = readFileSync31(voicePaths.log, "utf-8").trim().split("\n");
11203
11219
  return lines.slice(-count);
11204
11220
  }
11205
11221
  function status() {
11206
- if (!existsSync37(voicePaths.pid)) {
11222
+ if (!existsSync38(voicePaths.pid)) {
11207
11223
  console.log("Voice daemon: not running (no PID file)");
11208
11224
  return;
11209
11225
  }
@@ -11226,9 +11242,9 @@ function status() {
11226
11242
  }
11227
11243
 
11228
11244
  // src/commands/voice/stop.ts
11229
- import { existsSync as existsSync38, readFileSync as readFileSync32, unlinkSync as unlinkSync10 } from "fs";
11245
+ import { existsSync as existsSync39, readFileSync as readFileSync32, unlinkSync as unlinkSync10 } from "fs";
11230
11246
  function stop() {
11231
- if (!existsSync38(voicePaths.pid)) {
11247
+ if (!existsSync39(voicePaths.pid)) {
11232
11248
  console.log("Voice daemon is not running (no PID file)");
11233
11249
  return;
11234
11250
  }
@@ -11245,7 +11261,7 @@ function stop() {
11245
11261
  }
11246
11262
  try {
11247
11263
  const lockFile = getLockFile();
11248
- if (existsSync38(lockFile)) unlinkSync10(lockFile);
11264
+ if (existsSync39(lockFile)) unlinkSync10(lockFile);
11249
11265
  } catch {
11250
11266
  }
11251
11267
  console.log("Voice daemon stopped");
@@ -11329,7 +11345,7 @@ function extractCode(url, expectedState) {
11329
11345
  return code;
11330
11346
  }
11331
11347
  function waitForCallback(port, expectedState) {
11332
- return new Promise((resolve7, reject) => {
11348
+ return new Promise((resolve8, reject) => {
11333
11349
  const timeout = setTimeout(() => {
11334
11350
  server.close();
11335
11351
  reject(new Error("Authorization timed out after 120 seconds"));
@@ -11346,7 +11362,7 @@ function waitForCallback(port, expectedState) {
11346
11362
  const code = extractCode(url, expectedState);
11347
11363
  respondHtml(res, 200, "Authorization successful!");
11348
11364
  server.close();
11349
- resolve7(code);
11365
+ resolve8(code);
11350
11366
  } catch (err) {
11351
11367
  respondHtml(res, 400, err.message);
11352
11368
  server.close();
@@ -11467,11 +11483,11 @@ async function auth() {
11467
11483
 
11468
11484
  // src/commands/roam/showClaudeCodeIcon.ts
11469
11485
  import { readFileSync as readFileSync33 } from "fs";
11470
- import { join as join41 } from "path";
11486
+ import { join as join42 } from "path";
11471
11487
  async function showClaudeCodeIcon() {
11472
11488
  const appData = process.env.APPDATA;
11473
11489
  if (!appData) return;
11474
- const portFile = join41(appData, "Roam", "roam-local-api.port");
11490
+ const portFile = join42(appData, "Roam", "roam-local-api.port");
11475
11491
  let port;
11476
11492
  try {
11477
11493
  port = readFileSync33(portFile, "utf-8").trim();
@@ -11497,7 +11513,7 @@ function registerRoam(program2) {
11497
11513
  }
11498
11514
 
11499
11515
  // src/commands/run/index.ts
11500
- import { execSync as execSync40 } from "child_process";
11516
+ import { resolve as resolve5 } from "path";
11501
11517
 
11502
11518
  // src/commands/run/formatConfiguredCommands.ts
11503
11519
  function formatConfiguredCommands() {
@@ -11533,14 +11549,28 @@ function resolveParams(params, cliArgs) {
11533
11549
  return resolved;
11534
11550
  }
11535
11551
 
11552
+ // src/commands/run/runPreCommands.ts
11553
+ import { execSync as execSync40 } from "child_process";
11554
+ function runPreCommands(pre, cwd) {
11555
+ for (const cmd of pre) {
11556
+ try {
11557
+ execSync40(cmd, { stdio: "inherit", cwd });
11558
+ } catch (err) {
11559
+ const code = err && typeof err === "object" && "status" in err ? err.status : 1;
11560
+ process.exit(code);
11561
+ }
11562
+ }
11563
+ }
11564
+
11536
11565
  // src/commands/run/spawnRunCommand.ts
11537
11566
  import { spawn as spawn6 } from "child_process";
11538
- function spawnRunCommand(fullCommand, env) {
11567
+ function spawnRunCommand(fullCommand, env, cwd) {
11539
11568
  const start3 = Date.now();
11540
11569
  const child = spawn6(fullCommand, [], {
11541
11570
  stdio: "inherit",
11542
11571
  shell: true,
11543
- env: env ? { ...process.env, ...expandEnv(env) } : void 0
11572
+ env: env ? { ...process.env, ...expandEnv(env) } : void 0,
11573
+ cwd
11544
11574
  });
11545
11575
  child.on("close", (code) => {
11546
11576
  const elapsed = formatElapsed(Date.now() - start3);
@@ -11556,17 +11586,28 @@ Done in ${elapsed}`);
11556
11586
 
11557
11587
  // src/commands/run/add.ts
11558
11588
  import { mkdirSync as mkdirSync13, writeFileSync as writeFileSync28 } from "fs";
11559
- import { join as join42 } from "path";
11589
+ import { join as join43 } from "path";
11560
11590
  function findAddIndex() {
11561
11591
  const addIndex = process.argv.indexOf("add");
11562
11592
  if (addIndex === -1 || addIndex + 2 >= process.argv.length) return -1;
11563
11593
  return addIndex;
11564
11594
  }
11595
+ function extractOption(args, flag) {
11596
+ const index = args.indexOf(flag);
11597
+ if (index === -1) return { value: void 0, remaining: args };
11598
+ return {
11599
+ value: args[index + 1],
11600
+ remaining: [...args.slice(0, index), ...args.slice(index + 2)]
11601
+ };
11602
+ }
11565
11603
  function extractAddArgs(addIndex) {
11604
+ const rawArgs = process.argv.slice(addIndex + 3);
11605
+ const { value: cwd, remaining: args } = extractOption(rawArgs, "--cwd");
11566
11606
  return {
11567
11607
  name: process.argv[addIndex + 1],
11568
11608
  command: process.argv[addIndex + 2],
11569
- args: process.argv.slice(addIndex + 3)
11609
+ args,
11610
+ cwd
11570
11611
  };
11571
11612
  }
11572
11613
  function parseAddArguments() {
@@ -11595,14 +11636,14 @@ function getOrInitRunList() {
11595
11636
  if (!config.run) config.run = [];
11596
11637
  return { config, runList: config.run };
11597
11638
  }
11598
- function saveNewRunConfig(name, command, args) {
11639
+ function saveNewRunConfig(name, command, args, cwd) {
11599
11640
  const { config, runList } = getOrInitRunList();
11600
11641
  ensureNoDuplicate(runList, name);
11601
- runList.push(buildRunEntry(name, command, args));
11642
+ runList.push(buildRunEntry(name, command, args, { cwd }));
11602
11643
  saveConfig(config);
11603
11644
  }
11604
11645
  function createCommandFile(name) {
11605
- const dir = join42(".claude", "commands");
11646
+ const dir = join43(".claude", "commands");
11606
11647
  mkdirSync13(dir, { recursive: true });
11607
11648
  const content = `---
11608
11649
  description: Run ${name}
@@ -11610,13 +11651,13 @@ description: Run ${name}
11610
11651
 
11611
11652
  Run \`assist run ${name} $ARGUMENTS 2>&1\`.
11612
11653
  `;
11613
- const filePath = join42(dir, `${name}.md`);
11654
+ const filePath = join43(dir, `${name}.md`);
11614
11655
  writeFileSync28(filePath, content);
11615
11656
  console.log(`Created command file: ${filePath}`);
11616
11657
  }
11617
11658
  function add3() {
11618
- const { name, command, args } = requireParsedArgs();
11619
- saveNewRunConfig(name, command, args);
11659
+ const { name, command, args, cwd } = requireParsedArgs();
11660
+ saveNewRunConfig(name, command, args, cwd);
11620
11661
  createCommandFile(name);
11621
11662
  console.log(
11622
11663
  `Added run configuration: ${name} -> ${formatDisplay(command, args)}`
@@ -11659,16 +11700,6 @@ function listRunConfigs() {
11659
11700
  console.log(`${config.name}: ${config.command}${args}`);
11660
11701
  }
11661
11702
  }
11662
- function runPreCommands(pre) {
11663
- for (const cmd of pre) {
11664
- try {
11665
- execSync40(cmd, { stdio: "inherit" });
11666
- } catch (err) {
11667
- const code = err && typeof err === "object" && "status" in err ? err.status : 1;
11668
- process.exit(code);
11669
- }
11670
- }
11671
- }
11672
11703
  function run3(name, args) {
11673
11704
  if (!name) {
11674
11705
  console.error("error: missing required argument 'name'");
@@ -11676,19 +11707,21 @@ function run3(name, args) {
11676
11707
  process.exit(1);
11677
11708
  }
11678
11709
  const runConfig = findRunConfig(name);
11679
- if (runConfig.pre) runPreCommands(runConfig.pre);
11710
+ const resolvedCwd = runConfig.cwd ? resolve5(getConfigDir(), runConfig.cwd) : void 0;
11711
+ if (runConfig.pre) runPreCommands(runConfig.pre, resolvedCwd);
11680
11712
  const resolved = resolveParams(runConfig.params, args);
11681
11713
  spawnRunCommand(
11682
11714
  buildCommand(runConfig.command, runConfig.args ?? [], resolved),
11683
- runConfig.env
11715
+ runConfig.env,
11716
+ resolvedCwd
11684
11717
  );
11685
11718
  }
11686
11719
 
11687
11720
  // src/commands/screenshot/index.ts
11688
11721
  import { execSync as execSync41 } from "child_process";
11689
- import { existsSync as existsSync39, mkdirSync as mkdirSync14, unlinkSync as unlinkSync11, writeFileSync as writeFileSync29 } from "fs";
11722
+ import { existsSync as existsSync40, mkdirSync as mkdirSync14, unlinkSync as unlinkSync11, writeFileSync as writeFileSync29 } from "fs";
11690
11723
  import { tmpdir as tmpdir6 } from "os";
11691
- import { join as join43, resolve as resolve5 } from "path";
11724
+ import { join as join44, resolve as resolve6 } from "path";
11692
11725
  import chalk129 from "chalk";
11693
11726
 
11694
11727
  // src/commands/screenshot/captureWindowPs1.ts
@@ -11818,14 +11851,14 @@ Write-Output $OutputPath
11818
11851
 
11819
11852
  // src/commands/screenshot/index.ts
11820
11853
  function buildOutputPath(outputDir, processName) {
11821
- if (!existsSync39(outputDir)) {
11854
+ if (!existsSync40(outputDir)) {
11822
11855
  mkdirSync14(outputDir, { recursive: true });
11823
11856
  }
11824
11857
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
11825
- return resolve5(outputDir, `${processName}-${timestamp}.png`);
11858
+ return resolve6(outputDir, `${processName}-${timestamp}.png`);
11826
11859
  }
11827
11860
  function runPowerShellScript(processName, outputPath) {
11828
- const scriptPath = join43(tmpdir6(), `assist-screenshot-${Date.now()}.ps1`);
11861
+ const scriptPath = join44(tmpdir6(), `assist-screenshot-${Date.now()}.ps1`);
11829
11862
  writeFileSync29(scriptPath, captureWindowPs1, "utf-8");
11830
11863
  try {
11831
11864
  execSync41(
@@ -11838,7 +11871,7 @@ function runPowerShellScript(processName, outputPath) {
11838
11871
  }
11839
11872
  function screenshot(processName) {
11840
11873
  const config = loadConfig();
11841
- const outputDir = resolve5(config.screenshot.outputDir);
11874
+ const outputDir = resolve6(config.screenshot.outputDir);
11842
11875
  const outputPath = buildOutputPath(outputDir, processName);
11843
11876
  console.log(chalk129.gray(`Capturing window for process "${processName}" ...`));
11844
11877
  try {
@@ -12077,7 +12110,10 @@ program.command("commit").description("Create a git commit with validation").arg
12077
12110
  registerConfig(program);
12078
12111
  var runCommand = program.command("run").description("Run a configured command from assist.yml").argument("[name]", "Name of the configured command").argument("[args...]", "Arguments to pass to the command").allowUnknownOption().addHelpText("after", () => formatConfiguredCommands()).action((name, args) => run3(name, args));
12079
12112
  runCommand.command("list").description("List configured run commands").action(listRunConfigs);
12080
- runCommand.command("add").description("Add a new run configuration to assist.yml").argument("<name>", "Name for the run configuration").argument("<command>", "Command to execute").argument("[args...]", "Static args to pass to the command").addHelpText(
12113
+ runCommand.command("add").description("Add a new run configuration to assist.yml").argument("<name>", "Name for the run configuration").argument("<command>", "Command to execute").argument("[args...]", "Static args to pass to the command").option(
12114
+ "--cwd <dir>",
12115
+ "Working directory (resolved relative to the config file)"
12116
+ ).addHelpText(
12081
12117
  "after",
12082
12118
  '\nPositional params can be added to the config manually:\n params:\n - name: env # assist run deploy prod \u2192 appends "prod"\n required: true\n - name: tag\n default: latest'
12083
12119
  ).allowUnknownOption().allowExcessArguments().action(() => add3());
@@ -12110,6 +12146,7 @@ registerRavendb(program);
12110
12146
  registerSeq(program);
12111
12147
  registerTranscript(program);
12112
12148
  registerVoice(program);
12149
+ registerDeny(program);
12113
12150
  program.command("next").description("Alias for backlog next -w").action(() => next({ allowEdits: true }));
12114
12151
  program.command("draft").alias("feat").description("Launch Claude in /draft mode, chain into next on /next signal").action(() => launchMode("draft"));
12115
12152
  program.command("bug").description("Launch Claude in /bug mode, chain into next on /next signal").action(() => launchMode("bug"));