@staff0rd/assist 0.606.1 → 0.608.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.606.1",
9
+ version: "0.608.0",
10
10
  type: "module",
11
11
  main: "dist/index.js",
12
12
  bin: {
@@ -21712,6 +21712,16 @@ function addIssueToProject(projectId, contentId) {
21712
21712
  return id;
21713
21713
  }
21714
21714
 
21715
+ // src/commands/github/issue/addSubIssue.ts
21716
+ var MUTATION4 = `mutation($issueId: ID!, $subIssueId: ID!) {
21717
+ addSubIssue(input: { issueId: $issueId, subIssueId: $subIssueId }) {
21718
+ subIssue { id }
21719
+ }
21720
+ }`;
21721
+ function addSubIssue(parentId, childId) {
21722
+ runGhGraphqlJson(MUTATION4, { issueId: parentId, subIssueId: childId });
21723
+ }
21724
+
21715
21725
  // src/commands/github/issue/fetchIssueNodeId.ts
21716
21726
  var QUERY4 = `query($owner: String!, $repo: String!, $number: Int!) {
21717
21727
  repository(owner: $owner, name: $repo) {
@@ -21747,7 +21757,7 @@ function parseCreatedIssueUrl(output) {
21747
21757
  }
21748
21758
 
21749
21759
  // src/commands/github/issue/setProjectItemStatus.ts
21750
- var MUTATION4 = `mutation($projectId: ID!, $itemId: ID!, $fieldId: ID!, $optionId: String!) {
21760
+ var MUTATION5 = `mutation($projectId: ID!, $itemId: ID!, $fieldId: ID!, $optionId: String!) {
21751
21761
  updateProjectV2ItemFieldValue(input: {
21752
21762
  projectId: $projectId
21753
21763
  itemId: $itemId
@@ -21758,7 +21768,7 @@ var MUTATION4 = `mutation($projectId: ID!, $itemId: ID!, $fieldId: ID!, $optionI
21758
21768
  }
21759
21769
  }`;
21760
21770
  function setProjectItemStatus(input) {
21761
- runGhGraphqlJson(MUTATION4, input);
21771
+ runGhGraphqlJson(MUTATION5, input);
21762
21772
  }
21763
21773
 
21764
21774
  // src/commands/github/issue/applyCreatedIssueMetadata.ts
@@ -21766,11 +21776,15 @@ function applyCreatedIssueMetadata(createOutput, metadata2) {
21766
21776
  let step2 = "identifying the created issue";
21767
21777
  try {
21768
21778
  const issueId = fetchIssueNodeId(parseCreatedIssueUrl(createOutput));
21769
- const { issueType, project } = metadata2;
21779
+ const { issueType, parent, project } = metadata2;
21770
21780
  if (issueType) {
21771
21781
  step2 = `setting its issue type to ${issueType.name}`;
21772
21782
  updateIssueType(issueId, issueType.id);
21773
21783
  }
21784
+ if (parent) {
21785
+ step2 = `adding it as a sub-issue of ${parent.owner}/${parent.repo}#${parent.number}`;
21786
+ addSubIssue(parent.id, issueId);
21787
+ }
21774
21788
  if (project) {
21775
21789
  step2 = `adding it to project ${project.number} (${project.title})`;
21776
21790
  const itemId2 = addIssueToProject(project.id, issueId);
@@ -21796,11 +21810,16 @@ function applyCreatedIssueMetadata(createOutput, metadata2) {
21796
21810
  // src/commands/github/issue/issuePreviewMetadata.ts
21797
21811
  function issuePreviewMetadata(resolved) {
21798
21812
  if (!resolved) return [];
21799
- const { target, issueType, project, labels } = resolved;
21813
+ const { target, issueType, parent, project, labels } = resolved;
21800
21814
  const items2 = [
21801
21815
  { label: "Repository", value: `${target.owner}/${target.repo}` }
21802
21816
  ];
21803
21817
  if (issueType) items2.push({ label: "Type", value: issueType.name });
21818
+ if (parent)
21819
+ items2.push({
21820
+ label: "Parent",
21821
+ value: `${parent.owner}/${parent.repo}#${parent.number}`
21822
+ });
21804
21823
  if (project)
21805
21824
  items2.push({
21806
21825
  label: "Project",
@@ -21812,6 +21831,18 @@ function issuePreviewMetadata(resolved) {
21812
21831
  return items2;
21813
21832
  }
21814
21833
 
21834
+ // src/commands/github/issue/hasCreateIssueMetadataOptions.ts
21835
+ function hasCreateIssueMetadataOptions(options2) {
21836
+ if (options2.status && !options2.project) {
21837
+ throw new Error(
21838
+ "--status is a field on a project board, so it needs --project <number>"
21839
+ );
21840
+ }
21841
+ return Boolean(
21842
+ options2.type || options2.parent || options2.project || options2.label?.length
21843
+ );
21844
+ }
21845
+
21815
21846
  // src/commands/github/issue/resolveIssueLabels.ts
21816
21847
  var QUERY5 = `query($owner: String!, $repo: String!, $after: String) {
21817
21848
  repository(owner: $owner, name: $repo) {
@@ -21947,6 +21978,15 @@ function resolveIssueRepoTarget(repo) {
21947
21978
  return parseRepoSlug(repo);
21948
21979
  }
21949
21980
 
21981
+ // src/commands/github/issue/resolveCreateIssueParent.ts
21982
+ function resolveCreateIssueParent(target, parent) {
21983
+ const reference = resolveFixStructureTarget(
21984
+ parent,
21985
+ `${target.owner}/${target.repo}`
21986
+ );
21987
+ return { ...reference, id: fetchIssueNodeId(reference) };
21988
+ }
21989
+
21950
21990
  // src/commands/github/issue/readGhTokenScopes.ts
21951
21991
  import { spawnSync as spawnSync6 } from "child_process";
21952
21992
  var SCOPES_LINE = /Token scopes:\s*(.*)/;
@@ -22060,18 +22100,13 @@ function resolveCreateIssueProject(owner, projectNumber, statusName) {
22060
22100
 
22061
22101
  // src/commands/github/issue/resolveCreateIssueMetadata.ts
22062
22102
  function resolveCreateIssueMetadata(options2) {
22103
+ if (!hasCreateIssueMetadataOptions(options2)) return void 0;
22063
22104
  const labels = options2.label ?? [];
22064
- if (!options2.type && !options2.project && !options2.status && !labels.length)
22065
- return void 0;
22066
- if (options2.status && !options2.project) {
22067
- throw new Error(
22068
- "--status is a field on a project board, so it needs --project <number>"
22069
- );
22070
- }
22071
22105
  const target = resolveIssueRepoTarget(options2.repo);
22072
22106
  return {
22073
22107
  target,
22074
22108
  issueType: options2.type ? resolveIssueType(resolveOrgIssueTypes(target.owner), options2.type) : void 0,
22109
+ parent: options2.parent ? resolveCreateIssueParent(target, options2.parent) : void 0,
22075
22110
  project: options2.project ? resolveCreateIssueProject(target.owner, options2.project, options2.status) : void 0,
22076
22111
  labels: labels.length ? resolveIssueLabels(target, labels) : void 0
22077
22112
  };
@@ -22110,7 +22145,7 @@ function runGhIssueCreate(title, body, repo, labels) {
22110
22145
  }
22111
22146
 
22112
22147
  // src/commands/github/issue/createIssue.ts
22113
- var USAGE2 = "Usage: assist github issue create --title <title> --body <body> [-R <owner>/<repo>] [--type <name>] [--project <number>] [--status <name>] [--label <name>]";
22148
+ var USAGE2 = "Usage: assist github issue create --title <title> --body <body> [-R <owner>/<repo>] [--type <name>] [--parent <issue>] [--project <number>] [--status <name>] [--label <name>]";
22114
22149
  function preflight(options2) {
22115
22150
  try {
22116
22151
  return resolveCreateIssueMetadata(options2);
@@ -22145,6 +22180,9 @@ function registerCreateIssue(issueCommand) {
22145
22180
  ).option(
22146
22181
  "--type <name>",
22147
22182
  "Native issue type to set on the new issue (e.g. Epic)"
22183
+ ).option(
22184
+ "--parent <issue>",
22185
+ "Parent issue to file the new issue under, as owner/repo#number, a github.com issue URL, or a bare number"
22148
22186
  ).option(
22149
22187
  "--project <number>",
22150
22188
  "Number of the repo owner's GitHub Project to add the new issue to"
@@ -22158,7 +22196,7 @@ function registerCreateIssue(issueCommand) {
22158
22196
  []
22159
22197
  ).addHelpText(
22160
22198
  "after",
22161
- "\nThere is no What/Why/How template: an issue reports a problem, and the target repo's own issue template is unknowable from here. Write the body as the repo's maintainers would expect.\nIn an assist web session the title and body are previewed for approve/reject first (with inline comments); nothing is created until it is approved.\n--type, --project, --status and --label are all resolved before the preview, so an unknown name, a missing project scope or --status without --project creates nothing.\nThe project scope is needed for --project: gh auth refresh -h github.com -s project"
22199
+ "\nThere is no What/Why/How template: an issue reports a problem, and the target repo's own issue template is unknowable from here. Write the body as the repo's maintainers would expect.\nIn an assist web session the title and body are previewed for approve/reject first (with inline comments); nothing is created until it is approved.\n--type, --parent, --project, --status and --label are all resolved before the preview, so an unknown name, an unreadable parent, a missing project scope or --status without --project creates nothing.\nA bare --parent number is read against --repo, or the current repo; a parent in another repository is allowed.\nThe project scope is needed for --project: gh auth refresh -h github.com -s project"
22162
22200
  ).action(createIssue);
22163
22201
  }
22164
22202
 
@@ -29076,15 +29114,15 @@ function runReviewSubmission(mutation, body) {
29076
29114
  }
29077
29115
 
29078
29116
  // src/commands/review/submitBodyOnlyReview.ts
29079
- var MUTATION5 = `mutation($prId: ID!, $body: String) { addPullRequestReview(input: { pullRequestId: $prId, event: COMMENT, body: $body }) { pullRequestReview { id } } }`;
29117
+ var MUTATION6 = `mutation($prId: ID!, $body: String) { addPullRequestReview(input: { pullRequestId: $prId, event: COMMENT, body: $body }) { pullRequestReview { id } } }`;
29080
29118
  function submitBodyOnlyReview(body) {
29081
- runReviewSubmission(MUTATION5, body);
29119
+ runReviewSubmission(MUTATION6, body);
29082
29120
  }
29083
29121
 
29084
29122
  // src/commands/review/submitPendingReview.ts
29085
- var MUTATION6 = `mutation($prId: ID!, $body: String) { submitPullRequestReview(input: { pullRequestId: $prId, event: COMMENT, body: $body }) { pullRequestReview { id } } }`;
29123
+ var MUTATION7 = `mutation($prId: ID!, $body: String) { submitPullRequestReview(input: { pullRequestId: $prId, event: COMMENT, body: $body }) { pullRequestReview { id } } }`;
29086
29124
  function submitPendingReview(body) {
29087
- runReviewSubmission(MUTATION6, body);
29125
+ runReviewSubmission(MUTATION7, body);
29088
29126
  }
29089
29127
 
29090
29128
  // src/commands/review/postAndMaybeSubmit.ts
@@ -31062,6 +31100,79 @@ function registerSignal(program2) {
31062
31100
  });
31063
31101
  }
31064
31102
 
31103
+ // src/commands/slack/postSlackMessage.ts
31104
+ import { mkdirSync as mkdirSync22, writeFileSync as writeFileSync42 } from "fs";
31105
+
31106
+ // src/commands/slack/reviewProposedSlackMessage.ts
31107
+ import { randomUUID as randomUUID17 } from "crypto";
31108
+ async function reviewProposedSlackMessage(channel, body, working) {
31109
+ const sessionId = process.env.ASSIST_SESSION_ID;
31110
+ if (process.env.ASSIST_SESSION !== "1" || !sessionId) return body;
31111
+ const decision = await awaitPreviewApproval(
31112
+ "Slack message preview",
31113
+ {
31114
+ sessionId,
31115
+ requestId: randomUUID17(),
31116
+ title: `Post to ${channel}`,
31117
+ body,
31118
+ prNumber: null,
31119
+ kind: "slack-post"
31120
+ },
31121
+ {
31122
+ saveEditedBody: working.save,
31123
+ 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.`
31124
+ }
31125
+ );
31126
+ return decision.body ?? body;
31127
+ }
31128
+
31129
+ // src/commands/slack/slackWorkingFile.ts
31130
+ import { join as join73 } from "path";
31131
+ function slackWorkingFile(channel) {
31132
+ const slug = channel.replace(/^[#@]/, "").toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "channel";
31133
+ const dir = join73(getStoreDir(), "slack");
31134
+ return { dir, bodyPath: join73(dir, `${slug}.md`) };
31135
+ }
31136
+
31137
+ // src/commands/slack/postSlackMessage.ts
31138
+ var USAGE5 = "Usage: assist slack post <channel> --body <body|->";
31139
+ async function postSlackMessage(channelArg, options2) {
31140
+ const channel = channelArg.trim();
31141
+ const body = options2.body?.trim();
31142
+ if (!channel || !body) {
31143
+ console.error(USAGE5);
31144
+ process.exit(1);
31145
+ }
31146
+ const { dir, bodyPath } = slackWorkingFile(channel);
31147
+ mkdirSync22(dir, { recursive: true });
31148
+ const write = (text18) => writeFileSync42(bodyPath, `${text18}
31149
+ `);
31150
+ write(body);
31151
+ const approved = await reviewProposedSlackMessage(channel, body, {
31152
+ path: bodyPath,
31153
+ save: write
31154
+ });
31155
+ write(approved);
31156
+ console.log(`Approved for ${channel}. The body to post is at:`);
31157
+ console.log(bodyPath);
31158
+ }
31159
+
31160
+ // src/commands/registerSlack.ts
31161
+ function registerSlack(program2) {
31162
+ const slackCommand = program2.command("slack").description("Slack utilities");
31163
+ slackCommand.command("post <channel>").description(
31164
+ "Preview a markdown message bound for a Slack channel (body of - reads it from stdin)"
31165
+ ).option("--body <body>", "Message body (- reads it from stdin)").addHelpText(
31166
+ "after",
31167
+ "\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. 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."
31168
+ ).action(async (channel, options2) => {
31169
+ await postSlackMessage(channel, {
31170
+ ...options2,
31171
+ body: options2.body ? await readBodyArgument(options2.body) : void 0
31172
+ });
31173
+ });
31174
+ }
31175
+
31065
31176
  // src/commands/sql/sqlAuth.ts
31066
31177
  import chalk220 from "chalk";
31067
31178
 
@@ -32094,20 +32205,20 @@ async function configure() {
32094
32205
 
32095
32206
  // src/commands/transcript/list.ts
32096
32207
  import { existsSync as existsSync72, readdirSync as readdirSync20, statSync as statSync11 } from "fs";
32097
- import { join as join83 } from "path";
32208
+ import { join as join84 } from "path";
32098
32209
  function list4() {
32099
32210
  const { vttDir } = getTranscriptConfig();
32100
32211
  if (!existsSync72(vttDir)) return;
32101
32212
  for (const entry of readdirSync20(vttDir)) {
32102
32213
  if (!entry.endsWith(".vtt")) continue;
32103
- if (statSync11(join83(vttDir, entry)).isDirectory()) continue;
32214
+ if (statSync11(join84(vttDir, entry)).isDirectory()) continue;
32104
32215
  console.log(entry);
32105
32216
  }
32106
32217
  }
32107
32218
 
32108
32219
  // src/commands/transcript/move.ts
32109
- import { existsSync as existsSync73, mkdirSync as mkdirSync27, renameSync as renameSync2, writeFileSync as writeFileSync45 } from "fs";
32110
- import { basename as basename21, join as join84 } from "path";
32220
+ import { existsSync as existsSync73, mkdirSync as mkdirSync28, renameSync as renameSync2, writeFileSync as writeFileSync46 } from "fs";
32221
+ import { basename as basename21, join as join85 } from "path";
32111
32222
 
32112
32223
  // src/commands/transcript/convertVttToMarkdown.ts
32113
32224
  function convertVttToMarkdown(inputPath) {
@@ -32117,9 +32228,9 @@ function convertVttToMarkdown(inputPath) {
32117
32228
  // src/commands/transcript/move.ts
32118
32229
  var DATE_REGEX = /^\d{4}-\d{2}-\d{2}$/;
32119
32230
  function archiveRawVtt(vttDir, sourcePath, filename) {
32120
- const processedDir = join84(vttDir, "processed");
32121
- mkdirSync27(processedDir, { recursive: true });
32122
- renameSync2(sourcePath, join84(processedDir, filename));
32231
+ const processedDir = join85(vttDir, "processed");
32232
+ mkdirSync28(processedDir, { recursive: true });
32233
+ renameSync2(sourcePath, join85(processedDir, filename));
32123
32234
  }
32124
32235
  function move(file, options2) {
32125
32236
  const { date, client } = options2;
@@ -32129,19 +32240,19 @@ function move(file, options2) {
32129
32240
  }
32130
32241
  const { vttDir, transcriptsDir, summaryDir } = getTranscriptConfig();
32131
32242
  const filename = basename21(file);
32132
- const sourcePath = join84(vttDir, filename);
32243
+ const sourcePath = join85(vttDir, filename);
32133
32244
  if (!existsSync73(sourcePath)) {
32134
32245
  console.error(`Error: VTT file not found: ${sourcePath}`);
32135
32246
  process.exit(1);
32136
32247
  }
32137
32248
  const base = basename21(filename, ".vtt").replace(/ Transcription$/, "");
32138
32249
  const outputName = `${date} ${base}.md`;
32139
- const formattedDir = join84(transcriptsDir, client);
32140
- mkdirSync27(formattedDir, { recursive: true });
32141
- const formattedPath = join84(formattedDir, outputName);
32142
- writeFileSync45(formattedPath, convertVttToMarkdown(sourcePath), "utf8");
32250
+ const formattedDir = join85(transcriptsDir, client);
32251
+ mkdirSync28(formattedDir, { recursive: true });
32252
+ const formattedPath = join85(formattedDir, outputName);
32253
+ writeFileSync46(formattedPath, convertVttToMarkdown(sourcePath), "utf8");
32143
32254
  archiveRawVtt(vttDir, sourcePath, filename);
32144
- const summaryPath = join84(summaryDir, client, outputName);
32255
+ const summaryPath = join85(summaryDir, client, outputName);
32145
32256
  console.log(`Formatted transcript: ${formattedPath}`);
32146
32257
  console.log(`Summary target: ${summaryPath}`);
32147
32258
  }
@@ -32224,38 +32335,38 @@ function registerVerify(program2) {
32224
32335
 
32225
32336
  // src/commands/voice/devices.ts
32226
32337
  import { spawnSync as spawnSync9 } from "child_process";
32227
- import { join as join86 } from "path";
32338
+ import { join as join87 } from "path";
32228
32339
 
32229
32340
  // src/commands/voice/shared.ts
32230
32341
  import { homedir as homedir25 } from "os";
32231
- import { dirname as dirname36, join as join85 } from "path";
32342
+ import { dirname as dirname36, join as join86 } from "path";
32232
32343
  import { fileURLToPath as fileURLToPath9 } from "url";
32233
32344
  var __dirname6 = dirname36(fileURLToPath9(import.meta.url));
32234
- var VOICE_DIR = join85(homedir25(), ".assist", "voice");
32345
+ var VOICE_DIR = join86(homedir25(), ".assist", "voice");
32235
32346
  var voicePaths = {
32236
32347
  dir: VOICE_DIR,
32237
- pid: join85(VOICE_DIR, "voice.pid"),
32238
- log: join85(VOICE_DIR, "voice.log"),
32239
- venv: join85(VOICE_DIR, ".venv"),
32240
- lock: join85(VOICE_DIR, "voice.lock")
32348
+ pid: join86(VOICE_DIR, "voice.pid"),
32349
+ log: join86(VOICE_DIR, "voice.log"),
32350
+ venv: join86(VOICE_DIR, ".venv"),
32351
+ lock: join86(VOICE_DIR, "voice.lock")
32241
32352
  };
32242
32353
  function getPythonDir() {
32243
- return join85(__dirname6, "commands", "voice", "python");
32354
+ return join86(__dirname6, "commands", "voice", "python");
32244
32355
  }
32245
32356
  function getVenvPython() {
32246
- return process.platform === "win32" ? join85(voicePaths.venv, "Scripts", "python.exe") : join85(voicePaths.venv, "bin", "python");
32357
+ return process.platform === "win32" ? join86(voicePaths.venv, "Scripts", "python.exe") : join86(voicePaths.venv, "bin", "python");
32247
32358
  }
32248
32359
  function getLockDir() {
32249
32360
  const config = loadConfig();
32250
32361
  return config.voice?.lockDir ?? VOICE_DIR;
32251
32362
  }
32252
32363
  function getLockFile() {
32253
- return join85(getLockDir(), "voice.lock");
32364
+ return join86(getLockDir(), "voice.lock");
32254
32365
  }
32255
32366
 
32256
32367
  // src/commands/voice/devices.ts
32257
32368
  function devices() {
32258
- const script = join86(getPythonDir(), "list_devices.py");
32369
+ const script = join87(getPythonDir(), "list_devices.py");
32259
32370
  spawnSync9(getVenvPython(), [script], { stdio: "inherit" });
32260
32371
  }
32261
32372
 
@@ -32289,13 +32400,13 @@ function logs(options2) {
32289
32400
 
32290
32401
  // src/commands/voice/setup.ts
32291
32402
  import { spawnSync as spawnSync10 } from "child_process";
32292
- import { mkdirSync as mkdirSync29 } from "fs";
32293
- import { join as join88 } from "path";
32403
+ import { mkdirSync as mkdirSync30 } from "fs";
32404
+ import { join as join89 } from "path";
32294
32405
 
32295
32406
  // src/commands/voice/checkLockFile.ts
32296
32407
  import { execSync as execSync58 } from "child_process";
32297
- import { existsSync as existsSync75, mkdirSync as mkdirSync28, readFileSync as readFileSync57, writeFileSync as writeFileSync46 } from "fs";
32298
- import { join as join87 } from "path";
32408
+ import { existsSync as existsSync75, mkdirSync as mkdirSync29, readFileSync as readFileSync57, writeFileSync as writeFileSync47 } from "fs";
32409
+ import { join as join88 } from "path";
32299
32410
  function isProcessAlive2(pid) {
32300
32411
  try {
32301
32412
  process.kill(pid, 0);
@@ -32332,8 +32443,8 @@ function bootstrapVenv() {
32332
32443
  }
32333
32444
  function writeLockFile(pid) {
32334
32445
  const lockFile = getLockFile();
32335
- mkdirSync28(join87(lockFile, ".."), { recursive: true });
32336
- writeFileSync46(
32446
+ mkdirSync29(join88(lockFile, ".."), { recursive: true });
32447
+ writeFileSync47(
32337
32448
  lockFile,
32338
32449
  JSON.stringify({
32339
32450
  pid,
@@ -32345,10 +32456,10 @@ function writeLockFile(pid) {
32345
32456
 
32346
32457
  // src/commands/voice/setup.ts
32347
32458
  function setup() {
32348
- mkdirSync29(voicePaths.dir, { recursive: true });
32459
+ mkdirSync30(voicePaths.dir, { recursive: true });
32349
32460
  bootstrapVenv();
32350
32461
  console.log("\nDownloading models...\n");
32351
- const script = join88(getPythonDir(), "setup_models.py");
32462
+ const script = join89(getPythonDir(), "setup_models.py");
32352
32463
  const result = spawnSync10(getVenvPython(), [script], {
32353
32464
  stdio: "inherit",
32354
32465
  env: { ...process.env, VOICE_LOG_FILE: voicePaths.log }
@@ -32361,8 +32472,8 @@ function setup() {
32361
32472
 
32362
32473
  // src/commands/voice/start.ts
32363
32474
  import { spawn as spawn8 } from "child_process";
32364
- import { mkdirSync as mkdirSync30, writeFileSync as writeFileSync47 } from "fs";
32365
- import { join as join89 } from "path";
32475
+ import { mkdirSync as mkdirSync31, writeFileSync as writeFileSync48 } from "fs";
32476
+ import { join as join90 } from "path";
32366
32477
 
32367
32478
  // src/commands/voice/buildDaemonEnv.ts
32368
32479
  function buildDaemonEnv(options2) {
@@ -32390,17 +32501,17 @@ function spawnBackground(python, script, env) {
32390
32501
  console.error("Failed to start voice daemon");
32391
32502
  process.exit(1);
32392
32503
  }
32393
- writeFileSync47(voicePaths.pid, String(pid));
32504
+ writeFileSync48(voicePaths.pid, String(pid));
32394
32505
  writeLockFile(pid);
32395
32506
  console.log(`Voice daemon started (PID ${pid})`);
32396
32507
  }
32397
32508
  function start2(options2) {
32398
- mkdirSync30(voicePaths.dir, { recursive: true });
32509
+ mkdirSync31(voicePaths.dir, { recursive: true });
32399
32510
  checkLockFile();
32400
32511
  bootstrapVenv();
32401
32512
  const debug = options2.debug || options2.foreground || process.platform === "win32";
32402
32513
  const env = buildDaemonEnv({ debug });
32403
- const script = join89(getPythonDir(), "voice_daemon.py");
32514
+ const script = join90(getPythonDir(), "voice_daemon.py");
32404
32515
  const python = getVenvPython();
32405
32516
  if (options2.foreground) {
32406
32517
  spawnForeground(python, script, env);
@@ -32531,11 +32642,11 @@ function changedPaths(from, cwd) {
32531
32642
  }
32532
32643
 
32533
32644
  // src/commands/watch/readBuiltVersion.ts
32534
- import { join as join90 } from "path";
32645
+ import { join as join91 } from "path";
32535
32646
  function readBuiltVersion(cwd) {
32536
32647
  try {
32537
32648
  const root = runGit3(["rev-parse", "--show-toplevel"], cwd);
32538
- return readPackageJson(join90(root, "package.json")).version ?? "unknown";
32649
+ return readPackageJson(join91(root, "package.json")).version ?? "unknown";
32539
32650
  } catch {
32540
32651
  return "unknown";
32541
32652
  }
@@ -32896,13 +33007,13 @@ import { existsSync as existsSync80 } from "fs";
32896
33007
  // src/commands/run/resolveCommand.ts
32897
33008
  import { execFileSync as execFileSync16 } from "child_process";
32898
33009
  import { existsSync as existsSync79 } from "fs";
32899
- import { dirname as dirname37, join as join91, resolve as resolve20 } from "path";
33010
+ import { dirname as dirname37, join as join92, resolve as resolve20 } from "path";
32900
33011
  function resolveCommand2(command) {
32901
33012
  if (process.platform !== "win32" || command !== "bash") return command;
32902
33013
  try {
32903
33014
  const gitPath = execFileSync16("where", ["git"], { encoding: "utf8" }).trim().split("\r\n")[0];
32904
33015
  const gitRoot = resolve20(dirname37(gitPath), "..");
32905
- const gitBash = join91(gitRoot, "bin", "bash.exe");
33016
+ const gitBash = join92(gitRoot, "bin", "bash.exe");
32906
33017
  if (existsSync79(gitBash)) return gitBash;
32907
33018
  } catch {
32908
33019
  return command;
@@ -33330,7 +33441,7 @@ async function auth() {
33330
33441
  // src/commands/roam/postRoamActivity.ts
33331
33442
  import { execFileSync as execFileSync18 } from "child_process";
33332
33443
  import { readdirSync as readdirSync21, readFileSync as readFileSync60, statSync as statSync12 } from "fs";
33333
- import { join as join92 } from "path";
33444
+ import { join as join93 } from "path";
33334
33445
  function findPortFile(roamDir) {
33335
33446
  let entries;
33336
33447
  try {
@@ -33339,7 +33450,7 @@ function findPortFile(roamDir) {
33339
33450
  return void 0;
33340
33451
  }
33341
33452
  const candidates = entries.filter((name) => /^roam-local-api(-[^.]+)?\.port$/.test(name)).map((name) => {
33342
- const path90 = join92(roamDir, name);
33453
+ const path90 = join93(roamDir, name);
33343
33454
  try {
33344
33455
  return { path: path90, mtimeMs: statSync12(path90).mtimeMs };
33345
33456
  } catch {
@@ -33356,7 +33467,7 @@ var PID_BY_APP = {
33356
33467
  function postRoamActivity(app, event) {
33357
33468
  const appData = process.env.APPDATA;
33358
33469
  if (!appData) return;
33359
- const portFile = findPortFile(join92(appData, "Roam"));
33470
+ const portFile = findPortFile(join93(appData, "Roam"));
33360
33471
  if (!portFile) return;
33361
33472
  let port;
33362
33473
  try {
@@ -33491,8 +33602,8 @@ async function run3(name, args) {
33491
33602
  }
33492
33603
 
33493
33604
  // src/commands/run/add.ts
33494
- import { mkdirSync as mkdirSync31, writeFileSync as writeFileSync48 } from "fs";
33495
- import { join as join93 } from "path";
33605
+ import { mkdirSync as mkdirSync32, writeFileSync as writeFileSync49 } from "fs";
33606
+ import { join as join94 } from "path";
33496
33607
 
33497
33608
  // src/commands/run/extractOption.ts
33498
33609
  function extractOption(args, flag) {
@@ -33553,16 +33664,16 @@ function saveNewRunConfig(name, command, args, cwd) {
33553
33664
  saveConfig(config);
33554
33665
  }
33555
33666
  function createCommandFile(name) {
33556
- const dir = join93(".claude", "commands");
33557
- mkdirSync31(dir, { recursive: true });
33667
+ const dir = join94(".claude", "commands");
33668
+ mkdirSync32(dir, { recursive: true });
33558
33669
  const content = `---
33559
33670
  description: Run ${name}
33560
33671
  ---
33561
33672
 
33562
33673
  Run \`assist run ${name} $ARGUMENTS 2>&1\`.
33563
33674
  `;
33564
- const filePath = join93(dir, `${name}.md`);
33565
- writeFileSync48(filePath, content);
33675
+ const filePath = join94(dir, `${name}.md`);
33676
+ writeFileSync49(filePath, content);
33566
33677
  console.log(`Created command file: ${filePath}`);
33567
33678
  }
33568
33679
  function add3() {
@@ -33618,7 +33729,7 @@ function link2() {
33618
33729
 
33619
33730
  // src/commands/run/remove.ts
33620
33731
  import { existsSync as existsSync81, unlinkSync as unlinkSync21 } from "fs";
33621
- import { join as join94 } from "path";
33732
+ import { join as join95 } from "path";
33622
33733
  function findRemoveIndex() {
33623
33734
  const idx = process.argv.indexOf("remove");
33624
33735
  if (idx === -1 || idx + 1 >= process.argv.length) return -1;
@@ -33633,7 +33744,7 @@ function parseRemoveName() {
33633
33744
  return process.argv[idx + 1];
33634
33745
  }
33635
33746
  function deleteCommandFile(name) {
33636
- const filePath = join94(".claude", "commands", `${name}.md`);
33747
+ const filePath = join95(".claude", "commands", `${name}.md`);
33637
33748
  if (existsSync81(filePath)) {
33638
33749
  unlinkSync21(filePath);
33639
33750
  console.log(`Deleted command file: ${filePath}`);
@@ -33679,9 +33790,9 @@ function registerRun(program2) {
33679
33790
 
33680
33791
  // src/commands/screenshot/index.ts
33681
33792
  import { execSync as execSync60 } from "child_process";
33682
- import { existsSync as existsSync82, mkdirSync as mkdirSync32, unlinkSync as unlinkSync22, writeFileSync as writeFileSync49 } from "fs";
33793
+ import { existsSync as existsSync82, mkdirSync as mkdirSync33, unlinkSync as unlinkSync22, writeFileSync as writeFileSync50 } from "fs";
33683
33794
  import { tmpdir as tmpdir9 } from "os";
33684
- import { join as join95, resolve as resolve21 } from "path";
33795
+ import { join as join96, resolve as resolve21 } from "path";
33685
33796
  import chalk227 from "chalk";
33686
33797
 
33687
33798
  // src/commands/screenshot/captureWindowPs1.ts
@@ -33812,14 +33923,14 @@ Write-Output $OutputPath
33812
33923
  // src/commands/screenshot/index.ts
33813
33924
  function buildOutputPath(outputDir, processName) {
33814
33925
  if (!existsSync82(outputDir)) {
33815
- mkdirSync32(outputDir, { recursive: true });
33926
+ mkdirSync33(outputDir, { recursive: true });
33816
33927
  }
33817
33928
  const timestamp6 = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
33818
33929
  return resolve21(outputDir, `${processName}-${timestamp6}.png`);
33819
33930
  }
33820
33931
  function runPowerShellScript(processName, outputPath) {
33821
- const scriptPath = join95(tmpdir9(), `assist-screenshot-${Date.now()}.ps1`);
33822
- writeFileSync49(scriptPath, captureWindowPs1, "utf8");
33932
+ const scriptPath = join96(tmpdir9(), `assist-screenshot-${Date.now()}.ps1`);
33933
+ writeFileSync50(scriptPath, captureWindowPs1, "utf8");
33823
33934
  try {
33824
33935
  execSync60(
33825
33936
  `powershell -NoProfile -ExecutionPolicy Bypass -File "${scriptPath}" -ProcessName "${processName}" -OutputPath "${outputPath}"`,
@@ -34052,7 +34163,7 @@ function requestDrain(socket, lines2) {
34052
34163
  }
34053
34164
 
34054
34165
  // src/commands/sessions/daemon/runDaemon.ts
34055
- import { mkdirSync as mkdirSync36 } from "fs";
34166
+ import { mkdirSync as mkdirSync37 } from "fs";
34056
34167
 
34057
34168
  // src/commands/sessions/daemon/createAutoExit.ts
34058
34169
  var DEFAULT_GRACE_MS = 6e4;
@@ -34306,7 +34417,7 @@ var ClientHub = class extends Set {
34306
34417
  };
34307
34418
 
34308
34419
  // src/commands/sessions/daemon/createSession.ts
34309
- import { randomUUID as randomUUID17 } from "crypto";
34420
+ import { randomUUID as randomUUID18 } from "crypto";
34310
34421
 
34311
34422
  // src/commands/sessions/daemon/sessionBase.ts
34312
34423
  function sessionBase(id, status3) {
@@ -34502,7 +34613,7 @@ function spawnRun(opts) {
34502
34613
  function createSession(id, { prompt, cwd, design, auto, harness, holdPty } = {}) {
34503
34614
  if (harness && harness !== "claude")
34504
34615
  return createHarnessSession(id, harness, prompt, cwd, holdPty);
34505
- const claudeSessionId = randomUUID17();
34616
+ const claudeSessionId = randomUUID18();
34506
34617
  return {
34507
34618
  ...sessionBase(id, prompt ? "running" : "waiting"),
34508
34619
  name: `Session ${id}`,
@@ -34567,12 +34678,12 @@ import { basename as basename22 } from "path";
34567
34678
 
34568
34679
  // src/commands/sessions/daemon/worktree/deleteStrandedTree.ts
34569
34680
  import { existsSync as existsSync86 } from "fs";
34570
- import { join as join98 } from "path";
34681
+ import { join as join99 } from "path";
34571
34682
 
34572
34683
  // src/commands/sessions/daemon/worktree/deleteTreeDirectly.ts
34573
34684
  import { statSync as statSync14 } from "fs";
34574
34685
  import { rm as rm4 } from "fs/promises";
34575
- import { join as join97 } from "path";
34686
+ import { join as join98 } from "path";
34576
34687
  async function deleteTreeDirectly(clone, worktreePath, why) {
34577
34688
  if (holdsAGitDirectoryRatherThanALink(worktreePath)) {
34578
34689
  const refusal = "it is a clone of its own, not a linked worktree";
@@ -34600,7 +34711,7 @@ async function deleteTreeDirectly(clone, worktreePath, why) {
34600
34711
  return { removed: true };
34601
34712
  }
34602
34713
  function holdsAGitDirectoryRatherThanALink(worktreePath) {
34603
- return statSync14(join97(worktreePath, ".git"), {
34714
+ return statSync14(join98(worktreePath, ".git"), {
34604
34715
  throwIfNoEntry: false
34605
34716
  })?.isDirectory() === true;
34606
34717
  }
@@ -34636,7 +34747,7 @@ async function deleteStrandedTree(clone, worktreePath, cause) {
34636
34747
  );
34637
34748
  }
34638
34749
  function strandedReason(worktreePath, cause) {
34639
- if (!existsSync86(join98(worktreePath, ".git")))
34750
+ if (!existsSync86(join99(worktreePath, ".git")))
34640
34751
  return "its .git link is already gone";
34641
34752
  if (/not a working tree|not a git repository/i.test(reason2(cause)))
34642
34753
  return "git no longer recognises it as a working tree";
@@ -35102,7 +35213,8 @@ var PREVIEW_KINDS = [
35102
35213
  "github-issue",
35103
35214
  "github-issue-comment",
35104
35215
  "github-issue-edit",
35105
- "miro-board"
35216
+ "miro-board",
35217
+ "slack-post"
35106
35218
  ];
35107
35219
  function isPreviewKind(value) {
35108
35220
  return PREVIEW_KINDS.includes(value);
@@ -35126,6 +35238,7 @@ function previewTargetLabel(kind, itemType, prNumber, draft) {
35126
35238
  if (kind === "github-issue-edit") return "github issue edit";
35127
35239
  if (kind === "github-issue") return "github issue";
35128
35240
  if (kind === "miro-board") return "miro anchors";
35241
+ if (kind === "slack-post") return "slack post";
35129
35242
  if (kind === "backlog-item") return `backlog ${itemType}`;
35130
35243
  if (prNumber !== null) return `edit #${prNumber}`;
35131
35244
  return draft ? "create draft" : "create";
@@ -35395,7 +35508,7 @@ function handleFailedResume(session, exitCode, onStatusChange) {
35395
35508
  }
35396
35509
 
35397
35510
  // src/commands/sessions/daemon/watchActivity.ts
35398
- import { existsSync as existsSync90, mkdirSync as mkdirSync33, watch as watch2 } from "fs";
35511
+ import { existsSync as existsSync90, mkdirSync as mkdirSync34, watch as watch2 } from "fs";
35399
35512
  import { dirname as dirname39 } from "path";
35400
35513
 
35401
35514
  // src/commands/sessions/daemon/applyActivityToSession.ts
@@ -35460,7 +35573,7 @@ function watchActivity(session, notify2, onClaudeSessionId) {
35460
35573
  const path90 = activityPath(session.id);
35461
35574
  const dir = dirname39(path90);
35462
35575
  try {
35463
- mkdirSync33(dir, { recursive: true });
35576
+ mkdirSync34(dir, { recursive: true });
35464
35577
  } catch {
35465
35578
  return;
35466
35579
  }
@@ -35663,10 +35776,10 @@ function headContainsSessionId(filePath, claudeSessionId) {
35663
35776
  }
35664
35777
 
35665
35778
  // src/commands/sessions/daemon/ensureProjectDirExists.ts
35666
- import { mkdirSync as mkdirSync34 } from "fs";
35779
+ import { mkdirSync as mkdirSync35 } from "fs";
35667
35780
  function ensureProjectDirExists(dir, sessionId) {
35668
35781
  try {
35669
- mkdirSync34(dir, { recursive: true });
35782
+ mkdirSync35(dir, { recursive: true });
35670
35783
  return true;
35671
35784
  } catch (error) {
35672
35785
  daemonLog(
@@ -36615,7 +36728,7 @@ function codexRespawnPlan(session) {
36615
36728
  }
36616
36729
 
36617
36730
  // src/commands/sessions/daemon/interactiveRespawnPlan.ts
36618
- import { randomUUID as randomUUID18 } from "crypto";
36731
+ import { randomUUID as randomUUID19 } from "crypto";
36619
36732
  function interactiveRespawnPlan(session, resumes) {
36620
36733
  const { claudeSessionId, cwd, initialPrompt, design, auto } = session;
36621
36734
  if (!resumes) return null;
@@ -36635,7 +36748,7 @@ function interactiveRespawnPlan(session, resumes) {
36635
36748
  return null;
36636
36749
  }
36637
36750
  function freshClaudePlan(session, prompt, cwd) {
36638
- const claudeSessionId = randomUUID18();
36751
+ const claudeSessionId = randomUUID19();
36639
36752
  return {
36640
36753
  spawn: () => {
36641
36754
  session.claudeSessionId = claudeSessionId;
@@ -37520,10 +37633,10 @@ function startReusedRunPty(session, assistArgs, itemId2, hold, clients, onStatus
37520
37633
  }
37521
37634
 
37522
37635
  // src/commands/sessions/daemon/createWatcherSession.ts
37523
- import { randomUUID as randomUUID19 } from "crypto";
37636
+ import { randomUUID as randomUUID20 } from "crypto";
37524
37637
  var WATCH_PROMPT = "/watch";
37525
37638
  function createWatcherSession(id, cwd) {
37526
- const claudeSessionId = randomUUID19();
37639
+ const claudeSessionId = randomUUID20();
37527
37640
  return {
37528
37641
  ...sessionBase(id, "running"),
37529
37642
  name: `Session ${id}`,
@@ -38747,8 +38860,8 @@ function resumeSession(id, sessionId, cwd, name, holdPty, harness) {
38747
38860
  import { existsSync as existsSync96 } from "fs";
38748
38861
 
38749
38862
  // src/commands/sessions/daemon/worktree/carryTranscriptToTree.ts
38750
- import { copyFileSync as copyFileSync7, existsSync as existsSync95, mkdirSync as mkdirSync35 } from "fs";
38751
- import { join as join100 } from "path";
38863
+ import { copyFileSync as copyFileSync7, existsSync as existsSync95, mkdirSync as mkdirSync36 } from "fs";
38864
+ import { join as join101 } from "path";
38752
38865
  function carryTranscriptToTree(claudeSessionId, fromCwd, toCwd) {
38753
38866
  const dir = projectDirForCwd(toCwd);
38754
38867
  if (dir === projectDirForCwd(fromCwd)) {
@@ -38757,7 +38870,7 @@ function carryTranscriptToTree(claudeSessionId, fromCwd, toCwd) {
38757
38870
  );
38758
38871
  return;
38759
38872
  }
38760
- const dest = join100(dir, `${claudeSessionId}.jsonl`);
38873
+ const dest = join101(dir, `${claudeSessionId}.jsonl`);
38761
38874
  if (existsSync95(dest)) {
38762
38875
  daemonLog(`transcript ${claudeSessionId} already present in ${dir}`);
38763
38876
  return;
@@ -38770,7 +38883,7 @@ function carryTranscriptToTree(claudeSessionId, fromCwd, toCwd) {
38770
38883
  return;
38771
38884
  }
38772
38885
  try {
38773
- mkdirSync35(dir, { recursive: true });
38886
+ mkdirSync36(dir, { recursive: true });
38774
38887
  copyFileSync7(source, dest);
38775
38888
  daemonLog(
38776
38889
  `transcript ${source} copied to ${dest} so ${toCwd} can resume it`
@@ -39395,7 +39508,7 @@ function handleConnection(socket, manager) {
39395
39508
  }
39396
39509
 
39397
39510
  // src/commands/sessions/daemon/onListening.ts
39398
- import { unlinkSync as unlinkSync23, writeFileSync as writeFileSync50 } from "fs";
39511
+ import { unlinkSync as unlinkSync23, writeFileSync as writeFileSync51 } from "fs";
39399
39512
 
39400
39513
  // src/commands/sessions/daemon/startPidFileWatchdog.ts
39401
39514
  import { readFileSync as readFileSync64 } from "fs";
@@ -39417,7 +39530,7 @@ function ownsPidFile() {
39417
39530
 
39418
39531
  // src/commands/sessions/daemon/onListening.ts
39419
39532
  function onListening(manager, checkAutoExit) {
39420
- writeFileSync50(daemonPaths.pid, String(process.pid));
39533
+ writeFileSync51(daemonPaths.pid, String(process.pid));
39421
39534
  startPidFileWatchdog(() => {
39422
39535
  daemonLog("lost daemon.pid ownership; shutting down sessions and exiting");
39423
39536
  void manager.flushActiveMs().finally(() => {
@@ -39604,7 +39717,7 @@ async function recoverFromAddrInUse(server, manager, checkAutoExit) {
39604
39717
 
39605
39718
  // src/commands/sessions/daemon/runDaemon.ts
39606
39719
  async function runDaemon() {
39607
- mkdirSync36(daemonPaths.dir, { recursive: true });
39720
+ mkdirSync37(daemonPaths.dir, { recursive: true });
39608
39721
  daemonLog(
39609
39722
  `starting (reason: ${process.env.ASSIST_DAEMON_SPAWN_REASON ?? "manual"})`
39610
39723
  );
@@ -39884,9 +39997,9 @@ function buildLimitsSegment(rateLimits) {
39884
39997
 
39885
39998
  // src/commands/readGitBranch.ts
39886
39999
  import { readFileSync as readFileSync66, statSync as statSync16 } from "fs";
39887
- import { isAbsolute as isAbsolute5, join as join101, resolve as resolve23 } from "path";
40000
+ import { isAbsolute as isAbsolute5, join as join102, resolve as resolve23 } from "path";
39888
40001
  function resolveGitDir(cwd) {
39889
- const dotGit = join101(cwd, ".git");
40002
+ const dotGit = join102(cwd, ".git");
39890
40003
  let stat4;
39891
40004
  try {
39892
40005
  stat4 = statSync16(dotGit);
@@ -39916,7 +40029,7 @@ function readGitBranch(cwd) {
39916
40029
  }
39917
40030
  let head;
39918
40031
  try {
39919
- head = readFileSync66(join101(gitDir, "HEAD"), "utf8");
40032
+ head = readFileSync66(join102(gitDir, "HEAD"), "utf8");
39920
40033
  } catch {
39921
40034
  return null;
39922
40035
  }
@@ -40106,6 +40219,7 @@ registerNetcap(program);
40106
40219
  registerCriteriaExtension(program);
40107
40220
  registerRavendb(program);
40108
40221
  registerSeq(program);
40222
+ registerSlack(program);
40109
40223
  registerSql(program);
40110
40224
  registerTranscript(program);
40111
40225
  registerVoice(program);