@staff0rd/assist 0.607.0 → 0.609.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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.607.0",
9
+ version: "0.609.0",
10
10
  type: "module",
11
11
  main: "dist/index.js",
12
12
  bin: {
@@ -547,6 +547,9 @@ var assistConfigShape = {
547
547
  refreshToken: secretConfigValue(z3.string()).optional(),
548
548
  tokenExpiresAt: z3.number().optional()
549
549
  }).optional(),
550
+ slack: z3.strictObject({
551
+ channel: z3.string().optional()
552
+ }).optional(),
550
553
  prs: z3.strictObject({
551
554
  slack: z3.string().optional(),
552
555
  required: z3.boolean().default(false),
@@ -4761,6 +4764,15 @@ var sessionsConfigHelp = [
4761
4764
  }
4762
4765
  ];
4763
4766
 
4767
+ // src/commands/slack/slackConfigHelp.ts
4768
+ var slackConfigHelp = [
4769
+ {
4770
+ key: "slack.channel",
4771
+ setter: 'assist config set slack.channel "#general"',
4772
+ note: "channel 'assist slack post' targets when no [channel] argument is given"
4773
+ }
4774
+ ];
4775
+
4764
4776
  // src/commands/sql/sqlConfigHelp.ts
4765
4777
  var sqlConfigHelp = [
4766
4778
  {
@@ -4880,6 +4892,7 @@ var configHelpEntries = [
4880
4892
  ...runConfigHelp,
4881
4893
  ...seqConfigHelp,
4882
4894
  ...sessionsConfigHelp,
4895
+ ...slackConfigHelp,
4883
4896
  ...sqlConfigHelp,
4884
4897
  ...transcriptConfigHelp,
4885
4898
  ...verifyConfigHelp,
@@ -31100,6 +31113,114 @@ function registerSignal(program2) {
31100
31113
  });
31101
31114
  }
31102
31115
 
31116
+ // src/commands/slack/parseSlackThreadRef.ts
31117
+ import { InvalidArgumentError as InvalidArgumentError3 } from "commander";
31118
+ var MESSAGE_TS = /^\d{10}\.\d{6}$/;
31119
+ var PERMALINK_TS = /\/archives\/[^/?#]+\/p(\d{10})(\d{6})\b/;
31120
+ var PERMALINK_THREAD_TS = /[?&]thread_ts=(\d{10}\.\d{6})\b/;
31121
+ function parseSlackThreadRef(value) {
31122
+ const trimmed = value.trim();
31123
+ if (MESSAGE_TS.test(trimmed)) return trimmed;
31124
+ const thread = PERMALINK_THREAD_TS.exec(trimmed);
31125
+ if (thread) return thread[1];
31126
+ const permalink = PERMALINK_TS.exec(trimmed);
31127
+ if (permalink) return `${permalink[1]}.${permalink[2]}`;
31128
+ throw new InvalidArgumentError3(
31129
+ "Expected a message ts (1712345678.123456) or a Slack archives permalink (https://<workspace>.slack.com/archives/<channel>/p1712345678123456)."
31130
+ );
31131
+ }
31132
+
31133
+ // src/commands/slack/postSlackMessage.ts
31134
+ import { mkdirSync as mkdirSync22, writeFileSync as writeFileSync42 } from "fs";
31135
+
31136
+ // src/commands/slack/reviewProposedSlackMessage.ts
31137
+ import { randomUUID as randomUUID17 } from "crypto";
31138
+ async function reviewProposedSlackMessage(target, body, working) {
31139
+ const sessionId = process.env.ASSIST_SESSION_ID;
31140
+ if (process.env.ASSIST_SESSION !== "1" || !sessionId) return body;
31141
+ const { channel, threadTs } = target;
31142
+ const decision = await awaitPreviewApproval(
31143
+ "Slack message preview",
31144
+ {
31145
+ sessionId,
31146
+ requestId: randomUUID17(),
31147
+ title: threadTs ? `Reply in ${channel} thread ${threadTs}` : `Post to ${channel}`,
31148
+ body,
31149
+ prNumber: null,
31150
+ kind: "slack-post"
31151
+ },
31152
+ {
31153
+ saveEditedBody: working.save,
31154
+ rejectionAdvice: `Nothing was posted to ${channel}. The previewed markdown is at ${working.path}: revise that file in place and re-run this command to preview the revision.`
31155
+ }
31156
+ );
31157
+ return decision.body ?? body;
31158
+ }
31159
+
31160
+ // src/commands/slack/slackWorkingFile.ts
31161
+ import { join as join73 } from "path";
31162
+ function slackWorkingFile(channel) {
31163
+ const slug = channel.replace(/^[#@]/, "").toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "channel";
31164
+ const dir = join73(getStoreDir(), "slack");
31165
+ return { dir, bodyPath: join73(dir, `${slug}.md`) };
31166
+ }
31167
+
31168
+ // src/commands/slack/postSlackMessage.ts
31169
+ var USAGE5 = "Usage: assist slack post [channel] --body <body|->";
31170
+ async function postSlackMessage(channelArg, options2) {
31171
+ const channel = (channelArg ?? loadConfig().slack?.channel ?? "").trim();
31172
+ const body = options2.body?.trim();
31173
+ if (!channel) {
31174
+ console.error(
31175
+ 'No channel given and slack.channel is not set. Pass one, or set a default with: assist config set slack.channel "#general"'
31176
+ );
31177
+ console.error(USAGE5);
31178
+ process.exit(1);
31179
+ }
31180
+ if (!body) {
31181
+ console.error(USAGE5);
31182
+ process.exit(1);
31183
+ }
31184
+ const threadTs = options2.thread;
31185
+ const { dir, bodyPath } = slackWorkingFile(channel);
31186
+ mkdirSync22(dir, { recursive: true });
31187
+ const write = (text18) => writeFileSync42(bodyPath, `${text18}
31188
+ `);
31189
+ write(body);
31190
+ const approved = await reviewProposedSlackMessage(
31191
+ { channel, threadTs },
31192
+ body,
31193
+ { path: bodyPath, save: write }
31194
+ );
31195
+ write(approved);
31196
+ const target = threadTs ? `${channel} (thread_ts ${threadTs})` : channel;
31197
+ console.log(`Approved for ${target}. The body to post is at:`);
31198
+ console.log(bodyPath);
31199
+ }
31200
+
31201
+ // src/commands/registerSlack.ts
31202
+ function registerSlack(program2) {
31203
+ const slackCommand = program2.command("slack").description("Slack utilities");
31204
+ const postCommand = slackCommand.command("post [channel]").description(
31205
+ "Preview a markdown message bound for a Slack channel (body of - reads it from stdin)"
31206
+ ).option("--body <body>", "Message body (- reads it from stdin)").option(
31207
+ "--thread <ts-or-permalink>",
31208
+ "Reply in this thread: a message ts (1712345678.123456) or a Slack archives permalink",
31209
+ parseSlackThreadRef
31210
+ ).addHelpText(
31211
+ "after",
31212
+ "\nThe command does not post: Slack is reachable only over MCP, so it previews the message and hands the approved body back for /slack-post to send.\nIn an assist web session the body is previewed for approve/reject first (with inline comments). On approval the approved body \u2014 including any edit made in the pane \u2014 is written to a working file under ~/.assist/slack/ and its path printed on the last line, preceded by the resolved thread_ts when --thread was given. On rejection nothing is handed back: the command exits non-zero with the reason and any inline comments, leaving the previewed markdown in the working file to revise in place.\nOutside a web session there is no preview and the body passes straight through.\nslack_send_message accepts standard markdown as it is \u2014 bold, italic, code, blockquotes, lists, links, code blocks, tables and headers \u2014 capped at 5000 characters."
31213
+ ).action(
31214
+ async (channel, options2) => {
31215
+ await postSlackMessage(channel, {
31216
+ ...options2,
31217
+ body: options2.body ? await readBodyArgument(options2.body) : void 0
31218
+ });
31219
+ }
31220
+ );
31221
+ configHelp(postCommand, slackConfigHelp);
31222
+ }
31223
+
31103
31224
  // src/commands/sql/sqlAuth.ts
31104
31225
  import chalk220 from "chalk";
31105
31226
 
@@ -32132,20 +32253,20 @@ async function configure() {
32132
32253
 
32133
32254
  // src/commands/transcript/list.ts
32134
32255
  import { existsSync as existsSync72, readdirSync as readdirSync20, statSync as statSync11 } from "fs";
32135
- import { join as join83 } from "path";
32256
+ import { join as join84 } from "path";
32136
32257
  function list4() {
32137
32258
  const { vttDir } = getTranscriptConfig();
32138
32259
  if (!existsSync72(vttDir)) return;
32139
32260
  for (const entry of readdirSync20(vttDir)) {
32140
32261
  if (!entry.endsWith(".vtt")) continue;
32141
- if (statSync11(join83(vttDir, entry)).isDirectory()) continue;
32262
+ if (statSync11(join84(vttDir, entry)).isDirectory()) continue;
32142
32263
  console.log(entry);
32143
32264
  }
32144
32265
  }
32145
32266
 
32146
32267
  // src/commands/transcript/move.ts
32147
- import { existsSync as existsSync73, mkdirSync as mkdirSync27, renameSync as renameSync2, writeFileSync as writeFileSync45 } from "fs";
32148
- import { basename as basename21, join as join84 } from "path";
32268
+ import { existsSync as existsSync73, mkdirSync as mkdirSync28, renameSync as renameSync2, writeFileSync as writeFileSync46 } from "fs";
32269
+ import { basename as basename21, join as join85 } from "path";
32149
32270
 
32150
32271
  // src/commands/transcript/convertVttToMarkdown.ts
32151
32272
  function convertVttToMarkdown(inputPath) {
@@ -32155,9 +32276,9 @@ function convertVttToMarkdown(inputPath) {
32155
32276
  // src/commands/transcript/move.ts
32156
32277
  var DATE_REGEX = /^\d{4}-\d{2}-\d{2}$/;
32157
32278
  function archiveRawVtt(vttDir, sourcePath, filename) {
32158
- const processedDir = join84(vttDir, "processed");
32159
- mkdirSync27(processedDir, { recursive: true });
32160
- renameSync2(sourcePath, join84(processedDir, filename));
32279
+ const processedDir = join85(vttDir, "processed");
32280
+ mkdirSync28(processedDir, { recursive: true });
32281
+ renameSync2(sourcePath, join85(processedDir, filename));
32161
32282
  }
32162
32283
  function move(file, options2) {
32163
32284
  const { date, client } = options2;
@@ -32167,19 +32288,19 @@ function move(file, options2) {
32167
32288
  }
32168
32289
  const { vttDir, transcriptsDir, summaryDir } = getTranscriptConfig();
32169
32290
  const filename = basename21(file);
32170
- const sourcePath = join84(vttDir, filename);
32291
+ const sourcePath = join85(vttDir, filename);
32171
32292
  if (!existsSync73(sourcePath)) {
32172
32293
  console.error(`Error: VTT file not found: ${sourcePath}`);
32173
32294
  process.exit(1);
32174
32295
  }
32175
32296
  const base = basename21(filename, ".vtt").replace(/ Transcription$/, "");
32176
32297
  const outputName = `${date} ${base}.md`;
32177
- const formattedDir = join84(transcriptsDir, client);
32178
- mkdirSync27(formattedDir, { recursive: true });
32179
- const formattedPath = join84(formattedDir, outputName);
32180
- writeFileSync45(formattedPath, convertVttToMarkdown(sourcePath), "utf8");
32298
+ const formattedDir = join85(transcriptsDir, client);
32299
+ mkdirSync28(formattedDir, { recursive: true });
32300
+ const formattedPath = join85(formattedDir, outputName);
32301
+ writeFileSync46(formattedPath, convertVttToMarkdown(sourcePath), "utf8");
32181
32302
  archiveRawVtt(vttDir, sourcePath, filename);
32182
- const summaryPath = join84(summaryDir, client, outputName);
32303
+ const summaryPath = join85(summaryDir, client, outputName);
32183
32304
  console.log(`Formatted transcript: ${formattedPath}`);
32184
32305
  console.log(`Summary target: ${summaryPath}`);
32185
32306
  }
@@ -32262,38 +32383,38 @@ function registerVerify(program2) {
32262
32383
 
32263
32384
  // src/commands/voice/devices.ts
32264
32385
  import { spawnSync as spawnSync9 } from "child_process";
32265
- import { join as join86 } from "path";
32386
+ import { join as join87 } from "path";
32266
32387
 
32267
32388
  // src/commands/voice/shared.ts
32268
32389
  import { homedir as homedir25 } from "os";
32269
- import { dirname as dirname36, join as join85 } from "path";
32390
+ import { dirname as dirname36, join as join86 } from "path";
32270
32391
  import { fileURLToPath as fileURLToPath9 } from "url";
32271
32392
  var __dirname6 = dirname36(fileURLToPath9(import.meta.url));
32272
- var VOICE_DIR = join85(homedir25(), ".assist", "voice");
32393
+ var VOICE_DIR = join86(homedir25(), ".assist", "voice");
32273
32394
  var voicePaths = {
32274
32395
  dir: VOICE_DIR,
32275
- pid: join85(VOICE_DIR, "voice.pid"),
32276
- log: join85(VOICE_DIR, "voice.log"),
32277
- venv: join85(VOICE_DIR, ".venv"),
32278
- lock: join85(VOICE_DIR, "voice.lock")
32396
+ pid: join86(VOICE_DIR, "voice.pid"),
32397
+ log: join86(VOICE_DIR, "voice.log"),
32398
+ venv: join86(VOICE_DIR, ".venv"),
32399
+ lock: join86(VOICE_DIR, "voice.lock")
32279
32400
  };
32280
32401
  function getPythonDir() {
32281
- return join85(__dirname6, "commands", "voice", "python");
32402
+ return join86(__dirname6, "commands", "voice", "python");
32282
32403
  }
32283
32404
  function getVenvPython() {
32284
- return process.platform === "win32" ? join85(voicePaths.venv, "Scripts", "python.exe") : join85(voicePaths.venv, "bin", "python");
32405
+ return process.platform === "win32" ? join86(voicePaths.venv, "Scripts", "python.exe") : join86(voicePaths.venv, "bin", "python");
32285
32406
  }
32286
32407
  function getLockDir() {
32287
32408
  const config = loadConfig();
32288
32409
  return config.voice?.lockDir ?? VOICE_DIR;
32289
32410
  }
32290
32411
  function getLockFile() {
32291
- return join85(getLockDir(), "voice.lock");
32412
+ return join86(getLockDir(), "voice.lock");
32292
32413
  }
32293
32414
 
32294
32415
  // src/commands/voice/devices.ts
32295
32416
  function devices() {
32296
- const script = join86(getPythonDir(), "list_devices.py");
32417
+ const script = join87(getPythonDir(), "list_devices.py");
32297
32418
  spawnSync9(getVenvPython(), [script], { stdio: "inherit" });
32298
32419
  }
32299
32420
 
@@ -32327,13 +32448,13 @@ function logs(options2) {
32327
32448
 
32328
32449
  // src/commands/voice/setup.ts
32329
32450
  import { spawnSync as spawnSync10 } from "child_process";
32330
- import { mkdirSync as mkdirSync29 } from "fs";
32331
- import { join as join88 } from "path";
32451
+ import { mkdirSync as mkdirSync30 } from "fs";
32452
+ import { join as join89 } from "path";
32332
32453
 
32333
32454
  // src/commands/voice/checkLockFile.ts
32334
32455
  import { execSync as execSync58 } from "child_process";
32335
- import { existsSync as existsSync75, mkdirSync as mkdirSync28, readFileSync as readFileSync57, writeFileSync as writeFileSync46 } from "fs";
32336
- import { join as join87 } from "path";
32456
+ import { existsSync as existsSync75, mkdirSync as mkdirSync29, readFileSync as readFileSync57, writeFileSync as writeFileSync47 } from "fs";
32457
+ import { join as join88 } from "path";
32337
32458
  function isProcessAlive2(pid) {
32338
32459
  try {
32339
32460
  process.kill(pid, 0);
@@ -32370,8 +32491,8 @@ function bootstrapVenv() {
32370
32491
  }
32371
32492
  function writeLockFile(pid) {
32372
32493
  const lockFile = getLockFile();
32373
- mkdirSync28(join87(lockFile, ".."), { recursive: true });
32374
- writeFileSync46(
32494
+ mkdirSync29(join88(lockFile, ".."), { recursive: true });
32495
+ writeFileSync47(
32375
32496
  lockFile,
32376
32497
  JSON.stringify({
32377
32498
  pid,
@@ -32383,10 +32504,10 @@ function writeLockFile(pid) {
32383
32504
 
32384
32505
  // src/commands/voice/setup.ts
32385
32506
  function setup() {
32386
- mkdirSync29(voicePaths.dir, { recursive: true });
32507
+ mkdirSync30(voicePaths.dir, { recursive: true });
32387
32508
  bootstrapVenv();
32388
32509
  console.log("\nDownloading models...\n");
32389
- const script = join88(getPythonDir(), "setup_models.py");
32510
+ const script = join89(getPythonDir(), "setup_models.py");
32390
32511
  const result = spawnSync10(getVenvPython(), [script], {
32391
32512
  stdio: "inherit",
32392
32513
  env: { ...process.env, VOICE_LOG_FILE: voicePaths.log }
@@ -32399,8 +32520,8 @@ function setup() {
32399
32520
 
32400
32521
  // src/commands/voice/start.ts
32401
32522
  import { spawn as spawn8 } from "child_process";
32402
- import { mkdirSync as mkdirSync30, writeFileSync as writeFileSync47 } from "fs";
32403
- import { join as join89 } from "path";
32523
+ import { mkdirSync as mkdirSync31, writeFileSync as writeFileSync48 } from "fs";
32524
+ import { join as join90 } from "path";
32404
32525
 
32405
32526
  // src/commands/voice/buildDaemonEnv.ts
32406
32527
  function buildDaemonEnv(options2) {
@@ -32428,17 +32549,17 @@ function spawnBackground(python, script, env) {
32428
32549
  console.error("Failed to start voice daemon");
32429
32550
  process.exit(1);
32430
32551
  }
32431
- writeFileSync47(voicePaths.pid, String(pid));
32552
+ writeFileSync48(voicePaths.pid, String(pid));
32432
32553
  writeLockFile(pid);
32433
32554
  console.log(`Voice daemon started (PID ${pid})`);
32434
32555
  }
32435
32556
  function start2(options2) {
32436
- mkdirSync30(voicePaths.dir, { recursive: true });
32557
+ mkdirSync31(voicePaths.dir, { recursive: true });
32437
32558
  checkLockFile();
32438
32559
  bootstrapVenv();
32439
32560
  const debug = options2.debug || options2.foreground || process.platform === "win32";
32440
32561
  const env = buildDaemonEnv({ debug });
32441
- const script = join89(getPythonDir(), "voice_daemon.py");
32562
+ const script = join90(getPythonDir(), "voice_daemon.py");
32442
32563
  const python = getVenvPython();
32443
32564
  if (options2.foreground) {
32444
32565
  spawnForeground(python, script, env);
@@ -32569,11 +32690,11 @@ function changedPaths(from, cwd) {
32569
32690
  }
32570
32691
 
32571
32692
  // src/commands/watch/readBuiltVersion.ts
32572
- import { join as join90 } from "path";
32693
+ import { join as join91 } from "path";
32573
32694
  function readBuiltVersion(cwd) {
32574
32695
  try {
32575
32696
  const root = runGit3(["rev-parse", "--show-toplevel"], cwd);
32576
- return readPackageJson(join90(root, "package.json")).version ?? "unknown";
32697
+ return readPackageJson(join91(root, "package.json")).version ?? "unknown";
32577
32698
  } catch {
32578
32699
  return "unknown";
32579
32700
  }
@@ -32934,13 +33055,13 @@ import { existsSync as existsSync80 } from "fs";
32934
33055
  // src/commands/run/resolveCommand.ts
32935
33056
  import { execFileSync as execFileSync16 } from "child_process";
32936
33057
  import { existsSync as existsSync79 } from "fs";
32937
- import { dirname as dirname37, join as join91, resolve as resolve20 } from "path";
33058
+ import { dirname as dirname37, join as join92, resolve as resolve20 } from "path";
32938
33059
  function resolveCommand2(command) {
32939
33060
  if (process.platform !== "win32" || command !== "bash") return command;
32940
33061
  try {
32941
33062
  const gitPath = execFileSync16("where", ["git"], { encoding: "utf8" }).trim().split("\r\n")[0];
32942
33063
  const gitRoot = resolve20(dirname37(gitPath), "..");
32943
- const gitBash = join91(gitRoot, "bin", "bash.exe");
33064
+ const gitBash = join92(gitRoot, "bin", "bash.exe");
32944
33065
  if (existsSync79(gitBash)) return gitBash;
32945
33066
  } catch {
32946
33067
  return command;
@@ -33368,7 +33489,7 @@ async function auth() {
33368
33489
  // src/commands/roam/postRoamActivity.ts
33369
33490
  import { execFileSync as execFileSync18 } from "child_process";
33370
33491
  import { readdirSync as readdirSync21, readFileSync as readFileSync60, statSync as statSync12 } from "fs";
33371
- import { join as join92 } from "path";
33492
+ import { join as join93 } from "path";
33372
33493
  function findPortFile(roamDir) {
33373
33494
  let entries;
33374
33495
  try {
@@ -33377,7 +33498,7 @@ function findPortFile(roamDir) {
33377
33498
  return void 0;
33378
33499
  }
33379
33500
  const candidates = entries.filter((name) => /^roam-local-api(-[^.]+)?\.port$/.test(name)).map((name) => {
33380
- const path90 = join92(roamDir, name);
33501
+ const path90 = join93(roamDir, name);
33381
33502
  try {
33382
33503
  return { path: path90, mtimeMs: statSync12(path90).mtimeMs };
33383
33504
  } catch {
@@ -33394,7 +33515,7 @@ var PID_BY_APP = {
33394
33515
  function postRoamActivity(app, event) {
33395
33516
  const appData = process.env.APPDATA;
33396
33517
  if (!appData) return;
33397
- const portFile = findPortFile(join92(appData, "Roam"));
33518
+ const portFile = findPortFile(join93(appData, "Roam"));
33398
33519
  if (!portFile) return;
33399
33520
  let port;
33400
33521
  try {
@@ -33529,8 +33650,8 @@ async function run3(name, args) {
33529
33650
  }
33530
33651
 
33531
33652
  // src/commands/run/add.ts
33532
- import { mkdirSync as mkdirSync31, writeFileSync as writeFileSync48 } from "fs";
33533
- import { join as join93 } from "path";
33653
+ import { mkdirSync as mkdirSync32, writeFileSync as writeFileSync49 } from "fs";
33654
+ import { join as join94 } from "path";
33534
33655
 
33535
33656
  // src/commands/run/extractOption.ts
33536
33657
  function extractOption(args, flag) {
@@ -33591,16 +33712,16 @@ function saveNewRunConfig(name, command, args, cwd) {
33591
33712
  saveConfig(config);
33592
33713
  }
33593
33714
  function createCommandFile(name) {
33594
- const dir = join93(".claude", "commands");
33595
- mkdirSync31(dir, { recursive: true });
33715
+ const dir = join94(".claude", "commands");
33716
+ mkdirSync32(dir, { recursive: true });
33596
33717
  const content = `---
33597
33718
  description: Run ${name}
33598
33719
  ---
33599
33720
 
33600
33721
  Run \`assist run ${name} $ARGUMENTS 2>&1\`.
33601
33722
  `;
33602
- const filePath = join93(dir, `${name}.md`);
33603
- writeFileSync48(filePath, content);
33723
+ const filePath = join94(dir, `${name}.md`);
33724
+ writeFileSync49(filePath, content);
33604
33725
  console.log(`Created command file: ${filePath}`);
33605
33726
  }
33606
33727
  function add3() {
@@ -33656,7 +33777,7 @@ function link2() {
33656
33777
 
33657
33778
  // src/commands/run/remove.ts
33658
33779
  import { existsSync as existsSync81, unlinkSync as unlinkSync21 } from "fs";
33659
- import { join as join94 } from "path";
33780
+ import { join as join95 } from "path";
33660
33781
  function findRemoveIndex() {
33661
33782
  const idx = process.argv.indexOf("remove");
33662
33783
  if (idx === -1 || idx + 1 >= process.argv.length) return -1;
@@ -33671,7 +33792,7 @@ function parseRemoveName() {
33671
33792
  return process.argv[idx + 1];
33672
33793
  }
33673
33794
  function deleteCommandFile(name) {
33674
- const filePath = join94(".claude", "commands", `${name}.md`);
33795
+ const filePath = join95(".claude", "commands", `${name}.md`);
33675
33796
  if (existsSync81(filePath)) {
33676
33797
  unlinkSync21(filePath);
33677
33798
  console.log(`Deleted command file: ${filePath}`);
@@ -33717,9 +33838,9 @@ function registerRun(program2) {
33717
33838
 
33718
33839
  // src/commands/screenshot/index.ts
33719
33840
  import { execSync as execSync60 } from "child_process";
33720
- import { existsSync as existsSync82, mkdirSync as mkdirSync32, unlinkSync as unlinkSync22, writeFileSync as writeFileSync49 } from "fs";
33841
+ import { existsSync as existsSync82, mkdirSync as mkdirSync33, unlinkSync as unlinkSync22, writeFileSync as writeFileSync50 } from "fs";
33721
33842
  import { tmpdir as tmpdir9 } from "os";
33722
- import { join as join95, resolve as resolve21 } from "path";
33843
+ import { join as join96, resolve as resolve21 } from "path";
33723
33844
  import chalk227 from "chalk";
33724
33845
 
33725
33846
  // src/commands/screenshot/captureWindowPs1.ts
@@ -33850,14 +33971,14 @@ Write-Output $OutputPath
33850
33971
  // src/commands/screenshot/index.ts
33851
33972
  function buildOutputPath(outputDir, processName) {
33852
33973
  if (!existsSync82(outputDir)) {
33853
- mkdirSync32(outputDir, { recursive: true });
33974
+ mkdirSync33(outputDir, { recursive: true });
33854
33975
  }
33855
33976
  const timestamp6 = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
33856
33977
  return resolve21(outputDir, `${processName}-${timestamp6}.png`);
33857
33978
  }
33858
33979
  function runPowerShellScript(processName, outputPath) {
33859
- const scriptPath = join95(tmpdir9(), `assist-screenshot-${Date.now()}.ps1`);
33860
- writeFileSync49(scriptPath, captureWindowPs1, "utf8");
33980
+ const scriptPath = join96(tmpdir9(), `assist-screenshot-${Date.now()}.ps1`);
33981
+ writeFileSync50(scriptPath, captureWindowPs1, "utf8");
33861
33982
  try {
33862
33983
  execSync60(
33863
33984
  `powershell -NoProfile -ExecutionPolicy Bypass -File "${scriptPath}" -ProcessName "${processName}" -OutputPath "${outputPath}"`,
@@ -34090,7 +34211,7 @@ function requestDrain(socket, lines2) {
34090
34211
  }
34091
34212
 
34092
34213
  // src/commands/sessions/daemon/runDaemon.ts
34093
- import { mkdirSync as mkdirSync36 } from "fs";
34214
+ import { mkdirSync as mkdirSync37 } from "fs";
34094
34215
 
34095
34216
  // src/commands/sessions/daemon/createAutoExit.ts
34096
34217
  var DEFAULT_GRACE_MS = 6e4;
@@ -34344,7 +34465,7 @@ var ClientHub = class extends Set {
34344
34465
  };
34345
34466
 
34346
34467
  // src/commands/sessions/daemon/createSession.ts
34347
- import { randomUUID as randomUUID17 } from "crypto";
34468
+ import { randomUUID as randomUUID18 } from "crypto";
34348
34469
 
34349
34470
  // src/commands/sessions/daemon/sessionBase.ts
34350
34471
  function sessionBase(id, status3) {
@@ -34540,7 +34661,7 @@ function spawnRun(opts) {
34540
34661
  function createSession(id, { prompt, cwd, design, auto, harness, holdPty } = {}) {
34541
34662
  if (harness && harness !== "claude")
34542
34663
  return createHarnessSession(id, harness, prompt, cwd, holdPty);
34543
- const claudeSessionId = randomUUID17();
34664
+ const claudeSessionId = randomUUID18();
34544
34665
  return {
34545
34666
  ...sessionBase(id, prompt ? "running" : "waiting"),
34546
34667
  name: `Session ${id}`,
@@ -34605,12 +34726,12 @@ import { basename as basename22 } from "path";
34605
34726
 
34606
34727
  // src/commands/sessions/daemon/worktree/deleteStrandedTree.ts
34607
34728
  import { existsSync as existsSync86 } from "fs";
34608
- import { join as join98 } from "path";
34729
+ import { join as join99 } from "path";
34609
34730
 
34610
34731
  // src/commands/sessions/daemon/worktree/deleteTreeDirectly.ts
34611
34732
  import { statSync as statSync14 } from "fs";
34612
34733
  import { rm as rm4 } from "fs/promises";
34613
- import { join as join97 } from "path";
34734
+ import { join as join98 } from "path";
34614
34735
  async function deleteTreeDirectly(clone, worktreePath, why) {
34615
34736
  if (holdsAGitDirectoryRatherThanALink(worktreePath)) {
34616
34737
  const refusal = "it is a clone of its own, not a linked worktree";
@@ -34638,7 +34759,7 @@ async function deleteTreeDirectly(clone, worktreePath, why) {
34638
34759
  return { removed: true };
34639
34760
  }
34640
34761
  function holdsAGitDirectoryRatherThanALink(worktreePath) {
34641
- return statSync14(join97(worktreePath, ".git"), {
34762
+ return statSync14(join98(worktreePath, ".git"), {
34642
34763
  throwIfNoEntry: false
34643
34764
  })?.isDirectory() === true;
34644
34765
  }
@@ -34674,7 +34795,7 @@ async function deleteStrandedTree(clone, worktreePath, cause) {
34674
34795
  );
34675
34796
  }
34676
34797
  function strandedReason(worktreePath, cause) {
34677
- if (!existsSync86(join98(worktreePath, ".git")))
34798
+ if (!existsSync86(join99(worktreePath, ".git")))
34678
34799
  return "its .git link is already gone";
34679
34800
  if (/not a working tree|not a git repository/i.test(reason2(cause)))
34680
34801
  return "git no longer recognises it as a working tree";
@@ -35140,7 +35261,8 @@ var PREVIEW_KINDS = [
35140
35261
  "github-issue",
35141
35262
  "github-issue-comment",
35142
35263
  "github-issue-edit",
35143
- "miro-board"
35264
+ "miro-board",
35265
+ "slack-post"
35144
35266
  ];
35145
35267
  function isPreviewKind(value) {
35146
35268
  return PREVIEW_KINDS.includes(value);
@@ -35164,6 +35286,7 @@ function previewTargetLabel(kind, itemType, prNumber, draft) {
35164
35286
  if (kind === "github-issue-edit") return "github issue edit";
35165
35287
  if (kind === "github-issue") return "github issue";
35166
35288
  if (kind === "miro-board") return "miro anchors";
35289
+ if (kind === "slack-post") return "slack post";
35167
35290
  if (kind === "backlog-item") return `backlog ${itemType}`;
35168
35291
  if (prNumber !== null) return `edit #${prNumber}`;
35169
35292
  return draft ? "create draft" : "create";
@@ -35433,7 +35556,7 @@ function handleFailedResume(session, exitCode, onStatusChange) {
35433
35556
  }
35434
35557
 
35435
35558
  // src/commands/sessions/daemon/watchActivity.ts
35436
- import { existsSync as existsSync90, mkdirSync as mkdirSync33, watch as watch2 } from "fs";
35559
+ import { existsSync as existsSync90, mkdirSync as mkdirSync34, watch as watch2 } from "fs";
35437
35560
  import { dirname as dirname39 } from "path";
35438
35561
 
35439
35562
  // src/commands/sessions/daemon/applyActivityToSession.ts
@@ -35498,7 +35621,7 @@ function watchActivity(session, notify2, onClaudeSessionId) {
35498
35621
  const path90 = activityPath(session.id);
35499
35622
  const dir = dirname39(path90);
35500
35623
  try {
35501
- mkdirSync33(dir, { recursive: true });
35624
+ mkdirSync34(dir, { recursive: true });
35502
35625
  } catch {
35503
35626
  return;
35504
35627
  }
@@ -35701,10 +35824,10 @@ function headContainsSessionId(filePath, claudeSessionId) {
35701
35824
  }
35702
35825
 
35703
35826
  // src/commands/sessions/daemon/ensureProjectDirExists.ts
35704
- import { mkdirSync as mkdirSync34 } from "fs";
35827
+ import { mkdirSync as mkdirSync35 } from "fs";
35705
35828
  function ensureProjectDirExists(dir, sessionId) {
35706
35829
  try {
35707
- mkdirSync34(dir, { recursive: true });
35830
+ mkdirSync35(dir, { recursive: true });
35708
35831
  return true;
35709
35832
  } catch (error) {
35710
35833
  daemonLog(
@@ -36653,7 +36776,7 @@ function codexRespawnPlan(session) {
36653
36776
  }
36654
36777
 
36655
36778
  // src/commands/sessions/daemon/interactiveRespawnPlan.ts
36656
- import { randomUUID as randomUUID18 } from "crypto";
36779
+ import { randomUUID as randomUUID19 } from "crypto";
36657
36780
  function interactiveRespawnPlan(session, resumes) {
36658
36781
  const { claudeSessionId, cwd, initialPrompt, design, auto } = session;
36659
36782
  if (!resumes) return null;
@@ -36673,7 +36796,7 @@ function interactiveRespawnPlan(session, resumes) {
36673
36796
  return null;
36674
36797
  }
36675
36798
  function freshClaudePlan(session, prompt, cwd) {
36676
- const claudeSessionId = randomUUID18();
36799
+ const claudeSessionId = randomUUID19();
36677
36800
  return {
36678
36801
  spawn: () => {
36679
36802
  session.claudeSessionId = claudeSessionId;
@@ -37558,10 +37681,10 @@ function startReusedRunPty(session, assistArgs, itemId2, hold, clients, onStatus
37558
37681
  }
37559
37682
 
37560
37683
  // src/commands/sessions/daemon/createWatcherSession.ts
37561
- import { randomUUID as randomUUID19 } from "crypto";
37684
+ import { randomUUID as randomUUID20 } from "crypto";
37562
37685
  var WATCH_PROMPT = "/watch";
37563
37686
  function createWatcherSession(id, cwd) {
37564
- const claudeSessionId = randomUUID19();
37687
+ const claudeSessionId = randomUUID20();
37565
37688
  return {
37566
37689
  ...sessionBase(id, "running"),
37567
37690
  name: `Session ${id}`,
@@ -38785,8 +38908,8 @@ function resumeSession(id, sessionId, cwd, name, holdPty, harness) {
38785
38908
  import { existsSync as existsSync96 } from "fs";
38786
38909
 
38787
38910
  // src/commands/sessions/daemon/worktree/carryTranscriptToTree.ts
38788
- import { copyFileSync as copyFileSync7, existsSync as existsSync95, mkdirSync as mkdirSync35 } from "fs";
38789
- import { join as join100 } from "path";
38911
+ import { copyFileSync as copyFileSync7, existsSync as existsSync95, mkdirSync as mkdirSync36 } from "fs";
38912
+ import { join as join101 } from "path";
38790
38913
  function carryTranscriptToTree(claudeSessionId, fromCwd, toCwd) {
38791
38914
  const dir = projectDirForCwd(toCwd);
38792
38915
  if (dir === projectDirForCwd(fromCwd)) {
@@ -38795,7 +38918,7 @@ function carryTranscriptToTree(claudeSessionId, fromCwd, toCwd) {
38795
38918
  );
38796
38919
  return;
38797
38920
  }
38798
- const dest = join100(dir, `${claudeSessionId}.jsonl`);
38921
+ const dest = join101(dir, `${claudeSessionId}.jsonl`);
38799
38922
  if (existsSync95(dest)) {
38800
38923
  daemonLog(`transcript ${claudeSessionId} already present in ${dir}`);
38801
38924
  return;
@@ -38808,7 +38931,7 @@ function carryTranscriptToTree(claudeSessionId, fromCwd, toCwd) {
38808
38931
  return;
38809
38932
  }
38810
38933
  try {
38811
- mkdirSync35(dir, { recursive: true });
38934
+ mkdirSync36(dir, { recursive: true });
38812
38935
  copyFileSync7(source, dest);
38813
38936
  daemonLog(
38814
38937
  `transcript ${source} copied to ${dest} so ${toCwd} can resume it`
@@ -39433,7 +39556,7 @@ function handleConnection(socket, manager) {
39433
39556
  }
39434
39557
 
39435
39558
  // src/commands/sessions/daemon/onListening.ts
39436
- import { unlinkSync as unlinkSync23, writeFileSync as writeFileSync50 } from "fs";
39559
+ import { unlinkSync as unlinkSync23, writeFileSync as writeFileSync51 } from "fs";
39437
39560
 
39438
39561
  // src/commands/sessions/daemon/startPidFileWatchdog.ts
39439
39562
  import { readFileSync as readFileSync64 } from "fs";
@@ -39455,7 +39578,7 @@ function ownsPidFile() {
39455
39578
 
39456
39579
  // src/commands/sessions/daemon/onListening.ts
39457
39580
  function onListening(manager, checkAutoExit) {
39458
- writeFileSync50(daemonPaths.pid, String(process.pid));
39581
+ writeFileSync51(daemonPaths.pid, String(process.pid));
39459
39582
  startPidFileWatchdog(() => {
39460
39583
  daemonLog("lost daemon.pid ownership; shutting down sessions and exiting");
39461
39584
  void manager.flushActiveMs().finally(() => {
@@ -39642,7 +39765,7 @@ async function recoverFromAddrInUse(server, manager, checkAutoExit) {
39642
39765
 
39643
39766
  // src/commands/sessions/daemon/runDaemon.ts
39644
39767
  async function runDaemon() {
39645
- mkdirSync36(daemonPaths.dir, { recursive: true });
39768
+ mkdirSync37(daemonPaths.dir, { recursive: true });
39646
39769
  daemonLog(
39647
39770
  `starting (reason: ${process.env.ASSIST_DAEMON_SPAWN_REASON ?? "manual"})`
39648
39771
  );
@@ -39922,9 +40045,9 @@ function buildLimitsSegment(rateLimits) {
39922
40045
 
39923
40046
  // src/commands/readGitBranch.ts
39924
40047
  import { readFileSync as readFileSync66, statSync as statSync16 } from "fs";
39925
- import { isAbsolute as isAbsolute5, join as join101, resolve as resolve23 } from "path";
40048
+ import { isAbsolute as isAbsolute5, join as join102, resolve as resolve23 } from "path";
39926
40049
  function resolveGitDir(cwd) {
39927
- const dotGit = join101(cwd, ".git");
40050
+ const dotGit = join102(cwd, ".git");
39928
40051
  let stat4;
39929
40052
  try {
39930
40053
  stat4 = statSync16(dotGit);
@@ -39954,7 +40077,7 @@ function readGitBranch(cwd) {
39954
40077
  }
39955
40078
  let head;
39956
40079
  try {
39957
- head = readFileSync66(join101(gitDir, "HEAD"), "utf8");
40080
+ head = readFileSync66(join102(gitDir, "HEAD"), "utf8");
39958
40081
  } catch {
39959
40082
  return null;
39960
40083
  }
@@ -40144,6 +40267,7 @@ registerNetcap(program);
40144
40267
  registerCriteriaExtension(program);
40145
40268
  registerRavendb(program);
40146
40269
  registerSeq(program);
40270
+ registerSlack(program);
40147
40271
  registerSql(program);
40148
40272
  registerTranscript(program);
40149
40273
  registerVoice(program);