@staff0rd/assist 0.565.1 → 0.566.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.565.1",
9
+ version: "0.566.0",
10
10
  type: "module",
11
11
  main: "dist/index.js",
12
12
  bin: {
@@ -468,6 +468,9 @@ var DEFAULT_MODELS_DIR = "~/.assist/voice/models";
468
468
  var DEFAULT_BACKUP_DIR = "~/.assist/backups";
469
469
  var DEFAULT_CLONE_DIR = "~/git";
470
470
  var assistConfigShape = {
471
+ backlog: z3.strictObject({
472
+ previewComments: z3.boolean().default(false)
473
+ }).optional(),
471
474
  backup: z3.strictObject({
472
475
  dir: z3.string().default(DEFAULT_BACKUP_DIR)
473
476
  }).default({ dir: DEFAULT_BACKUP_DIR }),
@@ -4329,6 +4332,11 @@ var backlogConfigHelp = [
4329
4332
  setter: 'assist config set subtasks.0.title "Review"',
4330
4333
  note: "default sub-tasks seeded onto every new backlog item"
4331
4334
  },
4335
+ {
4336
+ key: "backlog.previewComments",
4337
+ setter: "assist config set backlog.previewComments true",
4338
+ note: "review 'backlog comment' in the web preview pane before it is written (default: off)"
4339
+ },
4332
4340
  {
4333
4341
  key: "clone.baseDir",
4334
4342
  setter: "assist config set clone.baseDir ~/git",
@@ -12568,6 +12576,11 @@ function applyScopedConfigSet(key, value, cwd, scope, globalConfigPath) {
12568
12576
  return result.ok ? { ok: true, payload: { target: result.target } } : result;
12569
12577
  }
12570
12578
 
12579
+ // src/commands/config/writesGlobalConfigFile.ts
12580
+ function writesGlobalConfigFile(scope) {
12581
+ return scope !== "project";
12582
+ }
12583
+
12571
12584
  // src/commands/config/ConfigWriteScope.ts
12572
12585
  function isConfigWriteScope(value) {
12573
12586
  return value === "project" || value === "global" || value === "repo";
@@ -12599,7 +12612,7 @@ async function handleConfigWrite(req, res, apply) {
12599
12612
  return;
12600
12613
  }
12601
12614
  const target = globalConfigTargetFor(parsed.cwd);
12602
- if (!target.ok) {
12615
+ if (!target.ok && writesGlobalConfigFile(parsed.scope)) {
12603
12616
  respondJson(res, 400, { error: target.error, errors: [target.error] });
12604
12617
  return;
12605
12618
  }
@@ -12607,7 +12620,7 @@ async function handleConfigWrite(req, res, apply) {
12607
12620
  const result = apply({
12608
12621
  ...parsed,
12609
12622
  cwd: toGitCwd(parsed.cwd),
12610
- globalConfigPath: target.path
12623
+ globalConfigPath: target.ok ? target.path : void 0
12611
12624
  });
12612
12625
  if (!result.ok) {
12613
12626
  respondJson(res, 400, {
@@ -13986,6 +13999,7 @@ async function awaitPreviewApproval(subject, request) {
13986
13999
 
13987
14000
  // src/commands/backlog/comment/reviewProposedComment.ts
13988
14001
  async function reviewProposedComment(item, text18) {
14002
+ if (loadConfig().backlog?.previewComments !== true) return;
13989
14003
  const sessionId = process.env.ASSIST_SESSION_ID;
13990
14004
  if (process.env.ASSIST_SESSION !== "1" || !sessionId) return;
13991
14005
  await awaitPreviewApproval("Backlog comment preview", {
@@ -22694,6 +22708,44 @@ function registerPrompts(program2) {
22694
22708
  program2.command("prompts").description("Show top denied tool calls by frequency").action(prompts2);
22695
22709
  }
22696
22710
 
22711
+ // src/commands/prs/postReviewComment.ts
22712
+ var MUTATION_SINGLE = `mutation($prId: ID!, $body: String!, $path: String!, $line: Int!) { addPullRequestReviewThread(input: { pullRequestId: $prId, body: $body, path: $path, line: $line, side: RIGHT }) { thread { id } } }`;
22713
+ var MUTATION_MULTI = `mutation($prId: ID!, $body: String!, $path: String!, $line: Int!, $startLine: Int!) { addPullRequestReviewThread(input: { pullRequestId: $prId, body: $body, path: $path, line: $line, startLine: $startLine, side: RIGHT, startSide: RIGHT }) { thread { id } } }`;
22714
+ function assertThreadCreated(stdout) {
22715
+ let parsed;
22716
+ try {
22717
+ parsed = JSON.parse(stdout);
22718
+ } catch {
22719
+ throw new Error(`GitHub returned an unparseable response: ${stdout}`);
22720
+ }
22721
+ const id = parsed.data?.addPullRequestReviewThread?.thread?.id;
22722
+ if (typeof id !== "string" || id.length === 0) {
22723
+ throw new Error(
22724
+ "GitHub did not create a review thread (no thread id returned); the line is likely outside the PR diff."
22725
+ );
22726
+ }
22727
+ }
22728
+ function postReviewComment(vars) {
22729
+ const { startLine, ...base } = vars;
22730
+ const stdout = startLine === void 0 ? runGhGraphql(MUTATION_SINGLE, base) : runGhGraphql(MUTATION_MULTI, { ...base, startLine });
22731
+ assertThreadCreated(stdout);
22732
+ }
22733
+
22734
+ // src/commands/prs/reviewProposedPrComment.ts
22735
+ import { randomUUID as randomUUID9 } from "crypto";
22736
+ async function reviewProposedPrComment(title, body, prNumber) {
22737
+ const sessionId = process.env.ASSIST_SESSION_ID;
22738
+ if (process.env.ASSIST_SESSION !== "1" || !sessionId) return;
22739
+ await awaitPreviewApproval("PR comment preview", {
22740
+ sessionId,
22741
+ requestId: randomUUID9(),
22742
+ title,
22743
+ body,
22744
+ prNumber,
22745
+ kind: "pr-comment"
22746
+ });
22747
+ }
22748
+
22697
22749
  // src/commands/prs/shared.ts
22698
22750
  import { execSync as execSync43 } from "child_process";
22699
22751
  function isGhNotInstalled(error) {
@@ -22778,8 +22830,6 @@ function findCurrentPrNumber() {
22778
22830
  }
22779
22831
 
22780
22832
  // src/commands/prs/comment.ts
22781
- var MUTATION_SINGLE = `mutation($prId: ID!, $body: String!, $path: String!, $line: Int!) { addPullRequestReviewThread(input: { pullRequestId: $prId, body: $body, path: $path, line: $line, side: RIGHT }) { thread { id } } }`;
22782
- var MUTATION_MULTI = `mutation($prId: ID!, $body: String!, $path: String!, $line: Int!, $startLine: Int!) { addPullRequestReviewThread(input: { pullRequestId: $prId, body: $body, path: $path, line: $line, startLine: $startLine, side: RIGHT, startSide: RIGHT }) { thread { id } } }`;
22783
22833
  function validateBody(body) {
22784
22834
  const lower = body.toLowerCase();
22785
22835
  if (lower.includes("claude") || lower.includes("opus")) {
@@ -22793,33 +22843,15 @@ function validateLine(line) {
22793
22843
  process.exit(1);
22794
22844
  }
22795
22845
  }
22796
- function assertThreadCreated(stdout) {
22797
- let parsed;
22798
- try {
22799
- parsed = JSON.parse(stdout);
22800
- } catch {
22801
- throw new Error(`GitHub returned an unparseable response: ${stdout}`);
22802
- }
22803
- const id = parsed.data?.addPullRequestReviewThread?.thread?.id;
22804
- if (typeof id !== "string" || id.length === 0) {
22805
- throw new Error(
22806
- "GitHub did not create a review thread (no thread id returned); the line is likely outside the PR diff."
22807
- );
22808
- }
22809
- }
22810
- function postComment(vars) {
22811
- const { startLine, ...base } = vars;
22812
- const stdout = startLine === void 0 ? runGhGraphql(MUTATION_SINGLE, base) : runGhGraphql(MUTATION_MULTI, { ...base, startLine });
22813
- assertThreadCreated(stdout);
22814
- }
22815
- function comment2(path80, line, body, startLine) {
22846
+ async function comment2(path80, line, body, startLine) {
22816
22847
  validateBody(body);
22817
22848
  validateLine(line);
22818
22849
  if (startLine !== void 0) validateLine(startLine);
22850
+ const range = startLine !== void 0 ? `${startLine}-${line}` : `${line}`;
22851
+ await reviewProposedPrComment(`Comment on ${path80}:${range}`, body, null);
22819
22852
  try {
22820
22853
  const prId = getCurrentPrNodeId();
22821
- postComment({ prId, body, path: path80, line, startLine });
22822
- const range = startLine !== void 0 ? `${startLine}-${line}` : `${line}`;
22854
+ postReviewComment({ prId, body, path: path80, line, startLine });
22823
22855
  console.log(`Added review comment on ${path80}:${range}`);
22824
22856
  } catch (error) {
22825
22857
  if (isGhNotInstalled(error)) {
@@ -22832,7 +22864,7 @@ function comment2(path80, line, body, startLine) {
22832
22864
  }
22833
22865
 
22834
22866
  // src/commands/prs/edit.ts
22835
- import { randomUUID as randomUUID9 } from "crypto";
22867
+ import { randomUUID as randomUUID10 } from "crypto";
22836
22868
 
22837
22869
  // src/commands/prs/appendScreenshots.ts
22838
22870
  function appendScreenshots(body, screenshots) {
@@ -23046,7 +23078,7 @@ async function edit(options2) {
23046
23078
  if (process.env.ASSIST_SESSION === "1" && sessionId) {
23047
23079
  const decision = await awaitPreviewApproval("PR preview", {
23048
23080
  sessionId,
23049
- requestId: randomUUID9(),
23081
+ requestId: randomUUID10(),
23050
23082
  title: options2.title ?? title,
23051
23083
  body: newBody,
23052
23084
  prNumber: number
@@ -23757,7 +23789,7 @@ async function placePr(prNumber, title, body, options2) {
23757
23789
  }
23758
23790
 
23759
23791
  // src/commands/prs/previewAndPlace.ts
23760
- import { randomUUID as randomUUID10 } from "crypto";
23792
+ import { randomUUID as randomUUID11 } from "crypto";
23761
23793
 
23762
23794
  // src/commands/sessions/shared/requestSession.ts
23763
23795
  function parseIncoming(line, type) {
@@ -23892,7 +23924,7 @@ function warn(reason4) {
23892
23924
  async function previewAndPlace(args) {
23893
23925
  const decision = await awaitPreviewApproval("PR preview", {
23894
23926
  sessionId: args.sessionId,
23895
- requestId: randomUUID10(),
23927
+ requestId: randomUUID11(),
23896
23928
  title: args.title,
23897
23929
  body: args.body,
23898
23930
  prNumber: args.prNumber,
@@ -23945,8 +23977,9 @@ function validateBody2(body) {
23945
23977
  process.exit(1);
23946
23978
  }
23947
23979
  }
23948
- function reply(commentId, body) {
23980
+ async function reply(commentId, body) {
23949
23981
  validateBody2(body);
23982
+ await reviewProposedPrComment(`Reply to comment #${commentId}`, body, null);
23950
23983
  try {
23951
23984
  const prNumber = getCurrentPrNumber();
23952
23985
  const { org, repo } = getRepoInfo();
@@ -23992,9 +24025,14 @@ function validateShaReferences(reason4) {
23992
24025
  process.exit(1);
23993
24026
  }
23994
24027
  }
23995
- function wontfix(commentId, reason4) {
24028
+ async function wontfix(commentId, reason4) {
23996
24029
  validateReason(reason4);
23997
24030
  validateShaReferences(reason4);
24031
+ await reviewProposedPrComment(
24032
+ `Won't fix comment #${commentId}`,
24033
+ reason4,
24034
+ null
24035
+ );
23998
24036
  try {
23999
24037
  resolveCommentWithReply(commentId, reason4);
24000
24038
  } catch (error) {
@@ -24029,7 +24067,7 @@ function registerPrsComments(prsCommand) {
24029
24067
  prsCommand.command("wontfix <comment-id> <reason>").description(
24030
24068
  "Reply with reason and resolve thread (reason of - reads it from stdin)"
24031
24069
  ).action(async (commentId, reason4) => {
24032
- wontfix(
24070
+ await wontfix(
24033
24071
  Number.parseInt(commentId, 10),
24034
24072
  await readBodyArgument(reason4)
24035
24073
  );
@@ -24037,12 +24075,19 @@ function registerPrsComments(prsCommand) {
24037
24075
  prsCommand.command("reply <comment-id> <body>").description(
24038
24076
  "Reply to a comment thread without resolving it (body of - reads it from stdin)"
24039
24077
  ).action(async (commentId, body) => {
24040
- reply(Number.parseInt(commentId, 10), await readBodyArgument(body));
24078
+ await reply(
24079
+ Number.parseInt(commentId, 10),
24080
+ await readBodyArgument(body)
24081
+ );
24041
24082
  });
24042
24083
  prsCommand.command("comment <path> <line> <body>").description(
24043
24084
  "Add a line comment to the pending review (body of - reads it from stdin)"
24044
24085
  ).action(async (path80, line, body) => {
24045
- comment2(path80, Number.parseInt(line, 10), await readBodyArgument(body));
24086
+ await comment2(
24087
+ path80,
24088
+ Number.parseInt(line, 10),
24089
+ await readBodyArgument(body)
24090
+ );
24046
24091
  });
24047
24092
  }
24048
24093
 
@@ -26362,10 +26407,10 @@ function registerRefactor(program2) {
26362
26407
  }
26363
26408
 
26364
26409
  // src/commands/review/checkoutOnlySession.ts
26365
- import { randomUUID as randomUUID11 } from "crypto";
26410
+ import { randomUUID as randomUUID12 } from "crypto";
26366
26411
  async function checkoutOnlySession(number) {
26367
26412
  await checkoutPr(number);
26368
- const claudeSessionId = randomUUID11();
26413
+ const claudeSessionId = randomUUID12();
26369
26414
  emitActivity({ kind: "command", name: "review", claudeSessionId });
26370
26415
  const { done: done2 } = spawnClaude("", {
26371
26416
  permissionMode: "acceptEdits",
@@ -31727,7 +31772,7 @@ var ClientHub = class extends Set {
31727
31772
  };
31728
31773
 
31729
31774
  // src/commands/sessions/daemon/createSession.ts
31730
- import { randomUUID as randomUUID12 } from "crypto";
31775
+ import { randomUUID as randomUUID13 } from "crypto";
31731
31776
 
31732
31777
  // src/commands/sessions/daemon/sessionBase.ts
31733
31778
  function sessionBase(id, status3) {
@@ -31923,7 +31968,7 @@ function spawnRun(opts) {
31923
31968
  function createSession(id, prompt, cwd, design, harness, holdPty) {
31924
31969
  if (harness && harness !== "claude")
31925
31970
  return createHarnessSession(id, harness, prompt, cwd, holdPty);
31926
- const claudeSessionId = randomUUID12();
31971
+ const claudeSessionId = randomUUID13();
31927
31972
  return {
31928
31973
  ...sessionBase(id, prompt ? "running" : "waiting"),
31929
31974
  name: `Session ${id}`,
@@ -32502,9 +32547,21 @@ function decidePrPreview(sessions, waiters, notify2, d) {
32502
32547
  notify2();
32503
32548
  }
32504
32549
 
32550
+ // src/commands/sessions/daemon/isPreviewKind.ts
32551
+ var PREVIEW_KINDS = [
32552
+ "pr",
32553
+ "backlog-item",
32554
+ "backlog-comment",
32555
+ "pr-comment"
32556
+ ];
32557
+ function isPreviewKind(value) {
32558
+ return PREVIEW_KINDS.includes(value);
32559
+ }
32560
+
32505
32561
  // src/commands/sessions/daemon/previewTargetLabel.ts
32506
32562
  function previewTargetLabel(kind, itemType, prNumber, draft) {
32507
32563
  if (kind === "backlog-comment") return "backlog comment";
32564
+ if (kind === "pr-comment") return "pr comment";
32508
32565
  if (kind === "backlog-item") return `backlog ${itemType}`;
32509
32566
  if (prNumber !== null) return `edit #${prNumber}`;
32510
32567
  return draft ? "create draft" : "create";
@@ -32523,7 +32580,7 @@ function setPrPreview(sessions, waiters, notify2, client, d) {
32523
32580
  return;
32524
32581
  }
32525
32582
  const prNumber = typeof d.prNumber === "number" ? d.prNumber : null;
32526
- const kind = d.kind === "backlog-item" || d.kind === "backlog-comment" ? d.kind : "pr";
32583
+ const kind = isPreviewKind(d.kind) ? d.kind : "pr";
32527
32584
  const itemType = d.itemType === "bug" ? "bug" : "story";
32528
32585
  const draft = d.draft === true;
32529
32586
  session.pendingPrPreview = {
@@ -33964,7 +34021,7 @@ function codexRespawnPlan(session) {
33964
34021
  }
33965
34022
 
33966
34023
  // src/commands/sessions/daemon/interactiveRespawnPlan.ts
33967
- import { randomUUID as randomUUID13 } from "crypto";
34024
+ import { randomUUID as randomUUID14 } from "crypto";
33968
34025
  function interactiveRespawnPlan(session, resumes) {
33969
34026
  const { claudeSessionId, cwd, initialPrompt } = session;
33970
34027
  if (!resumes) return null;
@@ -33982,7 +34039,7 @@ function interactiveRespawnPlan(session, resumes) {
33982
34039
  return null;
33983
34040
  }
33984
34041
  function freshClaudePlan(session, prompt, cwd) {
33985
- const claudeSessionId = randomUUID13();
34042
+ const claudeSessionId = randomUUID14();
33986
34043
  return {
33987
34044
  spawn: () => {
33988
34045
  session.claudeSessionId = claudeSessionId;
@@ -34860,10 +34917,10 @@ function startReusedRunPty(session, assistArgs, itemId2, hold, clients, onStatus
34860
34917
  }
34861
34918
 
34862
34919
  // src/commands/sessions/daemon/createWatcherSession.ts
34863
- import { randomUUID as randomUUID14 } from "crypto";
34920
+ import { randomUUID as randomUUID15 } from "crypto";
34864
34921
  var WATCH_PROMPT = "/watch";
34865
34922
  function createWatcherSession(id, cwd) {
34866
- const claudeSessionId = randomUUID14();
34923
+ const claudeSessionId = randomUUID15();
34867
34924
  return {
34868
34925
  ...sessionBase(id, "running"),
34869
34926
  name: `Session ${id}`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@staff0rd/assist",
3
- "version": "0.565.1",
3
+ "version": "0.566.0",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "bin": {