@staff0rd/assist 0.244.1 → 0.245.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/README.md +7 -6
- package/claude/commands/bug.md +6 -0
- package/claude/commands/draft.md +6 -0
- package/claude/commands/refine.md +8 -0
- package/dist/commands/sessions/web/bundle.js +1 -1
- package/dist/index.js +320 -272
- 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.245.0",
|
|
10
10
|
type: "module",
|
|
11
11
|
main: "dist/index.js",
|
|
12
12
|
bin: {
|
|
@@ -3632,15 +3632,15 @@ Phase ${phaseNumber} completed.`));
|
|
|
3632
3632
|
|
|
3633
3633
|
// src/commands/backlog/watchForMarker.ts
|
|
3634
3634
|
import { existsSync as existsSync20, unwatchFile, watchFile } from "fs";
|
|
3635
|
-
function watchForMarker(child) {
|
|
3635
|
+
function watchForMarker(child, options2) {
|
|
3636
3636
|
const statusPath = getSignalPath();
|
|
3637
3637
|
watchFile(statusPath, { interval: 1e3 }, () => {
|
|
3638
3638
|
if (!existsSync20(statusPath)) return;
|
|
3639
3639
|
const signal = readSignal();
|
|
3640
|
-
if (signal)
|
|
3641
|
-
|
|
3642
|
-
|
|
3643
|
-
|
|
3640
|
+
if (!signal) return;
|
|
3641
|
+
if (signal.event === "done" && !options2?.actOnDone) return;
|
|
3642
|
+
unwatchFile(statusPath);
|
|
3643
|
+
child.kill("SIGTERM");
|
|
3644
3644
|
});
|
|
3645
3645
|
}
|
|
3646
3646
|
function stopWatching() {
|
|
@@ -3809,7 +3809,7 @@ async function next(options2, startId) {
|
|
|
3809
3809
|
firstPick = false;
|
|
3810
3810
|
if (id === void 0) return;
|
|
3811
3811
|
const completed = await run2(id, options2);
|
|
3812
|
-
if (!completed) return;
|
|
3812
|
+
if (!completed || options2?.once) return;
|
|
3813
3813
|
}
|
|
3814
3814
|
}
|
|
3815
3815
|
|
|
@@ -4584,117 +4584,27 @@ async function web2(options2) {
|
|
|
4584
4584
|
await web({ port: options2.port, initialPath: "/backlog" });
|
|
4585
4585
|
}
|
|
4586
4586
|
|
|
4587
|
-
// src/commands/backlog/refine.ts
|
|
4588
|
-
import chalk47 from "chalk";
|
|
4589
|
-
import enquirer6 from "enquirer";
|
|
4590
|
-
|
|
4591
|
-
// src/commands/backlog/launchMode.ts
|
|
4592
|
-
import chalk46 from "chalk";
|
|
4593
|
-
|
|
4594
|
-
// src/commands/backlog/tryRunById.ts
|
|
4595
|
-
import chalk45 from "chalk";
|
|
4596
|
-
async function tryRunById(id, options2) {
|
|
4597
|
-
const items2 = await loadBacklog();
|
|
4598
|
-
const numericId = Number.parseInt(id, 10);
|
|
4599
|
-
const item = Number.isNaN(numericId) ? void 0 : items2.find((i) => i.id === numericId);
|
|
4600
|
-
if (!item) {
|
|
4601
|
-
console.log(chalk45.red(`Item #${id} not found.`));
|
|
4602
|
-
return false;
|
|
4603
|
-
}
|
|
4604
|
-
if (item.status === "done") {
|
|
4605
|
-
console.log(chalk45.red(`Item #${id} is already done.`));
|
|
4606
|
-
return false;
|
|
4607
|
-
}
|
|
4608
|
-
if (item.status === "wontdo") {
|
|
4609
|
-
console.log(chalk45.red(`Item #${id} is marked won't do.`));
|
|
4610
|
-
return false;
|
|
4611
|
-
}
|
|
4612
|
-
if (isBlocked(item, items2)) {
|
|
4613
|
-
console.log(
|
|
4614
|
-
chalk45.red(`Item #${id} is blocked by unresolved dependencies.`)
|
|
4615
|
-
);
|
|
4616
|
-
return false;
|
|
4617
|
-
}
|
|
4618
|
-
console.log(chalk45.bold(`
|
|
4619
|
-
Running backlog item #${id}...
|
|
4620
|
-
`));
|
|
4621
|
-
await run2(id, options2);
|
|
4622
|
-
return true;
|
|
4623
|
-
}
|
|
4624
|
-
|
|
4625
|
-
// src/commands/backlog/launchMode.ts
|
|
4626
|
-
async function launchMode(slashCommand) {
|
|
4627
|
-
pullIfConfigured();
|
|
4628
|
-
process.env.ASSIST_SESSION_ID = String(process.pid);
|
|
4629
|
-
const { child, done: done2 } = spawnClaude(`/${slashCommand}`, { allowEdits: true });
|
|
4630
|
-
watchForMarker(child);
|
|
4631
|
-
await done2;
|
|
4632
|
-
stopWatching();
|
|
4633
|
-
const signal = readSignal();
|
|
4634
|
-
cleanupSignal();
|
|
4635
|
-
if (signal?.event === "next") {
|
|
4636
|
-
if (typeof signal.id === "string" && signal.id) {
|
|
4637
|
-
if (await tryRunById(signal.id, { allowEdits: true })) return;
|
|
4638
|
-
}
|
|
4639
|
-
console.log(chalk46.bold("\nChaining into assist next...\n"));
|
|
4640
|
-
await next({ allowEdits: true });
|
|
4641
|
-
}
|
|
4642
|
-
}
|
|
4643
|
-
|
|
4644
|
-
// src/commands/backlog/refine.ts
|
|
4645
|
-
async function pickItemForRefine() {
|
|
4646
|
-
const items2 = await loadBacklog();
|
|
4647
|
-
const active = items2.filter(
|
|
4648
|
-
(i) => i.status === "todo" || i.status === "in-progress"
|
|
4649
|
-
);
|
|
4650
|
-
if (active.length === 0) {
|
|
4651
|
-
console.log(chalk47.yellow("No active backlog items to refine."));
|
|
4652
|
-
return void 0;
|
|
4653
|
-
}
|
|
4654
|
-
if (active.length === 1) {
|
|
4655
|
-
const item = active[0];
|
|
4656
|
-
console.log(chalk47.bold(`Auto-selecting item #${item.id}: ${item.name}`));
|
|
4657
|
-
return String(item.id);
|
|
4658
|
-
}
|
|
4659
|
-
const { selected } = await exitOnCancel(
|
|
4660
|
-
enquirer6.prompt({
|
|
4661
|
-
type: "select",
|
|
4662
|
-
name: "selected",
|
|
4663
|
-
message: "Choose a backlog item to refine:",
|
|
4664
|
-
choices: active.map((item) => ({
|
|
4665
|
-
name: `${typeLabel(item.type)} #${item.id}: ${item.name}`
|
|
4666
|
-
}))
|
|
4667
|
-
})
|
|
4668
|
-
);
|
|
4669
|
-
return selected.match(/#(\d+)/)?.[1] ?? "";
|
|
4670
|
-
}
|
|
4671
|
-
async function refine(id) {
|
|
4672
|
-
const itemId = id ?? await pickItemForRefine();
|
|
4673
|
-
if (!itemId) return;
|
|
4674
|
-
await launchMode(`refine ${itemId}`);
|
|
4675
|
-
}
|
|
4676
|
-
|
|
4677
4587
|
// src/commands/backlog/comment/index.ts
|
|
4678
|
-
import
|
|
4588
|
+
import chalk45 from "chalk";
|
|
4679
4589
|
async function comment(id, text2) {
|
|
4680
4590
|
const found = await findOneItem(id);
|
|
4681
4591
|
if (!found) process.exit(1);
|
|
4682
4592
|
await appendComment(found.orm, found.item.id, text2);
|
|
4683
|
-
console.log(
|
|
4593
|
+
console.log(chalk45.green(`Comment added to item #${id}.`));
|
|
4684
4594
|
}
|
|
4685
4595
|
|
|
4686
4596
|
// src/commands/backlog/comments/index.ts
|
|
4687
|
-
import
|
|
4597
|
+
import chalk46 from "chalk";
|
|
4688
4598
|
async function comments2(id) {
|
|
4689
4599
|
const found = await findOneItem(id);
|
|
4690
4600
|
if (!found) process.exit(1);
|
|
4691
4601
|
const { item } = found;
|
|
4692
4602
|
const entries = item.comments ?? [];
|
|
4693
4603
|
if (entries.length === 0) {
|
|
4694
|
-
console.log(
|
|
4604
|
+
console.log(chalk46.dim(`No comments on item #${id}.`));
|
|
4695
4605
|
return;
|
|
4696
4606
|
}
|
|
4697
|
-
console.log(
|
|
4607
|
+
console.log(chalk46.bold(`Comments for #${id}: ${item.name}
|
|
4698
4608
|
`));
|
|
4699
4609
|
for (const entry of entries) {
|
|
4700
4610
|
console.log(`${formatComment(entry)}
|
|
@@ -4703,7 +4613,7 @@ async function comments2(id) {
|
|
|
4703
4613
|
}
|
|
4704
4614
|
|
|
4705
4615
|
// src/commands/backlog/delete-comment/index.ts
|
|
4706
|
-
import
|
|
4616
|
+
import chalk47 from "chalk";
|
|
4707
4617
|
async function deleteCommentCmd(id, commentId) {
|
|
4708
4618
|
const found = await findOneItem(id);
|
|
4709
4619
|
if (!found) process.exit(1);
|
|
@@ -4715,16 +4625,16 @@ async function deleteCommentCmd(id, commentId) {
|
|
|
4715
4625
|
switch (outcome) {
|
|
4716
4626
|
case "deleted":
|
|
4717
4627
|
console.log(
|
|
4718
|
-
|
|
4628
|
+
chalk47.green(`Comment #${commentId} deleted from item #${id}.`)
|
|
4719
4629
|
);
|
|
4720
4630
|
break;
|
|
4721
4631
|
case "not-found":
|
|
4722
|
-
console.log(
|
|
4632
|
+
console.log(chalk47.red(`Comment #${commentId} not found on item #${id}.`));
|
|
4723
4633
|
process.exit(1);
|
|
4724
4634
|
break;
|
|
4725
4635
|
case "is-summary":
|
|
4726
4636
|
console.log(
|
|
4727
|
-
|
|
4637
|
+
chalk47.red(
|
|
4728
4638
|
`Comment #${commentId} is a phase summary and cannot be deleted.`
|
|
4729
4639
|
)
|
|
4730
4640
|
);
|
|
@@ -4742,7 +4652,7 @@ function registerCommentCommands(cmd) {
|
|
|
4742
4652
|
|
|
4743
4653
|
// src/commands/backlog/export/index.ts
|
|
4744
4654
|
import { writeFile } from "fs/promises";
|
|
4745
|
-
import
|
|
4655
|
+
import chalk48 from "chalk";
|
|
4746
4656
|
|
|
4747
4657
|
// src/commands/backlog/dump/DumpTable.ts
|
|
4748
4658
|
var DUMP_FORMAT = "assist-backlog-dump";
|
|
@@ -4809,7 +4719,7 @@ async function exportBacklog(file) {
|
|
|
4809
4719
|
if (file) {
|
|
4810
4720
|
await writeFile(file, dump);
|
|
4811
4721
|
console.error(
|
|
4812
|
-
|
|
4722
|
+
chalk48.green(`Exported backlog to ${file} (${dump.length} bytes).`)
|
|
4813
4723
|
);
|
|
4814
4724
|
return;
|
|
4815
4725
|
}
|
|
@@ -4825,7 +4735,7 @@ function registerExportCommand(cmd) {
|
|
|
4825
4735
|
|
|
4826
4736
|
// src/commands/backlog/import/index.ts
|
|
4827
4737
|
import { readFile } from "fs/promises";
|
|
4828
|
-
import
|
|
4738
|
+
import chalk50 from "chalk";
|
|
4829
4739
|
|
|
4830
4740
|
// src/commands/backlog/dump/countCopyRows.ts
|
|
4831
4741
|
function countCopyRows(data) {
|
|
@@ -4902,7 +4812,7 @@ function validateDump({ header, sections }) {
|
|
|
4902
4812
|
}
|
|
4903
4813
|
|
|
4904
4814
|
// src/commands/backlog/import/confirmReplace.ts
|
|
4905
|
-
import
|
|
4815
|
+
import chalk49 from "chalk";
|
|
4906
4816
|
async function countRows(client, table) {
|
|
4907
4817
|
const { rows } = await client.query(
|
|
4908
4818
|
`SELECT count(*)::int AS n FROM ${table}`
|
|
@@ -4913,7 +4823,7 @@ function printSummary(current, incoming) {
|
|
|
4913
4823
|
const lines = DUMP_TABLES.map(
|
|
4914
4824
|
(t, i) => ` ${t.name}: ${current[i]} \u2192 ${incoming[i]} rows`
|
|
4915
4825
|
);
|
|
4916
|
-
console.error(
|
|
4826
|
+
console.error(chalk49.bold("\nThis will REPLACE all backlog data:"));
|
|
4917
4827
|
console.error(`${lines.join("\n")}
|
|
4918
4828
|
`);
|
|
4919
4829
|
}
|
|
@@ -4989,13 +4899,13 @@ async function importBacklog(file, options2 = {}) {
|
|
|
4989
4899
|
);
|
|
4990
4900
|
await withBacklogClient(async (client) => {
|
|
4991
4901
|
if (!options2.yes && !await confirmReplace(client, incoming, !file)) {
|
|
4992
|
-
console.error(
|
|
4902
|
+
console.error(chalk50.yellow("Import cancelled; no changes made."));
|
|
4993
4903
|
return;
|
|
4994
4904
|
}
|
|
4995
4905
|
await restore(client, parsed);
|
|
4996
4906
|
const total = incoming.reduce((sum, n) => sum + n, 0);
|
|
4997
4907
|
console.error(
|
|
4998
|
-
|
|
4908
|
+
chalk50.green(
|
|
4999
4909
|
`Imported backlog: ${total} rows restored across ${DUMP_TABLES.length} tables.`
|
|
5000
4910
|
)
|
|
5001
4911
|
);
|
|
@@ -5012,16 +4922,16 @@ function registerImportCommand(cmd) {
|
|
|
5012
4922
|
}
|
|
5013
4923
|
|
|
5014
4924
|
// src/commands/backlog/add/index.ts
|
|
5015
|
-
import
|
|
4925
|
+
import chalk51 from "chalk";
|
|
5016
4926
|
|
|
5017
4927
|
// src/commands/backlog/add/shared.ts
|
|
5018
4928
|
import { spawnSync } from "child_process";
|
|
5019
4929
|
import { mkdtempSync, readFileSync as readFileSync14, unlinkSync as unlinkSync4, writeFileSync as writeFileSync13 } from "fs";
|
|
5020
4930
|
import { tmpdir } from "os";
|
|
5021
4931
|
import { join as join17 } from "path";
|
|
5022
|
-
import
|
|
4932
|
+
import enquirer6 from "enquirer";
|
|
5023
4933
|
async function promptType() {
|
|
5024
|
-
const { type } = await
|
|
4934
|
+
const { type } = await enquirer6.prompt({
|
|
5025
4935
|
type: "select",
|
|
5026
4936
|
name: "type",
|
|
5027
4937
|
message: "Type:",
|
|
@@ -5031,7 +4941,7 @@ async function promptType() {
|
|
|
5031
4941
|
return type;
|
|
5032
4942
|
}
|
|
5033
4943
|
async function promptName() {
|
|
5034
|
-
const { name } = await
|
|
4944
|
+
const { name } = await enquirer6.prompt({
|
|
5035
4945
|
type: "input",
|
|
5036
4946
|
name: "name",
|
|
5037
4947
|
message: "Name:",
|
|
@@ -5040,14 +4950,14 @@ async function promptName() {
|
|
|
5040
4950
|
return name.trim();
|
|
5041
4951
|
}
|
|
5042
4952
|
async function promptDescription() {
|
|
5043
|
-
const { useEditor } = await
|
|
4953
|
+
const { useEditor } = await enquirer6.prompt({
|
|
5044
4954
|
type: "confirm",
|
|
5045
4955
|
name: "useEditor",
|
|
5046
4956
|
message: "Open editor for description?",
|
|
5047
4957
|
initial: false
|
|
5048
4958
|
});
|
|
5049
4959
|
if (!useEditor) {
|
|
5050
|
-
const { description } = await
|
|
4960
|
+
const { description } = await enquirer6.prompt({
|
|
5051
4961
|
type: "input",
|
|
5052
4962
|
name: "description",
|
|
5053
4963
|
message: "Description (optional):"
|
|
@@ -5073,7 +4983,7 @@ function openEditor() {
|
|
|
5073
4983
|
async function promptAcceptanceCriteria() {
|
|
5074
4984
|
const criteria = [];
|
|
5075
4985
|
for (; ; ) {
|
|
5076
|
-
const { criterion } = await
|
|
4986
|
+
const { criterion } = await enquirer6.prompt({
|
|
5077
4987
|
type: "input",
|
|
5078
4988
|
name: "criterion",
|
|
5079
4989
|
message: "Acceptance criterion (empty to finish):"
|
|
@@ -5102,11 +5012,11 @@ async function add(options2) {
|
|
|
5102
5012
|
},
|
|
5103
5013
|
getOrigin()
|
|
5104
5014
|
);
|
|
5105
|
-
console.log(
|
|
5015
|
+
console.log(chalk51.green(`Added item #${id}: ${name}`));
|
|
5106
5016
|
}
|
|
5107
5017
|
|
|
5108
5018
|
// src/commands/backlog/addPhase.ts
|
|
5109
|
-
import
|
|
5019
|
+
import chalk53 from "chalk";
|
|
5110
5020
|
|
|
5111
5021
|
// src/commands/backlog/insertPhaseAt.ts
|
|
5112
5022
|
import { count, eq as eq14 } from "drizzle-orm";
|
|
@@ -5139,7 +5049,7 @@ async function insertPhaseAt(orm, itemId, phaseIdx, name, tasks, manualChecks, c
|
|
|
5139
5049
|
}
|
|
5140
5050
|
|
|
5141
5051
|
// src/commands/backlog/resolveInsertPosition.ts
|
|
5142
|
-
import
|
|
5052
|
+
import chalk52 from "chalk";
|
|
5143
5053
|
import { count as count2, eq as eq15 } from "drizzle-orm";
|
|
5144
5054
|
async function resolveInsertPosition(orm, itemId, position) {
|
|
5145
5055
|
const [row] = await orm.select({ cnt: count2() }).from(planPhases).where(eq15(planPhases.itemId, itemId));
|
|
@@ -5148,7 +5058,7 @@ async function resolveInsertPosition(orm, itemId, position) {
|
|
|
5148
5058
|
const pos = Number.parseInt(position, 10);
|
|
5149
5059
|
if (pos < 1 || pos > phaseCount + 1) {
|
|
5150
5060
|
console.log(
|
|
5151
|
-
|
|
5061
|
+
chalk52.red(
|
|
5152
5062
|
`Position ${pos} is out of range. Must be between 1 and ${phaseCount + 1}.`
|
|
5153
5063
|
)
|
|
5154
5064
|
);
|
|
@@ -5169,7 +5079,7 @@ async function addPhase(id, name, options2) {
|
|
|
5169
5079
|
if (!found) return;
|
|
5170
5080
|
const tasks = options2.task ?? [];
|
|
5171
5081
|
if (tasks.length === 0) {
|
|
5172
|
-
console.log(
|
|
5082
|
+
console.log(chalk53.red("At least one --task is required."));
|
|
5173
5083
|
process.exitCode = 1;
|
|
5174
5084
|
return;
|
|
5175
5085
|
}
|
|
@@ -5188,14 +5098,14 @@ async function addPhase(id, name, options2) {
|
|
|
5188
5098
|
);
|
|
5189
5099
|
const verb = options2.position !== void 0 ? "Inserted" : "Added";
|
|
5190
5100
|
console.log(
|
|
5191
|
-
|
|
5101
|
+
chalk53.green(
|
|
5192
5102
|
`${verb} phase ${phaseIdx + 1} "${name}" to item #${itemId} with ${tasks.length} task(s).`
|
|
5193
5103
|
)
|
|
5194
5104
|
);
|
|
5195
5105
|
}
|
|
5196
5106
|
|
|
5197
5107
|
// src/commands/backlog/list/index.ts
|
|
5198
|
-
import
|
|
5108
|
+
import chalk54 from "chalk";
|
|
5199
5109
|
|
|
5200
5110
|
// src/commands/backlog/originDisplayName.ts
|
|
5201
5111
|
function originDisplayName(origin) {
|
|
@@ -5247,7 +5157,7 @@ async function list2(options2) {
|
|
|
5247
5157
|
const allItems = await loadBacklog(options2.allRepos);
|
|
5248
5158
|
const items2 = filterItems(allItems, options2);
|
|
5249
5159
|
if (items2.length === 0) {
|
|
5250
|
-
console.log(
|
|
5160
|
+
console.log(chalk54.dim("Backlog is empty."));
|
|
5251
5161
|
return;
|
|
5252
5162
|
}
|
|
5253
5163
|
const labels = originDisplayLabels(
|
|
@@ -5256,9 +5166,9 @@ async function list2(options2) {
|
|
|
5256
5166
|
const repoNameOf = (item) => item.origin ? labels.get(item.origin) ?? "" : "";
|
|
5257
5167
|
const prefixWidth = options2.allRepos ? Math.max(0, ...items2.map((i) => repoNameOf(i).length)) : 0;
|
|
5258
5168
|
for (const item of items2) {
|
|
5259
|
-
const repoPrefix2 = options2.allRepos ? `${
|
|
5169
|
+
const repoPrefix2 = options2.allRepos ? `${chalk54.dim(repoNameOf(item).padEnd(prefixWidth))} ` : "";
|
|
5260
5170
|
console.log(
|
|
5261
|
-
`${repoPrefix2}${statusIcon(item.status)} ${typeLabel(item.type)} ${
|
|
5171
|
+
`${repoPrefix2}${statusIcon(item.status)} ${typeLabel(item.type)} ${chalk54.dim(`#${item.id}`)} ${item.name}${phaseLabel(item)}${dependencyLabel(item, allItems)}`
|
|
5262
5172
|
);
|
|
5263
5173
|
if (options2.verbose) {
|
|
5264
5174
|
printVerboseDetails(item);
|
|
@@ -5284,7 +5194,7 @@ function registerItemCommands(cmd) {
|
|
|
5284
5194
|
}
|
|
5285
5195
|
|
|
5286
5196
|
// src/commands/backlog/link.ts
|
|
5287
|
-
import
|
|
5197
|
+
import chalk56 from "chalk";
|
|
5288
5198
|
|
|
5289
5199
|
// src/commands/backlog/hasCycle.ts
|
|
5290
5200
|
function hasCycle(adjacency, fromId, toId) {
|
|
@@ -5316,14 +5226,14 @@ async function loadDependencyGraph(orm) {
|
|
|
5316
5226
|
}
|
|
5317
5227
|
|
|
5318
5228
|
// src/commands/backlog/validateLinkTarget.ts
|
|
5319
|
-
import
|
|
5229
|
+
import chalk55 from "chalk";
|
|
5320
5230
|
function validateLinkTarget(fromItem, fromNum, toNum, linkType) {
|
|
5321
5231
|
const duplicate = (fromItem.links ?? []).some(
|
|
5322
5232
|
(l) => l.targetId === toNum && l.type === linkType
|
|
5323
5233
|
);
|
|
5324
5234
|
if (duplicate) {
|
|
5325
5235
|
console.log(
|
|
5326
|
-
|
|
5236
|
+
chalk55.yellow(`Link already exists: #${fromNum} ${linkType} #${toNum}`)
|
|
5327
5237
|
);
|
|
5328
5238
|
return false;
|
|
5329
5239
|
}
|
|
@@ -5332,7 +5242,7 @@ function validateLinkTarget(fromItem, fromNum, toNum, linkType) {
|
|
|
5332
5242
|
|
|
5333
5243
|
// src/commands/backlog/link.ts
|
|
5334
5244
|
function fail(message) {
|
|
5335
|
-
console.log(
|
|
5245
|
+
console.log(chalk56.red(message));
|
|
5336
5246
|
return void 0;
|
|
5337
5247
|
}
|
|
5338
5248
|
function parseLinkType(type) {
|
|
@@ -5362,12 +5272,12 @@ async function link(fromId, toId, opts) {
|
|
|
5362
5272
|
if (await createsCycle(orm, linkType, fromNum, toNum)) return;
|
|
5363
5273
|
await orm.insert(links).values({ itemId: fromNum, type: linkType, targetId: toNum });
|
|
5364
5274
|
console.log(
|
|
5365
|
-
|
|
5275
|
+
chalk56.green(`Linked #${fromNum} ${linkType} #${toNum} (${toItem.name})`)
|
|
5366
5276
|
);
|
|
5367
5277
|
}
|
|
5368
5278
|
|
|
5369
5279
|
// src/commands/backlog/unlink.ts
|
|
5370
|
-
import
|
|
5280
|
+
import chalk57 from "chalk";
|
|
5371
5281
|
import { and as and4, eq as eq17 } from "drizzle-orm";
|
|
5372
5282
|
async function unlink(fromId, toId) {
|
|
5373
5283
|
const fromNum = Number.parseInt(fromId, 10);
|
|
@@ -5375,19 +5285,19 @@ async function unlink(fromId, toId) {
|
|
|
5375
5285
|
const { orm } = await getReady();
|
|
5376
5286
|
const fromItem = await loadItem(orm, fromNum);
|
|
5377
5287
|
if (!fromItem) {
|
|
5378
|
-
console.log(
|
|
5288
|
+
console.log(chalk57.red(`Item #${fromId} not found.`));
|
|
5379
5289
|
return;
|
|
5380
5290
|
}
|
|
5381
5291
|
if (!fromItem.links || fromItem.links.length === 0) {
|
|
5382
|
-
console.log(
|
|
5292
|
+
console.log(chalk57.yellow(`No links found on item #${fromId}.`));
|
|
5383
5293
|
return;
|
|
5384
5294
|
}
|
|
5385
5295
|
if (!fromItem.links.some((l) => l.targetId === toNum)) {
|
|
5386
|
-
console.log(
|
|
5296
|
+
console.log(chalk57.yellow(`No link from #${fromId} to #${toId} found.`));
|
|
5387
5297
|
return;
|
|
5388
5298
|
}
|
|
5389
5299
|
await orm.delete(links).where(and4(eq17(links.itemId, fromNum), eq17(links.targetId, toNum)));
|
|
5390
|
-
console.log(
|
|
5300
|
+
console.log(chalk57.green(`Removed link from #${fromId} to #${toId}.`));
|
|
5391
5301
|
}
|
|
5392
5302
|
|
|
5393
5303
|
// src/commands/backlog/registerLinkCommands.ts
|
|
@@ -5401,17 +5311,17 @@ function registerLinkCommands(cmd) {
|
|
|
5401
5311
|
}
|
|
5402
5312
|
|
|
5403
5313
|
// src/commands/backlog/move-repo/index.ts
|
|
5404
|
-
import
|
|
5314
|
+
import chalk59 from "chalk";
|
|
5405
5315
|
import { eq as eq19 } from "drizzle-orm";
|
|
5406
5316
|
|
|
5407
5317
|
// src/commands/backlog/move-repo/confirmMove.ts
|
|
5408
|
-
import
|
|
5318
|
+
import chalk58 from "chalk";
|
|
5409
5319
|
function pluralItems(n) {
|
|
5410
5320
|
return `${n} item${n === 1 ? "" : "s"}`;
|
|
5411
5321
|
}
|
|
5412
5322
|
async function confirmMove(cnt, oldOrigin, newOrigin) {
|
|
5413
5323
|
console.log(
|
|
5414
|
-
`${pluralItems(cnt)}: ${
|
|
5324
|
+
`${pluralItems(cnt)}: ${chalk58.cyan(oldOrigin)} \u2192 ${chalk58.cyan(newOrigin)}`
|
|
5415
5325
|
);
|
|
5416
5326
|
return promptConfirm(`Retag ${pluralItems(cnt)}?`);
|
|
5417
5327
|
}
|
|
@@ -5443,7 +5353,7 @@ Pass the full origin.`
|
|
|
5443
5353
|
|
|
5444
5354
|
// src/commands/backlog/move-repo/index.ts
|
|
5445
5355
|
function fail2(message) {
|
|
5446
|
-
console.log(
|
|
5356
|
+
console.log(chalk59.red(message));
|
|
5447
5357
|
process.exitCode = 1;
|
|
5448
5358
|
}
|
|
5449
5359
|
async function moveRepo(oldOriginRaw, newOriginRaw, options2 = {}) {
|
|
@@ -5459,12 +5369,12 @@ async function moveRepo(oldOriginRaw, newOriginRaw, options2 = {}) {
|
|
|
5459
5369
|
}
|
|
5460
5370
|
const cnt = await countByOrigin(orm, oldOrigin);
|
|
5461
5371
|
if (!options2.yes && !await confirmMove(cnt, oldOrigin, newOrigin)) {
|
|
5462
|
-
console.log(
|
|
5372
|
+
console.log(chalk59.yellow("Move cancelled; no changes made."));
|
|
5463
5373
|
return;
|
|
5464
5374
|
}
|
|
5465
5375
|
await orm.update(items).set({ origin: newOrigin }).where(eq19(items.origin, oldOrigin));
|
|
5466
5376
|
console.log(
|
|
5467
|
-
|
|
5377
|
+
chalk59.green(
|
|
5468
5378
|
`Moved ${pluralItems(cnt)} from "${oldOrigin}" to "${newOrigin}".`
|
|
5469
5379
|
)
|
|
5470
5380
|
);
|
|
@@ -5479,12 +5389,116 @@ function registerMoveRepoCommand(cmd) {
|
|
|
5479
5389
|
);
|
|
5480
5390
|
}
|
|
5481
5391
|
|
|
5392
|
+
// src/commands/backlog/registerNextCommand.ts
|
|
5393
|
+
function registerNextCommand(cmd) {
|
|
5394
|
+
cmd.command("next").argument("[id]", "Backlog item ID to run first").description("Pick and run the next backlog item, or open /draft if none").option("-w, --write", "Run Claude with auto permission mode (default)").option("--no-write", "Run Claude without auto permission mode").option("--once", "Exit after the first completed item run").action(
|
|
5395
|
+
(id, opts) => next({ allowEdits: opts.write !== false, once: opts.once }, id)
|
|
5396
|
+
);
|
|
5397
|
+
}
|
|
5398
|
+
|
|
5482
5399
|
// src/commands/backlog/registerPlanCommands.ts
|
|
5483
5400
|
function registerPlanCommands(cmd) {
|
|
5484
5401
|
cmd.command("plan <id>").description("Display the plan for a backlog item").action(plan);
|
|
5485
5402
|
cmd.command("phase-done <id> <phase> <summary>").description("Signal that a plan phase is complete").action(phaseDone);
|
|
5486
5403
|
}
|
|
5487
5404
|
|
|
5405
|
+
// src/commands/backlog/refine.ts
|
|
5406
|
+
import chalk62 from "chalk";
|
|
5407
|
+
import enquirer7 from "enquirer";
|
|
5408
|
+
|
|
5409
|
+
// src/commands/backlog/launchMode.ts
|
|
5410
|
+
import chalk61 from "chalk";
|
|
5411
|
+
|
|
5412
|
+
// src/commands/backlog/tryRunById.ts
|
|
5413
|
+
import chalk60 from "chalk";
|
|
5414
|
+
async function tryRunById(id, options2) {
|
|
5415
|
+
const items2 = await loadBacklog();
|
|
5416
|
+
const numericId = Number.parseInt(id, 10);
|
|
5417
|
+
const item = Number.isNaN(numericId) ? void 0 : items2.find((i) => i.id === numericId);
|
|
5418
|
+
if (!item) {
|
|
5419
|
+
console.log(chalk60.red(`Item #${id} not found.`));
|
|
5420
|
+
return false;
|
|
5421
|
+
}
|
|
5422
|
+
if (item.status === "done") {
|
|
5423
|
+
console.log(chalk60.red(`Item #${id} is already done.`));
|
|
5424
|
+
return false;
|
|
5425
|
+
}
|
|
5426
|
+
if (item.status === "wontdo") {
|
|
5427
|
+
console.log(chalk60.red(`Item #${id} is marked won't do.`));
|
|
5428
|
+
return false;
|
|
5429
|
+
}
|
|
5430
|
+
if (isBlocked(item, items2)) {
|
|
5431
|
+
console.log(
|
|
5432
|
+
chalk60.red(`Item #${id} is blocked by unresolved dependencies.`)
|
|
5433
|
+
);
|
|
5434
|
+
return false;
|
|
5435
|
+
}
|
|
5436
|
+
console.log(chalk60.bold(`
|
|
5437
|
+
Running backlog item #${id}...
|
|
5438
|
+
`));
|
|
5439
|
+
await run2(id, options2);
|
|
5440
|
+
return true;
|
|
5441
|
+
}
|
|
5442
|
+
|
|
5443
|
+
// src/commands/backlog/launchMode.ts
|
|
5444
|
+
async function launchMode(slashCommand, options2) {
|
|
5445
|
+
pullIfConfigured();
|
|
5446
|
+
process.env.ASSIST_SESSION_ID = String(process.pid);
|
|
5447
|
+
const { child, done: done2 } = spawnClaude(`/${slashCommand}`, { allowEdits: true });
|
|
5448
|
+
watchForMarker(child, { actOnDone: options2?.once });
|
|
5449
|
+
await done2;
|
|
5450
|
+
stopWatching();
|
|
5451
|
+
const signal = readSignal();
|
|
5452
|
+
cleanupSignal();
|
|
5453
|
+
if (signal?.event === "next") {
|
|
5454
|
+
if (typeof signal.id === "string" && signal.id) {
|
|
5455
|
+
if (await tryRunById(signal.id, { allowEdits: true })) return;
|
|
5456
|
+
}
|
|
5457
|
+
console.log(chalk61.bold("\nChaining into assist next...\n"));
|
|
5458
|
+
await next({ allowEdits: true, once: options2?.once });
|
|
5459
|
+
}
|
|
5460
|
+
}
|
|
5461
|
+
|
|
5462
|
+
// src/commands/backlog/refine.ts
|
|
5463
|
+
async function pickItemForRefine() {
|
|
5464
|
+
const items2 = await loadBacklog();
|
|
5465
|
+
const active = items2.filter(
|
|
5466
|
+
(i) => i.status === "todo" || i.status === "in-progress"
|
|
5467
|
+
);
|
|
5468
|
+
if (active.length === 0) {
|
|
5469
|
+
console.log(chalk62.yellow("No active backlog items to refine."));
|
|
5470
|
+
return void 0;
|
|
5471
|
+
}
|
|
5472
|
+
if (active.length === 1) {
|
|
5473
|
+
const item = active[0];
|
|
5474
|
+
console.log(chalk62.bold(`Auto-selecting item #${item.id}: ${item.name}`));
|
|
5475
|
+
return String(item.id);
|
|
5476
|
+
}
|
|
5477
|
+
const { selected } = await exitOnCancel(
|
|
5478
|
+
enquirer7.prompt({
|
|
5479
|
+
type: "select",
|
|
5480
|
+
name: "selected",
|
|
5481
|
+
message: "Choose a backlog item to refine:",
|
|
5482
|
+
choices: active.map((item) => ({
|
|
5483
|
+
name: `${typeLabel(item.type)} #${item.id}: ${item.name}`
|
|
5484
|
+
}))
|
|
5485
|
+
})
|
|
5486
|
+
);
|
|
5487
|
+
return selected.match(/#(\d+)/)?.[1] ?? "";
|
|
5488
|
+
}
|
|
5489
|
+
async function refine(id, options2) {
|
|
5490
|
+
const itemId = id ?? await pickItemForRefine();
|
|
5491
|
+
if (!itemId) return;
|
|
5492
|
+
await launchMode(`refine ${itemId}`, options2);
|
|
5493
|
+
}
|
|
5494
|
+
|
|
5495
|
+
// src/commands/backlog/registerRefineCommand.ts
|
|
5496
|
+
function registerRefineCommand(cmd) {
|
|
5497
|
+
cmd.command("refine").argument("[id]", "Backlog item ID").description("Alias for refine").option("--once", "Exit when the initial task completes").action(
|
|
5498
|
+
(id, opts) => refine(id, { once: opts.once })
|
|
5499
|
+
);
|
|
5500
|
+
}
|
|
5501
|
+
|
|
5488
5502
|
// src/commands/backlog/rewindPhase.ts
|
|
5489
5503
|
import chalk63 from "chalk";
|
|
5490
5504
|
function validateRewind2(item, phaseNumber) {
|
|
@@ -6021,14 +6035,6 @@ function registerShowCommands(cmd) {
|
|
|
6021
6035
|
function registerWebCommand(cmd) {
|
|
6022
6036
|
cmd.command("web").description("Open the backlog tab in the web dashboard").option("-p, --port <number>", "Port to listen on", "3100").action(web2);
|
|
6023
6037
|
}
|
|
6024
|
-
function registerRefineCommand(cmd) {
|
|
6025
|
-
cmd.command("refine").argument("[id]", "Backlog item ID").description("Alias for refine").action((id) => refine(id));
|
|
6026
|
-
}
|
|
6027
|
-
function registerNextCommand(cmd) {
|
|
6028
|
-
cmd.command("next").argument("[id]", "Backlog item ID to run first").description("Pick and run the next backlog item, or open /draft if none").option("-w, --write", "Run Claude with auto permission mode (default)").option("--no-write", "Run Claude without auto permission mode").action(
|
|
6029
|
-
(id, opts) => next({ allowEdits: opts.write !== false }, id)
|
|
6030
|
-
);
|
|
6031
|
-
}
|
|
6032
6038
|
var registrars = [
|
|
6033
6039
|
registerItemCommands,
|
|
6034
6040
|
registerShowCommands,
|
|
@@ -9598,13 +9604,21 @@ async function reviewComments(number) {
|
|
|
9598
9604
|
|
|
9599
9605
|
// src/commands/registerLaunch.ts
|
|
9600
9606
|
function registerLaunch(program2) {
|
|
9601
|
-
program2.command("next").argument("[id]", "Backlog item ID to run first").description("Alias for backlog next").
|
|
9607
|
+
program2.command("next").argument("[id]", "Backlog item ID to run first").description("Alias for backlog next").option("--once", "Exit after the first completed item run").action(
|
|
9608
|
+
(id, opts) => next({ allowEdits: true, once: opts.once }, id)
|
|
9609
|
+
);
|
|
9602
9610
|
program2.command("draft").alias("feat").description(
|
|
9603
9611
|
"Launch Claude in /draft mode, chain into next on /next signal"
|
|
9604
|
-
).
|
|
9605
|
-
|
|
9612
|
+
).option("--once", "Exit when the initial task completes").action(
|
|
9613
|
+
(opts) => launchMode("draft", { once: opts.once })
|
|
9614
|
+
);
|
|
9615
|
+
program2.command("bug").description("Launch Claude in /bug mode, chain into next on /next signal").option("--once", "Exit when the initial task completes").action(
|
|
9616
|
+
(opts) => launchMode("bug", { once: opts.once })
|
|
9617
|
+
);
|
|
9606
9618
|
program2.command("review-comments").argument("[number]", "PR number to check out first").description("Launch Claude in /review-comments mode (single session)").action((number) => reviewComments(number));
|
|
9607
|
-
program2.command("refine").argument("[id]", "Backlog item ID").description("Launch Claude in /refine mode to refine a backlog item").
|
|
9619
|
+
program2.command("refine").argument("[id]", "Backlog item ID").description("Launch Claude in /refine mode to refine a backlog item").option("--once", "Exit when the initial task completes").action(
|
|
9620
|
+
(id, opts) => refine(id, { once: opts.once })
|
|
9621
|
+
);
|
|
9608
9622
|
}
|
|
9609
9623
|
|
|
9610
9624
|
// src/commands/registerList.ts
|
|
@@ -12826,6 +12840,35 @@ function buildReviewPaths(repoRoot, key) {
|
|
|
12826
12840
|
};
|
|
12827
12841
|
}
|
|
12828
12842
|
|
|
12843
|
+
// src/commands/review/ensureReviewsIgnored.ts
|
|
12844
|
+
import {
|
|
12845
|
+
appendFileSync,
|
|
12846
|
+
existsSync as existsSync35,
|
|
12847
|
+
readFileSync as readFileSync29,
|
|
12848
|
+
writeFileSync as writeFileSync24
|
|
12849
|
+
} from "fs";
|
|
12850
|
+
import { join as join36 } from "path";
|
|
12851
|
+
var REVIEWS_ENTRY = ".assist/reviews";
|
|
12852
|
+
function coversReviews(line) {
|
|
12853
|
+
const pattern2 = line.trim().replace(/^\//, "").replace(/\/$/, "");
|
|
12854
|
+
return pattern2 === ".assist" || pattern2 === REVIEWS_ENTRY;
|
|
12855
|
+
}
|
|
12856
|
+
function ensureReviewsIgnored(repoRoot) {
|
|
12857
|
+
const gitignorePath = join36(repoRoot, ".gitignore");
|
|
12858
|
+
if (!existsSync35(gitignorePath)) {
|
|
12859
|
+
writeFileSync24(gitignorePath, `${REVIEWS_ENTRY}
|
|
12860
|
+
`);
|
|
12861
|
+
console.log(`Created .gitignore with ${REVIEWS_ENTRY} entry.`);
|
|
12862
|
+
return;
|
|
12863
|
+
}
|
|
12864
|
+
const content = readFileSync29(gitignorePath, "utf-8");
|
|
12865
|
+
if (content.split("\n").some(coversReviews)) return;
|
|
12866
|
+
const separator = content === "" || content.endsWith("\n") ? "" : "\n";
|
|
12867
|
+
appendFileSync(gitignorePath, `${separator}${REVIEWS_ENTRY}
|
|
12868
|
+
`);
|
|
12869
|
+
console.log(`Added ${REVIEWS_ENTRY} to .gitignore.`);
|
|
12870
|
+
}
|
|
12871
|
+
|
|
12829
12872
|
// src/commands/review/fetchExistingComments.ts
|
|
12830
12873
|
import { execSync as execSync40 } from "child_process";
|
|
12831
12874
|
function fetchRawComments(org, repo, prNumber) {
|
|
@@ -12965,7 +13008,7 @@ function gatherContext() {
|
|
|
12965
13008
|
}
|
|
12966
13009
|
|
|
12967
13010
|
// src/commands/review/postReviewToPr.ts
|
|
12968
|
-
import { readFileSync as
|
|
13011
|
+
import { readFileSync as readFileSync30 } from "fs";
|
|
12969
13012
|
|
|
12970
13013
|
// src/commands/review/parseFindings.ts
|
|
12971
13014
|
var SEVERITIES = ["blocker", "major", "minor", "nit"];
|
|
@@ -13195,7 +13238,7 @@ async function postReviewToPr(synthesisPath, options2) {
|
|
|
13195
13238
|
console.log("No PR found for current branch; nothing posted.");
|
|
13196
13239
|
return;
|
|
13197
13240
|
}
|
|
13198
|
-
const markdown =
|
|
13241
|
+
const markdown = readFileSync30(synthesisPath, "utf-8");
|
|
13199
13242
|
const findings = parseFindings(markdown);
|
|
13200
13243
|
if (findings.length === 0) {
|
|
13201
13244
|
console.log("Synthesis contains no findings; nothing to post.");
|
|
@@ -13272,16 +13315,16 @@ async function handlePostSynthesis(synthesisPath, options2) {
|
|
|
13272
13315
|
}
|
|
13273
13316
|
|
|
13274
13317
|
// src/commands/review/prepareReviewDir.ts
|
|
13275
|
-
import { existsSync as
|
|
13318
|
+
import { existsSync as existsSync36, mkdirSync as mkdirSync11, unlinkSync as unlinkSync10, writeFileSync as writeFileSync25 } from "fs";
|
|
13276
13319
|
function clearReviewFiles(paths) {
|
|
13277
13320
|
for (const path54 of [paths.claudePath, paths.codexPath, paths.synthesisPath]) {
|
|
13278
|
-
if (
|
|
13321
|
+
if (existsSync36(path54)) unlinkSync10(path54);
|
|
13279
13322
|
}
|
|
13280
13323
|
}
|
|
13281
13324
|
function prepareReviewDir(paths, requestBody, force) {
|
|
13282
13325
|
mkdirSync11(paths.reviewDir, { recursive: true });
|
|
13283
13326
|
if (force) clearReviewFiles(paths);
|
|
13284
|
-
|
|
13327
|
+
writeFileSync25(paths.requestPath, requestBody);
|
|
13285
13328
|
}
|
|
13286
13329
|
|
|
13287
13330
|
// src/commands/review/runApplySession.ts
|
|
@@ -13560,7 +13603,7 @@ function printReviewerFailures(results) {
|
|
|
13560
13603
|
}
|
|
13561
13604
|
|
|
13562
13605
|
// src/commands/review/runAndSynthesise.ts
|
|
13563
|
-
import { existsSync as
|
|
13606
|
+
import { existsSync as existsSync38, unlinkSync as unlinkSync12 } from "fs";
|
|
13564
13607
|
|
|
13565
13608
|
// src/commands/review/buildReviewerStdin.ts
|
|
13566
13609
|
var REVIEW_PROMPT = `You are acting as a reviewer for a proposed code change made by another engineer. The full review request \u2014 branch, base, changed files, and unified diff \u2014 is in request.md in the current working directory.
|
|
@@ -13624,7 +13667,7 @@ The review request is at: ${requestPath}
|
|
|
13624
13667
|
}
|
|
13625
13668
|
|
|
13626
13669
|
// src/commands/review/runClaudeReviewer.ts
|
|
13627
|
-
import { writeFileSync as
|
|
13670
|
+
import { writeFileSync as writeFileSync26 } from "fs";
|
|
13628
13671
|
|
|
13629
13672
|
// src/commands/review/finaliseReviewerSpinner.ts
|
|
13630
13673
|
var SUMMARY_MAX_LEN = 80;
|
|
@@ -13960,7 +14003,7 @@ async function runClaudeReviewer(spec) {
|
|
|
13960
14003
|
}
|
|
13961
14004
|
});
|
|
13962
14005
|
if (result.exitCode === 0 && finalText)
|
|
13963
|
-
|
|
14006
|
+
writeFileSync26(spec.outputPath, finalText);
|
|
13964
14007
|
return finaliseReviewerRun({ ...spec, command }, spinner, result);
|
|
13965
14008
|
}
|
|
13966
14009
|
|
|
@@ -13978,7 +14021,7 @@ function resolveClaude(args) {
|
|
|
13978
14021
|
}
|
|
13979
14022
|
|
|
13980
14023
|
// src/commands/review/runCodexReviewer.ts
|
|
13981
|
-
import { existsSync as
|
|
14024
|
+
import { existsSync as existsSync37, unlinkSync as unlinkSync11 } from "fs";
|
|
13982
14025
|
|
|
13983
14026
|
// src/commands/review/parseCodexEvent.ts
|
|
13984
14027
|
function isItemStarted(value) {
|
|
@@ -14032,7 +14075,7 @@ async function runCodexReviewer(spec) {
|
|
|
14032
14075
|
reportReviewerToolUse(spec.name, event, spinner);
|
|
14033
14076
|
}
|
|
14034
14077
|
});
|
|
14035
|
-
if (result.exitCode !== 0 &&
|
|
14078
|
+
if (result.exitCode !== 0 && existsSync37(spec.outputPath)) {
|
|
14036
14079
|
unlinkSync11(spec.outputPath);
|
|
14037
14080
|
}
|
|
14038
14081
|
return finaliseReviewerRun({ ...spec, command }, spinner, result);
|
|
@@ -14076,7 +14119,7 @@ async function runReviewers(reviewDir, claudePath, codexPath, stdinPrompt, optio
|
|
|
14076
14119
|
}
|
|
14077
14120
|
|
|
14078
14121
|
// src/commands/review/synthesise.ts
|
|
14079
|
-
import { readFileSync as
|
|
14122
|
+
import { readFileSync as readFileSync31 } from "fs";
|
|
14080
14123
|
|
|
14081
14124
|
// src/commands/review/buildSynthesisStdin.ts
|
|
14082
14125
|
var SYNTHESIS_PROMPT = `You are consolidating two independent code reviews of the same change. The original review request is in request.md. The two reviews are in claude.md and codex.md in the current working directory.
|
|
@@ -14132,7 +14175,7 @@ Files:
|
|
|
14132
14175
|
|
|
14133
14176
|
// src/commands/review/synthesise.ts
|
|
14134
14177
|
function printSummary2(synthesisPath) {
|
|
14135
|
-
const markdown =
|
|
14178
|
+
const markdown = readFileSync31(synthesisPath, "utf-8");
|
|
14136
14179
|
console.log("");
|
|
14137
14180
|
console.log(buildReviewSummary(markdown));
|
|
14138
14181
|
console.log("");
|
|
@@ -14180,7 +14223,7 @@ async function runAndSynthesise(args) {
|
|
|
14180
14223
|
console.error("Both reviewers failed; skipping synthesis.");
|
|
14181
14224
|
return { ok: false, failures };
|
|
14182
14225
|
}
|
|
14183
|
-
if (anyFresh &&
|
|
14226
|
+
if (anyFresh && existsSync38(paths.synthesisPath)) {
|
|
14184
14227
|
unlinkSync12(paths.synthesisPath);
|
|
14185
14228
|
}
|
|
14186
14229
|
const synthesisResult = await synthesise(paths, { multi });
|
|
@@ -14274,6 +14317,7 @@ async function runPostSynthesis(synthesisPath, options2) {
|
|
|
14274
14317
|
}
|
|
14275
14318
|
async function reviewPr(repoRoot, options2) {
|
|
14276
14319
|
const context = gatherChangedContext();
|
|
14320
|
+
ensureReviewsIgnored(repoRoot);
|
|
14277
14321
|
const paths = setupReviewDir(repoRoot, context, options2.force ?? false);
|
|
14278
14322
|
const synthesisOk = await runReviewPipeline(paths, {
|
|
14279
14323
|
verbose: options2.verbose ?? false
|
|
@@ -14679,6 +14723,10 @@ function registerSignal(program2) {
|
|
|
14679
14723
|
writeSignal("next", id ? { id } : void 0);
|
|
14680
14724
|
console.log("Signal written.");
|
|
14681
14725
|
});
|
|
14726
|
+
signalCommand.command("done").description("Write a done signal to end a --once launch session").action(() => {
|
|
14727
|
+
writeSignal("done");
|
|
14728
|
+
console.log("Signal written.");
|
|
14729
|
+
});
|
|
14682
14730
|
}
|
|
14683
14731
|
|
|
14684
14732
|
// src/commands/sql/sqlAuth.ts
|
|
@@ -14951,8 +14999,8 @@ function registerSql(program2) {
|
|
|
14951
14999
|
}
|
|
14952
15000
|
|
|
14953
15001
|
// src/commands/transcript/shared.ts
|
|
14954
|
-
import { existsSync as
|
|
14955
|
-
import { basename as basename6, join as
|
|
15002
|
+
import { existsSync as existsSync39, readdirSync as readdirSync6, statSync as statSync3 } from "fs";
|
|
15003
|
+
import { basename as basename6, join as join37, relative as relative2 } from "path";
|
|
14956
15004
|
import * as readline2 from "readline";
|
|
14957
15005
|
var DATE_PREFIX_REGEX = /^\d{4}-\d{2}-\d{2}/;
|
|
14958
15006
|
function getDatePrefix(daysOffset = 0) {
|
|
@@ -14967,10 +15015,10 @@ function isValidDatePrefix(filename) {
|
|
|
14967
15015
|
return DATE_PREFIX_REGEX.test(filename);
|
|
14968
15016
|
}
|
|
14969
15017
|
function collectFiles(dir, extension) {
|
|
14970
|
-
if (!
|
|
15018
|
+
if (!existsSync39(dir)) return [];
|
|
14971
15019
|
const results = [];
|
|
14972
15020
|
for (const entry of readdirSync6(dir)) {
|
|
14973
|
-
const fullPath =
|
|
15021
|
+
const fullPath = join37(dir, entry);
|
|
14974
15022
|
if (statSync3(fullPath).isDirectory()) {
|
|
14975
15023
|
results.push(...collectFiles(fullPath, extension));
|
|
14976
15024
|
} else if (entry.endsWith(extension)) {
|
|
@@ -15064,14 +15112,14 @@ async function configure() {
|
|
|
15064
15112
|
}
|
|
15065
15113
|
|
|
15066
15114
|
// src/commands/transcript/format/index.ts
|
|
15067
|
-
import { existsSync as
|
|
15115
|
+
import { existsSync as existsSync41 } from "fs";
|
|
15068
15116
|
|
|
15069
15117
|
// src/commands/transcript/format/fixInvalidDatePrefixes/index.ts
|
|
15070
|
-
import { dirname as dirname19, join as
|
|
15118
|
+
import { dirname as dirname19, join as join39 } from "path";
|
|
15071
15119
|
|
|
15072
15120
|
// src/commands/transcript/format/fixInvalidDatePrefixes/promptForDateFix.ts
|
|
15073
15121
|
import { renameSync as renameSync3 } from "fs";
|
|
15074
|
-
import { join as
|
|
15122
|
+
import { join as join38 } from "path";
|
|
15075
15123
|
async function resolveDate(rl, choice) {
|
|
15076
15124
|
if (choice === "1") return getDatePrefix(0);
|
|
15077
15125
|
if (choice === "2") return getDatePrefix(-1);
|
|
@@ -15086,7 +15134,7 @@ async function resolveDate(rl, choice) {
|
|
|
15086
15134
|
}
|
|
15087
15135
|
function renameWithPrefix(vttDir, vttFile, prefix2) {
|
|
15088
15136
|
const newFilename = `${prefix2}.${vttFile}`;
|
|
15089
|
-
renameSync3(
|
|
15137
|
+
renameSync3(join38(vttDir, vttFile), join38(vttDir, newFilename));
|
|
15090
15138
|
console.log(`Renamed to: ${newFilename}`);
|
|
15091
15139
|
return newFilename;
|
|
15092
15140
|
}
|
|
@@ -15120,12 +15168,12 @@ async function fixInvalidDatePrefixes(vttFiles) {
|
|
|
15120
15168
|
const vttFileDir = dirname19(vttFile.absolutePath);
|
|
15121
15169
|
const newFilename = await promptForDateFix(vttFile.filename, vttFileDir);
|
|
15122
15170
|
if (newFilename) {
|
|
15123
|
-
const newRelativePath =
|
|
15171
|
+
const newRelativePath = join39(
|
|
15124
15172
|
dirname19(vttFile.relativePath),
|
|
15125
15173
|
newFilename
|
|
15126
15174
|
);
|
|
15127
15175
|
vttFiles[i] = {
|
|
15128
|
-
absolutePath:
|
|
15176
|
+
absolutePath: join39(vttFileDir, newFilename),
|
|
15129
15177
|
relativePath: newRelativePath,
|
|
15130
15178
|
filename: newFilename
|
|
15131
15179
|
};
|
|
@@ -15138,8 +15186,8 @@ async function fixInvalidDatePrefixes(vttFiles) {
|
|
|
15138
15186
|
}
|
|
15139
15187
|
|
|
15140
15188
|
// src/commands/transcript/format/processVttFile/index.ts
|
|
15141
|
-
import { existsSync as
|
|
15142
|
-
import { basename as basename7, dirname as dirname20, join as
|
|
15189
|
+
import { existsSync as existsSync40, mkdirSync as mkdirSync12, readFileSync as readFileSync32, writeFileSync as writeFileSync27 } from "fs";
|
|
15190
|
+
import { basename as basename7, dirname as dirname20, join as join40 } from "path";
|
|
15143
15191
|
|
|
15144
15192
|
// src/commands/transcript/cleanText.ts
|
|
15145
15193
|
function cleanText(text2) {
|
|
@@ -15349,21 +15397,21 @@ function toMdFilename(vttFilename) {
|
|
|
15349
15397
|
return `${basename7(vttFilename, ".vtt").replace(/\s*Transcription\s*/g, " ").trim()}.md`;
|
|
15350
15398
|
}
|
|
15351
15399
|
function resolveOutputDir(relativeDir, transcriptsDir) {
|
|
15352
|
-
return relativeDir === "." ? transcriptsDir :
|
|
15400
|
+
return relativeDir === "." ? transcriptsDir : join40(transcriptsDir, relativeDir);
|
|
15353
15401
|
}
|
|
15354
15402
|
function buildOutputPaths(vttFile, transcriptsDir) {
|
|
15355
15403
|
const mdFile = toMdFilename(vttFile.filename);
|
|
15356
15404
|
const relativeDir = dirname20(vttFile.relativePath);
|
|
15357
15405
|
const outputDir = resolveOutputDir(relativeDir, transcriptsDir);
|
|
15358
|
-
const outputPath =
|
|
15406
|
+
const outputPath = join40(outputDir, mdFile);
|
|
15359
15407
|
return { outputDir, outputPath, mdFile, relativeDir };
|
|
15360
15408
|
}
|
|
15361
15409
|
function logSkipped(relativeDir, mdFile) {
|
|
15362
|
-
console.log(`Skipping (already exists): ${
|
|
15410
|
+
console.log(`Skipping (already exists): ${join40(relativeDir, mdFile)}`);
|
|
15363
15411
|
return "skipped";
|
|
15364
15412
|
}
|
|
15365
15413
|
function ensureDirectory(dir, label2) {
|
|
15366
|
-
if (!
|
|
15414
|
+
if (!existsSync40(dir)) {
|
|
15367
15415
|
mkdirSync12(dir, { recursive: true });
|
|
15368
15416
|
console.log(`Created ${label2}: ${dir}`);
|
|
15369
15417
|
}
|
|
@@ -15386,10 +15434,10 @@ function logReduction(cueCount, messageCount) {
|
|
|
15386
15434
|
}
|
|
15387
15435
|
function readAndParseCues(inputPath) {
|
|
15388
15436
|
console.log(`Reading: ${inputPath}`);
|
|
15389
|
-
return processCues(
|
|
15437
|
+
return processCues(readFileSync32(inputPath, "utf-8"));
|
|
15390
15438
|
}
|
|
15391
15439
|
function writeFormatted(outputPath, content) {
|
|
15392
|
-
|
|
15440
|
+
writeFileSync27(outputPath, content, "utf-8");
|
|
15393
15441
|
console.log(`Written: ${outputPath}`);
|
|
15394
15442
|
}
|
|
15395
15443
|
function convertVttToMarkdown(inputPath, outputPath) {
|
|
@@ -15399,7 +15447,7 @@ function convertVttToMarkdown(inputPath, outputPath) {
|
|
|
15399
15447
|
logReduction(cues.length, chatMessages.length);
|
|
15400
15448
|
}
|
|
15401
15449
|
function tryProcessVtt(vttFile, paths) {
|
|
15402
|
-
if (
|
|
15450
|
+
if (existsSync40(paths.outputPath))
|
|
15403
15451
|
return logSkipped(paths.relativeDir, paths.mdFile);
|
|
15404
15452
|
convertVttToMarkdown(vttFile.absolutePath, paths.outputPath);
|
|
15405
15453
|
return "processed";
|
|
@@ -15425,7 +15473,7 @@ function processAllFiles(vttFiles, transcriptsDir) {
|
|
|
15425
15473
|
logSummary(counts);
|
|
15426
15474
|
}
|
|
15427
15475
|
function requireVttDir(vttDir) {
|
|
15428
|
-
if (!
|
|
15476
|
+
if (!existsSync41(vttDir)) {
|
|
15429
15477
|
console.error(`VTT directory not found: ${vttDir}`);
|
|
15430
15478
|
process.exit(1);
|
|
15431
15479
|
}
|
|
@@ -15457,18 +15505,18 @@ async function format() {
|
|
|
15457
15505
|
}
|
|
15458
15506
|
|
|
15459
15507
|
// src/commands/transcript/summarise/index.ts
|
|
15460
|
-
import { existsSync as
|
|
15461
|
-
import { basename as basename8, dirname as dirname22, join as
|
|
15508
|
+
import { existsSync as existsSync43 } from "fs";
|
|
15509
|
+
import { basename as basename8, dirname as dirname22, join as join42, relative as relative3 } from "path";
|
|
15462
15510
|
|
|
15463
15511
|
// src/commands/transcript/summarise/processStagedFile/index.ts
|
|
15464
15512
|
import {
|
|
15465
|
-
existsSync as
|
|
15513
|
+
existsSync as existsSync42,
|
|
15466
15514
|
mkdirSync as mkdirSync13,
|
|
15467
|
-
readFileSync as
|
|
15515
|
+
readFileSync as readFileSync33,
|
|
15468
15516
|
renameSync as renameSync4,
|
|
15469
15517
|
rmSync
|
|
15470
15518
|
} from "fs";
|
|
15471
|
-
import { dirname as dirname21, join as
|
|
15519
|
+
import { dirname as dirname21, join as join41 } from "path";
|
|
15472
15520
|
|
|
15473
15521
|
// src/commands/transcript/summarise/processStagedFile/validateStagedContent.ts
|
|
15474
15522
|
import chalk154 from "chalk";
|
|
@@ -15497,9 +15545,9 @@ function validateStagedContent(filename, content) {
|
|
|
15497
15545
|
}
|
|
15498
15546
|
|
|
15499
15547
|
// src/commands/transcript/summarise/processStagedFile/index.ts
|
|
15500
|
-
var STAGING_DIR =
|
|
15548
|
+
var STAGING_DIR = join41(process.cwd(), ".assist", "transcript");
|
|
15501
15549
|
function processStagedFile() {
|
|
15502
|
-
if (!
|
|
15550
|
+
if (!existsSync42(STAGING_DIR)) {
|
|
15503
15551
|
return false;
|
|
15504
15552
|
}
|
|
15505
15553
|
const stagedFiles = findMdFilesRecursive(STAGING_DIR);
|
|
@@ -15508,7 +15556,7 @@ function processStagedFile() {
|
|
|
15508
15556
|
}
|
|
15509
15557
|
const { transcriptsDir, summaryDir } = getTranscriptConfig();
|
|
15510
15558
|
const stagedFile = stagedFiles[0];
|
|
15511
|
-
const content =
|
|
15559
|
+
const content = readFileSync33(stagedFile.absolutePath, "utf-8");
|
|
15512
15560
|
validateStagedContent(stagedFile.filename, content);
|
|
15513
15561
|
const stagedBaseName = getTranscriptBaseName(stagedFile.filename);
|
|
15514
15562
|
const transcriptFiles = findMdFilesRecursive(transcriptsDir);
|
|
@@ -15521,9 +15569,9 @@ function processStagedFile() {
|
|
|
15521
15569
|
);
|
|
15522
15570
|
process.exit(1);
|
|
15523
15571
|
}
|
|
15524
|
-
const destPath =
|
|
15572
|
+
const destPath = join41(summaryDir, matchingTranscript.relativePath);
|
|
15525
15573
|
const destDir = dirname21(destPath);
|
|
15526
|
-
if (!
|
|
15574
|
+
if (!existsSync42(destDir)) {
|
|
15527
15575
|
mkdirSync13(destDir, { recursive: true });
|
|
15528
15576
|
}
|
|
15529
15577
|
renameSync4(stagedFile.absolutePath, destPath);
|
|
@@ -15537,7 +15585,7 @@ function processStagedFile() {
|
|
|
15537
15585
|
// src/commands/transcript/summarise/index.ts
|
|
15538
15586
|
function buildRelativeKey(relativePath, baseName) {
|
|
15539
15587
|
const relDir = dirname22(relativePath);
|
|
15540
|
-
return relDir === "." ? baseName :
|
|
15588
|
+
return relDir === "." ? baseName : join42(relDir, baseName);
|
|
15541
15589
|
}
|
|
15542
15590
|
function buildSummaryIndex(summaryDir) {
|
|
15543
15591
|
const summaryFiles = findMdFilesRecursive(summaryDir);
|
|
@@ -15550,7 +15598,7 @@ function buildSummaryIndex(summaryDir) {
|
|
|
15550
15598
|
function summarise3() {
|
|
15551
15599
|
processStagedFile();
|
|
15552
15600
|
const { transcriptsDir, summaryDir } = getTranscriptConfig();
|
|
15553
|
-
if (!
|
|
15601
|
+
if (!existsSync43(transcriptsDir)) {
|
|
15554
15602
|
console.log("No transcripts directory found.");
|
|
15555
15603
|
return;
|
|
15556
15604
|
}
|
|
@@ -15571,8 +15619,8 @@ function summarise3() {
|
|
|
15571
15619
|
}
|
|
15572
15620
|
const next3 = missing[0];
|
|
15573
15621
|
const outputFilename = `${getTranscriptBaseName(next3.filename)}.md`;
|
|
15574
|
-
const outputPath =
|
|
15575
|
-
const summaryFileDir =
|
|
15622
|
+
const outputPath = join42(STAGING_DIR, outputFilename);
|
|
15623
|
+
const summaryFileDir = join42(summaryDir, dirname22(next3.relativePath));
|
|
15576
15624
|
const relativeTranscriptPath = encodeURI(
|
|
15577
15625
|
relative3(summaryFileDir, next3.absolutePath).replace(/\\/g, "/")
|
|
15578
15626
|
);
|
|
@@ -15621,50 +15669,50 @@ function registerVerify(program2) {
|
|
|
15621
15669
|
|
|
15622
15670
|
// src/commands/voice/devices.ts
|
|
15623
15671
|
import { spawnSync as spawnSync4 } from "child_process";
|
|
15624
|
-
import { join as
|
|
15672
|
+
import { join as join44 } from "path";
|
|
15625
15673
|
|
|
15626
15674
|
// src/commands/voice/shared.ts
|
|
15627
15675
|
import { homedir as homedir9 } from "os";
|
|
15628
|
-
import { dirname as dirname23, join as
|
|
15676
|
+
import { dirname as dirname23, join as join43 } from "path";
|
|
15629
15677
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
15630
15678
|
var __dirname6 = dirname23(fileURLToPath6(import.meta.url));
|
|
15631
|
-
var VOICE_DIR =
|
|
15679
|
+
var VOICE_DIR = join43(homedir9(), ".assist", "voice");
|
|
15632
15680
|
var voicePaths = {
|
|
15633
15681
|
dir: VOICE_DIR,
|
|
15634
|
-
pid:
|
|
15635
|
-
log:
|
|
15636
|
-
venv:
|
|
15637
|
-
lock:
|
|
15682
|
+
pid: join43(VOICE_DIR, "voice.pid"),
|
|
15683
|
+
log: join43(VOICE_DIR, "voice.log"),
|
|
15684
|
+
venv: join43(VOICE_DIR, ".venv"),
|
|
15685
|
+
lock: join43(VOICE_DIR, "voice.lock")
|
|
15638
15686
|
};
|
|
15639
15687
|
function getPythonDir() {
|
|
15640
|
-
return
|
|
15688
|
+
return join43(__dirname6, "commands", "voice", "python");
|
|
15641
15689
|
}
|
|
15642
15690
|
function getVenvPython() {
|
|
15643
|
-
return process.platform === "win32" ?
|
|
15691
|
+
return process.platform === "win32" ? join43(voicePaths.venv, "Scripts", "python.exe") : join43(voicePaths.venv, "bin", "python");
|
|
15644
15692
|
}
|
|
15645
15693
|
function getLockDir() {
|
|
15646
15694
|
const config = loadConfig();
|
|
15647
15695
|
return config.voice?.lockDir ?? VOICE_DIR;
|
|
15648
15696
|
}
|
|
15649
15697
|
function getLockFile() {
|
|
15650
|
-
return
|
|
15698
|
+
return join43(getLockDir(), "voice.lock");
|
|
15651
15699
|
}
|
|
15652
15700
|
|
|
15653
15701
|
// src/commands/voice/devices.ts
|
|
15654
15702
|
function devices() {
|
|
15655
|
-
const script =
|
|
15703
|
+
const script = join44(getPythonDir(), "list_devices.py");
|
|
15656
15704
|
spawnSync4(getVenvPython(), [script], { stdio: "inherit" });
|
|
15657
15705
|
}
|
|
15658
15706
|
|
|
15659
15707
|
// src/commands/voice/logs.ts
|
|
15660
|
-
import { existsSync as
|
|
15708
|
+
import { existsSync as existsSync44, readFileSync as readFileSync34 } from "fs";
|
|
15661
15709
|
function logs(options2) {
|
|
15662
|
-
if (!
|
|
15710
|
+
if (!existsSync44(voicePaths.log)) {
|
|
15663
15711
|
console.log("No voice log file found");
|
|
15664
15712
|
return;
|
|
15665
15713
|
}
|
|
15666
15714
|
const count6 = Number.parseInt(options2.lines ?? "150", 10);
|
|
15667
|
-
const content =
|
|
15715
|
+
const content = readFileSync34(voicePaths.log, "utf-8").trim();
|
|
15668
15716
|
if (!content) {
|
|
15669
15717
|
console.log("Voice log is empty");
|
|
15670
15718
|
return;
|
|
@@ -15687,12 +15735,12 @@ function logs(options2) {
|
|
|
15687
15735
|
// src/commands/voice/setup.ts
|
|
15688
15736
|
import { spawnSync as spawnSync5 } from "child_process";
|
|
15689
15737
|
import { mkdirSync as mkdirSync15 } from "fs";
|
|
15690
|
-
import { join as
|
|
15738
|
+
import { join as join46 } from "path";
|
|
15691
15739
|
|
|
15692
15740
|
// src/commands/voice/checkLockFile.ts
|
|
15693
15741
|
import { execSync as execSync44 } from "child_process";
|
|
15694
|
-
import { existsSync as
|
|
15695
|
-
import { join as
|
|
15742
|
+
import { existsSync as existsSync45, mkdirSync as mkdirSync14, readFileSync as readFileSync35, writeFileSync as writeFileSync28 } from "fs";
|
|
15743
|
+
import { join as join45 } from "path";
|
|
15696
15744
|
function isProcessAlive2(pid) {
|
|
15697
15745
|
try {
|
|
15698
15746
|
process.kill(pid, 0);
|
|
@@ -15703,9 +15751,9 @@ function isProcessAlive2(pid) {
|
|
|
15703
15751
|
}
|
|
15704
15752
|
function checkLockFile() {
|
|
15705
15753
|
const lockFile = getLockFile();
|
|
15706
|
-
if (!
|
|
15754
|
+
if (!existsSync45(lockFile)) return;
|
|
15707
15755
|
try {
|
|
15708
|
-
const lock = JSON.parse(
|
|
15756
|
+
const lock = JSON.parse(readFileSync35(lockFile, "utf-8"));
|
|
15709
15757
|
if (lock.pid && isProcessAlive2(lock.pid)) {
|
|
15710
15758
|
console.error(
|
|
15711
15759
|
`Voice daemon already running (PID ${lock.pid}, env: ${lock.env}). Stop it first with: assist voice stop`
|
|
@@ -15716,7 +15764,7 @@ function checkLockFile() {
|
|
|
15716
15764
|
}
|
|
15717
15765
|
}
|
|
15718
15766
|
function bootstrapVenv() {
|
|
15719
|
-
if (
|
|
15767
|
+
if (existsSync45(getVenvPython())) return;
|
|
15720
15768
|
console.log("Setting up Python environment...");
|
|
15721
15769
|
const pythonDir = getPythonDir();
|
|
15722
15770
|
execSync44(
|
|
@@ -15729,8 +15777,8 @@ function bootstrapVenv() {
|
|
|
15729
15777
|
}
|
|
15730
15778
|
function writeLockFile(pid) {
|
|
15731
15779
|
const lockFile = getLockFile();
|
|
15732
|
-
mkdirSync14(
|
|
15733
|
-
|
|
15780
|
+
mkdirSync14(join45(lockFile, ".."), { recursive: true });
|
|
15781
|
+
writeFileSync28(
|
|
15734
15782
|
lockFile,
|
|
15735
15783
|
JSON.stringify({
|
|
15736
15784
|
pid,
|
|
@@ -15745,7 +15793,7 @@ function setup() {
|
|
|
15745
15793
|
mkdirSync15(voicePaths.dir, { recursive: true });
|
|
15746
15794
|
bootstrapVenv();
|
|
15747
15795
|
console.log("\nDownloading models...\n");
|
|
15748
|
-
const script =
|
|
15796
|
+
const script = join46(getPythonDir(), "setup_models.py");
|
|
15749
15797
|
const result = spawnSync5(getVenvPython(), [script], {
|
|
15750
15798
|
stdio: "inherit",
|
|
15751
15799
|
env: { ...process.env, VOICE_LOG_FILE: voicePaths.log }
|
|
@@ -15758,8 +15806,8 @@ function setup() {
|
|
|
15758
15806
|
|
|
15759
15807
|
// src/commands/voice/start.ts
|
|
15760
15808
|
import { spawn as spawn7 } from "child_process";
|
|
15761
|
-
import { mkdirSync as mkdirSync16, writeFileSync as
|
|
15762
|
-
import { join as
|
|
15809
|
+
import { mkdirSync as mkdirSync16, writeFileSync as writeFileSync29 } from "fs";
|
|
15810
|
+
import { join as join47 } from "path";
|
|
15763
15811
|
|
|
15764
15812
|
// src/commands/voice/buildDaemonEnv.ts
|
|
15765
15813
|
function buildDaemonEnv(options2) {
|
|
@@ -15787,7 +15835,7 @@ function spawnBackground(python, script, env) {
|
|
|
15787
15835
|
console.error("Failed to start voice daemon");
|
|
15788
15836
|
process.exit(1);
|
|
15789
15837
|
}
|
|
15790
|
-
|
|
15838
|
+
writeFileSync29(voicePaths.pid, String(pid));
|
|
15791
15839
|
writeLockFile(pid);
|
|
15792
15840
|
console.log(`Voice daemon started (PID ${pid})`);
|
|
15793
15841
|
}
|
|
@@ -15797,7 +15845,7 @@ function start2(options2) {
|
|
|
15797
15845
|
bootstrapVenv();
|
|
15798
15846
|
const debug = options2.debug || options2.foreground || process.platform === "win32";
|
|
15799
15847
|
const env = buildDaemonEnv({ debug });
|
|
15800
|
-
const script =
|
|
15848
|
+
const script = join47(getPythonDir(), "voice_daemon.py");
|
|
15801
15849
|
const python = getVenvPython();
|
|
15802
15850
|
if (options2.foreground) {
|
|
15803
15851
|
spawnForeground(python, script, env);
|
|
@@ -15807,7 +15855,7 @@ function start2(options2) {
|
|
|
15807
15855
|
}
|
|
15808
15856
|
|
|
15809
15857
|
// src/commands/voice/status.ts
|
|
15810
|
-
import { existsSync as
|
|
15858
|
+
import { existsSync as existsSync46, readFileSync as readFileSync36 } from "fs";
|
|
15811
15859
|
function isProcessAlive3(pid) {
|
|
15812
15860
|
try {
|
|
15813
15861
|
process.kill(pid, 0);
|
|
@@ -15817,16 +15865,16 @@ function isProcessAlive3(pid) {
|
|
|
15817
15865
|
}
|
|
15818
15866
|
}
|
|
15819
15867
|
function readRecentLogs(count6) {
|
|
15820
|
-
if (!
|
|
15821
|
-
const lines =
|
|
15868
|
+
if (!existsSync46(voicePaths.log)) return [];
|
|
15869
|
+
const lines = readFileSync36(voicePaths.log, "utf-8").trim().split("\n");
|
|
15822
15870
|
return lines.slice(-count6);
|
|
15823
15871
|
}
|
|
15824
15872
|
function status() {
|
|
15825
|
-
if (!
|
|
15873
|
+
if (!existsSync46(voicePaths.pid)) {
|
|
15826
15874
|
console.log("Voice daemon: not running (no PID file)");
|
|
15827
15875
|
return;
|
|
15828
15876
|
}
|
|
15829
|
-
const pid = Number.parseInt(
|
|
15877
|
+
const pid = Number.parseInt(readFileSync36(voicePaths.pid, "utf-8").trim(), 10);
|
|
15830
15878
|
const alive = isProcessAlive3(pid);
|
|
15831
15879
|
console.log(`Voice daemon: ${alive ? "running" : "dead"} (PID ${pid})`);
|
|
15832
15880
|
const recent = readRecentLogs(5);
|
|
@@ -15845,13 +15893,13 @@ function status() {
|
|
|
15845
15893
|
}
|
|
15846
15894
|
|
|
15847
15895
|
// src/commands/voice/stop.ts
|
|
15848
|
-
import { existsSync as
|
|
15896
|
+
import { existsSync as existsSync47, readFileSync as readFileSync37, unlinkSync as unlinkSync13 } from "fs";
|
|
15849
15897
|
function stop2() {
|
|
15850
|
-
if (!
|
|
15898
|
+
if (!existsSync47(voicePaths.pid)) {
|
|
15851
15899
|
console.log("Voice daemon is not running (no PID file)");
|
|
15852
15900
|
return;
|
|
15853
15901
|
}
|
|
15854
|
-
const pid = Number.parseInt(
|
|
15902
|
+
const pid = Number.parseInt(readFileSync37(voicePaths.pid, "utf-8").trim(), 10);
|
|
15855
15903
|
try {
|
|
15856
15904
|
process.kill(pid, "SIGTERM");
|
|
15857
15905
|
console.log(`Sent SIGTERM to voice daemon (PID ${pid})`);
|
|
@@ -15864,7 +15912,7 @@ function stop2() {
|
|
|
15864
15912
|
}
|
|
15865
15913
|
try {
|
|
15866
15914
|
const lockFile = getLockFile();
|
|
15867
|
-
if (
|
|
15915
|
+
if (existsSync47(lockFile)) unlinkSync13(lockFile);
|
|
15868
15916
|
} catch {
|
|
15869
15917
|
}
|
|
15870
15918
|
console.log("Voice daemon stopped");
|
|
@@ -16086,8 +16134,8 @@ async function auth() {
|
|
|
16086
16134
|
|
|
16087
16135
|
// src/commands/roam/postRoamActivity.ts
|
|
16088
16136
|
import { execFileSync as execFileSync7 } from "child_process";
|
|
16089
|
-
import { readdirSync as readdirSync7, readFileSync as
|
|
16090
|
-
import { join as
|
|
16137
|
+
import { readdirSync as readdirSync7, readFileSync as readFileSync38, statSync as statSync4 } from "fs";
|
|
16138
|
+
import { join as join48 } from "path";
|
|
16091
16139
|
function findPortFile(roamDir) {
|
|
16092
16140
|
let entries;
|
|
16093
16141
|
try {
|
|
@@ -16096,7 +16144,7 @@ function findPortFile(roamDir) {
|
|
|
16096
16144
|
return void 0;
|
|
16097
16145
|
}
|
|
16098
16146
|
const candidates = entries.filter((name) => /^roam-local-api(-[^.]+)?\.port$/.test(name)).map((name) => {
|
|
16099
|
-
const path54 =
|
|
16147
|
+
const path54 = join48(roamDir, name);
|
|
16100
16148
|
try {
|
|
16101
16149
|
return { path: path54, mtimeMs: statSync4(path54).mtimeMs };
|
|
16102
16150
|
} catch {
|
|
@@ -16108,11 +16156,11 @@ function findPortFile(roamDir) {
|
|
|
16108
16156
|
function postRoamActivity(app, event) {
|
|
16109
16157
|
const appData = process.env.APPDATA;
|
|
16110
16158
|
if (!appData) return;
|
|
16111
|
-
const portFile = findPortFile(
|
|
16159
|
+
const portFile = findPortFile(join48(appData, "Roam"));
|
|
16112
16160
|
if (!portFile) return;
|
|
16113
16161
|
let port;
|
|
16114
16162
|
try {
|
|
16115
|
-
port =
|
|
16163
|
+
port = readFileSync38(portFile, "utf-8").trim();
|
|
16116
16164
|
} catch {
|
|
16117
16165
|
return;
|
|
16118
16166
|
}
|
|
@@ -16246,15 +16294,15 @@ function runPreCommands(pre, cwd) {
|
|
|
16246
16294
|
|
|
16247
16295
|
// src/commands/run/spawnRunCommand.ts
|
|
16248
16296
|
import { execFileSync as execFileSync8, spawn as spawn8 } from "child_process";
|
|
16249
|
-
import { existsSync as
|
|
16250
|
-
import { dirname as dirname24, join as
|
|
16297
|
+
import { existsSync as existsSync48 } from "fs";
|
|
16298
|
+
import { dirname as dirname24, join as join49, resolve as resolve11 } from "path";
|
|
16251
16299
|
function resolveCommand2(command) {
|
|
16252
16300
|
if (process.platform !== "win32" || command !== "bash") return command;
|
|
16253
16301
|
try {
|
|
16254
16302
|
const gitPath = execFileSync8("where", ["git"], { encoding: "utf8" }).trim().split("\r\n")[0];
|
|
16255
16303
|
const gitRoot = resolve11(dirname24(gitPath), "..");
|
|
16256
|
-
const gitBash =
|
|
16257
|
-
if (
|
|
16304
|
+
const gitBash = join49(gitRoot, "bin", "bash.exe");
|
|
16305
|
+
if (existsSync48(gitBash)) return gitBash;
|
|
16258
16306
|
} catch {
|
|
16259
16307
|
}
|
|
16260
16308
|
return command;
|
|
@@ -16321,8 +16369,8 @@ function run3(name, args) {
|
|
|
16321
16369
|
}
|
|
16322
16370
|
|
|
16323
16371
|
// src/commands/run/add.ts
|
|
16324
|
-
import { mkdirSync as mkdirSync17, writeFileSync as
|
|
16325
|
-
import { join as
|
|
16372
|
+
import { mkdirSync as mkdirSync17, writeFileSync as writeFileSync30 } from "fs";
|
|
16373
|
+
import { join as join50 } from "path";
|
|
16326
16374
|
|
|
16327
16375
|
// src/commands/run/extractOption.ts
|
|
16328
16376
|
function extractOption(args, flag) {
|
|
@@ -16383,7 +16431,7 @@ function saveNewRunConfig(name, command, args, cwd) {
|
|
|
16383
16431
|
saveConfig(config);
|
|
16384
16432
|
}
|
|
16385
16433
|
function createCommandFile(name) {
|
|
16386
|
-
const dir =
|
|
16434
|
+
const dir = join50(".claude", "commands");
|
|
16387
16435
|
mkdirSync17(dir, { recursive: true });
|
|
16388
16436
|
const content = `---
|
|
16389
16437
|
description: Run ${name}
|
|
@@ -16391,8 +16439,8 @@ description: Run ${name}
|
|
|
16391
16439
|
|
|
16392
16440
|
Run \`assist run ${name} $ARGUMENTS 2>&1\`.
|
|
16393
16441
|
`;
|
|
16394
|
-
const filePath =
|
|
16395
|
-
|
|
16442
|
+
const filePath = join50(dir, `${name}.md`);
|
|
16443
|
+
writeFileSync30(filePath, content);
|
|
16396
16444
|
console.log(`Created command file: ${filePath}`);
|
|
16397
16445
|
}
|
|
16398
16446
|
function add3() {
|
|
@@ -16447,8 +16495,8 @@ function link2() {
|
|
|
16447
16495
|
}
|
|
16448
16496
|
|
|
16449
16497
|
// src/commands/run/remove.ts
|
|
16450
|
-
import { existsSync as
|
|
16451
|
-
import { join as
|
|
16498
|
+
import { existsSync as existsSync49, unlinkSync as unlinkSync14 } from "fs";
|
|
16499
|
+
import { join as join51 } from "path";
|
|
16452
16500
|
function findRemoveIndex() {
|
|
16453
16501
|
const idx = process.argv.indexOf("remove");
|
|
16454
16502
|
if (idx === -1 || idx + 1 >= process.argv.length) return -1;
|
|
@@ -16463,8 +16511,8 @@ function parseRemoveName() {
|
|
|
16463
16511
|
return process.argv[idx + 1];
|
|
16464
16512
|
}
|
|
16465
16513
|
function deleteCommandFile(name) {
|
|
16466
|
-
const filePath =
|
|
16467
|
-
if (
|
|
16514
|
+
const filePath = join51(".claude", "commands", `${name}.md`);
|
|
16515
|
+
if (existsSync49(filePath)) {
|
|
16468
16516
|
unlinkSync14(filePath);
|
|
16469
16517
|
console.log(`Deleted command file: ${filePath}`);
|
|
16470
16518
|
}
|
|
@@ -16500,9 +16548,9 @@ function registerRun(program2) {
|
|
|
16500
16548
|
|
|
16501
16549
|
// src/commands/screenshot/index.ts
|
|
16502
16550
|
import { execSync as execSync47 } from "child_process";
|
|
16503
|
-
import { existsSync as
|
|
16551
|
+
import { existsSync as existsSync50, mkdirSync as mkdirSync18, unlinkSync as unlinkSync15, writeFileSync as writeFileSync31 } from "fs";
|
|
16504
16552
|
import { tmpdir as tmpdir7 } from "os";
|
|
16505
|
-
import { join as
|
|
16553
|
+
import { join as join52, resolve as resolve13 } from "path";
|
|
16506
16554
|
import chalk156 from "chalk";
|
|
16507
16555
|
|
|
16508
16556
|
// src/commands/screenshot/captureWindowPs1.ts
|
|
@@ -16632,15 +16680,15 @@ Write-Output $OutputPath
|
|
|
16632
16680
|
|
|
16633
16681
|
// src/commands/screenshot/index.ts
|
|
16634
16682
|
function buildOutputPath(outputDir, processName) {
|
|
16635
|
-
if (!
|
|
16683
|
+
if (!existsSync50(outputDir)) {
|
|
16636
16684
|
mkdirSync18(outputDir, { recursive: true });
|
|
16637
16685
|
}
|
|
16638
16686
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
16639
16687
|
return resolve13(outputDir, `${processName}-${timestamp}.png`);
|
|
16640
16688
|
}
|
|
16641
16689
|
function runPowerShellScript(processName, outputPath) {
|
|
16642
|
-
const scriptPath =
|
|
16643
|
-
|
|
16690
|
+
const scriptPath = join52(tmpdir7(), `assist-screenshot-${Date.now()}.ps1`);
|
|
16691
|
+
writeFileSync31(scriptPath, captureWindowPs1, "utf-8");
|
|
16644
16692
|
try {
|
|
16645
16693
|
execSync47(
|
|
16646
16694
|
`powershell -NoProfile -ExecutionPolicy Bypass -File "${scriptPath}" -ProcessName "${processName}" -OutputPath "${outputPath}"`,
|
|
@@ -16666,7 +16714,7 @@ function screenshot(processName) {
|
|
|
16666
16714
|
}
|
|
16667
16715
|
|
|
16668
16716
|
// src/commands/sessions/daemon/daemonStatus.ts
|
|
16669
|
-
import { existsSync as
|
|
16717
|
+
import { existsSync as existsSync51, readFileSync as readFileSync39 } from "fs";
|
|
16670
16718
|
import { createInterface as createInterface4 } from "readline";
|
|
16671
16719
|
var STATUS_TIMEOUT_MS = 5e3;
|
|
16672
16720
|
async function daemonStatus() {
|
|
@@ -16690,8 +16738,8 @@ async function daemonStatus() {
|
|
|
16690
16738
|
}
|
|
16691
16739
|
}
|
|
16692
16740
|
function describePid() {
|
|
16693
|
-
if (!
|
|
16694
|
-
return ` (PID ${
|
|
16741
|
+
if (!existsSync51(daemonPaths.pid)) return "";
|
|
16742
|
+
return ` (PID ${readFileSync39(daemonPaths.pid, "utf-8").trim()})`;
|
|
16695
16743
|
}
|
|
16696
16744
|
function readSessionList(socket) {
|
|
16697
16745
|
return new Promise((resolve16) => {
|
|
@@ -16758,7 +16806,7 @@ async function restartDaemon() {
|
|
|
16758
16806
|
}
|
|
16759
16807
|
|
|
16760
16808
|
// src/commands/sessions/daemon/runDaemon.ts
|
|
16761
|
-
import { existsSync as
|
|
16809
|
+
import { existsSync as existsSync53, mkdirSync as mkdirSync19, unlinkSync as unlinkSync16, writeFileSync as writeFileSync32 } from "fs";
|
|
16762
16810
|
import * as net2 from "net";
|
|
16763
16811
|
|
|
16764
16812
|
// src/commands/sessions/daemon/createAutoExit.ts
|
|
@@ -17034,7 +17082,7 @@ function repoPrefix(cwd) {
|
|
|
17034
17082
|
import * as pty from "node-pty";
|
|
17035
17083
|
|
|
17036
17084
|
// src/commands/sessions/daemon/ensureSpawnHelperExecutable.ts
|
|
17037
|
-
import { chmodSync, existsSync as
|
|
17085
|
+
import { chmodSync, existsSync as existsSync52, statSync as statSync5 } from "fs";
|
|
17038
17086
|
import { createRequire as createRequire3 } from "module";
|
|
17039
17087
|
import path48 from "path";
|
|
17040
17088
|
var require4 = createRequire3(import.meta.url);
|
|
@@ -17049,7 +17097,7 @@ function ensureSpawnHelperExecutable() {
|
|
|
17049
17097
|
`${process.platform}-${process.arch}`,
|
|
17050
17098
|
"spawn-helper"
|
|
17051
17099
|
);
|
|
17052
|
-
if (!
|
|
17100
|
+
if (!existsSync52(helper)) return;
|
|
17053
17101
|
const mode = statSync5(helper).mode;
|
|
17054
17102
|
if ((mode & 73) === 0) chmodSync(helper, mode | 493);
|
|
17055
17103
|
}
|
|
@@ -17516,7 +17564,7 @@ async function runDaemon() {
|
|
|
17516
17564
|
process.exitCode = 1;
|
|
17517
17565
|
return;
|
|
17518
17566
|
}
|
|
17519
|
-
if (process.platform !== "win32" &&
|
|
17567
|
+
if (process.platform !== "win32" && existsSync53(daemonPaths.socket)) {
|
|
17520
17568
|
unlinkSync16(daemonPaths.socket);
|
|
17521
17569
|
}
|
|
17522
17570
|
const checkAutoExit = createAutoExit(() => {
|
|
@@ -17529,7 +17577,7 @@ async function runDaemon() {
|
|
|
17529
17577
|
(socket) => handleConnection(socket, manager)
|
|
17530
17578
|
);
|
|
17531
17579
|
server.listen(daemonPaths.socket, () => {
|
|
17532
|
-
|
|
17580
|
+
writeFileSync32(daemonPaths.pid, String(process.pid));
|
|
17533
17581
|
console.log(`Sessions daemon listening on ${daemonPaths.socket}`);
|
|
17534
17582
|
checkAutoExit(manager.isIdle());
|
|
17535
17583
|
});
|