@staff0rd/assist 0.375.0 → 0.376.1
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/README.md +2 -2
- package/dist/commands/sessions/web/bundle.js +64 -64
- package/dist/index.js +107 -34
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import { Command } from "commander";
|
|
|
6
6
|
// package.json
|
|
7
7
|
var package_default = {
|
|
8
8
|
name: "@staff0rd/assist",
|
|
9
|
-
version: "0.
|
|
9
|
+
version: "0.376.1",
|
|
10
10
|
type: "module",
|
|
11
11
|
main: "dist/index.js",
|
|
12
12
|
bin: {
|
|
@@ -4589,11 +4589,80 @@ async function recordBranchActivity(branchName) {
|
|
|
4589
4589
|
]);
|
|
4590
4590
|
}
|
|
4591
4591
|
|
|
4592
|
+
// src/commands/branch/generateBranchSlug.ts
|
|
4593
|
+
import { execFile } from "child_process";
|
|
4594
|
+
import { promisify } from "util";
|
|
4595
|
+
|
|
4596
|
+
// src/shared/withSpinner.ts
|
|
4597
|
+
var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
4598
|
+
var TICK_MS = 80;
|
|
4599
|
+
async function withSpinner(text9, task) {
|
|
4600
|
+
if (!process.stderr.isTTY) return task();
|
|
4601
|
+
let frame = 0;
|
|
4602
|
+
const render = () => {
|
|
4603
|
+
process.stderr.write(`\r${SPINNER_FRAMES[frame]} ${text9}`);
|
|
4604
|
+
};
|
|
4605
|
+
render();
|
|
4606
|
+
const timer = setInterval(() => {
|
|
4607
|
+
frame = (frame + 1) % SPINNER_FRAMES.length;
|
|
4608
|
+
render();
|
|
4609
|
+
}, TICK_MS);
|
|
4610
|
+
try {
|
|
4611
|
+
return await task();
|
|
4612
|
+
} finally {
|
|
4613
|
+
clearInterval(timer);
|
|
4614
|
+
process.stderr.write("\r\x1B[K");
|
|
4615
|
+
}
|
|
4616
|
+
}
|
|
4617
|
+
|
|
4592
4618
|
// src/commands/branch/deriveBranchSlug.ts
|
|
4619
|
+
var MAX_SLUG_WORDS = 5;
|
|
4593
4620
|
function deriveBranchSlug(name) {
|
|
4594
|
-
const
|
|
4621
|
+
const words = name.toLowerCase().replace(/[^a-z0-9]+/g, "-").split("-").filter((word) => word.length > 0).filter((word) => !/^\d+$/.test(word));
|
|
4622
|
+
const slug = words.slice(0, MAX_SLUG_WORDS).join("-");
|
|
4595
4623
|
return slug || "story";
|
|
4596
4624
|
}
|
|
4625
|
+
function isConciseSlug(slug) {
|
|
4626
|
+
return slug.split("-").filter(Boolean).length <= MAX_SLUG_WORDS;
|
|
4627
|
+
}
|
|
4628
|
+
|
|
4629
|
+
// src/commands/branch/generateBranchSlug.ts
|
|
4630
|
+
var execFileAsync = promisify(execFile);
|
|
4631
|
+
async function generateBranchSlug(description) {
|
|
4632
|
+
const fallback = deriveBranchSlug(description);
|
|
4633
|
+
const suggestion = await requestSlug(description);
|
|
4634
|
+
if (!suggestion) return fallback;
|
|
4635
|
+
const slug = deriveBranchSlug(suggestion);
|
|
4636
|
+
return slug === "story" ? fallback : slug;
|
|
4637
|
+
}
|
|
4638
|
+
async function requestSlug(description) {
|
|
4639
|
+
try {
|
|
4640
|
+
const { stdout } = await withSpinner(
|
|
4641
|
+
"Generating a concise branch name",
|
|
4642
|
+
() => execFileAsync(
|
|
4643
|
+
"claude",
|
|
4644
|
+
["-p", "--model", "haiku", buildPrompt(description)],
|
|
4645
|
+
{ encoding: "utf8", timeout: 3e4 }
|
|
4646
|
+
)
|
|
4647
|
+
);
|
|
4648
|
+
const slug = stdout.trim().split("\n")[0].replace(/^["'`]|["'`]$/g, "").trim();
|
|
4649
|
+
return slug || void 0;
|
|
4650
|
+
} catch {
|
|
4651
|
+
return void 0;
|
|
4652
|
+
}
|
|
4653
|
+
}
|
|
4654
|
+
function buildPrompt(description) {
|
|
4655
|
+
return [
|
|
4656
|
+
"Suggest a concise git branch name for the work described below.",
|
|
4657
|
+
"Rules:",
|
|
4658
|
+
"- kebab-case: lowercase letters, digits, and single hyphens only",
|
|
4659
|
+
"- 2 to 4 words that capture the essence of the work",
|
|
4660
|
+
"- no ticket/issue numbers and no standalone numbers",
|
|
4661
|
+
"- reply with ONLY the branch name, no quotes or explanation",
|
|
4662
|
+
"",
|
|
4663
|
+
`Work: ${description}`
|
|
4664
|
+
].join("\n");
|
|
4665
|
+
}
|
|
4597
4666
|
|
|
4598
4667
|
// src/commands/backlog/ensureStoryBranch.ts
|
|
4599
4668
|
async function ensureStoryBranch(item) {
|
|
@@ -4601,7 +4670,7 @@ async function ensureStoryBranch(item) {
|
|
|
4601
4670
|
if (!config.prs?.required) return;
|
|
4602
4671
|
if (hasBranchRef(item)) return;
|
|
4603
4672
|
process.env.ASSIST_BACKLOG_ITEM_ID = String(item.id);
|
|
4604
|
-
const slug =
|
|
4673
|
+
const slug = await generateBranchSlug(item.name);
|
|
4605
4674
|
const { branchName } = await createBranch({ slug, jira: item.jiraKey });
|
|
4606
4675
|
appendDaemonLog(
|
|
4607
4676
|
`backlog run ${item.id}: prs.required set and no branch recorded; created ${branchName}`
|
|
@@ -6975,11 +7044,11 @@ function getHtml() {
|
|
|
6975
7044
|
}
|
|
6976
7045
|
|
|
6977
7046
|
// src/commands/sessions/web/getReviewSynthesis.ts
|
|
6978
|
-
import { execFile } from "child_process";
|
|
7047
|
+
import { execFile as execFile2 } from "child_process";
|
|
6979
7048
|
import { readFileSync as readFileSync17 } from "fs";
|
|
6980
7049
|
import { homedir as homedir9 } from "os";
|
|
6981
7050
|
import { basename as basename3, join as join22 } from "path";
|
|
6982
|
-
import { promisify } from "util";
|
|
7051
|
+
import { promisify as promisify2 } from "util";
|
|
6983
7052
|
|
|
6984
7053
|
// src/commands/sessions/web/findSynthesisForBranch.ts
|
|
6985
7054
|
import { existsSync as existsSync24, readdirSync, statSync as statSync2 } from "fs";
|
|
@@ -7014,9 +7083,9 @@ function windowsCwdToWslPath(cwd) {
|
|
|
7014
7083
|
}
|
|
7015
7084
|
|
|
7016
7085
|
// src/commands/sessions/web/getReviewSynthesis.ts
|
|
7017
|
-
var
|
|
7086
|
+
var execFileAsync2 = promisify2(execFile2);
|
|
7018
7087
|
function runGit(cwd, args) {
|
|
7019
|
-
return
|
|
7088
|
+
return execFileAsync2("git", args, {
|
|
7020
7089
|
encoding: "utf8",
|
|
7021
7090
|
cwd: windowsCwdToWslPath(cwd)
|
|
7022
7091
|
}).then((r) => r.stdout.trim());
|
|
@@ -7060,8 +7129,8 @@ function githubUrl(req, res) {
|
|
|
7060
7129
|
}
|
|
7061
7130
|
|
|
7062
7131
|
// src/commands/sessions/web/gitStatus.ts
|
|
7063
|
-
import { execFile as
|
|
7064
|
-
import { promisify as
|
|
7132
|
+
import { execFile as execFile3 } from "child_process";
|
|
7133
|
+
import { promisify as promisify3 } from "util";
|
|
7065
7134
|
|
|
7066
7135
|
// src/commands/sessions/web/parseGitStatus.ts
|
|
7067
7136
|
function extractPath(rest) {
|
|
@@ -7091,7 +7160,7 @@ function parseGitStatus(output) {
|
|
|
7091
7160
|
}
|
|
7092
7161
|
|
|
7093
7162
|
// src/commands/sessions/web/gitStatus.ts
|
|
7094
|
-
var
|
|
7163
|
+
var execFileAsync3 = promisify3(execFile3);
|
|
7095
7164
|
async function gitStatus(req, res) {
|
|
7096
7165
|
const cwd = getCwdParam(req, res);
|
|
7097
7166
|
if (!cwd) return;
|
|
@@ -7104,7 +7173,7 @@ async function gitStatus(req, res) {
|
|
|
7104
7173
|
function runGitStatus(cwd) {
|
|
7105
7174
|
const args = ["status", "--porcelain", "--untracked-files=all"];
|
|
7106
7175
|
const { file, argv } = /^[A-Za-z]:[\\/]/.test(cwd) ? { file: "git.exe", argv: ["-C", cwd, ...args] } : { file: "git", argv: args };
|
|
7107
|
-
return
|
|
7176
|
+
return execFileAsync3(file, argv, {
|
|
7108
7177
|
encoding: "utf8",
|
|
7109
7178
|
...file === "git" ? { cwd } : {}
|
|
7110
7179
|
}).then((r) => r.stdout);
|
|
@@ -7303,8 +7372,8 @@ async function listUsageHistory(req, res) {
|
|
|
7303
7372
|
|
|
7304
7373
|
// src/commands/sessions/web/openInCode.ts
|
|
7305
7374
|
import { exec } from "child_process";
|
|
7306
|
-
import { promisify as
|
|
7307
|
-
var execAsync =
|
|
7375
|
+
import { promisify as promisify4 } from "util";
|
|
7376
|
+
var execAsync = promisify4(exec);
|
|
7308
7377
|
async function openInCode(req, res) {
|
|
7309
7378
|
const cwd = getCwdParam(req, res);
|
|
7310
7379
|
if (!cwd) return;
|
|
@@ -7320,9 +7389,9 @@ async function openInCode(req, res) {
|
|
|
7320
7389
|
}
|
|
7321
7390
|
|
|
7322
7391
|
// src/commands/sessions/web/createCachedGhJson.ts
|
|
7323
|
-
import { execFile as
|
|
7324
|
-
import { promisify as
|
|
7325
|
-
var
|
|
7392
|
+
import { execFile as execFile4 } from "child_process";
|
|
7393
|
+
import { promisify as promisify5 } from "util";
|
|
7394
|
+
var execFileAsync4 = promisify5(execFile4);
|
|
7326
7395
|
var CACHE_TTL_MS = 3e4;
|
|
7327
7396
|
function createCachedGhJson(args, parse3, fallback, options2 = {}) {
|
|
7328
7397
|
const { cacheFallback = true } = options2;
|
|
@@ -7334,7 +7403,7 @@ function createCachedGhJson(args, parse3, fallback, options2 = {}) {
|
|
|
7334
7403
|
if (cached && cached.expires > now) return cached.value;
|
|
7335
7404
|
let value = fallback;
|
|
7336
7405
|
try {
|
|
7337
|
-
const { stdout } = await
|
|
7406
|
+
const { stdout } = await execFileAsync4("gh", [...args, ...extraArgs], {
|
|
7338
7407
|
encoding: "utf8",
|
|
7339
7408
|
cwd: windowsCwdToWslPath(cwd)
|
|
7340
7409
|
});
|
|
@@ -7378,9 +7447,9 @@ async function prList(req, res) {
|
|
|
7378
7447
|
}
|
|
7379
7448
|
|
|
7380
7449
|
// src/commands/sessions/web/prStatus.ts
|
|
7381
|
-
import { execFile as
|
|
7382
|
-
import { promisify as
|
|
7383
|
-
var
|
|
7450
|
+
import { execFile as execFile5 } from "child_process";
|
|
7451
|
+
import { promisify as promisify6 } from "util";
|
|
7452
|
+
var execFileAsync5 = promisify6(execFile5);
|
|
7384
7453
|
function toPrSummary(parsed) {
|
|
7385
7454
|
if (typeof parsed.number !== "number") return null;
|
|
7386
7455
|
return {
|
|
@@ -7410,7 +7479,7 @@ var getOpenPrForBranch = createCachedGhJson(
|
|
|
7410
7479
|
);
|
|
7411
7480
|
async function getCurrentBranch(cwd) {
|
|
7412
7481
|
try {
|
|
7413
|
-
const { stdout } = await
|
|
7482
|
+
const { stdout } = await execFileAsync5(
|
|
7414
7483
|
"git",
|
|
7415
7484
|
["rev-parse", "--abbrev-ref", "HEAD"],
|
|
7416
7485
|
{ encoding: "utf8", cwd: windowsCwdToWslPath(cwd) }
|
|
@@ -9984,14 +10053,18 @@ function validateSlug(slug) {
|
|
|
9984
10053
|
|
|
9985
10054
|
// src/commands/branch/branch.ts
|
|
9986
10055
|
async function branch(slug, options2) {
|
|
9987
|
-
const
|
|
10056
|
+
const conciseSlug = isConciseSlug(slug) ? slug : await generateBranchSlug(slug);
|
|
10057
|
+
if (conciseSlug !== slug) {
|
|
10058
|
+
console.log(`Shortened "${slug}" to "${conciseSlug}"`);
|
|
10059
|
+
}
|
|
10060
|
+
const slugError = validateSlug(conciseSlug);
|
|
9988
10061
|
if (slugError) {
|
|
9989
10062
|
console.error(`Error: ${slugError}`);
|
|
9990
10063
|
process.exit(1);
|
|
9991
10064
|
}
|
|
9992
10065
|
try {
|
|
9993
10066
|
const { branchName, defaultBranch } = await createBranch({
|
|
9994
|
-
slug,
|
|
10067
|
+
slug: conciseSlug,
|
|
9995
10068
|
jira: options2.jira
|
|
9996
10069
|
});
|
|
9997
10070
|
console.log(
|
|
@@ -18862,7 +18935,7 @@ function cachedReviewerResult(name, outputPath) {
|
|
|
18862
18935
|
import { createLogUpdate as createLogUpdate2 } from "log-update";
|
|
18863
18936
|
|
|
18864
18937
|
// src/commands/review/renderEntries.ts
|
|
18865
|
-
var
|
|
18938
|
+
var SPINNER_FRAMES2 = [
|
|
18866
18939
|
"\u280B",
|
|
18867
18940
|
"\u2819",
|
|
18868
18941
|
"\u2839",
|
|
@@ -18889,11 +18962,11 @@ function renderEntries(entries, frame) {
|
|
|
18889
18962
|
function renderEntry(entry, frame) {
|
|
18890
18963
|
if (entry.state === "succeeded") return `\u2714 ${entry.text}`;
|
|
18891
18964
|
if (entry.state === "failed") return `\u2716 ${entry.text}`;
|
|
18892
|
-
return `${
|
|
18965
|
+
return `${SPINNER_FRAMES2[frame]} ${entry.text}`;
|
|
18893
18966
|
}
|
|
18894
18967
|
|
|
18895
18968
|
// src/commands/review/MultiSpinner.ts
|
|
18896
|
-
var
|
|
18969
|
+
var TICK_MS2 = 80;
|
|
18897
18970
|
var MultiSpinner = class {
|
|
18898
18971
|
entries = [];
|
|
18899
18972
|
log = createLogUpdate2(process.stdout);
|
|
@@ -18943,9 +19016,9 @@ var MultiSpinner = class {
|
|
|
18943
19016
|
if (this.timer || this.finished) return;
|
|
18944
19017
|
this.render();
|
|
18945
19018
|
this.timer = setInterval(() => {
|
|
18946
|
-
this.frame = (this.frame + 1) %
|
|
19019
|
+
this.frame = (this.frame + 1) % SPINNER_FRAMES2.length;
|
|
18947
19020
|
this.render();
|
|
18948
|
-
},
|
|
19021
|
+
}, TICK_MS2);
|
|
18949
19022
|
}
|
|
18950
19023
|
render() {
|
|
18951
19024
|
this.log(renderEntries(this.entries, this.frame));
|
|
@@ -20506,7 +20579,7 @@ function askQuestion(rl, question) {
|
|
|
20506
20579
|
}
|
|
20507
20580
|
|
|
20508
20581
|
// src/commands/transcript/configure.ts
|
|
20509
|
-
function
|
|
20582
|
+
function buildPrompt2(label2, current) {
|
|
20510
20583
|
return current ? `${label2} [${current}]: ` : `${label2}: `;
|
|
20511
20584
|
}
|
|
20512
20585
|
function printExisting(existing) {
|
|
@@ -20519,15 +20592,15 @@ function printExisting(existing) {
|
|
|
20519
20592
|
async function promptDirectories(rl, existing) {
|
|
20520
20593
|
const vttDir = await askQuestion(
|
|
20521
20594
|
rl,
|
|
20522
|
-
|
|
20595
|
+
buildPrompt2("VTT directory", existing?.vttDir)
|
|
20523
20596
|
);
|
|
20524
20597
|
const transcriptsDir = await askQuestion(
|
|
20525
20598
|
rl,
|
|
20526
|
-
|
|
20599
|
+
buildPrompt2("Transcripts directory", existing?.transcriptsDir)
|
|
20527
20600
|
);
|
|
20528
20601
|
const summaryDir = await askQuestion(
|
|
20529
20602
|
rl,
|
|
20530
|
-
|
|
20603
|
+
buildPrompt2("Summary directory", existing?.summaryDir)
|
|
20531
20604
|
);
|
|
20532
20605
|
return {
|
|
20533
20606
|
vttDir: vttDir || existing?.vttDir || "",
|
|
@@ -24871,7 +24944,7 @@ function summariseSession(jsonlPath2) {
|
|
|
24871
24944
|
if (!firstMessage && backlogIds.length === 0) {
|
|
24872
24945
|
return void 0;
|
|
24873
24946
|
}
|
|
24874
|
-
const prompt =
|
|
24947
|
+
const prompt = buildPrompt3(firstMessage, backlogIds);
|
|
24875
24948
|
try {
|
|
24876
24949
|
const output = execFileSync10("claude", ["-p", "--model", "haiku", prompt], {
|
|
24877
24950
|
encoding: "utf8",
|
|
@@ -24885,7 +24958,7 @@ function summariseSession(jsonlPath2) {
|
|
|
24885
24958
|
return void 0;
|
|
24886
24959
|
}
|
|
24887
24960
|
}
|
|
24888
|
-
function
|
|
24961
|
+
function buildPrompt3(firstMessage, backlogIds) {
|
|
24889
24962
|
const parts = [
|
|
24890
24963
|
"Summarise this Claude Code session in ONE short sentence (under 100 chars).",
|
|
24891
24964
|
"Return ONLY the summary, no quotes or explanation."
|