@staff0rd/assist 0.180.1 → 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 +288 -250
  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.180.1",
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;
@@ -3643,7 +3632,7 @@ async function notify() {
3643
3632
  // src/commands/activity/activityChart.ts
3644
3633
  import blessed from "blessed";
3645
3634
  import contrib from "blessed-contrib";
3646
- function activityChart(data) {
3635
+ function activityChart(data, range) {
3647
3636
  const screen = blessed.screen({
3648
3637
  smartCSR: true,
3649
3638
  title: "Commit Activity"
@@ -3652,7 +3641,7 @@ function activityChart(data) {
3652
3641
  const labels = data.map((d) => d.date.slice(5));
3653
3642
  const values = data.map((d) => d.count);
3654
3643
  const line = grid.set(0, 0, 1, 1, contrib.line, {
3655
- label: " Commits per week (press q to close) ",
3644
+ label: ` Commits per week \xB7 ${range.since} \u2192 ${range.until} (press q to close) `,
3656
3645
  showLegend: true,
3657
3646
  legend: { width: 12 },
3658
3647
  xLabelPadding: 3,
@@ -3727,7 +3716,8 @@ async function activity(options2) {
3727
3716
  weekly.set(weekStart, (weekly.get(weekStart) ?? 0) + count);
3728
3717
  }
3729
3718
  const weeklyData = [...weekly.entries()].map(([date, count]) => ({ date, count })).sort((a, b) => a.date.localeCompare(b.date));
3730
- activityChart(weeklyData);
3719
+ const until = data[data.length - 1].date;
3720
+ activityChart(weeklyData, { since, until });
3731
3721
  }
3732
3722
 
3733
3723
  // src/commands/registerActivity.ts
@@ -3802,7 +3792,7 @@ function commitBacklog(id, name) {
3802
3792
 
3803
3793
  // src/commands/backlog/add/shared.ts
3804
3794
  import { spawnSync } from "child_process";
3805
- 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";
3806
3796
  import { tmpdir } from "os";
3807
3797
  import { join as join16 } from "path";
3808
3798
  import enquirer7 from "enquirer";
@@ -3852,7 +3842,7 @@ function openEditor() {
3852
3842
  unlinkSync4(filePath);
3853
3843
  return void 0;
3854
3844
  }
3855
- const content = readFileSync16(filePath, "utf-8").trim();
3845
+ const content = readFileSync15(filePath, "utf-8").trim();
3856
3846
  unlinkSync4(filePath);
3857
3847
  return content || void 0;
3858
3848
  }
@@ -4539,7 +4529,7 @@ function extractGraphqlQuery(args) {
4539
4529
  }
4540
4530
 
4541
4531
  // src/shared/loadCliReads.ts
4542
- 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";
4543
4533
  import { dirname as dirname14, resolve as resolve2 } from "path";
4544
4534
  import { fileURLToPath as fileURLToPath4 } from "url";
4545
4535
  var __filename2 = fileURLToPath4(import.meta.url);
@@ -4549,7 +4539,7 @@ function packageRoot() {
4549
4539
  }
4550
4540
  function readLines(path50) {
4551
4541
  if (!existsSync19(path50)) return [];
4552
- return readFileSync17(path50, "utf-8").split("\n").filter((line) => line.trim() !== "");
4542
+ return readFileSync16(path50, "utf-8").split("\n").filter((line) => line.trim() !== "");
4553
4543
  }
4554
4544
  var cachedReads;
4555
4545
  var cachedWrites;
@@ -4595,7 +4585,7 @@ function findCliWrite(command) {
4595
4585
  }
4596
4586
 
4597
4587
  // src/shared/readSettingsPerms.ts
4598
- import { existsSync as existsSync20, readFileSync as readFileSync18 } from "fs";
4588
+ import { existsSync as existsSync20, readFileSync as readFileSync17 } from "fs";
4599
4589
  import { homedir as homedir3 } from "os";
4600
4590
  import { join as join17 } from "path";
4601
4591
  function readSettingsPerms(key) {
@@ -4613,7 +4603,7 @@ function readSettingsPerms(key) {
4613
4603
  function readPermissionArray(filePath, key) {
4614
4604
  if (!existsSync20(filePath)) return [];
4615
4605
  try {
4616
- const data = JSON.parse(readFileSync18(filePath, "utf-8"));
4606
+ const data = JSON.parse(readFileSync17(filePath, "utf-8"));
4617
4607
  const arr = data?.permissions?.[key];
4618
4608
  return Array.isArray(arr) ? arr.filter((e) => typeof e === "string") : [];
4619
4609
  } catch {
@@ -4863,53 +4853,8 @@ function cliHookCheck(command, toolName = "Bash") {
4863
4853
  ${reasons.join("\n")}`);
4864
4854
  }
4865
4855
 
4866
- // src/commands/deny/denyAdd.ts
4867
- import chalk61 from "chalk";
4868
- function denyAdd(pattern2, message) {
4869
- const config = loadProjectConfig();
4870
- const deny = config.deny ?? [];
4871
- if (deny.some((r) => r.pattern === pattern2)) {
4872
- console.log(chalk61.yellow(`Deny rule already exists for: ${pattern2}`));
4873
- return;
4874
- }
4875
- deny.push({ pattern: pattern2, message });
4876
- config.deny = deny;
4877
- saveConfig(config);
4878
- console.log(chalk61.green(`Added deny rule: ${pattern2} \u2192 ${message}`));
4879
- }
4880
-
4881
- // src/commands/deny/denyList.ts
4882
- import chalk62 from "chalk";
4883
- function denyList() {
4884
- const config = loadConfig();
4885
- const deny = config.deny;
4886
- if (!deny || deny.length === 0) {
4887
- console.log(chalk62.dim("No deny rules configured."));
4888
- return;
4889
- }
4890
- for (const rule of deny) {
4891
- console.log(`${chalk62.red(rule.pattern)} \u2192 ${rule.message}`);
4892
- }
4893
- }
4894
-
4895
- // src/commands/deny/denyRemove.ts
4896
- import chalk63 from "chalk";
4897
- function denyRemove(pattern2) {
4898
- const config = loadProjectConfig();
4899
- const deny = config.deny ?? [];
4900
- const index = deny.findIndex((r) => r.pattern === pattern2);
4901
- if (index === -1) {
4902
- console.log(chalk63.yellow(`No deny rule found for: ${pattern2}`));
4903
- return;
4904
- }
4905
- deny.splice(index, 1);
4906
- config.deny = deny.length > 0 ? deny : void 0;
4907
- saveConfig(config);
4908
- console.log(chalk63.green(`Removed deny rule: ${pattern2}`));
4909
- }
4910
-
4911
4856
  // src/commands/permitCliReads/index.ts
4912
- 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";
4913
4858
  import { homedir as homedir4 } from "os";
4914
4859
  import { join as join18 } from "path";
4915
4860
 
@@ -4955,11 +4900,11 @@ function assertCliExists(cli) {
4955
4900
  }
4956
4901
 
4957
4902
  // src/commands/permitCliReads/colorize.ts
4958
- import chalk64 from "chalk";
4903
+ import chalk61 from "chalk";
4959
4904
  function colorize(plainOutput) {
4960
4905
  return plainOutput.split("\n").map((line) => {
4961
- if (line.startsWith(" R ")) return chalk64.green(line);
4962
- 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);
4963
4908
  return line;
4964
4909
  }).join("\n");
4965
4910
  }
@@ -5041,12 +4986,12 @@ function hasSubcommands(helpText) {
5041
4986
  // src/commands/permitCliReads/runHelp.ts
5042
4987
  import { exec as exec2 } from "child_process";
5043
4988
  function runHelp(args) {
5044
- return new Promise((resolve7) => {
4989
+ return new Promise((resolve8) => {
5045
4990
  exec2(
5046
4991
  `${args.join(" ")} --help`,
5047
4992
  { encoding: "utf-8", timeout: 3e4 },
5048
4993
  (_err, stdout, stderr) => {
5049
- resolve7(stdout || stderr || "");
4994
+ resolve8(stdout || stderr || "");
5050
4995
  }
5051
4996
  );
5052
4997
  });
@@ -5218,7 +5163,7 @@ function logPath(cli) {
5218
5163
  function readCache(cli) {
5219
5164
  const path50 = logPath(cli);
5220
5165
  if (!existsSync21(path50)) return void 0;
5221
- return readFileSync19(path50, "utf-8");
5166
+ return readFileSync18(path50, "utf-8");
5222
5167
  }
5223
5168
  function writeCache(cli, output) {
5224
5169
  const dir = join18(homedir4(), ".assist");
@@ -5256,6 +5201,59 @@ async function permitCliReads(cli, options2 = { noCache: false }) {
5256
5201
  updateSettings(binary, commands);
5257
5202
  }
5258
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
+
5259
5257
  // src/commands/registerCliHook.ts
5260
5258
  function registerCliHook(program2) {
5261
5259
  const cmd = program2.command("cli-hook").description("PreToolUse hook for auto-approving read-only CLI commands").action(() => {
@@ -5270,10 +5268,7 @@ function registerCliHook(program2) {
5270
5268
  ).option("--no-cache", "Force fresh discovery, ignoring cached results").action((cli, options2) => {
5271
5269
  permitCliReads(cli.join(" "), { noCache: !options2.cache });
5272
5270
  });
5273
- const denyCommand = cmd.command("deny").description("Manage command deny rules").action(denyList);
5274
- 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);
5275
- denyCommand.command("remove").description("Remove a deny rule by pattern").argument("<pattern>", "Command prefix to remove").action(denyRemove);
5276
- denyCommand.command("list").description("List all deny rules").action(denyList);
5271
+ registerDeny(cmd);
5277
5272
  }
5278
5273
 
5279
5274
  // src/commands/complexity/analyze.ts
@@ -5927,7 +5922,7 @@ function registerConfig(program2) {
5927
5922
  }
5928
5923
 
5929
5924
  // src/commands/deploy/redirect.ts
5930
- 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";
5931
5926
  import chalk73 from "chalk";
5932
5927
  var TRAILING_SLASH_SCRIPT = ` <script>
5933
5928
  if (!window.location.pathname.endsWith('/')) {
@@ -5940,7 +5935,7 @@ function redirect() {
5940
5935
  console.log(chalk73.yellow("No index.html found"));
5941
5936
  return;
5942
5937
  }
5943
- const content = readFileSync20(indexPath, "utf-8");
5938
+ const content = readFileSync19(indexPath, "utf-8");
5944
5939
  if (content.includes("window.location.pathname.endsWith('/')")) {
5945
5940
  console.log(chalk73.dim("Trailing slash script already present"));
5946
5941
  return;
@@ -5981,10 +5976,32 @@ function loadBlogSkipDays(repoName) {
5981
5976
  import { execSync as execSync18 } from "child_process";
5982
5977
  import chalk74 from "chalk";
5983
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
+
5984
6001
  // src/commands/devlog/loadDevlogEntries.ts
5985
6002
  import { readdirSync, readFileSync as readFileSync21 } from "fs";
5986
- import { join as join20 } from "path";
5987
- 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");
5988
6005
  function extractFrontmatter(content) {
5989
6006
  const fm = content.match(/^---\n([\s\S]*?)\n---/);
5990
6007
  return fm?.[1] ?? null;
@@ -6012,7 +6029,7 @@ function readDevlogFiles(callback) {
6012
6029
  try {
6013
6030
  const files = readdirSync(DEVLOG_DIR).filter((f) => f.endsWith(".md"));
6014
6031
  for (const file of files) {
6015
- const content = readFileSync21(join20(DEVLOG_DIR, file), "utf-8");
6032
+ const content = readFileSync21(join21(DEVLOG_DIR, file), "utf-8");
6016
6033
  const parsed = parseFrontmatter(content, file);
6017
6034
  if (parsed) callback(parsed);
6018
6035
  }
@@ -6399,11 +6416,11 @@ function repos(options2) {
6399
6416
 
6400
6417
  // src/commands/devlog/skip.ts
6401
6418
  import { writeFileSync as writeFileSync19 } from "fs";
6402
- import { join as join21 } from "path";
6419
+ import { join as join22 } from "path";
6403
6420
  import chalk79 from "chalk";
6404
6421
  import { stringify as stringifyYaml3 } from "yaml";
6405
6422
  function getBlogConfigPath() {
6406
- return join21(BLOG_REPO_ROOT, "assist.yml");
6423
+ return join22(BLOG_REPO_ROOT, "assist.yml");
6407
6424
  }
6408
6425
  function skip(date) {
6409
6426
  if (!/^\d{4}-\d{2}-\d{2}$/.test(date)) {
@@ -6464,16 +6481,16 @@ function registerDevlog(program2) {
6464
6481
 
6465
6482
  // src/commands/dotnet/checkBuildLocks.ts
6466
6483
  import { closeSync, openSync, readdirSync as readdirSync2 } from "fs";
6467
- import { join as join22 } from "path";
6484
+ import { join as join23 } from "path";
6468
6485
  import chalk81 from "chalk";
6469
6486
 
6470
6487
  // src/shared/findRepoRoot.ts
6471
- import { existsSync as existsSync23 } from "fs";
6488
+ import { existsSync as existsSync24 } from "fs";
6472
6489
  import path21 from "path";
6473
6490
  function findRepoRoot(dir) {
6474
6491
  let current = dir;
6475
6492
  while (current !== path21.dirname(current)) {
6476
- if (existsSync23(path21.join(current, ".git"))) {
6493
+ if (existsSync24(path21.join(current, ".git"))) {
6477
6494
  return current;
6478
6495
  }
6479
6496
  current = path21.dirname(current);
@@ -6492,7 +6509,7 @@ function isLockedDll(debugDir) {
6492
6509
  }
6493
6510
  for (const file of files) {
6494
6511
  if (!file.toLowerCase().endsWith(".dll")) continue;
6495
- const dllPath = join22(debugDir, file);
6512
+ const dllPath = join23(debugDir, file);
6496
6513
  try {
6497
6514
  const fd = openSync(dllPath, "r+");
6498
6515
  closeSync(fd);
@@ -6510,13 +6527,13 @@ function findFirstLockedDll(dir) {
6510
6527
  return null;
6511
6528
  }
6512
6529
  if (entries.includes("bin")) {
6513
- const locked = isLockedDll(join22(dir, "bin", "Debug"));
6530
+ const locked = isLockedDll(join23(dir, "bin", "Debug"));
6514
6531
  if (locked) return locked;
6515
6532
  }
6516
6533
  for (const entry of entries) {
6517
6534
  if (SKIP_DIRS.has(entry) || entry === "bin" || entry.startsWith("."))
6518
6535
  continue;
6519
- const found = findFirstLockedDll(join22(dir, entry));
6536
+ const found = findFirstLockedDll(join23(dir, entry));
6520
6537
  if (found) return found;
6521
6538
  }
6522
6539
  return null;
@@ -6684,12 +6701,12 @@ function printJson(tree, totalCount, solutions) {
6684
6701
  }
6685
6702
 
6686
6703
  // src/commands/dotnet/resolveCsproj.ts
6687
- import { existsSync as existsSync24 } from "fs";
6704
+ import { existsSync as existsSync25 } from "fs";
6688
6705
  import path24 from "path";
6689
6706
  import chalk83 from "chalk";
6690
6707
  function resolveCsproj(csprojPath) {
6691
6708
  const resolved = path24.resolve(csprojPath);
6692
- if (!existsSync24(resolved)) {
6709
+ if (!existsSync25(resolved)) {
6693
6710
  console.error(chalk83.red(`File not found: ${resolved}`));
6694
6711
  process.exit(1);
6695
6712
  }
@@ -6857,17 +6874,17 @@ function filterIssues(issues, all, cliOnly, cliSuppress) {
6857
6874
  }
6858
6875
 
6859
6876
  // src/commands/dotnet/resolveSolution.ts
6860
- import { existsSync as existsSync25 } from "fs";
6877
+ import { existsSync as existsSync26 } from "fs";
6861
6878
  import path25 from "path";
6862
6879
  import chalk87 from "chalk";
6863
6880
 
6864
6881
  // src/commands/dotnet/findSolution.ts
6865
6882
  import { readdirSync as readdirSync4 } from "fs";
6866
- import { dirname as dirname16, join as join23 } from "path";
6883
+ import { dirname as dirname16, join as join24 } from "path";
6867
6884
  import chalk86 from "chalk";
6868
6885
  function findSlnInDir(dir) {
6869
6886
  try {
6870
- 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));
6871
6888
  } catch {
6872
6889
  return [];
6873
6890
  }
@@ -6898,7 +6915,7 @@ function findSolution() {
6898
6915
  function resolveSolution(sln) {
6899
6916
  if (sln) {
6900
6917
  const resolved = path25.resolve(sln);
6901
- if (!existsSync25(resolved)) {
6918
+ if (!existsSync26(resolved)) {
6902
6919
  console.error(chalk87.red(`Solution file not found: ${resolved}`));
6903
6920
  process.exit(1);
6904
6921
  }
@@ -6938,7 +6955,7 @@ function parseInspectReport(json) {
6938
6955
 
6939
6956
  // src/commands/dotnet/runInspectCode.ts
6940
6957
  import { execSync as execSync24 } from "child_process";
6941
- 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";
6942
6959
  import { tmpdir as tmpdir2 } from "os";
6943
6960
  import path26 from "path";
6944
6961
  import chalk88 from "chalk";
@@ -6969,7 +6986,7 @@ function runInspectCode(slnPath, include, swea) {
6969
6986
  console.error(chalk88.red("jb inspectcode failed"));
6970
6987
  process.exit(1);
6971
6988
  }
6972
- if (!existsSync26(reportPath)) {
6989
+ if (!existsSync27(reportPath)) {
6973
6990
  console.error(chalk88.red("Report file not generated"));
6974
6991
  process.exit(1);
6975
6992
  }
@@ -7201,18 +7218,18 @@ function acceptanceCriteria(issueKey) {
7201
7218
  import { execSync as execSync27 } from "child_process";
7202
7219
 
7203
7220
  // src/shared/loadJson.ts
7204
- 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";
7205
7222
  import { homedir as homedir6 } from "os";
7206
- import { join as join24 } from "path";
7223
+ import { join as join25 } from "path";
7207
7224
  function getStoreDir() {
7208
- return join24(homedir6(), ".assist");
7225
+ return join25(homedir6(), ".assist");
7209
7226
  }
7210
7227
  function getStorePath(filename) {
7211
- return join24(getStoreDir(), filename);
7228
+ return join25(getStoreDir(), filename);
7212
7229
  }
7213
7230
  function loadJson(filename) {
7214
7231
  const path50 = getStorePath(filename);
7215
- if (existsSync27(path50)) {
7232
+ if (existsSync28(path50)) {
7216
7233
  try {
7217
7234
  return JSON.parse(readFileSync25(path50, "utf-8"));
7218
7235
  } catch {
@@ -7223,7 +7240,7 @@ function loadJson(filename) {
7223
7240
  }
7224
7241
  function saveJson(filename, data) {
7225
7242
  const dir = getStoreDir();
7226
- if (!existsSync27(dir)) {
7243
+ if (!existsSync28(dir)) {
7227
7244
  mkdirSync6(dir, { recursive: true });
7228
7245
  }
7229
7246
  writeFileSync20(getStorePath(filename), JSON.stringify(data, null, 2));
@@ -7540,7 +7557,7 @@ function registerNews(program2) {
7540
7557
  import { spawnSync as spawnSync2 } from "child_process";
7541
7558
  import { unlinkSync as unlinkSync6, writeFileSync as writeFileSync21 } from "fs";
7542
7559
  import { tmpdir as tmpdir3 } from "os";
7543
- import { join as join25 } from "path";
7560
+ import { join as join26 } from "path";
7544
7561
 
7545
7562
  // src/commands/prs/shared.ts
7546
7563
  import { execSync as execSync28 } from "child_process";
@@ -7612,7 +7629,7 @@ function comment2(path50, line, body) {
7612
7629
  validateLine(line);
7613
7630
  try {
7614
7631
  const prId = getCurrentPrNodeId();
7615
- const queryFile = join25(tmpdir3(), `gh-query-${Date.now()}.graphql`);
7632
+ const queryFile = join26(tmpdir3(), `gh-query-${Date.now()}.graphql`);
7616
7633
  writeFileSync21(queryFile, MUTATION);
7617
7634
  try {
7618
7635
  const result = spawnSync2(
@@ -7657,18 +7674,18 @@ import { execSync as execSync30 } from "child_process";
7657
7674
  import { execSync as execSync29 } from "child_process";
7658
7675
  import { unlinkSync as unlinkSync8, writeFileSync as writeFileSync22 } from "fs";
7659
7676
  import { tmpdir as tmpdir4 } from "os";
7660
- import { join as join27 } from "path";
7677
+ import { join as join28 } from "path";
7661
7678
 
7662
7679
  // src/commands/prs/loadCommentsCache.ts
7663
- import { existsSync as existsSync28, readFileSync as readFileSync26, unlinkSync as unlinkSync7 } from "fs";
7664
- 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";
7665
7682
  import { parse as parse2 } from "yaml";
7666
7683
  function getCachePath(prNumber) {
7667
- return join26(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`);
7684
+ return join27(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`);
7668
7685
  }
7669
7686
  function loadCommentsCache(prNumber) {
7670
7687
  const cachePath = getCachePath(prNumber);
7671
- if (!existsSync28(cachePath)) {
7688
+ if (!existsSync29(cachePath)) {
7672
7689
  return null;
7673
7690
  }
7674
7691
  const content = readFileSync26(cachePath, "utf-8");
@@ -7676,7 +7693,7 @@ function loadCommentsCache(prNumber) {
7676
7693
  }
7677
7694
  function deleteCommentsCache(prNumber) {
7678
7695
  const cachePath = getCachePath(prNumber);
7679
- if (existsSync28(cachePath)) {
7696
+ if (existsSync29(cachePath)) {
7680
7697
  unlinkSync7(cachePath);
7681
7698
  console.log("No more unresolved line comments. Cache dropped.");
7682
7699
  }
@@ -7691,7 +7708,7 @@ function replyToComment(org, repo, prNumber, commentId, message) {
7691
7708
  }
7692
7709
  function resolveThread(threadId) {
7693
7710
  const mutation = `mutation($threadId: ID!) { resolveReviewThread(input: {threadId: $threadId}) { thread { isResolved } } }`;
7694
- const queryFile = join27(tmpdir4(), `gh-mutation-${Date.now()}.graphql`);
7711
+ const queryFile = join28(tmpdir4(), `gh-mutation-${Date.now()}.graphql`);
7695
7712
  writeFileSync22(queryFile, mutation);
7696
7713
  try {
7697
7714
  execSync29(
@@ -7773,18 +7790,18 @@ function fixed(commentId, sha) {
7773
7790
  }
7774
7791
 
7775
7792
  // src/commands/prs/listComments/index.ts
7776
- import { existsSync as existsSync29, mkdirSync as mkdirSync7, writeFileSync as writeFileSync24 } from "fs";
7777
- 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";
7778
7795
  import { stringify } from "yaml";
7779
7796
 
7780
7797
  // src/commands/prs/fetchThreadIds.ts
7781
7798
  import { execSync as execSync31 } from "child_process";
7782
7799
  import { unlinkSync as unlinkSync9, writeFileSync as writeFileSync23 } from "fs";
7783
7800
  import { tmpdir as tmpdir5 } from "os";
7784
- import { join as join28 } from "path";
7801
+ import { join as join29 } from "path";
7785
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 } } } } } } }`;
7786
7803
  function fetchThreadIds(org, repo, prNumber) {
7787
- const queryFile = join28(tmpdir5(), `gh-query-${Date.now()}.graphql`);
7804
+ const queryFile = join29(tmpdir5(), `gh-query-${Date.now()}.graphql`);
7788
7805
  writeFileSync23(queryFile, THREAD_QUERY);
7789
7806
  try {
7790
7807
  const result = execSync31(
@@ -7898,8 +7915,8 @@ function printComments2(result) {
7898
7915
 
7899
7916
  // src/commands/prs/listComments/index.ts
7900
7917
  function writeCommentsCache(prNumber, comments2) {
7901
- const assistDir = join29(process.cwd(), ".assist");
7902
- if (!existsSync29(assistDir)) {
7918
+ const assistDir = join30(process.cwd(), ".assist");
7919
+ if (!existsSync30(assistDir)) {
7903
7920
  mkdirSync7(assistDir, { recursive: true });
7904
7921
  }
7905
7922
  const cacheData = {
@@ -7907,7 +7924,7 @@ function writeCommentsCache(prNumber, comments2) {
7907
7924
  fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
7908
7925
  comments: comments2
7909
7926
  };
7910
- const cachePath = join29(assistDir, `pr-${prNumber}-comments.yaml`);
7927
+ const cachePath = join30(assistDir, `pr-${prNumber}-comments.yaml`);
7911
7928
  writeFileSync24(cachePath, stringify(cacheData));
7912
7929
  }
7913
7930
  function handleKnownErrors(error) {
@@ -7940,7 +7957,7 @@ async function listComments() {
7940
7957
  ];
7941
7958
  updateCache(prNumber, allComments);
7942
7959
  const hasLineComments = allComments.some((c) => c.type === "line");
7943
- 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;
7944
7961
  return { comments: allComments, cachePath };
7945
7962
  } catch (error) {
7946
7963
  const handled = handleKnownErrors(error);
@@ -8710,7 +8727,7 @@ function getViolations(pattern2, options2 = {}, maxLines = DEFAULT_MAX_LINES) {
8710
8727
 
8711
8728
  // src/commands/refactor/check/index.ts
8712
8729
  function runScript(script, cwd) {
8713
- return new Promise((resolve7) => {
8730
+ return new Promise((resolve8) => {
8714
8731
  const child = spawn4("npm", ["run", script], {
8715
8732
  stdio: "pipe",
8716
8733
  shell: true,
@@ -8724,7 +8741,7 @@ function runScript(script, cwd) {
8724
8741
  output += data.toString();
8725
8742
  });
8726
8743
  child.on("close", (code) => {
8727
- resolve7({ script, code: code ?? 1, output });
8744
+ resolve8({ script, code: code ?? 1, output });
8728
8745
  });
8729
8746
  });
8730
8747
  }
@@ -10334,8 +10351,8 @@ function registerSeq(program2) {
10334
10351
  }
10335
10352
 
10336
10353
  // src/commands/transcript/shared.ts
10337
- import { existsSync as existsSync30, readdirSync as readdirSync5, statSync as statSync4 } from "fs";
10338
- 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";
10339
10356
  import * as readline2 from "readline";
10340
10357
  var DATE_PREFIX_REGEX = /^\d{4}-\d{2}-\d{2}/;
10341
10358
  function getDatePrefix(daysOffset = 0) {
@@ -10350,10 +10367,10 @@ function isValidDatePrefix(filename) {
10350
10367
  return DATE_PREFIX_REGEX.test(filename);
10351
10368
  }
10352
10369
  function collectFiles(dir, extension) {
10353
- if (!existsSync30(dir)) return [];
10370
+ if (!existsSync31(dir)) return [];
10354
10371
  const results = [];
10355
10372
  for (const entry of readdirSync5(dir)) {
10356
- const fullPath = join30(dir, entry);
10373
+ const fullPath = join31(dir, entry);
10357
10374
  if (statSync4(fullPath).isDirectory()) {
10358
10375
  results.push(...collectFiles(fullPath, extension));
10359
10376
  } else if (entry.endsWith(extension)) {
@@ -10385,9 +10402,9 @@ function createReadlineInterface() {
10385
10402
  });
10386
10403
  }
10387
10404
  function askQuestion(rl, question) {
10388
- return new Promise((resolve7) => {
10405
+ return new Promise((resolve8) => {
10389
10406
  rl.question(question, (answer) => {
10390
- resolve7(answer.trim());
10407
+ resolve8(answer.trim());
10391
10408
  });
10392
10409
  });
10393
10410
  }
@@ -10447,14 +10464,14 @@ async function configure() {
10447
10464
  }
10448
10465
 
10449
10466
  // src/commands/transcript/format/index.ts
10450
- import { existsSync as existsSync32 } from "fs";
10467
+ import { existsSync as existsSync33 } from "fs";
10451
10468
 
10452
10469
  // src/commands/transcript/format/fixInvalidDatePrefixes/index.ts
10453
- import { dirname as dirname18, join as join32 } from "path";
10470
+ import { dirname as dirname18, join as join33 } from "path";
10454
10471
 
10455
10472
  // src/commands/transcript/format/fixInvalidDatePrefixes/promptForDateFix.ts
10456
10473
  import { renameSync as renameSync2 } from "fs";
10457
- import { join as join31 } from "path";
10474
+ import { join as join32 } from "path";
10458
10475
  async function resolveDate(rl, choice) {
10459
10476
  if (choice === "1") return getDatePrefix(0);
10460
10477
  if (choice === "2") return getDatePrefix(-1);
@@ -10469,7 +10486,7 @@ async function resolveDate(rl, choice) {
10469
10486
  }
10470
10487
  function renameWithPrefix(vttDir, vttFile, prefix2) {
10471
10488
  const newFilename = `${prefix2}.${vttFile}`;
10472
- renameSync2(join31(vttDir, vttFile), join31(vttDir, newFilename));
10489
+ renameSync2(join32(vttDir, vttFile), join32(vttDir, newFilename));
10473
10490
  console.log(`Renamed to: ${newFilename}`);
10474
10491
  return newFilename;
10475
10492
  }
@@ -10503,12 +10520,12 @@ async function fixInvalidDatePrefixes(vttFiles) {
10503
10520
  const vttFileDir = dirname18(vttFile.absolutePath);
10504
10521
  const newFilename = await promptForDateFix(vttFile.filename, vttFileDir);
10505
10522
  if (newFilename) {
10506
- const newRelativePath = join32(
10523
+ const newRelativePath = join33(
10507
10524
  dirname18(vttFile.relativePath),
10508
10525
  newFilename
10509
10526
  );
10510
10527
  vttFiles[i] = {
10511
- absolutePath: join32(vttFileDir, newFilename),
10528
+ absolutePath: join33(vttFileDir, newFilename),
10512
10529
  relativePath: newRelativePath,
10513
10530
  filename: newFilename
10514
10531
  };
@@ -10521,8 +10538,8 @@ async function fixInvalidDatePrefixes(vttFiles) {
10521
10538
  }
10522
10539
 
10523
10540
  // src/commands/transcript/format/processVttFile/index.ts
10524
- import { existsSync as existsSync31, mkdirSync as mkdirSync8, readFileSync as readFileSync27, writeFileSync as writeFileSync25 } from "fs";
10525
- 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";
10526
10543
 
10527
10544
  // src/commands/transcript/cleanText.ts
10528
10545
  function cleanText(text) {
@@ -10732,21 +10749,21 @@ function toMdFilename(vttFilename) {
10732
10749
  return `${basename5(vttFilename, ".vtt").replace(/\s*Transcription\s*/g, " ").trim()}.md`;
10733
10750
  }
10734
10751
  function resolveOutputDir(relativeDir, transcriptsDir) {
10735
- return relativeDir === "." ? transcriptsDir : join33(transcriptsDir, relativeDir);
10752
+ return relativeDir === "." ? transcriptsDir : join34(transcriptsDir, relativeDir);
10736
10753
  }
10737
10754
  function buildOutputPaths(vttFile, transcriptsDir) {
10738
10755
  const mdFile = toMdFilename(vttFile.filename);
10739
10756
  const relativeDir = dirname19(vttFile.relativePath);
10740
10757
  const outputDir = resolveOutputDir(relativeDir, transcriptsDir);
10741
- const outputPath = join33(outputDir, mdFile);
10758
+ const outputPath = join34(outputDir, mdFile);
10742
10759
  return { outputDir, outputPath, mdFile, relativeDir };
10743
10760
  }
10744
10761
  function logSkipped(relativeDir, mdFile) {
10745
- console.log(`Skipping (already exists): ${join33(relativeDir, mdFile)}`);
10762
+ console.log(`Skipping (already exists): ${join34(relativeDir, mdFile)}`);
10746
10763
  return "skipped";
10747
10764
  }
10748
10765
  function ensureDirectory(dir, label2) {
10749
- if (!existsSync31(dir)) {
10766
+ if (!existsSync32(dir)) {
10750
10767
  mkdirSync8(dir, { recursive: true });
10751
10768
  console.log(`Created ${label2}: ${dir}`);
10752
10769
  }
@@ -10782,7 +10799,7 @@ function convertVttToMarkdown(inputPath, outputPath) {
10782
10799
  logReduction(cues.length, chatMessages.length);
10783
10800
  }
10784
10801
  function tryProcessVtt(vttFile, paths) {
10785
- if (existsSync31(paths.outputPath))
10802
+ if (existsSync32(paths.outputPath))
10786
10803
  return logSkipped(paths.relativeDir, paths.mdFile);
10787
10804
  convertVttToMarkdown(vttFile.absolutePath, paths.outputPath);
10788
10805
  return "processed";
@@ -10808,7 +10825,7 @@ function processAllFiles(vttFiles, transcriptsDir) {
10808
10825
  logSummary(counts);
10809
10826
  }
10810
10827
  function requireVttDir(vttDir) {
10811
- if (!existsSync32(vttDir)) {
10828
+ if (!existsSync33(vttDir)) {
10812
10829
  console.error(`VTT directory not found: ${vttDir}`);
10813
10830
  process.exit(1);
10814
10831
  }
@@ -10840,18 +10857,18 @@ async function format() {
10840
10857
  }
10841
10858
 
10842
10859
  // src/commands/transcript/summarise/index.ts
10843
- import { existsSync as existsSync34 } from "fs";
10844
- 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";
10845
10862
 
10846
10863
  // src/commands/transcript/summarise/processStagedFile/index.ts
10847
10864
  import {
10848
- existsSync as existsSync33,
10865
+ existsSync as existsSync34,
10849
10866
  mkdirSync as mkdirSync9,
10850
10867
  readFileSync as readFileSync28,
10851
10868
  renameSync as renameSync3,
10852
10869
  rmSync
10853
10870
  } from "fs";
10854
- import { dirname as dirname20, join as join34 } from "path";
10871
+ import { dirname as dirname20, join as join35 } from "path";
10855
10872
 
10856
10873
  // src/commands/transcript/summarise/processStagedFile/validateStagedContent.ts
10857
10874
  import chalk127 from "chalk";
@@ -10880,9 +10897,9 @@ function validateStagedContent(filename, content) {
10880
10897
  }
10881
10898
 
10882
10899
  // src/commands/transcript/summarise/processStagedFile/index.ts
10883
- var STAGING_DIR = join34(process.cwd(), ".assist", "transcript");
10900
+ var STAGING_DIR = join35(process.cwd(), ".assist", "transcript");
10884
10901
  function processStagedFile() {
10885
- if (!existsSync33(STAGING_DIR)) {
10902
+ if (!existsSync34(STAGING_DIR)) {
10886
10903
  return false;
10887
10904
  }
10888
10905
  const stagedFiles = findMdFilesRecursive(STAGING_DIR);
@@ -10904,9 +10921,9 @@ function processStagedFile() {
10904
10921
  );
10905
10922
  process.exit(1);
10906
10923
  }
10907
- const destPath = join34(summaryDir, matchingTranscript.relativePath);
10924
+ const destPath = join35(summaryDir, matchingTranscript.relativePath);
10908
10925
  const destDir = dirname20(destPath);
10909
- if (!existsSync33(destDir)) {
10926
+ if (!existsSync34(destDir)) {
10910
10927
  mkdirSync9(destDir, { recursive: true });
10911
10928
  }
10912
10929
  renameSync3(stagedFile.absolutePath, destPath);
@@ -10920,7 +10937,7 @@ function processStagedFile() {
10920
10937
  // src/commands/transcript/summarise/index.ts
10921
10938
  function buildRelativeKey(relativePath, baseName) {
10922
10939
  const relDir = dirname21(relativePath);
10923
- return relDir === "." ? baseName : join35(relDir, baseName);
10940
+ return relDir === "." ? baseName : join36(relDir, baseName);
10924
10941
  }
10925
10942
  function buildSummaryIndex(summaryDir) {
10926
10943
  const summaryFiles = findMdFilesRecursive(summaryDir);
@@ -10933,7 +10950,7 @@ function buildSummaryIndex(summaryDir) {
10933
10950
  function summarise2() {
10934
10951
  processStagedFile();
10935
10952
  const { transcriptsDir, summaryDir } = getTranscriptConfig();
10936
- if (!existsSync34(transcriptsDir)) {
10953
+ if (!existsSync35(transcriptsDir)) {
10937
10954
  console.log("No transcripts directory found.");
10938
10955
  return;
10939
10956
  }
@@ -10954,8 +10971,8 @@ function summarise2() {
10954
10971
  }
10955
10972
  const next3 = missing[0];
10956
10973
  const outputFilename = `${getTranscriptBaseName(next3.filename)}.md`;
10957
- const outputPath = join35(STAGING_DIR, outputFilename);
10958
- const summaryFileDir = join35(summaryDir, dirname21(next3.relativePath));
10974
+ const outputPath = join36(STAGING_DIR, outputFilename);
10975
+ const summaryFileDir = join36(summaryDir, dirname21(next3.relativePath));
10959
10976
  const relativeTranscriptPath = encodeURI(
10960
10977
  relative2(summaryFileDir, next3.absolutePath).replace(/\\/g, "/")
10961
10978
  );
@@ -11001,45 +11018,45 @@ function registerVerify(program2) {
11001
11018
 
11002
11019
  // src/commands/voice/devices.ts
11003
11020
  import { spawnSync as spawnSync3 } from "child_process";
11004
- import { join as join37 } from "path";
11021
+ import { join as join38 } from "path";
11005
11022
 
11006
11023
  // src/commands/voice/shared.ts
11007
11024
  import { homedir as homedir7 } from "os";
11008
- import { dirname as dirname22, join as join36 } from "path";
11025
+ import { dirname as dirname22, join as join37 } from "path";
11009
11026
  import { fileURLToPath as fileURLToPath6 } from "url";
11010
11027
  var __dirname6 = dirname22(fileURLToPath6(import.meta.url));
11011
- var VOICE_DIR = join36(homedir7(), ".assist", "voice");
11028
+ var VOICE_DIR = join37(homedir7(), ".assist", "voice");
11012
11029
  var voicePaths = {
11013
11030
  dir: VOICE_DIR,
11014
- pid: join36(VOICE_DIR, "voice.pid"),
11015
- log: join36(VOICE_DIR, "voice.log"),
11016
- venv: join36(VOICE_DIR, ".venv"),
11017
- 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")
11018
11035
  };
11019
11036
  function getPythonDir() {
11020
- return join36(__dirname6, "commands", "voice", "python");
11037
+ return join37(__dirname6, "commands", "voice", "python");
11021
11038
  }
11022
11039
  function getVenvPython() {
11023
- 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");
11024
11041
  }
11025
11042
  function getLockDir() {
11026
11043
  const config = loadConfig();
11027
11044
  return config.voice?.lockDir ?? VOICE_DIR;
11028
11045
  }
11029
11046
  function getLockFile() {
11030
- return join36(getLockDir(), "voice.lock");
11047
+ return join37(getLockDir(), "voice.lock");
11031
11048
  }
11032
11049
 
11033
11050
  // src/commands/voice/devices.ts
11034
11051
  function devices() {
11035
- const script = join37(getPythonDir(), "list_devices.py");
11052
+ const script = join38(getPythonDir(), "list_devices.py");
11036
11053
  spawnSync3(getVenvPython(), [script], { stdio: "inherit" });
11037
11054
  }
11038
11055
 
11039
11056
  // src/commands/voice/logs.ts
11040
- import { existsSync as existsSync35, readFileSync as readFileSync29 } from "fs";
11057
+ import { existsSync as existsSync36, readFileSync as readFileSync29 } from "fs";
11041
11058
  function logs(options2) {
11042
- if (!existsSync35(voicePaths.log)) {
11059
+ if (!existsSync36(voicePaths.log)) {
11043
11060
  console.log("No voice log file found");
11044
11061
  return;
11045
11062
  }
@@ -11067,12 +11084,12 @@ function logs(options2) {
11067
11084
  // src/commands/voice/setup.ts
11068
11085
  import { spawnSync as spawnSync4 } from "child_process";
11069
11086
  import { mkdirSync as mkdirSync11 } from "fs";
11070
- import { join as join39 } from "path";
11087
+ import { join as join40 } from "path";
11071
11088
 
11072
11089
  // src/commands/voice/checkLockFile.ts
11073
11090
  import { execSync as execSync38 } from "child_process";
11074
- import { existsSync as existsSync36, mkdirSync as mkdirSync10, readFileSync as readFileSync30, writeFileSync as writeFileSync26 } from "fs";
11075
- 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";
11076
11093
  function isProcessAlive2(pid) {
11077
11094
  try {
11078
11095
  process.kill(pid, 0);
@@ -11083,7 +11100,7 @@ function isProcessAlive2(pid) {
11083
11100
  }
11084
11101
  function checkLockFile() {
11085
11102
  const lockFile = getLockFile();
11086
- if (!existsSync36(lockFile)) return;
11103
+ if (!existsSync37(lockFile)) return;
11087
11104
  try {
11088
11105
  const lock = JSON.parse(readFileSync30(lockFile, "utf-8"));
11089
11106
  if (lock.pid && isProcessAlive2(lock.pid)) {
@@ -11096,7 +11113,7 @@ function checkLockFile() {
11096
11113
  }
11097
11114
  }
11098
11115
  function bootstrapVenv() {
11099
- if (existsSync36(getVenvPython())) return;
11116
+ if (existsSync37(getVenvPython())) return;
11100
11117
  console.log("Setting up Python environment...");
11101
11118
  const pythonDir = getPythonDir();
11102
11119
  execSync38(
@@ -11109,7 +11126,7 @@ function bootstrapVenv() {
11109
11126
  }
11110
11127
  function writeLockFile(pid) {
11111
11128
  const lockFile = getLockFile();
11112
- mkdirSync10(join38(lockFile, ".."), { recursive: true });
11129
+ mkdirSync10(join39(lockFile, ".."), { recursive: true });
11113
11130
  writeFileSync26(
11114
11131
  lockFile,
11115
11132
  JSON.stringify({
@@ -11125,7 +11142,7 @@ function setup() {
11125
11142
  mkdirSync11(voicePaths.dir, { recursive: true });
11126
11143
  bootstrapVenv();
11127
11144
  console.log("\nDownloading models...\n");
11128
- const script = join39(getPythonDir(), "setup_models.py");
11145
+ const script = join40(getPythonDir(), "setup_models.py");
11129
11146
  const result = spawnSync4(getVenvPython(), [script], {
11130
11147
  stdio: "inherit",
11131
11148
  env: { ...process.env, VOICE_LOG_FILE: voicePaths.log }
@@ -11139,7 +11156,7 @@ function setup() {
11139
11156
  // src/commands/voice/start.ts
11140
11157
  import { spawn as spawn5 } from "child_process";
11141
11158
  import { mkdirSync as mkdirSync12, writeFileSync as writeFileSync27 } from "fs";
11142
- import { join as join40 } from "path";
11159
+ import { join as join41 } from "path";
11143
11160
 
11144
11161
  // src/commands/voice/buildDaemonEnv.ts
11145
11162
  function buildDaemonEnv(options2) {
@@ -11177,7 +11194,7 @@ function start2(options2) {
11177
11194
  bootstrapVenv();
11178
11195
  const debug = options2.debug || options2.foreground || process.platform === "win32";
11179
11196
  const env = buildDaemonEnv({ debug });
11180
- const script = join40(getPythonDir(), "voice_daemon.py");
11197
+ const script = join41(getPythonDir(), "voice_daemon.py");
11181
11198
  const python = getVenvPython();
11182
11199
  if (options2.foreground) {
11183
11200
  spawnForeground(python, script, env);
@@ -11187,7 +11204,7 @@ function start2(options2) {
11187
11204
  }
11188
11205
 
11189
11206
  // src/commands/voice/status.ts
11190
- import { existsSync as existsSync37, readFileSync as readFileSync31 } from "fs";
11207
+ import { existsSync as existsSync38, readFileSync as readFileSync31 } from "fs";
11191
11208
  function isProcessAlive3(pid) {
11192
11209
  try {
11193
11210
  process.kill(pid, 0);
@@ -11197,12 +11214,12 @@ function isProcessAlive3(pid) {
11197
11214
  }
11198
11215
  }
11199
11216
  function readRecentLogs(count) {
11200
- if (!existsSync37(voicePaths.log)) return [];
11217
+ if (!existsSync38(voicePaths.log)) return [];
11201
11218
  const lines = readFileSync31(voicePaths.log, "utf-8").trim().split("\n");
11202
11219
  return lines.slice(-count);
11203
11220
  }
11204
11221
  function status() {
11205
- if (!existsSync37(voicePaths.pid)) {
11222
+ if (!existsSync38(voicePaths.pid)) {
11206
11223
  console.log("Voice daemon: not running (no PID file)");
11207
11224
  return;
11208
11225
  }
@@ -11225,9 +11242,9 @@ function status() {
11225
11242
  }
11226
11243
 
11227
11244
  // src/commands/voice/stop.ts
11228
- 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";
11229
11246
  function stop() {
11230
- if (!existsSync38(voicePaths.pid)) {
11247
+ if (!existsSync39(voicePaths.pid)) {
11231
11248
  console.log("Voice daemon is not running (no PID file)");
11232
11249
  return;
11233
11250
  }
@@ -11244,7 +11261,7 @@ function stop() {
11244
11261
  }
11245
11262
  try {
11246
11263
  const lockFile = getLockFile();
11247
- if (existsSync38(lockFile)) unlinkSync10(lockFile);
11264
+ if (existsSync39(lockFile)) unlinkSync10(lockFile);
11248
11265
  } catch {
11249
11266
  }
11250
11267
  console.log("Voice daemon stopped");
@@ -11328,7 +11345,7 @@ function extractCode(url, expectedState) {
11328
11345
  return code;
11329
11346
  }
11330
11347
  function waitForCallback(port, expectedState) {
11331
- return new Promise((resolve7, reject) => {
11348
+ return new Promise((resolve8, reject) => {
11332
11349
  const timeout = setTimeout(() => {
11333
11350
  server.close();
11334
11351
  reject(new Error("Authorization timed out after 120 seconds"));
@@ -11345,7 +11362,7 @@ function waitForCallback(port, expectedState) {
11345
11362
  const code = extractCode(url, expectedState);
11346
11363
  respondHtml(res, 200, "Authorization successful!");
11347
11364
  server.close();
11348
- resolve7(code);
11365
+ resolve8(code);
11349
11366
  } catch (err) {
11350
11367
  respondHtml(res, 400, err.message);
11351
11368
  server.close();
@@ -11466,11 +11483,11 @@ async function auth() {
11466
11483
 
11467
11484
  // src/commands/roam/showClaudeCodeIcon.ts
11468
11485
  import { readFileSync as readFileSync33 } from "fs";
11469
- import { join as join41 } from "path";
11486
+ import { join as join42 } from "path";
11470
11487
  async function showClaudeCodeIcon() {
11471
11488
  const appData = process.env.APPDATA;
11472
11489
  if (!appData) return;
11473
- const portFile = join41(appData, "Roam", "roam-local-api.port");
11490
+ const portFile = join42(appData, "Roam", "roam-local-api.port");
11474
11491
  let port;
11475
11492
  try {
11476
11493
  port = readFileSync33(portFile, "utf-8").trim();
@@ -11496,7 +11513,7 @@ function registerRoam(program2) {
11496
11513
  }
11497
11514
 
11498
11515
  // src/commands/run/index.ts
11499
- import { execSync as execSync40 } from "child_process";
11516
+ import { resolve as resolve5 } from "path";
11500
11517
 
11501
11518
  // src/commands/run/formatConfiguredCommands.ts
11502
11519
  function formatConfiguredCommands() {
@@ -11532,14 +11549,28 @@ function resolveParams(params, cliArgs) {
11532
11549
  return resolved;
11533
11550
  }
11534
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
+
11535
11565
  // src/commands/run/spawnRunCommand.ts
11536
11566
  import { spawn as spawn6 } from "child_process";
11537
- function spawnRunCommand(fullCommand, env) {
11567
+ function spawnRunCommand(fullCommand, env, cwd) {
11538
11568
  const start3 = Date.now();
11539
11569
  const child = spawn6(fullCommand, [], {
11540
11570
  stdio: "inherit",
11541
11571
  shell: true,
11542
- env: env ? { ...process.env, ...expandEnv(env) } : void 0
11572
+ env: env ? { ...process.env, ...expandEnv(env) } : void 0,
11573
+ cwd
11543
11574
  });
11544
11575
  child.on("close", (code) => {
11545
11576
  const elapsed = formatElapsed(Date.now() - start3);
@@ -11555,17 +11586,28 @@ Done in ${elapsed}`);
11555
11586
 
11556
11587
  // src/commands/run/add.ts
11557
11588
  import { mkdirSync as mkdirSync13, writeFileSync as writeFileSync28 } from "fs";
11558
- import { join as join42 } from "path";
11589
+ import { join as join43 } from "path";
11559
11590
  function findAddIndex() {
11560
11591
  const addIndex = process.argv.indexOf("add");
11561
11592
  if (addIndex === -1 || addIndex + 2 >= process.argv.length) return -1;
11562
11593
  return addIndex;
11563
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
+ }
11564
11603
  function extractAddArgs(addIndex) {
11604
+ const rawArgs = process.argv.slice(addIndex + 3);
11605
+ const { value: cwd, remaining: args } = extractOption(rawArgs, "--cwd");
11565
11606
  return {
11566
11607
  name: process.argv[addIndex + 1],
11567
11608
  command: process.argv[addIndex + 2],
11568
- args: process.argv.slice(addIndex + 3)
11609
+ args,
11610
+ cwd
11569
11611
  };
11570
11612
  }
11571
11613
  function parseAddArguments() {
@@ -11594,14 +11636,14 @@ function getOrInitRunList() {
11594
11636
  if (!config.run) config.run = [];
11595
11637
  return { config, runList: config.run };
11596
11638
  }
11597
- function saveNewRunConfig(name, command, args) {
11639
+ function saveNewRunConfig(name, command, args, cwd) {
11598
11640
  const { config, runList } = getOrInitRunList();
11599
11641
  ensureNoDuplicate(runList, name);
11600
- runList.push(buildRunEntry(name, command, args));
11642
+ runList.push(buildRunEntry(name, command, args, { cwd }));
11601
11643
  saveConfig(config);
11602
11644
  }
11603
11645
  function createCommandFile(name) {
11604
- const dir = join42(".claude", "commands");
11646
+ const dir = join43(".claude", "commands");
11605
11647
  mkdirSync13(dir, { recursive: true });
11606
11648
  const content = `---
11607
11649
  description: Run ${name}
@@ -11609,13 +11651,13 @@ description: Run ${name}
11609
11651
 
11610
11652
  Run \`assist run ${name} $ARGUMENTS 2>&1\`.
11611
11653
  `;
11612
- const filePath = join42(dir, `${name}.md`);
11654
+ const filePath = join43(dir, `${name}.md`);
11613
11655
  writeFileSync28(filePath, content);
11614
11656
  console.log(`Created command file: ${filePath}`);
11615
11657
  }
11616
11658
  function add3() {
11617
- const { name, command, args } = requireParsedArgs();
11618
- saveNewRunConfig(name, command, args);
11659
+ const { name, command, args, cwd } = requireParsedArgs();
11660
+ saveNewRunConfig(name, command, args, cwd);
11619
11661
  createCommandFile(name);
11620
11662
  console.log(
11621
11663
  `Added run configuration: ${name} -> ${formatDisplay(command, args)}`
@@ -11658,16 +11700,6 @@ function listRunConfigs() {
11658
11700
  console.log(`${config.name}: ${config.command}${args}`);
11659
11701
  }
11660
11702
  }
11661
- function runPreCommands(pre) {
11662
- for (const cmd of pre) {
11663
- try {
11664
- execSync40(cmd, { stdio: "inherit" });
11665
- } catch (err) {
11666
- const code = err && typeof err === "object" && "status" in err ? err.status : 1;
11667
- process.exit(code);
11668
- }
11669
- }
11670
- }
11671
11703
  function run3(name, args) {
11672
11704
  if (!name) {
11673
11705
  console.error("error: missing required argument 'name'");
@@ -11675,19 +11707,21 @@ function run3(name, args) {
11675
11707
  process.exit(1);
11676
11708
  }
11677
11709
  const runConfig = findRunConfig(name);
11678
- 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);
11679
11712
  const resolved = resolveParams(runConfig.params, args);
11680
11713
  spawnRunCommand(
11681
11714
  buildCommand(runConfig.command, runConfig.args ?? [], resolved),
11682
- runConfig.env
11715
+ runConfig.env,
11716
+ resolvedCwd
11683
11717
  );
11684
11718
  }
11685
11719
 
11686
11720
  // src/commands/screenshot/index.ts
11687
11721
  import { execSync as execSync41 } from "child_process";
11688
- 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";
11689
11723
  import { tmpdir as tmpdir6 } from "os";
11690
- import { join as join43, resolve as resolve5 } from "path";
11724
+ import { join as join44, resolve as resolve6 } from "path";
11691
11725
  import chalk129 from "chalk";
11692
11726
 
11693
11727
  // src/commands/screenshot/captureWindowPs1.ts
@@ -11817,14 +11851,14 @@ Write-Output $OutputPath
11817
11851
 
11818
11852
  // src/commands/screenshot/index.ts
11819
11853
  function buildOutputPath(outputDir, processName) {
11820
- if (!existsSync39(outputDir)) {
11854
+ if (!existsSync40(outputDir)) {
11821
11855
  mkdirSync14(outputDir, { recursive: true });
11822
11856
  }
11823
11857
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
11824
- return resolve5(outputDir, `${processName}-${timestamp}.png`);
11858
+ return resolve6(outputDir, `${processName}-${timestamp}.png`);
11825
11859
  }
11826
11860
  function runPowerShellScript(processName, outputPath) {
11827
- const scriptPath = join43(tmpdir6(), `assist-screenshot-${Date.now()}.ps1`);
11861
+ const scriptPath = join44(tmpdir6(), `assist-screenshot-${Date.now()}.ps1`);
11828
11862
  writeFileSync29(scriptPath, captureWindowPs1, "utf-8");
11829
11863
  try {
11830
11864
  execSync41(
@@ -11837,7 +11871,7 @@ function runPowerShellScript(processName, outputPath) {
11837
11871
  }
11838
11872
  function screenshot(processName) {
11839
11873
  const config = loadConfig();
11840
- const outputDir = resolve5(config.screenshot.outputDir);
11874
+ const outputDir = resolve6(config.screenshot.outputDir);
11841
11875
  const outputPath = buildOutputPath(outputDir, processName);
11842
11876
  console.log(chalk129.gray(`Capturing window for process "${processName}" ...`));
11843
11877
  try {
@@ -12076,7 +12110,10 @@ program.command("commit").description("Create a git commit with validation").arg
12076
12110
  registerConfig(program);
12077
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));
12078
12112
  runCommand.command("list").description("List configured run commands").action(listRunConfigs);
12079
- 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(
12080
12117
  "after",
12081
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'
12082
12119
  ).allowUnknownOption().allowExcessArguments().action(() => add3());
@@ -12109,6 +12146,7 @@ registerRavendb(program);
12109
12146
  registerSeq(program);
12110
12147
  registerTranscript(program);
12111
12148
  registerVoice(program);
12149
+ registerDeny(program);
12112
12150
  program.command("next").description("Alias for backlog next -w").action(() => next({ allowEdits: true }));
12113
12151
  program.command("draft").alias("feat").description("Launch Claude in /draft mode, chain into next on /next signal").action(() => launchMode("draft"));
12114
12152
  program.command("bug").description("Launch Claude in /bug mode, chain into next on /next signal").action(() => launchMode("bug"));