@staff0rd/assist 0.518.0 → 0.520.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.518.0",
9
+ version: "0.520.0",
10
10
  type: "module",
11
11
  main: "dist/index.js",
12
12
  bin: {
@@ -10322,7 +10322,10 @@ async function fileContent(req, res) {
10322
10322
  respondJson(res, 413, { error: "File too large" });
10323
10323
  return;
10324
10324
  }
10325
- respondJson(res, 200, { content: await readFile(resolved.target, "utf8") });
10325
+ respondJson(res, 200, {
10326
+ content: await readFile(resolved.target, "utf8"),
10327
+ mtimeMs: info.mtimeMs
10328
+ });
10326
10329
  } catch {
10327
10330
  respondJson(res, 404, { error: "File not found" });
10328
10331
  }
@@ -12078,7 +12081,7 @@ async function uploadPrImage(req, res) {
12078
12081
  }
12079
12082
 
12080
12083
  // src/commands/sessions/web/writeFileContent.ts
12081
- import { readFile as readFile2, writeFile as writeFile3 } from "fs/promises";
12084
+ import { readFile as readFile2, stat as stat3, writeFile as writeFile3 } from "fs/promises";
12082
12085
 
12083
12086
  // src/commands/sessions/web/formatWithOxfmt.ts
12084
12087
  import { execFile as execFile8 } from "child_process";
@@ -12108,26 +12111,50 @@ async function formatWithOxfmt(target, root) {
12108
12111
  });
12109
12112
  }
12110
12113
 
