@staff0rd/assist 0.147.1 → 0.147.3
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/claude/commands/test-cover.md +1 -1
- package/claude/commands/test-review.md +1 -1
- package/dist/index.js +39 -85
- package/package.json +1 -1
|
@@ -51,7 +51,7 @@ Use a behavioural, BDD-style structure:
|
|
|
51
51
|
|
|
52
52
|
- **Outer `describe`** — the function or module under test
|
|
53
53
|
- **Inner `describe("when ...")`** — groups tests that share the same setup/scenario
|
|
54
|
-
- **`it("should ...")`** — asserts a single rule or behaviour
|
|
54
|
+
- **`it("should ...")`** — asserts a single rule or behaviour. State specifiers (flags, syntax variants, conditions) belong in `when` blocks, never in `it` descriptions — keep assertions as bare outcomes (e.g. "should allow", "should reject")
|
|
55
55
|
|
|
56
56
|
Each test follows an **Arrange, Act, Assert** pattern. Do NOT add `// arrange`, `// act`, `// assert` comments — just structure the code in that order with whitespace separating the three sections.
|
|
57
57
|
|
|
@@ -35,7 +35,7 @@ Assess each test file against these criteria:
|
|
|
35
35
|
### BDD structure and Arrange-Act-Assert
|
|
36
36
|
- Does the outer `describe` name the function or module under test?
|
|
37
37
|
- Do inner `describe("when ...")` blocks group tests by shared setup/scenario?
|
|
38
|
-
- Do `it` blocks use `should` phrasing (e.g., `it("should
|
|
38
|
+
- Do `it` blocks use `should` phrasing with bare outcomes (e.g., `it("should allow")`, `it("should reject")`)? State specifiers (flags, syntax variants, conditions) belong in `when` blocks, never in `it` descriptions.
|
|
39
39
|
- Does each test follow Arrange, Act, Assert ordering (without comments labelling the sections)?
|
|
40
40
|
- Are assertions minimal per test — ideally one, at most two closely related? If multiple things are asserted about the same action, are they split into separate `it` blocks under the same `describe("when ...")`?
|
|
41
41
|
|
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.147.
|
|
9
|
+
version: "0.147.3",
|
|
10
10
|
type: "module",
|
|
11
11
|
main: "dist/index.js",
|
|
12
12
|
bin: {
|
|
@@ -2608,7 +2608,7 @@ async function list2(options2) {
|
|
|
2608
2608
|
|
|
2609
2609
|
// src/commands/backlog/next.ts
|
|
2610
2610
|
import chalk36 from "chalk";
|
|
2611
|
-
import
|
|
2611
|
+
import enquirer6 from "enquirer";
|
|
2612
2612
|
|
|
2613
2613
|
// src/commands/backlog/run.ts
|
|
2614
2614
|
import chalk35 from "chalk";
|
|
@@ -2714,10 +2714,8 @@ function buildReviewPhase() {
|
|
|
2714
2714
|
import chalk34 from "chalk";
|
|
2715
2715
|
|
|
2716
2716
|
// src/commands/backlog/resolvePhaseResult.ts
|
|
2717
|
-
import { spawnSync as spawnSync2 } from "child_process";
|
|
2718
2717
|
import { existsSync as existsSync16, unlinkSync as unlinkSync3 } from "fs";
|
|
2719
2718
|
import chalk33 from "chalk";
|
|
2720
|
-
import enquirer6 from "enquirer";
|
|
2721
2719
|
|
|
2722
2720
|
// src/commands/backlog/handleIncompletePhase.ts
|
|
2723
2721
|
import enquirer5 from "enquirer";
|
|
@@ -2756,19 +2754,6 @@ function phaseDone(id, phase) {
|
|
|
2756
2754
|
console.log(chalk32.green(`Phase ${phase} of item #${id} marked as complete.`));
|
|
2757
2755
|
}
|
|
2758
2756
|
|
|
2759
|
-
// src/commands/backlog/spawnClaude.ts
|
|
2760
|
-
import { spawn as spawn3 } from "child_process";
|
|
2761
|
-
function spawnClaude(prompt) {
|
|
2762
|
-
const child = spawn3("claude", [prompt], {
|
|
2763
|
-
stdio: "inherit"
|
|
2764
|
-
});
|
|
2765
|
-
const done2 = new Promise((resolve7, reject) => {
|
|
2766
|
-
child.on("close", (code) => resolve7(code ?? 0));
|
|
2767
|
-
child.on("error", reject);
|
|
2768
|
-
});
|
|
2769
|
-
return { child, done: done2 };
|
|
2770
|
-
}
|
|
2771
|
-
|
|
2772
2757
|
// src/commands/backlog/resolvePhaseResult.ts
|
|
2773
2758
|
function cleanupMarker() {
|
|
2774
2759
|
const statusPath = getPhaseStatusPath();
|
|
@@ -2776,56 +2761,29 @@ function cleanupMarker() {
|
|
|
2776
2761
|
unlinkSync3(statusPath);
|
|
2777
2762
|
}
|
|
2778
2763
|
}
|
|
2779
|
-
function
|
|
2780
|
-
const result = spawnSync2("assist", ["verify"], {
|
|
2781
|
-
stdio: "inherit",
|
|
2782
|
-
shell: true
|
|
2783
|
-
});
|
|
2784
|
-
return result.status === 0;
|
|
2785
|
-
}
|
|
2786
|
-
async function handleCompletedPhase(phaseIndex) {
|
|
2787
|
-
cleanupMarker();
|
|
2788
|
-
console.log(
|
|
2789
|
-
chalk33.green(`
|
|
2790
|
-
Phase ${phaseIndex + 1} completed. Running verify...`)
|
|
2791
|
-
);
|
|
2792
|
-
if (runVerify()) {
|
|
2793
|
-
console.log(chalk33.green("Verification passed."));
|
|
2794
|
-
return true;
|
|
2795
|
-
}
|
|
2796
|
-
while (true) {
|
|
2797
|
-
const { action } = await enquirer6.prompt({
|
|
2798
|
-
type: "select",
|
|
2799
|
-
name: "action",
|
|
2800
|
-
message: "Verification failed. What would you like to do?",
|
|
2801
|
-
choices: ["Fix", "Continue to next phase", "Abort"]
|
|
2802
|
-
});
|
|
2803
|
-
if (action === "Fix") {
|
|
2804
|
-
const { done: done2 } = spawnClaude(
|
|
2805
|
-
"Run /verify and fix all failures. Do not move on until every check passes."
|
|
2806
|
-
);
|
|
2807
|
-
await done2;
|
|
2808
|
-
if (runVerify()) {
|
|
2809
|
-
console.log(chalk33.green("Verification passed."));
|
|
2810
|
-
return true;
|
|
2811
|
-
}
|
|
2812
|
-
continue;
|
|
2813
|
-
}
|
|
2814
|
-
return action === "Continue to next phase";
|
|
2815
|
-
}
|
|
2816
|
-
}
|
|
2817
|
-
async function resolvePhaseResult(phaseIndex, options2) {
|
|
2764
|
+
async function resolvePhaseResult(phaseIndex) {
|
|
2818
2765
|
if (!existsSync16(getPhaseStatusPath())) {
|
|
2819
2766
|
const action = await handleIncompletePhase();
|
|
2820
2767
|
if (action === "abort") return -1;
|
|
2821
2768
|
return action === "skip" ? 1 : 0;
|
|
2822
2769
|
}
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2770
|
+
cleanupMarker();
|
|
2771
|
+
console.log(chalk33.green(`
|
|
2772
|
+
Phase ${phaseIndex + 1} completed.`));
|
|
2773
|
+
return 1;
|
|
2774
|
+
}
|
|
2775
|
+
|
|
2776
|
+
// src/commands/backlog/spawnClaude.ts
|
|
2777
|
+
import { spawn as spawn3 } from "child_process";
|
|
2778
|
+
function spawnClaude(prompt) {
|
|
2779
|
+
const child = spawn3("claude", [prompt], {
|
|
2780
|
+
stdio: "inherit"
|
|
2781
|
+
});
|
|
2782
|
+
const done2 = new Promise((resolve7, reject) => {
|
|
2783
|
+
child.on("close", (code) => resolve7(code ?? 0));
|
|
2784
|
+
child.on("error", reject);
|
|
2785
|
+
});
|
|
2786
|
+
return { child, done: done2 };
|
|
2829
2787
|
}
|
|
2830
2788
|
|
|
2831
2789
|
// src/commands/backlog/watchForMarker.ts
|
|
@@ -2844,7 +2802,7 @@ function stopWatching() {
|
|
|
2844
2802
|
}
|
|
2845
2803
|
|
|
2846
2804
|
// src/commands/backlog/executePhase.ts
|
|
2847
|
-
async function executePhase(item, phaseIndex, phases
|
|
2805
|
+
async function executePhase(item, phaseIndex, phases) {
|
|
2848
2806
|
const phase = phases[phaseIndex];
|
|
2849
2807
|
console.log(
|
|
2850
2808
|
chalk34.bold(
|
|
@@ -2859,9 +2817,7 @@ async function executePhase(item, phaseIndex, phases, options2) {
|
|
|
2859
2817
|
watchForMarker(child);
|
|
2860
2818
|
await done2;
|
|
2861
2819
|
stopWatching();
|
|
2862
|
-
const delta = await resolvePhaseResult(phaseIndex
|
|
2863
|
-
skipVerify: options2?.skipVerify
|
|
2864
|
-
});
|
|
2820
|
+
const delta = await resolvePhaseResult(phaseIndex);
|
|
2865
2821
|
return delta < 0 ? -1 : phaseIndex + delta;
|
|
2866
2822
|
}
|
|
2867
2823
|
|
|
@@ -2911,9 +2867,7 @@ async function run2(id) {
|
|
|
2911
2867
|
const reviewPhase = buildReviewPhase();
|
|
2912
2868
|
const allPhases = [...plan2, reviewPhase];
|
|
2913
2869
|
const reviewIndex = plan2.length;
|
|
2914
|
-
const reviewResult = await executePhase(item, reviewIndex, allPhases
|
|
2915
|
-
skipVerify: true
|
|
2916
|
-
});
|
|
2870
|
+
const reviewResult = await executePhase(item, reviewIndex, allPhases);
|
|
2917
2871
|
if (reviewResult < 0) return;
|
|
2918
2872
|
if (item.status !== "done") setStatus(id, "done");
|
|
2919
2873
|
console.log(chalk35.green(`
|
|
@@ -2943,7 +2897,7 @@ async function next() {
|
|
|
2943
2897
|
name: `${typeLabel(i.type)} #${i.id}: ${i.name}`,
|
|
2944
2898
|
value: String(i.id)
|
|
2945
2899
|
}));
|
|
2946
|
-
const { selected } = await
|
|
2900
|
+
const { selected } = await enquirer6.prompt({
|
|
2947
2901
|
type: "select",
|
|
2948
2902
|
name: "selected",
|
|
2949
2903
|
message: "Choose a backlog item to start:",
|
|
@@ -5755,10 +5709,10 @@ function registerJira(program2) {
|
|
|
5755
5709
|
|
|
5756
5710
|
// src/commands/news/add/index.ts
|
|
5757
5711
|
import chalk68 from "chalk";
|
|
5758
|
-
import
|
|
5712
|
+
import enquirer7 from "enquirer";
|
|
5759
5713
|
async function add2(url) {
|
|
5760
5714
|
if (!url) {
|
|
5761
|
-
const response = await
|
|
5715
|
+
const response = await enquirer7.prompt({
|
|
5762
5716
|
type: "input",
|
|
5763
5717
|
name: "url",
|
|
5764
5718
|
message: "RSS feed URL:",
|
|
@@ -5978,7 +5932,7 @@ function registerNews(program2) {
|
|
|
5978
5932
|
}
|
|
5979
5933
|
|
|
5980
5934
|
// src/commands/prs/comment.ts
|
|
5981
|
-
import { spawnSync as
|
|
5935
|
+
import { spawnSync as spawnSync2 } from "child_process";
|
|
5982
5936
|
import { unlinkSync as unlinkSync5, writeFileSync as writeFileSync19 } from "fs";
|
|
5983
5937
|
import { tmpdir as tmpdir3 } from "os";
|
|
5984
5938
|
import { join as join20 } from "path";
|
|
@@ -6056,7 +6010,7 @@ function comment(path49, line, body) {
|
|
|
6056
6010
|
const queryFile = join20(tmpdir3(), `gh-query-${Date.now()}.graphql`);
|
|
6057
6011
|
writeFileSync19(queryFile, MUTATION);
|
|
6058
6012
|
try {
|
|
6059
|
-
const result =
|
|
6013
|
+
const result = spawnSync2(
|
|
6060
6014
|
"gh",
|
|
6061
6015
|
[
|
|
6062
6016
|
"api",
|
|
@@ -6394,7 +6348,7 @@ async function listComments() {
|
|
|
6394
6348
|
import { execSync as execSync30 } from "child_process";
|
|
6395
6349
|
|
|
6396
6350
|
// src/commands/prs/prs/displayPaginated/index.ts
|
|
6397
|
-
import
|
|
6351
|
+
import enquirer8 from "enquirer";
|
|
6398
6352
|
|
|
6399
6353
|
// src/commands/prs/prs/displayPaginated/printPr.ts
|
|
6400
6354
|
import chalk71 from "chalk";
|
|
@@ -6464,7 +6418,7 @@ function parseAction(action) {
|
|
|
6464
6418
|
}
|
|
6465
6419
|
async function promptNavigation(currentPage, totalPages) {
|
|
6466
6420
|
const choices = buildNavChoices(currentPage, totalPages);
|
|
6467
|
-
const { action } = await
|
|
6421
|
+
const { action } = await enquirer8.prompt({
|
|
6468
6422
|
type: "select",
|
|
6469
6423
|
name: "action",
|
|
6470
6424
|
message: "Navigate",
|
|
@@ -9346,7 +9300,7 @@ function registerVerify(program2) {
|
|
|
9346
9300
|
}
|
|
9347
9301
|
|
|
9348
9302
|
// src/commands/voice/devices.ts
|
|
9349
|
-
import { spawnSync as
|
|
9303
|
+
import { spawnSync as spawnSync3 } from "child_process";
|
|
9350
9304
|
import { join as join32 } from "path";
|
|
9351
9305
|
|
|
9352
9306
|
// src/commands/voice/shared.ts
|
|
@@ -9379,7 +9333,7 @@ function getLockFile() {
|
|
|
9379
9333
|
// src/commands/voice/devices.ts
|
|
9380
9334
|
function devices() {
|
|
9381
9335
|
const script = join32(getPythonDir(), "list_devices.py");
|
|
9382
|
-
|
|
9336
|
+
spawnSync3(getVenvPython(), [script], { stdio: "inherit" });
|
|
9383
9337
|
}
|
|
9384
9338
|
|
|
9385
9339
|
// src/commands/voice/logs.ts
|
|
@@ -9411,7 +9365,7 @@ function logs(options2) {
|
|
|
9411
9365
|
}
|
|
9412
9366
|
|
|
9413
9367
|
// src/commands/voice/setup.ts
|
|
9414
|
-
import { spawnSync as
|
|
9368
|
+
import { spawnSync as spawnSync4 } from "child_process";
|
|
9415
9369
|
import { mkdirSync as mkdirSync10 } from "fs";
|
|
9416
9370
|
import { join as join34 } from "path";
|
|
9417
9371
|
|
|
@@ -9472,7 +9426,7 @@ function setup() {
|
|
|
9472
9426
|
bootstrapVenv();
|
|
9473
9427
|
console.log("\nDownloading models...\n");
|
|
9474
9428
|
const script = join34(getPythonDir(), "setup_models.py");
|
|
9475
|
-
const result =
|
|
9429
|
+
const result = spawnSync4(getVenvPython(), [script], {
|
|
9476
9430
|
stdio: "inherit",
|
|
9477
9431
|
env: { ...process.env, VOICE_LOG_FILE: voicePaths.log }
|
|
9478
9432
|
});
|
|
@@ -9744,7 +9698,7 @@ async function exchangeToken(params) {
|
|
|
9744
9698
|
}
|
|
9745
9699
|
|
|
9746
9700
|
// src/commands/roam/promptCredentials.ts
|
|
9747
|
-
import
|
|
9701
|
+
import enquirer9 from "enquirer";
|
|
9748
9702
|
function censor(value) {
|
|
9749
9703
|
const visible = value.slice(-4);
|
|
9750
9704
|
return `${"*".repeat(value.length - 4)}${visible}`;
|
|
@@ -9753,7 +9707,7 @@ function label(name, existing) {
|
|
|
9753
9707
|
return existing ? `${name} (${censor(existing)})` : name;
|
|
9754
9708
|
}
|
|
9755
9709
|
async function promptField(name, existing) {
|
|
9756
|
-
const { value } = await
|
|
9710
|
+
const { value } = await enquirer9.prompt({
|
|
9757
9711
|
type: "input",
|
|
9758
9712
|
name: "value",
|
|
9759
9713
|
message: `${label(name, existing)}:`,
|
|
@@ -10276,7 +10230,7 @@ import { fileURLToPath as fileURLToPath7 } from "url";
|
|
|
10276
10230
|
import * as fs23 from "fs";
|
|
10277
10231
|
import * as path45 from "path";
|
|
10278
10232
|
import chalk105 from "chalk";
|
|
10279
|
-
async function syncClaudeMd(claudeDir, targetBase) {
|
|
10233
|
+
async function syncClaudeMd(claudeDir, targetBase, options2) {
|
|
10280
10234
|
const source = path45.join(claudeDir, "CLAUDE.md");
|
|
10281
10235
|
const target = path45.join(targetBase, "CLAUDE.md");
|
|
10282
10236
|
const sourceContent = fs23.readFileSync(source, "utf-8");
|
|
@@ -10288,7 +10242,7 @@ async function syncClaudeMd(claudeDir, targetBase) {
|
|
|
10288
10242
|
);
|
|
10289
10243
|
console.log();
|
|
10290
10244
|
printDiff(targetContent, sourceContent);
|
|
10291
|
-
const confirm = await promptConfirm(
|
|
10245
|
+
const confirm = options2?.yes || await promptConfirm(
|
|
10292
10246
|
chalk105.red("Overwrite existing CLAUDE.md?"),
|
|
10293
10247
|
false
|
|
10294
10248
|
);
|
|
@@ -10350,7 +10304,7 @@ async function sync(options2) {
|
|
|
10350
10304
|
const targetBase = path47.join(os.homedir(), ".claude");
|
|
10351
10305
|
syncCommands(claudeDir, targetBase);
|
|
10352
10306
|
await syncSettings(claudeDir, targetBase, { yes: options2?.yes });
|
|
10353
|
-
await syncClaudeMd(claudeDir, targetBase);
|
|
10307
|
+
await syncClaudeMd(claudeDir, targetBase, { yes: options2?.yes });
|
|
10354
10308
|
}
|
|
10355
10309
|
function syncCommands(claudeDir, targetBase) {
|
|
10356
10310
|
const sourceDir = path47.join(claudeDir, "commands");
|