12111
- // src/commands/sessions/web/writeFileContent.ts
12112
- async function writeFileContent(req, res) {
12113
- const resolved = getFileTarget(req, res);
12114
- if (!resolved) return;
12114
+ // src/commands/sessions/web/getFileWriteBody.ts
12115
+ async function getFileWriteBody(req, res) {
12115
12116
  let body;
12116
12117
  try {
12117
12118
  body = await readJsonBody(req);
12118
12119
  } catch {
12119
12120
  respondJson(res, 400, { error: "Invalid JSON body" });
12120
- return;
12121
+ return null;
12121
12122
  }
12122
12123
  if (typeof body.content !== "string") {
12123
12124
  respondJson(res, 400, { error: "Missing content" });
12125
+ return null;
12126
+ }
12127
+ if (typeof body.mtimeMs !== "number") {
12128
+ respondJson(res, 400, { error: "Missing mtimeMs" });
12129
+ return null;
12130
+ }
12131
+ return { content: body.content, mtimeMs: body.mtimeMs };
12132
+ }
12133
+
12134
+ // src/commands/sessions/web/writeFileContent.ts
12135
+ var STALE_MESSAGE = "The file changed on disk since it was opened";
12136
+ async function currentMtimeMs(target) {
12137
+ try {
12138
+ return (await stat3(target)).mtimeMs;
12139
+ } catch {
12140
+ return null;
12141
+ }
12142
+ }
12143
+ async function writeFileContent(req, res) {
12144
+ const resolved = getFileTarget(req, res);
12145
+ if (!resolved) return;
12146
+ const body = await getFileWriteBody(req, res);
12147
+ if (!body) return;
12148
+ if (await currentMtimeMs(resolved.target) !== body.mtimeMs) {
12149
+ respondJson(res, 409, { error: STALE_MESSAGE });
12124
12150
  return;
12125
12151
  }
12126
12152
  try {
12127
12153
  await writeFile3(resolved.target, body.content, "utf8");
12128
12154
  await formatWithOxfmt(resolved.target, repoRoot(resolved.cwd));
12129
12155
  respondJson(res, 200, {
12130
- content: await readFile2(resolved.target, "utf8")
12156
+ content: await readFile2(resolved.target, "utf8"),
12157
+ mtimeMs: await currentMtimeMs(resolved.target)
12131
12158
  });
12132
12159
  } catch (error) {
12133
12160
  respondJson(res, 500, {
@@ -18499,10 +18526,10 @@ function findSlnFiles(dir, maxDepth, depth = 0) {
18499
18526
  continue;
18500
18527
  const full = path32.join(dir, entry);
18501
18528
  try {
18502
- const stat3 = statSync6(full);
18503
- if (stat3.isFile() && entry.endsWith(".sln")) {
18529
+ const stat4 = statSync6(full);
18530
+ if (stat4.isFile() && entry.endsWith(".sln")) {
18504
18531
  results.push(full);
18505
- } else if (stat3.isDirectory()) {
18532
+ } else if (stat4.isDirectory()) {
18506
18533
  results.push(...findSlnFiles(full, maxDepth, depth + 1));
18507
18534
  }
18508
18535
  } catch {
@@ -22603,6 +22630,65 @@ function wontfix(commentId, reason4) {
22603
22630
  }
22604
22631
  }
22605
22632
 
22633
+ // src/commands/prs/prConcisenessGuidance.ts
22634
+ var prConcisenessGuidance = `Brevity budget \u2014 one paragraph per section, and these are ceilings, not targets:
22635
+
22636
+ ## What 2\u20133 sentences.
22637
+ ## Why 1\u20132 sentences.
22638
+ ## How omit by default; a sentence or two, only for non-obvious decisions.
22639
+
22640
+ The budget is a total, not a per-paragraph allowance. Splitting a section across
22641
+ two paragraphs buys no extra room. The whole body should read in well under a
22642
+ minute \u2014 roughly 6 sentences and 900 characters of prose for a typical change,
22643
+ counting every section together. A body that is long-winded overall is wrong even
22644
+ when each paragraph is individually short.
22645
+
22646
+ Terse technical register. Write like a commit message, not a report. Short
22647
+ declarative sentences, one clause each: state the fact and stop. Cut
22648
+ scene-setting, restatements of the heading, "this change \u2026", "in order to", "it
22649
+ is worth noting", hedges ("essentially", "fairly", "somewhat"), and adverbs that
22650
+ carry no information. Present tense, active voice. If a sentence can lose half
22651
+ its words and still say the same thing, it is too long.
22652
+
22653
+ Wordy: This change introduces a new validation step so that the command is
22654
+ able to reject pull request bodies which exceed the configured limit.
22655
+ Terse: Rejects bodies over the limit.
22656
+
22657
+ Sentence count is a floor on brevity, not the whole of it \u2014 a body inside the
22658
+ budget can still be too verbose, and then it needs cutting rather than reflowing.
22659
+ Prefer deleting a sentence to shortening it.
22660
+
22661
+ Write prose. A short paragraph is the natural form for ## What and ## Why \u2014
22662
+ bullets in ## What are a smell. Use bullets only when there are genuinely several
22663
+ independent, parallel items (3+); a single bullet is never right. A single
22664
+ non-list paragraph over ~600 characters or ~4 sentences is a wall of text and
22665
+ will be rejected.`;
22666
+
22667
+ // src/commands/prs/editHelpText.ts
22668
+ function editHelpText() {
22669
+ return `
22670
+ Update individual sections of the current branch's pull request. Only the sections
22671
+ you pass are replaced; every other section of the existing body is preserved.
22672
+
22673
+ Do not reference Claude or any AI assistance in the title or body. Wrap symbols,
22674
+ file paths, function names, class names, variable names, config keys, CLI
22675
+ commands, and flag names in backticks.
22676
+
22677
+ A replacement section is held to the same standard as one written by
22678
+ 'assist prs raise', and the budget applies to the resulting body as a whole \u2014 an
22679
+ edit must not push the body over it. Read the sections you are not touching first:
22680
+ if the section you are replacing was the concise one, trimming it further will not
22681
+ rescue a body that is already long-winded.
22682
+
22683
+ ## What what is observably different for someone using or calling this.
22684
+ ## Why the problem or motivation that made the change worth doing.
22685
+ ## How only non-obvious decisions the diff alone won't explain; omit by
22686
+ default.
22687
+
22688
+ ${prConcisenessGuidance}
22689
+ `;
22690
+ }
22691
+
22606
22692
  // src/commands/registerPrsEdit.ts
22607
22693
  function collect3(value, previous) {
22608
22694
  return previous.concat([value]);
@@ -22615,7 +22701,7 @@ function registerPrsEdit(prsCommand) {
22615
22701
  "Jira issue key resolved by this PR, appended to ## Why (repeatable)",
22616
22702
  collect3,
22617
22703
  []
22618
- ).action(edit);
22704
+ ).addHelpText("after", () => editHelpText()).action(edit);
22619
22705
  }
22620
22706
 
22621
22707
  // src/commands/prs/raiseHelpText.ts
@@ -22667,17 +22753,7 @@ a genuine non-obvious decision. Litmus \u2014 a sentence is almost certainly mec
22667
22753
  X filters/needs/uses", or names an internal component, property, function, or
22668
22754
  file.
22669
22755
 
22670
- Brevity budget \u2014 keep each section within these limits:
22671
-
22672
- ## What a few sentences (2\u20133).
22673
- ## Why 1\u20132 sentences.
22674
- ## How omit by default; a sentence or two, only for non-obvious decisions.
22675
-
22676
- Write prose. A short paragraph is the natural form for ## What and ## Why \u2014
22677
- bullets in ## What are a smell. Use bullets only when there are genuinely several
22678
- independent, parallel items (3+); a single bullet is never right. A single
22679
- non-list paragraph over ~600 characters or ~4 sentences is a wall of text and
22680
- will be rejected.
22756
+ ${prConcisenessGuidance}
22681
22757
 
22682
22758
  If a pull request already exists for the branch, this command errors \u2014 pass
22683
22759
  --force to fully overwrite its title and body, or use 'assist prs edit' to update
@@ -34246,13 +34322,13 @@ import { readFileSync as readFileSync54, statSync as statSync14 } from "fs";
34246
34322
  import { isAbsolute as isAbsolute4, join as join78, resolve as resolve21 } from "path";
34247
34323
  function resolveGitDir(cwd) {
34248
34324
  const dotGit = join78(cwd, ".git");
34249
- let stat3;
34325
+ let stat4;
34250
34326
  try {
34251
- stat3 = statSync14(dotGit);
34327
+ stat4 = statSync14(dotGit);
34252
34328
  } catch {
34253
34329
  return null;
34254
34330
  }
34255
- if (stat3.isDirectory()) {
34331
+ if (stat4.isDirectory()) {
34256
34332
  return dotGit;
34257
34333
  }
34258
34334
  let contents;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@staff0rd/assist",
3
- "version": "0.518.0",
3
+ "version": "0.520.0",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "bin": {