@staff0rd/assist 0.748.2 → 0.750.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import { Command } from "commander";
|
|
|
6
6
|
// package.json
|
|
7
7
|
var package_default = {
|
|
8
8
|
name: "@staff0rd/assist",
|
|
9
|
-
version: "0.
|
|
9
|
+
version: "0.750.0",
|
|
10
10
|
type: "module",
|
|
11
11
|
main: "dist/index.js",
|
|
12
12
|
bin: {
|
|
@@ -12903,8 +12903,8 @@ var seqConfigHelp = [
|
|
|
12903
12903
|
var nodesConfigHelp = [
|
|
12904
12904
|
{
|
|
12905
12905
|
key: "sessions.links",
|
|
12906
|
-
setter: "assist sessions nodes link <name> http://127.0.0.1:<port> (or --ssh <alias> --port <port>)",
|
|
12907
|
-
note: "linked nodes whose sessions merge into this node's web UI, each direct (url) or over an ssh tunnel (ssh alias, peer port, localPort); each name must match the peer's sessions.nodeName"
|
|
12906
|
+
setter: "assist sessions nodes link <name> http://127.0.0.1:<port> (or --tailscale <host> --port <port>, or --ssh <alias> --port <port>)",
|
|
12907
|
+
note: "linked nodes whose sessions merge into this node's web UI, each direct (url, including a Tailscale <host>.<tailnet>.ts.net https url) or over an ssh tunnel (ssh alias, peer port, localPort); each name must match the peer's sessions.nodeName"
|
|
12908
12908
|
},
|
|
12909
12909
|
{
|
|
12910
12910
|
key: "sessions.linkVersionCheck",
|
|
@@ -13593,8 +13593,8 @@ function subsequenceScore(text18, query) {
|
|
|
13593
13593
|
function scoreFilePath(path106, query) {
|
|
13594
13594
|
const needle = query.trim().toLowerCase();
|
|
13595
13595
|
if (!needle) return 0;
|
|
13596
|
-
const
|
|
13597
|
-
const inBasename = subsequenceScore(
|
|
13596
|
+
const basename32 = path106.slice(path106.lastIndexOf("/") + 1);
|
|
13597
|
+
const inBasename = subsequenceScore(basename32, needle);
|
|
13598
13598
|
if (inBasename !== null) return BASENAME_WEIGHT + inBasename;
|
|
13599
13599
|
return subsequenceScore(path106, needle);
|
|
13600
13600
|
}
|
|
@@ -20685,7 +20685,7 @@ async function criteriaExtension() {
|
|
|
20685
20685
|
// src/commands/criteriaExtension/signCriteriaExtension.ts
|
|
20686
20686
|
import { rm as rm3 } from "fs/promises";
|
|
20687
20687
|
import { homedir as homedir19, tmpdir as tmpdir4 } from "os";
|
|
20688
|
-
import { join as
|
|
20688
|
+
import { join as join52 } from "path";
|
|
20689
20689
|
import chalk139 from "chalk";
|
|
20690
20690
|
|
|
20691
20691
|
// src/commands/criteriaExtension/copySignedXpi.ts
|
|
@@ -20747,7 +20747,7 @@ function signPreflightProblem(source) {
|
|
|
20747
20747
|
|
|
20748
20748
|
// src/commands/criteriaExtension/stageCriteriaExtension.ts
|
|
20749
20749
|
import { cp as cp3, mkdir as mkdir4, readFile as readFile4, rm as rm2, writeFile as writeFile4 } from "fs/promises";
|
|
20750
|
-
import { join as join50 } from "path";
|
|
20750
|
+
import { basename as basename13, join as join50 } from "path";
|
|
20751
20751
|
|
|
20752
20752
|
// src/commands/criteriaExtension/stampManifestVersion.ts
|
|
20753
20753
|
function stampManifestVersion(manifest, version2) {
|
|
@@ -20760,7 +20760,10 @@ function stampManifestVersion(manifest, version2) {
|
|
|
20760
20760
|
async function stageCriteriaExtension(source, staging, version2) {
|
|
20761
20761
|
await rm2(staging, { recursive: true, force: true });
|
|
20762
20762
|
await mkdir4(staging, { recursive: true });
|
|
20763
|
-
await cp3(source, staging, {
|
|
20763
|
+
await cp3(source, staging, {
|
|
20764
|
+
recursive: true,
|
|
20765
|
+
filter: (path106) => basename13(path106) !== "updates.json"
|
|
20766
|
+
});
|
|
20764
20767
|
const manifest = join50(staging, "manifest.json");
|
|
20765
20768
|
const stamped = stampManifestVersion(
|
|
20766
20769
|
await readFile4(manifest, "utf8"),
|
|
@@ -20769,9 +20772,44 @@ async function stageCriteriaExtension(source, staging, version2) {
|
|
|
20769
20772
|
await writeFile4(manifest, stamped);
|
|
20770
20773
|
}
|
|
20771
20774
|
|
|
20775
|
+
// src/commands/criteriaExtension/writeUpdateManifest.ts
|
|
20776
|
+
import { readFile as readFile5, writeFile as writeFile5 } from "fs/promises";
|
|
20777
|
+
import { join as join51 } from "path";
|
|
20778
|
+
|
|
20779
|
+
// src/commands/criteriaExtension/buildUpdateManifest.ts
|
|
20780
|
+
var RELEASE_DOWNLOAD_URL = "https://github.com/staff0rd/assist/releases/download";
|
|
20781
|
+
function buildUpdateManifest(manifest, version2) {
|
|
20782
|
+
const { id } = JSON.parse(manifest).browser_specific_settings.gecko;
|
|
20783
|
+
const updates = {
|
|
20784
|
+
addons: {
|
|
20785
|
+
[id]: {
|
|
20786
|
+
updates: [
|
|
20787
|
+
{
|
|
20788
|
+
version: version2,
|
|
20789
|
+
update_link: `${RELEASE_DOWNLOAD_URL}/v${version2}/criteria-extension.xpi`
|
|
20790
|
+
}
|
|
20791
|
+
]
|
|
20792
|
+
}
|
|
20793
|
+
}
|
|
20794
|
+
};
|
|
20795
|
+
return `${JSON.stringify(updates, null, " ")}
|
|
20796
|
+
`;
|
|
20797
|
+
}
|
|
20798
|
+
|
|
20799
|
+
// src/commands/criteriaExtension/writeUpdateManifest.ts
|
|
20800
|
+
async function writeUpdateManifest(source, dir, version2) {
|
|
20801
|
+
await writeFile5(
|
|
20802
|
+
join51(dir, "updates.json"),
|
|
20803
|
+
buildUpdateManifest(
|
|
20804
|
+
await readFile5(join51(source, "manifest.json"), "utf8"),
|
|
20805
|
+
version2
|
|
20806
|
+
)
|
|
20807
|
+
);
|
|
20808
|
+
}
|
|
20809
|
+
|
|
20772
20810
|
// src/commands/criteriaExtension/signCriteriaExtension.ts
|
|
20773
|
-
var ARTIFACTS_DIR =
|
|
20774
|
-
var STAGING_DIR =
|
|
20811
|
+
var ARTIFACTS_DIR = join52(homedir19(), ".assist", "criteria-extension");
|
|
20812
|
+
var STAGING_DIR = join52(tmpdir4(), "assist-criteria-extension");
|
|
20775
20813
|
async function signCriteriaExtension() {
|
|
20776
20814
|
const source = criteriaExtensionDir();
|
|
20777
20815
|
const problem = signPreflightProblem(source);
|
|
@@ -20804,6 +20842,7 @@ async function signCriteriaExtension() {
|
|
|
20804
20842
|
process.exitCode = 1;
|
|
20805
20843
|
return;
|
|
20806
20844
|
}
|
|
20845
|
+
await writeUpdateManifest(source, ARTIFACTS_DIR, version2);
|
|
20807
20846
|
const path106 = await signedAddonInstallPath(
|
|
20808
20847
|
await copySignedXpi(xpi, ARTIFACTS_DIR)
|
|
20809
20848
|
);
|
|
@@ -20894,12 +20933,12 @@ import { unlinkSync as unlinkSync9, writeFileSync as writeFileSync26 } from "fs"
|
|
|
20894
20933
|
import chalk141 from "chalk";
|
|
20895
20934
|
|
|
20896
20935
|
// src/commands/dbMigration/getMigrationPinPath.ts
|
|
20897
|
-
import { join as
|
|
20936
|
+
import { join as join53 } from "path";
|
|
20898
20937
|
function getMigrationPinPath(pin2) {
|
|
20899
|
-
return
|
|
20938
|
+
return join53(getRestrictedDir(), `db-migration-pin-${pin2}.json`);
|
|
20900
20939
|
}
|
|
20901
20940
|
function getMigrationApprovalPath(migrationId) {
|
|
20902
|
-
return
|
|
20941
|
+
return join53(getRestrictedDir(), `db-migration-approval-${migrationId}.json`);
|
|
20903
20942
|
}
|
|
20904
20943
|
|
|
20905
20944
|
// src/commands/dbMigration/readMigrationPinState.ts
|
|
@@ -21033,14 +21072,14 @@ function registerDeploy(program2) {
|
|
|
21033
21072
|
|
|
21034
21073
|
// src/commands/devlog/list.ts
|
|
21035
21074
|
import { execFileSync as execFileSync5 } from "child_process";
|
|
21036
|
-
import { basename as
|
|
21075
|
+
import { basename as basename15 } from "path";
|
|
21037
21076
|
|
|
21038
21077
|
// src/commands/devlog/loadBlogSkipDays.ts
|
|
21039
21078
|
import { homedir as homedir20 } from "os";
|
|
21040
|
-
import { join as
|
|
21041
|
-
var BLOG_REPO_ROOT =
|
|
21079
|
+
import { join as join54 } from "path";
|
|
21080
|
+
var BLOG_REPO_ROOT = join54(homedir20(), "git/blog");
|
|
21042
21081
|
function loadBlogSkipDays(repoName) {
|
|
21043
|
-
const config = loadRawYaml(
|
|
21082
|
+
const config = loadRawYaml(join54(BLOG_REPO_ROOT, "assist.yml"));
|
|
21044
21083
|
const devlog = config.devlog;
|
|
21045
21084
|
const skip2 = devlog?.skip;
|
|
21046
21085
|
return new Set(skip2?.[repoName]);
|
|
@@ -21052,13 +21091,13 @@ import chalk144 from "chalk";
|
|
|
21052
21091
|
|
|
21053
21092
|
// src/shared/getRepoName.ts
|
|
21054
21093
|
import { existsSync as existsSync50, readFileSync as readFileSync33 } from "fs";
|
|
21055
|
-
import { basename as
|
|
21094
|
+
import { basename as basename14, join as join55 } from "path";
|
|
21056
21095
|
function getRepoName() {
|
|
21057
21096
|
const config = loadConfig();
|
|
21058
21097
|
if (config.devlog?.name) {
|
|
21059
21098
|
return config.devlog.name;
|
|
21060
21099
|
}
|
|
21061
|
-
const packageJsonPath =
|
|
21100
|
+
const packageJsonPath = join55(process.cwd(), "package.json");
|
|
21062
21101
|
if (existsSync50(packageJsonPath)) {
|
|
21063
21102
|
try {
|
|
21064
21103
|
const content = readFileSync33(packageJsonPath, "utf8");
|
|
@@ -21069,13 +21108,13 @@ function getRepoName() {
|
|
|
21069
21108
|
} catch {
|
|
21070
21109
|
}
|
|
21071
21110
|
}
|
|
21072
|
-
return
|
|
21111
|
+
return basename14(process.cwd());
|
|
21073
21112
|
}
|
|
21074
21113
|
|
|
21075
21114
|
// src/commands/devlog/loadDevlogEntries.ts
|
|
21076
21115
|
import { readdirSync as readdirSync6, readFileSync as readFileSync34 } from "fs";
|
|
21077
|
-
import { join as
|
|
21078
|
-
var DEVLOG_DIR =
|
|
21116
|
+
import { join as join56 } from "path";
|
|
21117
|
+
var DEVLOG_DIR = join56(BLOG_REPO_ROOT, "src/content/devlog");
|
|
21079
21118
|
function extractFrontmatter(content) {
|
|
21080
21119
|
const fm = content.match(/^---\n([\s\S]*?)\n---/);
|
|
21081
21120
|
return fm?.[1] ?? null;
|
|
@@ -21103,7 +21142,7 @@ function readDevlogFiles(callback) {
|
|
|
21103
21142
|
try {
|
|
21104
21143
|
const files = readdirSync6(DEVLOG_DIR).filter((f) => f.endsWith(".md"));
|
|
21105
21144
|
for (const file of files) {
|
|
21106
|
-
const content = readFileSync34(
|
|
21145
|
+
const content = readFileSync34(join56(DEVLOG_DIR, file), "utf8");
|
|
21107
21146
|
const parsed = parseFrontmatter(content, file);
|
|
21108
21147
|
if (parsed) callback(parsed);
|
|
21109
21148
|
}
|
|
@@ -21205,7 +21244,7 @@ function list2(options2) {
|
|
|
21205
21244
|
const config = loadConfig();
|
|
21206
21245
|
const days = options2.days ?? 30;
|
|
21207
21246
|
const ignore3 = options2.ignore ?? config.devlog?.ignore ?? [];
|
|
21208
|
-
const repoName =
|
|
21247
|
+
const repoName = basename15(process.cwd());
|
|
21209
21248
|
const skipDays = loadBlogSkipDays(repoName);
|
|
21210
21249
|
const devlogEntries = loadDevlogEntries(repoName);
|
|
21211
21250
|
const args = ["log"];
|
|
@@ -21491,11 +21530,11 @@ function repos(options2) {
|
|
|
21491
21530
|
|
|
21492
21531
|
// src/commands/devlog/skip.ts
|
|
21493
21532
|
import { writeFileSync as writeFileSync29 } from "fs";
|
|
21494
|
-
import { join as
|
|
21533
|
+
import { join as join57 } from "path";
|
|
21495
21534
|
import chalk149 from "chalk";
|
|
21496
21535
|
import { stringify as stringifyYaml3 } from "yaml";
|
|
21497
21536
|
function getBlogConfigPath() {
|
|
21498
|
-
return
|
|
21537
|
+
return join57(BLOG_REPO_ROOT, "assist.yml");
|
|
21499
21538
|
}
|
|
21500
21539
|
function skip(date) {
|
|
21501
21540
|
if (!/^\d{4}-\d{2}-\d{2}$/.test(date)) {
|
|
@@ -21557,7 +21596,7 @@ function registerDevlog(program2) {
|
|
|
21557
21596
|
|
|
21558
21597
|
// src/commands/dotnet/checkBuildLocks.ts
|
|
21559
21598
|
import { closeSync as closeSync4, openSync as openSync5, readdirSync as readdirSync7 } from "fs";
|
|
21560
|
-
import { join as
|
|
21599
|
+
import { join as join58 } from "path";
|
|
21561
21600
|
import chalk151 from "chalk";
|
|
21562
21601
|
var SKIP_DIRS = /* @__PURE__ */ new Set(["node_modules", ".git", "packages"]);
|
|
21563
21602
|
function isLockedDll(debugDir) {
|
|
@@ -21569,7 +21608,7 @@ function isLockedDll(debugDir) {
|
|
|
21569
21608
|
}
|
|
21570
21609
|
for (const file of files) {
|
|
21571
21610
|
if (!file.toLowerCase().endsWith(".dll")) continue;
|
|
21572
|
-
const dllPath =
|
|
21611
|
+
const dllPath = join58(debugDir, file);
|
|
21573
21612
|
try {
|
|
21574
21613
|
const fd = openSync5(dllPath, "r+");
|
|
21575
21614
|
closeSync4(fd);
|
|
@@ -21587,13 +21626,13 @@ function findFirstLockedDll(dir) {
|
|
|
21587
21626
|
return null;
|
|
21588
21627
|
}
|
|
21589
21628
|
if (entries.includes("bin")) {
|
|
21590
|
-
const locked = isLockedDll(
|
|
21629
|
+
const locked = isLockedDll(join58(dir, "bin", "Debug"));
|
|
21591
21630
|
if (locked) return locked;
|
|
21592
21631
|
}
|
|
21593
21632
|
for (const entry of entries) {
|
|
21594
21633
|
if (SKIP_DIRS.has(entry) || entry === "bin" || entry.startsWith("."))
|
|
21595
21634
|
continue;
|
|
21596
|
-
const found = findFirstLockedDll(
|
|
21635
|
+
const found = findFirstLockedDll(join58(dir, entry));
|
|
21597
21636
|
if (found) return found;
|
|
21598
21637
|
}
|
|
21599
21638
|
return null;
|
|
@@ -21940,11 +21979,11 @@ import chalk157 from "chalk";
|
|
|
21940
21979
|
|
|
21941
21980
|
// src/commands/dotnet/findSolution.ts
|
|
21942
21981
|
import { readdirSync as readdirSync9 } from "fs";
|
|
21943
|
-
import { dirname as dirname27, join as
|
|
21982
|
+
import { dirname as dirname27, join as join59 } from "path";
|
|
21944
21983
|
import chalk156 from "chalk";
|
|
21945
21984
|
function findSlnInDir(dir) {
|
|
21946
21985
|
try {
|
|
21947
|
-
return readdirSync9(dir).filter((f) => f.endsWith(".sln")).map((f) =>
|
|
21986
|
+
return readdirSync9(dir).filter((f) => f.endsWith(".sln")).map((f) => join59(dir, f));
|
|
21948
21987
|
} catch {
|
|
21949
21988
|
return [];
|
|
21950
21989
|
}
|
|
@@ -22939,7 +22978,7 @@ function aggregateCommitters(authorLists) {
|
|
|
22939
22978
|
import { spawnSync as spawnSync6 } from "child_process";
|
|
22940
22979
|
import { unlinkSync as unlinkSync12, writeFileSync as writeFileSync30 } from "fs";
|
|
22941
22980
|
import { tmpdir as tmpdir6 } from "os";
|
|
22942
|
-
import { join as
|
|
22981
|
+
import { join as join60 } from "path";
|
|
22943
22982
|
function buildArgs2(queryFile, vars) {
|
|
22944
22983
|
const args = ["api", "graphql", "-F", `query=@${queryFile}`];
|
|
22945
22984
|
for (const [key, value] of Object.entries(vars)) {
|
|
@@ -22949,7 +22988,7 @@ function buildArgs2(queryFile, vars) {
|
|
|
22949
22988
|
return args;
|
|
22950
22989
|
}
|
|
22951
22990
|
function runGhGraphql(mutation, vars) {
|
|
22952
|
-
const queryFile =
|
|
22991
|
+
const queryFile = join60(tmpdir6(), `gh-query-${Date.now()}.graphql`);
|
|
22953
22992
|
writeFileSync30(queryFile, mutation);
|
|
22954
22993
|
try {
|
|
22955
22994
|
const result = spawnSync6("gh", buildArgs2(queryFile, vars), {
|
|
@@ -24229,14 +24268,14 @@ function fetchIssue2(number, repo) {
|
|
|
24229
24268
|
import { existsSync as existsSync55, readFileSync as readFileSync38 } from "fs";
|
|
24230
24269
|
|
|
24231
24270
|
// src/commands/github/issue/issueWorkingFile.ts
|
|
24232
|
-
import { join as
|
|
24271
|
+
import { join as join61 } from "path";
|
|
24233
24272
|
function issueWorkingFile(slug2, number) {
|
|
24234
24273
|
const [owner = "unknown", repo = "unknown"] = slug2.split("/");
|
|
24235
|
-
const dir =
|
|
24274
|
+
const dir = join61(getStoreDir(), "github-issues", owner, repo);
|
|
24236
24275
|
return {
|
|
24237
24276
|
dir,
|
|
24238
|
-
bodyPath:
|
|
24239
|
-
metaPath:
|
|
24277
|
+
bodyPath: join61(dir, `${number}.md`),
|
|
24278
|
+
metaPath: join61(dir, `${number}.json`)
|
|
24240
24279
|
};
|
|
24241
24280
|
}
|
|
24242
24281
|
|
|
@@ -24663,18 +24702,18 @@ import {
|
|
|
24663
24702
|
rmSync as rmSync3,
|
|
24664
24703
|
statSync as statSync9
|
|
24665
24704
|
} from "fs";
|
|
24666
|
-
import { basename as
|
|
24705
|
+
import { basename as basename16, join as join64 } from "path";
|
|
24667
24706
|
|
|
24668
24707
|
// src/commands/handover/getHandoverPath.ts
|
|
24669
|
-
import { join as
|
|
24708
|
+
import { join as join62 } from "path";
|
|
24670
24709
|
function getHandoverPath(cwd = process.cwd()) {
|
|
24671
|
-
return
|
|
24710
|
+
return join62(cwd, ".assist", "HANDOVER.md");
|
|
24672
24711
|
}
|
|
24673
24712
|
|
|
24674
24713
|
// src/commands/handover/getHandoversDir.ts
|
|
24675
|
-
import { join as
|
|
24714
|
+
import { join as join63 } from "path";
|
|
24676
24715
|
function getHandoversDir(cwd = process.cwd()) {
|
|
24677
|
-
return
|
|
24716
|
+
return join63(cwd, ".assist", "handovers");
|
|
24678
24717
|
}
|
|
24679
24718
|
|
|
24680
24719
|
// src/commands/handover/parseArchiveTimestamp.ts
|
|
@@ -24715,7 +24754,7 @@ function collectMarkdown(dir) {
|
|
|
24715
24754
|
if (!existsSync56(dir)) return [];
|
|
24716
24755
|
const out = [];
|
|
24717
24756
|
for (const entry of readdirSync10(dir, { withFileTypes: true })) {
|
|
24718
|
-
const full =
|
|
24757
|
+
const full = join64(dir, entry.name);
|
|
24719
24758
|
if (entry.isDirectory()) out.push(...collectMarkdown(full));
|
|
24720
24759
|
else if (entry.isFile() && entry.name.endsWith(".md")) out.push(full);
|
|
24721
24760
|
}
|
|
@@ -24734,7 +24773,7 @@ async function migrateFile(orm, origin, file, createdAt) {
|
|
|
24734
24773
|
async function migrateDiskHandovers(orm, origin, cwd = process.cwd()) {
|
|
24735
24774
|
let migrated = 0;
|
|
24736
24775
|
for (const file of collectMarkdown(getHandoversDir(cwd))) {
|
|
24737
|
-
const createdAt = parseArchiveTimestamp(
|
|
24776
|
+
const createdAt = parseArchiveTimestamp(basename16(file)) ?? statSync9(file).mtime;
|
|
24738
24777
|
await migrateFile(orm, origin, file, createdAt);
|
|
24739
24778
|
migrated++;
|
|
24740
24779
|
}
|
|
@@ -25097,17 +25136,17 @@ function canonicalTreePath(path106) {
|
|
|
25097
25136
|
|
|
25098
25137
|
// src/commands/sessions/daemon/worktree/createWorktree.ts
|
|
25099
25138
|
import { existsSync as existsSync57 } from "fs";
|
|
25100
|
-
import { basename as
|
|
25139
|
+
import { basename as basename18, dirname as dirname28 } from "path";
|
|
25101
25140
|
|
|
25102
25141
|
// src/commands/sessions/daemon/worktree/planAllocation.ts
|
|
25103
|
-
import { basename as
|
|
25142
|
+
import { basename as basename17, join as join65 } from "path";
|
|
25104
25143
|
function planAllocation(clone, boundTreeRoots2) {
|
|
25105
25144
|
return boundTreeRoots2.has(clone) ? "spill" : "primary";
|
|
25106
25145
|
}
|
|
25107
25146
|
function nextWorktreePath(clone, base, isTaken) {
|
|
25108
|
-
const name =
|
|
25147
|
+
const name = basename17(clone);
|
|
25109
25148
|
for (let n = 2; n < 1e3; n++) {
|
|
25110
|
-
const candidate =
|
|
25149
|
+
const candidate = join65(base, `${name}-${n}`);
|
|
25111
25150
|
if (!isTaken(candidate)) return candidate;
|
|
25112
25151
|
}
|
|
25113
25152
|
throw new Error(`no free worktree suffix for ${clone}`);
|
|
@@ -25143,7 +25182,7 @@ function createWorktree(clone, strategy, boundTreeRoots2, preferredPath) {
|
|
|
25143
25182
|
const base = strategy.root ? expandTilde2(strategy.root) : dirname28(clone);
|
|
25144
25183
|
const registered = new Set(listWorktreePaths(clone));
|
|
25145
25184
|
const branches = new Set(listLocalBranches(clone));
|
|
25146
|
-
const isTaken = (candidate) => registered.has(candidate) || existsSync57(candidate) || boundTreeRoots2.has(candidate) || branches.has(
|
|
25185
|
+
const isTaken = (candidate) => registered.has(candidate) || existsSync57(candidate) || boundTreeRoots2.has(candidate) || branches.has(basename18(candidate));
|
|
25147
25186
|
const path106 = preferredPath && !isTaken(preferredPath) ? preferredPath : nextWorktreePath(clone, base, isTaken);
|
|
25148
25187
|
const start3 = worktreeStartPoint(clone, strategy.trunk);
|
|
25149
25188
|
gitSync(clone, [
|
|
@@ -25151,13 +25190,13 @@ function createWorktree(clone, strategy, boundTreeRoots2, preferredPath) {
|
|
|
25151
25190
|
"add",
|
|
25152
25191
|
start3.track ? "--track" : "--no-track",
|
|
25153
25192
|
"-b",
|
|
25154
|
-
|
|
25193
|
+
basename18(path106),
|
|
25155
25194
|
path106,
|
|
25156
25195
|
start3.ref
|
|
25157
25196
|
]);
|
|
25158
25197
|
recordWorktree(path106, clone, getCurrentOrigin(clone));
|
|
25159
25198
|
daemonLog(
|
|
25160
|
-
start3.track ? `worktree allocated ${path106} (branch ${
|
|
25199
|
+
start3.track ? `worktree allocated ${path106} (branch ${basename18(path106)} tracking ${start3.ref}) for clone ${clone}` : `worktree allocated ${path106} (branch ${basename18(path106)} off ${start3.ref}, no mainline tracking) for clone ${clone}`
|
|
25161
25200
|
);
|
|
25162
25201
|
return path106;
|
|
25163
25202
|
}
|
|
@@ -25459,19 +25498,19 @@ function persistedTreeRoots() {
|
|
|
25459
25498
|
|
|
25460
25499
|
// src/commands/sessions/daemon/worktree/seedWorktree.ts
|
|
25461
25500
|
import { copyFileSync, existsSync as existsSync60, mkdirSync as mkdirSync17 } from "fs";
|
|
25462
|
-
import { dirname as dirname29, join as
|
|
25501
|
+
import { dirname as dirname29, join as join67 } from "path";
|
|
25463
25502
|
|
|
25464
25503
|
// src/commands/sessions/daemon/worktree/runInstall.ts
|
|
25465
25504
|
import { resolve as resolve16 } from "path";
|
|
25466
25505
|
|
|
25467
25506
|
// src/commands/sessions/daemon/worktree/detectInstallCommand.ts
|
|
25468
25507
|
import { existsSync as existsSync59 } from "fs";
|
|
25469
|
-
import { join as
|
|
25508
|
+
import { join as join66 } from "path";
|
|
25470
25509
|
function detectInstallCommand(dir) {
|
|
25471
|
-
if (!existsSync59(
|
|
25472
|
-
if (existsSync59(
|
|
25473
|
-
if (existsSync59(
|
|
25474
|
-
if (existsSync59(
|
|
25510
|
+
if (!existsSync59(join66(dir, "package.json"))) return null;
|
|
25511
|
+
if (existsSync59(join66(dir, "pnpm-lock.yaml"))) return "pnpm install";
|
|
25512
|
+
if (existsSync59(join66(dir, "yarn.lock"))) return "yarn install";
|
|
25513
|
+
if (existsSync59(join66(dir, "bun.lockb"))) return "bun install";
|
|
25475
25514
|
return "npm install";
|
|
25476
25515
|
}
|
|
25477
25516
|
|
|
@@ -25633,9 +25672,9 @@ function seedWorktree(worktreePath, clone, onSeeded = () => {
|
|
|
25633
25672
|
}
|
|
25634
25673
|
function copyConfigFiles(worktreePath, clone, copy) {
|
|
25635
25674
|
for (const rel of copy) {
|
|
25636
|
-
const src =
|
|
25675
|
+
const src = join67(clone, rel);
|
|
25637
25676
|
if (!existsSync60(src)) continue;
|
|
25638
|
-
const dest =
|
|
25677
|
+
const dest = join67(worktreePath, rel);
|
|
25639
25678
|
try {
|
|
25640
25679
|
mkdirSync17(dirname29(dest), { recursive: true });
|
|
25641
25680
|
copyFileSync(src, dest);
|
|
@@ -25945,7 +25984,7 @@ import chalk173 from "chalk";
|
|
|
25945
25984
|
|
|
25946
25985
|
// src/commands/mermaid/exportFile.ts
|
|
25947
25986
|
import { readFileSync as readFileSync40, writeFileSync as writeFileSync32 } from "fs";
|
|
25948
|
-
import { basename as
|
|
25987
|
+
import { basename as basename19, extname as extname2, resolve as resolve17 } from "path";
|
|
25949
25988
|
import chalk172 from "chalk";
|
|
25950
25989
|
|
|
25951
25990
|
// src/commands/mermaid/renderBlock.ts
|
|
@@ -25972,7 +26011,7 @@ async function renderBlock(krokiUrl, source) {
|
|
|
25972
26011
|
async function exportFile(file, outDir, krokiUrl, onlyIndex) {
|
|
25973
26012
|
const content = readFileSync40(file, "utf8");
|
|
25974
26013
|
const blocks = extractMermaidBlocks(content);
|
|
25975
|
-
const stem =
|
|
26014
|
+
const stem = basename19(file, extname2(file));
|
|
25976
26015
|
if (onlyIndex !== void 0) {
|
|
25977
26016
|
if (onlyIndex < 1 || onlyIndex > blocks.length) {
|
|
25978
26017
|
console.error(
|
|
@@ -26667,17 +26706,17 @@ function createNetcapHandler(options2) {
|
|
|
26667
26706
|
}
|
|
26668
26707
|
|
|
26669
26708
|
// src/commands/netcap/prepareExtensionForLoad.ts
|
|
26670
|
-
import { cp as cp4, readFile as
|
|
26709
|
+
import { cp as cp4, readFile as readFile6, writeFile as writeFile6 } from "fs/promises";
|
|
26671
26710
|
import { networkInterfaces } from "os";
|
|
26672
|
-
import { join as
|
|
26711
|
+
import { join as join69 } from "path";
|
|
26673
26712
|
import chalk176 from "chalk";
|
|
26674
26713
|
|
|
26675
26714
|
// src/commands/netcap/netcapExtensionDir.ts
|
|
26676
|
-
import { dirname as dirname31, join as
|
|
26715
|
+
import { dirname as dirname31, join as join68 } from "path";
|
|
26677
26716
|
import { fileURLToPath as fileURLToPath7 } from "url";
|
|
26678
26717
|
var moduleDir2 = dirname31(fileURLToPath7(import.meta.url));
|
|
26679
26718
|
function netcapExtensionDir() {
|
|
26680
|
-
return
|
|
26719
|
+
return join68(moduleDir2, "commands", "netcap", "netcap-extension");
|
|
26681
26720
|
}
|
|
26682
26721
|
|
|
26683
26722
|
// src/commands/netcap/prepareExtensionForLoad.ts
|
|
@@ -26692,9 +26731,9 @@ function lanIPv4() {
|
|
|
26692
26731
|
return void 0;
|
|
26693
26732
|
}
|
|
26694
26733
|
async function configureBackground(dir, host, port, filter) {
|
|
26695
|
-
const file =
|
|
26696
|
-
const source = await
|
|
26697
|
-
await
|
|
26734
|
+
const file = join69(dir, "background.js");
|
|
26735
|
+
const source = await readFile6(file, "utf8");
|
|
26736
|
+
await writeFile6(
|
|
26698
26737
|
file,
|
|
26699
26738
|
source.replace(
|
|
26700
26739
|
/const RECEIVER = "[^"]*";/,
|
|
@@ -26732,20 +26771,20 @@ async function prepareExtensionForLoad(port, filter = "") {
|
|
|
26732
26771
|
}
|
|
26733
26772
|
|
|
26734
26773
|
// src/commands/netcap/resolveNetcapOutPath.ts
|
|
26735
|
-
import { isAbsolute as isAbsolute4, join as
|
|
26774
|
+
import { isAbsolute as isAbsolute4, join as join71, resolve as resolve20 } from "path";
|
|
26736
26775
|
|
|
26737
26776
|
// src/commands/netcap/defaultCapturePath.ts
|
|
26738
26777
|
import { homedir as homedir21 } from "os";
|
|
26739
|
-
import { join as
|
|
26778
|
+
import { join as join70 } from "path";
|
|
26740
26779
|
function defaultCapturePath() {
|
|
26741
|
-
return
|
|
26780
|
+
return join70(homedir21(), ".assist", "netcap", "capture.jsonl");
|
|
26742
26781
|
}
|
|
26743
26782
|
|
|
26744
26783
|
// src/commands/netcap/resolveNetcapOutPath.ts
|
|
26745
26784
|
function resolveNetcapOutPath(out) {
|
|
26746
26785
|
if (!out) return defaultCapturePath();
|
|
26747
26786
|
const dir = isAbsolute4(out) ? out : resolve20(process.cwd(), out);
|
|
26748
|
-
return
|
|
26787
|
+
return join71(dir, "capture.jsonl");
|
|
26749
26788
|
}
|
|
26750
26789
|
|
|
26751
26790
|
// src/commands/netcap/netcap.ts
|
|
@@ -26792,7 +26831,7 @@ netcap stopped \u2014 captured ${count8} ${count8 === 1 ? "entry" : "entries"} t
|
|
|
26792
26831
|
|
|
26793
26832
|
// src/commands/netcap/netcapExtract.ts
|
|
26794
26833
|
import { writeFileSync as writeFileSync34 } from "fs";
|
|
26795
|
-
import { join as
|
|
26834
|
+
import { join as join72 } from "path";
|
|
26796
26835
|
import chalk178 from "chalk";
|
|
26797
26836
|
|
|
26798
26837
|
// src/commands/netcap/extractPostsFromCapture.ts
|
|
@@ -27237,7 +27276,7 @@ function extractPostsFromCapture(captureFile) {
|
|
|
27237
27276
|
function netcapExtract(file) {
|
|
27238
27277
|
const captureFile = file ?? defaultCapturePath();
|
|
27239
27278
|
const posts = extractPostsFromCapture(captureFile);
|
|
27240
|
-
const outFile =
|
|
27279
|
+
const outFile = join72(captureFile, "..", "posts.json");
|
|
27241
27280
|
writeFileSync34(outFile, `${JSON.stringify(posts, null, 2)}
|
|
27242
27281
|
`);
|
|
27243
27282
|
console.log(
|
|
@@ -27600,7 +27639,7 @@ import { execSync as execSync41 } from "child_process";
|
|
|
27600
27639
|
import { execSync as execSync40 } from "child_process";
|
|
27601
27640
|
import { unlinkSync as unlinkSync14, writeFileSync as writeFileSync35 } from "fs";
|
|
27602
27641
|
import { tmpdir as tmpdir7 } from "os";
|
|
27603
|
-
import { join as
|
|
27642
|
+
import { join as join74 } from "path";
|
|
27604
27643
|
|
|
27605
27644
|
// src/commands/prs/loadCommentsCache.ts
|
|
27606
27645
|
import { existsSync as existsSync62, readFileSync as readFileSync44, unlinkSync as unlinkSync13 } from "fs";
|
|
@@ -27608,9 +27647,9 @@ import { parse as parse3 } from "yaml";
|
|
|
27608
27647
|
|
|
27609
27648
|
// src/commands/prs/commentsCachePath.ts
|
|
27610
27649
|
import { homedir as homedir22 } from "os";
|
|
27611
|
-
import { join as
|
|
27650
|
+
import { join as join73 } from "path";
|
|
27612
27651
|
function commentsCachePath(org, repo, prNumber) {
|
|
27613
|
-
return
|
|
27652
|
+
return join73(
|
|
27614
27653
|
homedir22(),
|
|
27615
27654
|
".assist",
|
|
27616
27655
|
"pr-comments",
|
|
@@ -27659,7 +27698,7 @@ function replyToComment(org, repo, prNumber, commentId, message3) {
|
|
|
27659
27698
|
// src/commands/prs/resolveCommentWithReply.ts
|
|
27660
27699
|
function resolveThread(threadId) {
|
|
27661
27700
|
const mutation = `mutation($threadId: ID!) { resolveReviewThread(input: {threadId: $threadId}) { thread { isResolved } } }`;
|
|
27662
|
-
const queryFile =
|
|
27701
|
+
const queryFile = join74(tmpdir7(), `gh-mutation-${Date.now()}.graphql`);
|
|
27663
27702
|
writeFileSync35(queryFile, mutation);
|
|
27664
27703
|
try {
|
|
27665
27704
|
execSync40(
|
|
@@ -27744,10 +27783,10 @@ function fixed(commentId, sha) {
|
|
|
27744
27783
|
import { execSync as execSync42 } from "child_process";
|
|
27745
27784
|
import { unlinkSync as unlinkSync15, writeFileSync as writeFileSync36 } from "fs";
|
|
27746
27785
|
import { tmpdir as tmpdir8 } from "os";
|
|
27747
|
-
import { join as
|
|
27786
|
+
import { join as join75 } from "path";
|
|
27748
27787
|
var THREAD_QUERY = `query($owner: String!, $repo: String!, $prNumber: Int!) { repository(owner: $owner, name: $repo) { pullRequest(number: $prNumber) { reviewThreads(first: 100) { nodes { id isResolved comments(first: 100) { nodes { databaseId } } } } } } }`;
|
|
27749
27788
|
function fetchThreadIds(org, repo, prNumber) {
|
|
27750
|
-
const queryFile =
|
|
27789
|
+
const queryFile = join75(tmpdir8(), `gh-query-${Date.now()}.graphql`);
|
|
27751
27790
|
writeFileSync36(queryFile, THREAD_QUERY);
|
|
27752
27791
|
try {
|
|
27753
27792
|
const result = execSync42(
|
|
@@ -27822,10 +27861,10 @@ import { stringify as stringify3 } from "yaml";
|
|
|
27822
27861
|
|
|
27823
27862
|
// src/commands/prs/removeStaleCommentsCaches.ts
|
|
27824
27863
|
import { readdirSync as readdirSync12, unlinkSync as unlinkSync16 } from "fs";
|
|
27825
|
-
import { join as
|
|
27864
|
+
import { join as join76 } from "path";
|
|
27826
27865
|
var STALE_PATTERN = /^pr-\d+-comments\.yaml$/;
|
|
27827
27866
|
function removeStaleCommentsCaches(cwd = process.cwd()) {
|
|
27828
|
-
const dir =
|
|
27867
|
+
const dir = join76(cwd, ".assist");
|
|
27829
27868
|
let entries;
|
|
27830
27869
|
try {
|
|
27831
27870
|
entries = readdirSync12(dir);
|
|
@@ -27833,7 +27872,7 @@ function removeStaleCommentsCaches(cwd = process.cwd()) {
|
|
|
27833
27872
|
return;
|
|
27834
27873
|
}
|
|
27835
27874
|
for (const entry of entries.filter((e) => STALE_PATTERN.test(e))) {
|
|
27836
|
-
unlinkSync16(
|
|
27875
|
+
unlinkSync16(join76(dir, entry));
|
|
27837
27876
|
}
|
|
27838
27877
|
}
|
|
27839
27878
|
|
|
@@ -30455,7 +30494,7 @@ async function notify() {
|
|
|
30455
30494
|
import { execSync as execSync52 } from "child_process";
|
|
30456
30495
|
import { existsSync as existsSync63, mkdirSync as mkdirSync21, unlinkSync as unlinkSync17, writeFileSync as writeFileSync38 } from "fs";
|
|
30457
30496
|
import { tmpdir as tmpdir9 } from "os";
|
|
30458
|
-
import { join as
|
|
30497
|
+
import { join as join77, resolve as resolve21 } from "path";
|
|
30459
30498
|
import chalk203 from "chalk";
|
|
30460
30499
|
|
|
30461
30500
|
// src/commands/screenshot/captureWindowPs1.ts
|
|
@@ -30592,7 +30631,7 @@ function buildOutputPath(outputDir, processName) {
|
|
|
30592
30631
|
return resolve21(outputDir, `${processName}-${timestamp6}.png`);
|
|
30593
30632
|
}
|
|
30594
30633
|
function runPowerShellScript(processName, outputPath) {
|
|
30595
|
-
const scriptPath =
|
|
30634
|
+
const scriptPath = join77(tmpdir9(), `assist-screenshot-${Date.now()}.ps1`);
|
|
30596
30635
|
writeFileSync38(scriptPath, captureWindowPs1, "utf8");
|
|
30597
30636
|
try {
|
|
30598
30637
|
execSync52(
|
|
@@ -30707,9 +30746,9 @@ function buildLimitsSegment(rateLimits) {
|
|
|
30707
30746
|
|
|
30708
30747
|
// src/commands/readGitBranch.ts
|
|
30709
30748
|
import { readFileSync as readFileSync47, statSync as statSync10 } from "fs";
|
|
30710
|
-
import { isAbsolute as isAbsolute5, join as
|
|
30749
|
+
import { isAbsolute as isAbsolute5, join as join78, resolve as resolve22 } from "path";
|
|
30711
30750
|
function resolveGitDir(cwd) {
|
|
30712
|
-
const dotGit =
|
|
30751
|
+
const dotGit = join78(cwd, ".git");
|
|
30713
30752
|
let stat4;
|
|
30714
30753
|
try {
|
|
30715
30754
|
stat4 = statSync10(dotGit);
|
|
@@ -30739,7 +30778,7 @@ function readGitBranch(cwd) {
|
|
|
30739
30778
|
}
|
|
30740
30779
|
let head;
|
|
30741
30780
|
try {
|
|
30742
|
-
head = readFileSync47(
|
|
30781
|
+
head = readFileSync47(join78(gitDir, "HEAD"), "utf8");
|
|
30743
30782
|
} catch {
|
|
30744
30783
|
return null;
|
|
30745
30784
|
}
|
|
@@ -33362,7 +33401,7 @@ function groupFilesByDirectory(files) {
|
|
|
33362
33401
|
}
|
|
33363
33402
|
|
|
33364
33403
|
// src/commands/review/highLevel/buildHighLevelTree.ts
|
|
33365
|
-
function
|
|
33404
|
+
function basename20(path106) {
|
|
33366
33405
|
return path106.slice(path106.lastIndexOf("/") + 1);
|
|
33367
33406
|
}
|
|
33368
33407
|
function sum(nodes, key) {
|
|
@@ -33378,7 +33417,7 @@ function nodesOf(at2, prefix2) {
|
|
|
33378
33417
|
const files = at2.files.map(
|
|
33379
33418
|
(file) => ({
|
|
33380
33419
|
kind: "file",
|
|
33381
|
-
name:
|
|
33420
|
+
name: basename20(file.path),
|
|
33382
33421
|
...file
|
|
33383
33422
|
})
|
|
33384
33423
|
);
|
|
@@ -33698,12 +33737,12 @@ function fetchHighLevelPr(prNumber, repo) {
|
|
|
33698
33737
|
import { existsSync as existsSync64, readFileSync as readFileSync48 } from "fs";
|
|
33699
33738
|
|
|
33700
33739
|
// src/commands/review/highLevel/highLevelReviewPath.ts
|
|
33701
|
-
import { join as
|
|
33740
|
+
import { join as join79 } from "path";
|
|
33702
33741
|
function slug(value) {
|
|
33703
33742
|
return value.replace(/[^\w.-]+/g, "-");
|
|
33704
33743
|
}
|
|
33705
33744
|
function highLevelReviewPath(repo, headRef, headSha) {
|
|
33706
|
-
return
|
|
33745
|
+
return join79(
|
|
33707
33746
|
getStoreDir(),
|
|
33708
33747
|
"high-level-reviews",
|
|
33709
33748
|
slug(repo),
|
|
@@ -34779,7 +34818,7 @@ import { format } from "util";
|
|
|
34779
34818
|
|
|
34780
34819
|
// src/commands/review/createReviewLogSink.ts
|
|
34781
34820
|
import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync23 } from "fs";
|
|
34782
|
-
import { join as
|
|
34821
|
+
import { join as join80 } from "path";
|
|
34783
34822
|
|
|
34784
34823
|
// src/shared/stripAnsi.ts
|
|
34785
34824
|
var ANSI = new RegExp(
|
|
@@ -34807,7 +34846,7 @@ function createReviewLogSink() {
|
|
|
34807
34846
|
},
|
|
34808
34847
|
attach(reviewDir) {
|
|
34809
34848
|
mkdirSync23(reviewDir, { recursive: true });
|
|
34810
|
-
logPath2 =
|
|
34849
|
+
logPath2 = join80(reviewDir, LOG_FILE);
|
|
34811
34850
|
const lines2 = [
|
|
34812
34851
|
"",
|
|
34813
34852
|
`=== ${(/* @__PURE__ */ new Date()).toISOString()} ===`,
|
|
@@ -35889,21 +35928,21 @@ ${annotateDiffWithLineNumbers(context.diff.trimEnd())}
|
|
|
35889
35928
|
|
|
35890
35929
|
// src/commands/review/buildReviewPaths.ts
|
|
35891
35930
|
import { homedir as homedir23 } from "os";
|
|
35892
|
-
import { basename as
|
|
35931
|
+
import { basename as basename21, join as join81 } from "path";
|
|
35893
35932
|
function buildReviewPaths(repoRoot2, key) {
|
|
35894
|
-
const reviewDir =
|
|
35933
|
+
const reviewDir = join81(
|
|
35895
35934
|
homedir23(),
|
|
35896
35935
|
".assist",
|
|
35897
35936
|
"reviews",
|
|
35898
|
-
|
|
35937
|
+
basename21(repoRoot2),
|
|
35899
35938
|
key
|
|
35900
35939
|
);
|
|
35901
35940
|
return {
|
|
35902
35941
|
reviewDir,
|
|
35903
|
-
requestPath:
|
|
35904
|
-
claudePath:
|
|
35905
|
-
codexPath:
|
|
35906
|
-
synthesisPath:
|
|
35942
|
+
requestPath: join81(reviewDir, "request.md"),
|
|
35943
|
+
claudePath: join81(reviewDir, "claude.md"),
|
|
35944
|
+
codexPath: join81(reviewDir, "codex.md"),
|
|
35945
|
+
synthesisPath: join81(reviewDir, "synthesis.md")
|
|
35907
35946
|
};
|
|
35908
35947
|
}
|
|
35909
35948
|
|
|
@@ -36884,12 +36923,12 @@ async function reviewProposedSlackMessage(target, body, workingPath) {
|
|
|
36884
36923
|
}
|
|
36885
36924
|
|
|
36886
36925
|
// src/commands/slack/slackWorkingFile.ts
|
|
36887
|
-
import { join as
|
|
36926
|
+
import { join as join82 } from "path";
|
|
36888
36927
|
function slackWorkingFile(channel, partIndex) {
|
|
36889
36928
|
const slug2 = channel.replace(/^[#@]/, "").toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "channel";
|
|
36890
|
-
const dir =
|
|
36929
|
+
const dir = join82(getStoreDir(), "slack");
|
|
36891
36930
|
const name = partIndex === void 0 ? slug2 : `${slug2}-${partIndex}`;
|
|
36892
|
-
return { dir, bodyPath:
|
|
36931
|
+
return { dir, bodyPath: join82(dir, `${name}.md`) };
|
|
36893
36932
|
}
|
|
36894
36933
|
|
|
36895
36934
|
// src/commands/slack/previewSlackThreadParts.ts
|
|
@@ -38069,20 +38108,20 @@ async function configure() {
|
|
|
38069
38108
|
|
|
38070
38109
|
// src/commands/transcript/list.ts
|
|
38071
38110
|
import { existsSync as existsSync76, readdirSync as readdirSync20, statSync as statSync12 } from "fs";
|
|
38072
|
-
import { join as
|
|
38111
|
+
import { join as join94 } from "path";
|
|
38073
38112
|
function list3() {
|
|
38074
38113
|
const { vttDir } = getTranscriptConfig();
|
|
38075
38114
|
if (!existsSync76(vttDir)) return;
|
|
38076
38115
|
for (const entry of readdirSync20(vttDir)) {
|
|
38077
38116
|
if (!entry.endsWith(".vtt")) continue;
|
|
38078
|
-
if (statSync12(
|
|
38117
|
+
if (statSync12(join94(vttDir, entry)).isDirectory()) continue;
|
|
38079
38118
|
console.log(entry);
|
|
38080
38119
|
}
|
|
38081
38120
|
}
|
|
38082
38121
|
|
|
38083
38122
|
// src/commands/transcript/move.ts
|
|
38084
38123
|
import { existsSync as existsSync77, mkdirSync as mkdirSync32, renameSync as renameSync2, writeFileSync as writeFileSync50 } from "fs";
|
|
38085
|
-
import { basename as
|
|
38124
|
+
import { basename as basename25, join as join95 } from "path";
|
|
38086
38125
|
|
|
38087
38126
|
// src/commands/transcript/convertVttToMarkdown.ts
|
|
38088
38127
|
function convertVttToMarkdown(inputPath) {
|
|
@@ -38092,9 +38131,9 @@ function convertVttToMarkdown(inputPath) {
|
|
|
38092
38131
|
// src/commands/transcript/move.ts
|
|
38093
38132
|
var DATE_REGEX = /^\d{4}-\d{2}-\d{2}$/;
|
|
38094
38133
|
function archiveRawVtt(vttDir, sourcePath, filename) {
|
|
38095
|
-
const processedDir =
|
|
38134
|
+
const processedDir = join95(vttDir, "processed");
|
|
38096
38135
|
mkdirSync32(processedDir, { recursive: true });
|
|
38097
|
-
renameSync2(sourcePath,
|
|
38136
|
+
renameSync2(sourcePath, join95(processedDir, filename));
|
|
38098
38137
|
}
|
|
38099
38138
|
function move(file, options2) {
|
|
38100
38139
|
const { date, client } = options2;
|
|
@@ -38103,27 +38142,27 @@ function move(file, options2) {
|
|
|
38103
38142
|
process.exit(1);
|
|
38104
38143
|
}
|
|
38105
38144
|
const { vttDir, transcriptsDir, summaryDir } = getTranscriptConfig();
|
|
38106
|
-
const filename =
|
|
38107
|
-
const sourcePath =
|
|
38145
|
+
const filename = basename25(file);
|
|
38146
|
+
const sourcePath = join95(vttDir, filename);
|
|
38108
38147
|
if (!existsSync77(sourcePath)) {
|
|
38109
38148
|
console.error(`Error: VTT file not found: ${sourcePath}`);
|
|
38110
38149
|
process.exit(1);
|
|
38111
38150
|
}
|
|
38112
|
-
const base =
|
|
38151
|
+
const base = basename25(filename, ".vtt").replace(/ Transcription$/, "");
|
|
38113
38152
|
const outputName = `${date} ${base}.md`;
|
|
38114
|
-
const formattedDir =
|
|
38153
|
+
const formattedDir = join95(transcriptsDir, client);
|
|
38115
38154
|
mkdirSync32(formattedDir, { recursive: true });
|
|
38116
|
-
const formattedPath =
|
|
38155
|
+
const formattedPath = join95(formattedDir, outputName);
|
|
38117
38156
|
writeFileSync50(formattedPath, convertVttToMarkdown(sourcePath), "utf8");
|
|
38118
38157
|
archiveRawVtt(vttDir, sourcePath, filename);
|
|
38119
|
-
const summaryPath =
|
|
38158
|
+
const summaryPath = join95(summaryDir, client, outputName);
|
|
38120
38159
|
console.log(`Formatted transcript: ${formattedPath}`);
|
|
38121
38160
|
console.log(`Summary target: ${summaryPath}`);
|
|
38122
38161
|
}
|
|
38123
38162
|
|
|
38124
38163
|
// src/commands/transcript/merge.ts
|
|
38125
38164
|
import { existsSync as existsSync78, writeFileSync as writeFileSync51 } from "fs";
|
|
38126
|
-
import { basename as
|
|
38165
|
+
import { basename as basename26 } from "path";
|
|
38127
38166
|
|
|
38128
38167
|
// src/commands/transcript/failTranscript.ts
|
|
38129
38168
|
function failTranscript(message3) {
|
|
@@ -38269,7 +38308,7 @@ function readSource3(file) {
|
|
|
38269
38308
|
if (!existsSync78(file)) failTranscript(`VTT file not found: ${file}`);
|
|
38270
38309
|
const cues = readCleanedCues(file);
|
|
38271
38310
|
if (cues.length === 0) failTranscript(`no cues found in: ${file}`);
|
|
38272
|
-
return { path: file, name:
|
|
38311
|
+
return { path: file, name: basename26(file), cues };
|
|
38273
38312
|
}
|
|
38274
38313
|
function wholePassages(sources) {
|
|
38275
38314
|
return sources.map((source) => ({
|
|
@@ -38930,7 +38969,7 @@ function listMigrationFiles(dir) {
|
|
|
38930
38969
|
|
|
38931
38970
|
// src/commands/verify/migrations/readBaselineMigrations.ts
|
|
38932
38971
|
import { execSync as execSync63 } from "child_process";
|
|
38933
|
-
import { basename as
|
|
38972
|
+
import { basename as basename27 } from "path";
|
|
38934
38973
|
var MIGRATION_FILE3 = /^migration\d+[A-Za-z0-9]*\.ts$/;
|
|
38935
38974
|
function readBaselineMigrations(repoRelativeDir, ref) {
|
|
38936
38975
|
const baseline = /* @__PURE__ */ new Map();
|
|
@@ -38943,7 +38982,7 @@ function readBaselineMigrations(repoRelativeDir, ref) {
|
|
|
38943
38982
|
} catch {
|
|
38944
38983
|
return baseline;
|
|
38945
38984
|
}
|
|
38946
|
-
const paths = listing.split("\n").map((line) => line.trim()).filter(Boolean).filter((path106) => MIGRATION_FILE3.test(
|
|
38985
|
+
const paths = listing.split("\n").map((line) => line.trim()).filter(Boolean).filter((path106) => MIGRATION_FILE3.test(basename27(path106)));
|
|
38947
38986
|
for (const path106 of paths) {
|
|
38948
38987
|
try {
|
|
38949
38988
|
const content = execSync63(`git show "${ref}:${path106}"`, {
|
|
@@ -38951,7 +38990,7 @@ function readBaselineMigrations(repoRelativeDir, ref) {
|
|
|
38951
38990
|
maxBuffer: 16 * 1024 * 1024,
|
|
38952
38991
|
stdio: ["pipe", "pipe", "pipe"]
|
|
38953
38992
|
});
|
|
38954
|
-
baseline.set(
|
|
38993
|
+
baseline.set(basename27(path106), content);
|
|
38955
38994
|
} catch {
|
|
38956
38995
|
}
|
|
38957
38996
|
}
|
|
@@ -39152,38 +39191,38 @@ function registerVerify(program2) {
|
|
|
39152
39191
|
|
|
39153
39192
|
// src/commands/voice/devices.ts
|
|
39154
39193
|
import { spawnSync as spawnSync9 } from "child_process";
|
|
39155
|
-
import { join as
|
|
39194
|
+
import { join as join97 } from "path";
|
|
39156
39195
|
|
|
39157
39196
|
// src/commands/voice/shared.ts
|
|
39158
39197
|
import { homedir as homedir25 } from "os";
|
|
39159
|
-
import { dirname as dirname40, join as
|
|
39198
|
+
import { dirname as dirname40, join as join96 } from "path";
|
|
39160
39199
|
import { fileURLToPath as fileURLToPath10 } from "url";
|
|
39161
39200
|
var __dirname6 = dirname40(fileURLToPath10(import.meta.url));
|
|
39162
|
-
var VOICE_DIR =
|
|
39201
|
+
var VOICE_DIR = join96(homedir25(), ".assist", "voice");
|
|
39163
39202
|
var voicePaths = {
|
|
39164
39203
|
dir: VOICE_DIR,
|
|
39165
|
-
pid:
|
|
39166
|
-
log:
|
|
39167
|
-
venv:
|
|
39168
|
-
lock:
|
|
39204
|
+
pid: join96(VOICE_DIR, "voice.pid"),
|
|
39205
|
+
log: join96(VOICE_DIR, "voice.log"),
|
|
39206
|
+
venv: join96(VOICE_DIR, ".venv"),
|
|
39207
|
+
lock: join96(VOICE_DIR, "voice.lock")
|
|
39169
39208
|
};
|
|
39170
39209
|
function getPythonDir() {
|
|
39171
|
-
return
|
|
39210
|
+
return join96(__dirname6, "commands", "voice", "python");
|
|
39172
39211
|
}
|
|
39173
39212
|
function getVenvPython() {
|
|
39174
|
-
return process.platform === "win32" ?
|
|
39213
|
+
return process.platform === "win32" ? join96(voicePaths.venv, "Scripts", "python.exe") : join96(voicePaths.venv, "bin", "python");
|
|
39175
39214
|
}
|
|
39176
39215
|
function getLockDir() {
|
|
39177
39216
|
const config = loadConfig();
|
|
39178
39217
|
return config.voice?.lockDir ?? VOICE_DIR;
|
|
39179
39218
|
}
|
|
39180
39219
|
function getLockFile() {
|
|
39181
|
-
return
|
|
39220
|
+
return join96(getLockDir(), "voice.lock");
|
|
39182
39221
|
}
|
|
39183
39222
|
|
|
39184
39223
|
// src/commands/voice/devices.ts
|
|
39185
39224
|
function devices() {
|
|
39186
|
-
const script =
|
|
39225
|
+
const script = join97(getPythonDir(), "list_devices.py");
|
|
39187
39226
|
spawnSync9(getVenvPython(), [script], { stdio: "inherit" });
|
|
39188
39227
|
}
|
|
39189
39228
|
|
|
@@ -39218,12 +39257,12 @@ function logs(options2) {
|
|
|
39218
39257
|
// src/commands/voice/setup.ts
|
|
39219
39258
|
import { spawnSync as spawnSync10 } from "child_process";
|
|
39220
39259
|
import { mkdirSync as mkdirSync34 } from "fs";
|
|
39221
|
-
import { join as
|
|
39260
|
+
import { join as join99 } from "path";
|
|
39222
39261
|
|
|
39223
39262
|
// src/commands/voice/checkLockFile.ts
|
|
39224
39263
|
import { execSync as execSync66 } from "child_process";
|
|
39225
39264
|
import { existsSync as existsSync81, mkdirSync as mkdirSync33, readFileSync as readFileSync64, writeFileSync as writeFileSync52 } from "fs";
|
|
39226
|
-
import { join as
|
|
39265
|
+
import { join as join98 } from "path";
|
|
39227
39266
|
function isProcessAlive2(pid) {
|
|
39228
39267
|
try {
|
|
39229
39268
|
process.kill(pid, 0);
|
|
@@ -39260,7 +39299,7 @@ function bootstrapVenv() {
|
|
|
39260
39299
|
}
|
|
39261
39300
|
function writeLockFile(pid) {
|
|
39262
39301
|
const lockFile = getLockFile();
|
|
39263
|
-
mkdirSync33(
|
|
39302
|
+
mkdirSync33(join98(lockFile, ".."), { recursive: true });
|
|
39264
39303
|
writeFileSync52(
|
|
39265
39304
|
lockFile,
|
|
39266
39305
|
JSON.stringify({
|
|
@@ -39276,7 +39315,7 @@ function setup() {
|
|
|
39276
39315
|
mkdirSync34(voicePaths.dir, { recursive: true });
|
|
39277
39316
|
bootstrapVenv();
|
|
39278
39317
|
console.log("\nDownloading models...\n");
|
|
39279
|
-
const script =
|
|
39318
|
+
const script = join99(getPythonDir(), "setup_models.py");
|
|
39280
39319
|
const result = spawnSync10(getVenvPython(), [script], {
|
|
39281
39320
|
stdio: "inherit",
|
|
39282
39321
|
env: { ...process.env, VOICE_LOG_FILE: voicePaths.log }
|
|
@@ -39290,7 +39329,7 @@ function setup() {
|
|
|
39290
39329
|
// src/commands/voice/start.ts
|
|
39291
39330
|
import { spawn as spawn9 } from "child_process";
|
|
39292
39331
|
import { mkdirSync as mkdirSync35, writeFileSync as writeFileSync53 } from "fs";
|
|
39293
|
-
import { join as
|
|
39332
|
+
import { join as join100 } from "path";
|
|
39294
39333
|
|
|
39295
39334
|
// src/commands/voice/buildDaemonEnv.ts
|
|
39296
39335
|
function buildDaemonEnv(options2) {
|
|
@@ -39328,7 +39367,7 @@ function start2(options2) {
|
|
|
39328
39367
|
bootstrapVenv();
|
|
39329
39368
|
const debug = options2.debug || options2.foreground || process.platform === "win32";
|
|
39330
39369
|
const env = buildDaemonEnv({ debug });
|
|
39331
|
-
const script =
|
|
39370
|
+
const script = join100(getPythonDir(), "voice_daemon.py");
|
|
39332
39371
|
const python = getVenvPython();
|
|
39333
39372
|
if (options2.foreground) {
|
|
39334
39373
|
spawnForeground(python, script, env);
|
|
@@ -39459,11 +39498,11 @@ function changedPaths(from, cwd) {
|
|
|
39459
39498
|
}
|
|
39460
39499
|
|
|
39461
39500
|
// src/commands/watch/readBuiltVersion.ts
|
|
39462
|
-
import { join as
|
|
39501
|
+
import { join as join101 } from "path";
|
|
39463
39502
|
function readBuiltVersion(cwd) {
|
|
39464
39503
|
try {
|
|
39465
39504
|
const root2 = runGit3(["rev-parse", "--show-toplevel"], cwd);
|
|
39466
|
-
return readPackageJson(
|
|
39505
|
+
return readPackageJson(join101(root2, "package.json")).version ?? "unknown";
|
|
39467
39506
|
} catch {
|
|
39468
39507
|
return "unknown";
|
|
39469
39508
|
}
|
|
@@ -40197,7 +40236,7 @@ async function auth() {
|
|
|
40197
40236
|
// src/commands/roam/postRoamActivity.ts
|
|
40198
40237
|
import { execFileSync as execFileSync23 } from "child_process";
|
|
40199
40238
|
import { readdirSync as readdirSync22, readFileSync as readFileSync67, statSync as statSync13 } from "fs";
|
|
40200
|
-
import { join as
|
|
40239
|
+
import { join as join102 } from "path";
|
|
40201
40240
|
function findPortFile(roamDir) {
|
|
40202
40241
|
let entries;
|
|
40203
40242
|
try {
|
|
@@ -40206,7 +40245,7 @@ function findPortFile(roamDir) {
|
|
|
40206
40245
|
return void 0;
|
|
40207
40246
|
}
|
|
40208
40247
|
const candidates = entries.filter((name) => /^roam-local-api(-[^.]+)?\.port$/.test(name)).map((name) => {
|
|
40209
|
-
const path106 =
|
|
40248
|
+
const path106 = join102(roamDir, name);
|
|
40210
40249
|
try {
|
|
40211
40250
|
return { path: path106, mtimeMs: statSync13(path106).mtimeMs };
|
|
40212
40251
|
} catch {
|
|
@@ -40223,7 +40262,7 @@ var PID_BY_APP = {
|
|
|
40223
40262
|
function postRoamActivity(app, event) {
|
|
40224
40263
|
const appData = process.env.APPDATA;
|
|
40225
40264
|
if (!appData) return;
|
|
40226
|
-
const portFile = findPortFile(
|
|
40265
|
+
const portFile = findPortFile(join102(appData, "Roam"));
|
|
40227
40266
|
if (!portFile) return;
|
|
40228
40267
|
let port;
|
|
40229
40268
|
try {
|
|
@@ -40359,7 +40398,7 @@ async function run3(name, args) {
|
|
|
40359
40398
|
|
|
40360
40399
|
// src/commands/run/add.ts
|
|
40361
40400
|
import { mkdirSync as mkdirSync36, writeFileSync as writeFileSync54 } from "fs";
|
|
40362
|
-
import { join as
|
|
40401
|
+
import { join as join103 } from "path";
|
|
40363
40402
|
|
|
40364
40403
|
// src/commands/run/extractOption.ts
|
|
40365
40404
|
function extractOption(args, flag) {
|
|
@@ -40420,7 +40459,7 @@ function saveNewRunConfig(name, command, args, cwd) {
|
|
|
40420
40459
|
saveConfig(config);
|
|
40421
40460
|
}
|
|
40422
40461
|
function createCommandFile(name) {
|
|
40423
|
-
const dir =
|
|
40462
|
+
const dir = join103(".claude", "commands");
|
|
40424
40463
|
mkdirSync36(dir, { recursive: true });
|
|
40425
40464
|
const content = `---
|
|
40426
40465
|
description: Run ${name}
|
|
@@ -40428,7 +40467,7 @@ description: Run ${name}
|
|
|
40428
40467
|
|
|
40429
40468
|
Run \`assist run ${name} $ARGUMENTS 2>&1\`.
|
|
40430
40469
|
`;
|
|
40431
|
-
const filePath =
|
|
40470
|
+
const filePath = join103(dir, `${name}.md`);
|
|
40432
40471
|
writeFileSync54(filePath, content);
|
|
40433
40472
|
console.log(`Created command file: ${filePath}`);
|
|
40434
40473
|
}
|
|
@@ -40485,7 +40524,7 @@ function link2() {
|
|
|
40485
40524
|
|
|
40486
40525
|
// src/commands/run/remove.ts
|
|
40487
40526
|
import { existsSync as existsSync85, unlinkSync as unlinkSync22 } from "fs";
|
|
40488
|
-
import { join as
|
|
40527
|
+
import { join as join104 } from "path";
|
|
40489
40528
|
function findRemoveIndex() {
|
|
40490
40529
|
const idx = process.argv.indexOf("remove");
|
|
40491
40530
|
if (idx === -1 || idx + 1 >= process.argv.length) return -1;
|
|
@@ -40500,7 +40539,7 @@ function parseRemoveName() {
|
|
|
40500
40539
|
return process.argv[idx + 1];
|
|
40501
40540
|
}
|
|
40502
40541
|
function deleteCommandFile(name) {
|
|
40503
|
-
const filePath =
|
|
40542
|
+
const filePath = join104(".claude", "commands", `${name}.md`);
|
|
40504
40543
|
if (existsSync85(filePath)) {
|
|
40505
40544
|
unlinkSync22(filePath);
|
|
40506
40545
|
console.log(`Deleted command file: ${filePath}`);
|
|
@@ -41344,16 +41383,16 @@ function setStatus2(session, newStatus) {
|
|
|
41344
41383
|
|
|
41345
41384
|
// src/commands/sessions/daemon/worktree/reapWorktree.ts
|
|
41346
41385
|
import { existsSync as existsSync90 } from "fs";
|
|
41347
|
-
import { basename as
|
|
41386
|
+
import { basename as basename28 } from "path";
|
|
41348
41387
|
|
|
41349
41388
|
// src/commands/sessions/daemon/worktree/deleteStrandedTree.ts
|
|
41350
41389
|
import { existsSync as existsSync89 } from "fs";
|
|
41351
|
-
import { join as
|
|
41390
|
+
import { join as join107 } from "path";
|
|
41352
41391
|
|
|
41353
41392
|
// src/commands/sessions/daemon/worktree/deleteTreeDirectly.ts
|
|
41354
41393
|
import { statSync as statSync15 } from "fs";
|
|
41355
41394
|
import { rm as rm4 } from "fs/promises";
|
|
41356
|
-
import { join as
|
|
41395
|
+
import { join as join106 } from "path";
|
|
41357
41396
|
async function deleteTreeDirectly(clone, worktreePath, why) {
|
|
41358
41397
|
if (holdsAGitDirectoryRatherThanALink(worktreePath)) {
|
|
41359
41398
|
const refusal = "it is a clone of its own, not a linked worktree";
|
|
@@ -41381,7 +41420,7 @@ async function deleteTreeDirectly(clone, worktreePath, why) {
|
|
|
41381
41420
|
return { removed: true };
|
|
41382
41421
|
}
|
|
41383
41422
|
function holdsAGitDirectoryRatherThanALink(worktreePath) {
|
|
41384
|
-
return statSync15(
|
|
41423
|
+
return statSync15(join106(worktreePath, ".git"), {
|
|
41385
41424
|
throwIfNoEntry: false
|
|
41386
41425
|
})?.isDirectory() === true;
|
|
41387
41426
|
}
|
|
@@ -41417,7 +41456,7 @@ async function deleteStrandedTree(clone, worktreePath, cause) {
|
|
|
41417
41456
|
);
|
|
41418
41457
|
}
|
|
41419
41458
|
function strandedReason(worktreePath, cause) {
|
|
41420
|
-
if (!existsSync89(
|
|
41459
|
+
if (!existsSync89(join107(worktreePath, ".git")))
|
|
41421
41460
|
return "its .git link is already gone";
|
|
41422
41461
|
if (/not a working tree|not a git repository/i.test(reason2(cause)))
|
|
41423
41462
|
return "git no longer recognises it as a working tree";
|
|
@@ -41487,7 +41526,7 @@ async function reapWorktree(worktreePath, force = false) {
|
|
|
41487
41526
|
const clone = owningClone(worktreePath);
|
|
41488
41527
|
const removal = await removeTree(clone, worktreePath, force);
|
|
41489
41528
|
if (!removal.removed) return removal;
|
|
41490
|
-
await deleteWorktreeBranch(clone,
|
|
41529
|
+
await deleteWorktreeBranch(clone, basename28(worktreePath));
|
|
41491
41530
|
forgetWorktree(worktreePath);
|
|
41492
41531
|
daemonLog(`worktree ${worktreePath} reaped${force ? " (forced)" : ""}`);
|
|
41493
41532
|
return removal;
|
|
@@ -44215,7 +44254,7 @@ function rearmStoppedSessions(sessions, notify2) {
|
|
|
44215
44254
|
|
|
44216
44255
|
// src/commands/sessions/daemon/worktree/reconcileWorktreesOnRestore.ts
|
|
44217
44256
|
import { existsSync as existsSync96 } from "fs";
|
|
44218
|
-
import { basename as
|
|
44257
|
+
import { basename as basename30 } from "path";
|
|
44219
44258
|
|
|
44220
44259
|
// src/commands/sessions/daemon/worktree/accountedTrees.ts
|
|
44221
44260
|
function accountedTrees(sessions) {
|
|
@@ -44357,7 +44396,7 @@ function capped2(lines2) {
|
|
|
44357
44396
|
}
|
|
44358
44397
|
|
|
44359
44398
|
// src/commands/sessions/daemon/worktree/resurfaceOrphanedWorktree.ts
|
|
44360
|
-
import { basename as
|
|
44399
|
+
import { basename as basename29 } from "path";
|
|
44361
44400
|
function resurfaceOrphanedWorktree(sessions, spawnWith, recovered, notify2) {
|
|
44362
44401
|
const { orphan, reason: reason4, held } = recovered;
|
|
44363
44402
|
let id;
|
|
@@ -44380,7 +44419,7 @@ function orphanedSession(id, recovered) {
|
|
|
44380
44419
|
const { orphan, reason: reason4, held } = recovered;
|
|
44381
44420
|
return {
|
|
44382
44421
|
...sessionBase(id, "stopped"),
|
|
44383
|
-
name: `recovered ${
|
|
44422
|
+
name: `recovered ${basename29(orphan.path)}`,
|
|
44384
44423
|
subtitle: `${held.summary} in ${orphan.path}`,
|
|
44385
44424
|
commandType: "claude",
|
|
44386
44425
|
pty: null,
|
|
@@ -44441,7 +44480,7 @@ async function recoverOrphanedWorktrees(sessions, spawnWith, notify2) {
|
|
|
44441
44480
|
logVanishedTree(sessions, path106);
|
|
44442
44481
|
vanished.set(clone, [
|
|
44443
44482
|
...vanished.get(clone) ?? [],
|
|
44444
|
-
{ path: path106, branch:
|
|
44483
|
+
{ path: path106, branch: basename30(path106) }
|
|
44445
44484
|
]);
|
|
44446
44485
|
continue;
|
|
44447
44486
|
}
|
|
@@ -46058,7 +46097,7 @@ import { existsSync as existsSync98 } from "fs";
|
|
|
46058
46097
|
|
|
46059
46098
|
// src/commands/sessions/daemon/worktree/carryTranscriptToTree.ts
|
|
46060
46099
|
import { copyFileSync as copyFileSync5, existsSync as existsSync97, mkdirSync as mkdirSync39 } from "fs";
|
|
46061
|
-
import { join as
|
|
46100
|
+
import { join as join109 } from "path";
|
|
46062
46101
|
function carryTranscriptToTree(claudeSessionId, fromCwd, toCwd) {
|
|
46063
46102
|
const dir = projectDirForCwd(toCwd);
|
|
46064
46103
|
if (dir === projectDirForCwd(fromCwd)) {
|
|
@@ -46067,7 +46106,7 @@ function carryTranscriptToTree(claudeSessionId, fromCwd, toCwd) {
|
|
|
46067
46106
|
);
|
|
46068
46107
|
return;
|
|
46069
46108
|
}
|
|
46070
|
-
const dest =
|
|
46109
|
+
const dest = join109(dir, `${claudeSessionId}.jsonl`);
|
|
46071
46110
|
if (existsSync97(dest)) {
|
|
46072
46111
|
daemonLog(`transcript ${claudeSessionId} already present in ${dir}`);
|
|
46073
46112
|
return;
|
|
@@ -47256,6 +47295,73 @@ async function sshHop(ssh, probes) {
|
|
|
47256
47295
|
);
|
|
47257
47296
|
}
|
|
47258
47297
|
|
|
47298
|
+
// src/commands/sessions/nodes/tailscaleStatus.ts
|
|
47299
|
+
import { execFile as execFile13 } from "child_process";
|
|
47300
|
+
import { promisify as promisify12 } from "util";
|
|
47301
|
+
var execFileAsync11 = promisify12(execFile13);
|
|
47302
|
+
var STATUS_TIMEOUT_MS2 = 1e4;
|
|
47303
|
+
function tailscaleCli() {
|
|
47304
|
+
return detectPlatform() === "wsl" ? "tailscale.exe" : "tailscale";
|
|
47305
|
+
}
|
|
47306
|
+
async function tailscaleStatus() {
|
|
47307
|
+
const { stdout } = await execFileAsync11(tailscaleCli(), ["status", "--json"], {
|
|
47308
|
+
encoding: "utf8",
|
|
47309
|
+
timeout: STATUS_TIMEOUT_MS2,
|
|
47310
|
+
windowsHide: true
|
|
47311
|
+
});
|
|
47312
|
+
return JSON.parse(stdout);
|
|
47313
|
+
}
|
|
47314
|
+
|
|
47315
|
+
// src/commands/sessions/nodes/findTailscalePeer.ts
|
|
47316
|
+
function findTailscalePeer(status3, hostname2) {
|
|
47317
|
+
const nodes = [
|
|
47318
|
+
...status3.Self ? [{ ...status3.Self, Online: true }] : [],
|
|
47319
|
+
...Object.values(status3.Peer ?? {})
|
|
47320
|
+
];
|
|
47321
|
+
return nodes.find(
|
|
47322
|
+
(node) => node.DNSName?.replace(/\.$/, "").toLowerCase() === hostname2
|
|
47323
|
+
);
|
|
47324
|
+
}
|
|
47325
|
+
|
|
47326
|
+
// src/commands/sessions/nodes/tailscaleHop.ts
|
|
47327
|
+
async function tailscaleHop(spec, probes) {
|
|
47328
|
+
const cli = tailscaleCli();
|
|
47329
|
+
let status3;
|
|
47330
|
+
try {
|
|
47331
|
+
status3 = await probes.tailscale();
|
|
47332
|
+
} catch (error) {
|
|
47333
|
+
return failed2(
|
|
47334
|
+
"tailscale",
|
|
47335
|
+
describePeerError(error),
|
|
47336
|
+
`\`${cli} status --json\` failed \u2014 install Tailscale on this node and sign in with \`${cli} up\``
|
|
47337
|
+
);
|
|
47338
|
+
}
|
|
47339
|
+
if (status3.BackendState !== "Running")
|
|
47340
|
+
return failed2(
|
|
47341
|
+
"tailscale",
|
|
47342
|
+
`Tailscale on this node is ${status3.BackendState ?? "not running"}`,
|
|
47343
|
+
`run \`${cli} up\` on this node`
|
|
47344
|
+
);
|
|
47345
|
+
const { hostname: hostname2 } = new URL(spec.url);
|
|
47346
|
+
const peer = findTailscalePeer(status3, hostname2);
|
|
47347
|
+
if (!peer)
|
|
47348
|
+
return failed2(
|
|
47349
|
+
"tailscale",
|
|
47350
|
+
`${hostname2} is not in this node's tailnet`,
|
|
47351
|
+
`check the host in \`${cli} status\`, then relink with \`assist sessions nodes link ${spec.name} --tailscale <host> --port <port>\``
|
|
47352
|
+
);
|
|
47353
|
+
if (!peer.Online)
|
|
47354
|
+
return failed2(
|
|
47355
|
+
"tailscale",
|
|
47356
|
+
`${hostname2} is offline in the tailnet`,
|
|
47357
|
+
`is ${spec.name}'s machine awake with Tailscale running and signed in?`
|
|
47358
|
+
);
|
|
47359
|
+
return passed(
|
|
47360
|
+
"tailscale",
|
|
47361
|
+
`${hostname2} online${peer.TailscaleIPs?.[0] ? ` (${peer.TailscaleIPs[0]})` : ""}`
|
|
47362
|
+
);
|
|
47363
|
+
}
|
|
47364
|
+
|
|
47259
47365
|
// src/commands/sessions/nodes/tunnelHop.ts
|
|
47260
47366
|
async function tunnelHop(spec, ssh, probes) {
|
|
47261
47367
|
const bound = `127.0.0.1:${ssh.localPort}`;
|
|
@@ -47268,10 +47374,26 @@ async function tunnelHop(spec, ssh, probes) {
|
|
|
47268
47374
|
);
|
|
47269
47375
|
}
|
|
47270
47376
|
|
|
47377
|
+
// src/commands/sessions/nodes/tailscaleServeRemediation.ts
|
|
47378
|
+
function tailscaleServeRemediation(spec, error) {
|
|
47379
|
+
const status3 = error.status;
|
|
47380
|
+
if (status3 !== void 0 && status3 !== 502) return void 0;
|
|
47381
|
+
const { hostname: hostname2, port } = new URL(spec.url);
|
|
47382
|
+
const servePort = port || "443";
|
|
47383
|
+
return status3 === 502 ? `tailscale serve on ${hostname2} answered but nothing listens on 127.0.0.1:${servePort} behind it \u2014 is ${spec.name}'s web server running (project-switch webservers)?` : `nothing serves https on ${servePort} on ${hostname2} \u2014 run \`tailscale serve --bg --https=${servePort} http://127.0.0.1:${servePort}\` on ${spec.name} (tailscale.exe under WSL)`;
|
|
47384
|
+
}
|
|
47385
|
+
|
|
47386
|
+
// src/commands/sessions/nodes/isTailscaleLink.ts
|
|
47387
|
+
function isTailscaleLink(spec) {
|
|
47388
|
+
return new URL(spec.url).hostname.endsWith(".ts.net");
|
|
47389
|
+
}
|
|
47390
|
+
|
|
47271
47391
|
// src/commands/sessions/nodes/webHop.ts
|
|
47272
47392
|
function webRemediation(spec, error) {
|
|
47273
47393
|
if (spec.ssh && error.status === void 0)
|
|
47274
47394
|
return `nothing listening on ${spec.ssh.port} on ${spec.ssh.alias} \u2014 is project-switch running ${spec.name}'s web server?`;
|
|
47395
|
+
const serve = isTailscaleLink(spec) ? tailscaleServeRemediation(spec, error) : void 0;
|
|
47396
|
+
if (serve) return serve;
|
|
47275
47397
|
const { hostname: hostname2, port } = new URL(spec.url);
|
|
47276
47398
|
switch (peerErrorCode(error)) {
|
|
47277
47399
|
case "ECONNREFUSED":
|
|
@@ -47311,7 +47433,7 @@ async function webHop(spec, probes) {
|
|
|
47311
47433
|
};
|
|
47312
47434
|
}
|
|
47313
47435
|
|
|
47314
|
-
// src/commands/sessions/nodes/
|
|
47436
|
+
// src/commands/sessions/nodes/peerDaemonHop.ts
|
|
47315
47437
|
function peerDaemonHop(spec, health2) {
|
|
47316
47438
|
if (health2.daemon?.reachable) return passed("daemon", "reachable");
|
|
47317
47439
|
return failed2(
|
|
@@ -47320,6 +47442,8 @@ function peerDaemonHop(spec, health2) {
|
|
|
47320
47442
|
`run \`assist daemon status\` on ${spec.name}; restarting its web server starts the daemon`
|
|
47321
47443
|
);
|
|
47322
47444
|
}
|
|
47445
|
+
|
|
47446
|
+
// src/commands/sessions/nodes/diagnoseLink.ts
|
|
47323
47447
|
async function diagnoseLink(spec, probes) {
|
|
47324
47448
|
const hops = [];
|
|
47325
47449
|
const done2 = () => ({ ...spec, ok: hops.every((h) => h.ok), hops });
|
|
@@ -47334,6 +47458,10 @@ async function diagnoseLink(spec, probes) {
|
|
|
47334
47458
|
if (!hops.at(-1)?.ok) return done2();
|
|
47335
47459
|
}
|
|
47336
47460
|
}
|
|
47461
|
+
if (isTailscaleLink(spec)) {
|
|
47462
|
+
hops.push(await tailscaleHop(spec, probes));
|
|
47463
|
+
if (!hops.at(-1)?.ok) return done2();
|
|
47464
|
+
}
|
|
47337
47465
|
const web3 = await webHop(spec, probes);
|
|
47338
47466
|
hops.push(web3.hop);
|
|
47339
47467
|
if (!web3.health) return done2();
|
|
@@ -47481,7 +47609,7 @@ function printDiagnosis(diagnosis) {
|
|
|
47481
47609
|
console.log(`${chalk253.bold(diagnosis.name)} ${chalk253.dim(diagnosis.url)}`);
|
|
47482
47610
|
for (const hop of diagnosis.hops) {
|
|
47483
47611
|
const mark = hop.ok ? chalk253.green("\u2713") : chalk253.red("\u2717");
|
|
47484
|
-
console.log(` ${mark} ${hop.hop.padEnd(
|
|
47612
|
+
console.log(` ${mark} ${hop.hop.padEnd(9)} ${hop.detail ?? hop.error}`);
|
|
47485
47613
|
if (hop.remediation) console.log(` ${chalk253.yellow(hop.remediation)}`);
|
|
47486
47614
|
}
|
|
47487
47615
|
}
|
|
@@ -47494,6 +47622,7 @@ function doctorProbes(live) {
|
|
|
47494
47622
|
sshAgent: probeSshAgent,
|
|
47495
47623
|
ssh: probeSsh,
|
|
47496
47624
|
tunnel: (localPort) => portAccepts(localPort),
|
|
47625
|
+
tailscale: tailscaleStatus,
|
|
47497
47626
|
linkState: (name) => {
|
|
47498
47627
|
if (!live) return "no-daemon";
|
|
47499
47628
|
return live.links.find((l) => l.name === name) ?? "unknown-link";
|
|
@@ -47557,41 +47686,87 @@ async function writeLinks(links2) {
|
|
|
47557
47686
|
saveGlobalConfig(updated2);
|
|
47558
47687
|
}
|
|
47559
47688
|
|
|
47560
|
-
// src/commands/sessions/nodes/
|
|
47561
|
-
function
|
|
47562
|
-
|
|
47563
|
-
|
|
47564
|
-
|
|
47565
|
-
|
|
47689
|
+
// src/commands/sessions/nodes/tailnetSuffix.ts
|
|
47690
|
+
function tailnetSuffix(status3) {
|
|
47691
|
+
if (status3.BackendState !== "Running")
|
|
47692
|
+
throw new Error(
|
|
47693
|
+
`Tailscale is not running on this node (${status3.BackendState ?? "unknown state"}) \u2014 run \`${tailscaleCli()} up\``
|
|
47694
|
+
);
|
|
47695
|
+
const suffix = status3.CurrentTailnet?.MagicDNSSuffix ?? status3.MagicDNSSuffix ?? "";
|
|
47696
|
+
if (status3.CurrentTailnet?.MagicDNSEnabled === false || !suffix)
|
|
47697
|
+
throw new Error(
|
|
47698
|
+
"MagicDNS is off in this tailnet \u2014 turn on MagicDNS and HTTPS certificates on the DNS page of the Tailscale admin console"
|
|
47699
|
+
);
|
|
47700
|
+
return suffix.replace(/\.$/, "");
|
|
47701
|
+
}
|
|
47702
|
+
|
|
47703
|
+
// src/commands/sessions/nodes/tailscaleLinkUrl.ts
|
|
47704
|
+
async function localTailnetSuffix() {
|
|
47705
|
+
return tailnetSuffix(await tailscaleStatus());
|
|
47566
47706
|
}
|
|
47707
|
+
async function tailscaleLinkUrl(host, port, resolveSuffix = localTailnetSuffix) {
|
|
47708
|
+
const suffix = await resolveSuffix();
|
|
47709
|
+
const fqdn = host.replace(/\.$/, "");
|
|
47710
|
+
const bare = fqdn.endsWith(`.${suffix}`) ? fqdn.slice(0, -suffix.length - 1) : fqdn;
|
|
47711
|
+
return `https://${bare}.${suffix}:${port}`;
|
|
47712
|
+
}
|
|
47713
|
+
|
|
47714
|
+
// src/commands/sessions/nodes/parsePort.ts
|
|
47567
47715
|
function parsePort(flag, value) {
|
|
47568
47716
|
const port = Number(value);
|
|
47569
47717
|
if (!Number.isInteger(port) || port < 1 || port > 65535)
|
|
47570
47718
|
throw new Error(`${flag} must be a port number, got ${value}`);
|
|
47571
47719
|
return port;
|
|
47572
47720
|
}
|
|
47573
|
-
|
|
47574
|
-
|
|
47575
|
-
|
|
47576
|
-
|
|
47577
|
-
|
|
47721
|
+
|
|
47722
|
+
// src/commands/sessions/nodes/parseLinkUrl.ts
|
|
47723
|
+
function parseLinkUrl(url) {
|
|
47724
|
+
const parsed = new URL(url);
|
|
47725
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:")
|
|
47726
|
+
throw new Error(`link url must be http(s): ${url}`);
|
|
47727
|
+
return parsed.origin;
|
|
47578
47728
|
}
|
|
47579
|
-
|
|
47580
|
-
|
|
47581
|
-
|
|
47729
|
+
|
|
47730
|
+
// src/commands/sessions/nodes/buildLink.ts
|
|
47731
|
+
async function buildLink(name, url, options2, others, resolveTailnetSuffix) {
|
|
47732
|
+
if ([url, options2.ssh, options2.tailscale].filter(Boolean).length > 1)
|
|
47733
|
+
throw new Error(
|
|
47734
|
+
"pass only one of <url>, --tailscale <host> or --ssh <alias>"
|
|
47735
|
+
);
|
|
47582
47736
|
if (url) return { name, url: parseLinkUrl(url) };
|
|
47737
|
+
if (options2.tailscale) {
|
|
47738
|
+
const port2 = parsePort("--port", options2.port);
|
|
47739
|
+
return {
|
|
47740
|
+
name,
|
|
47741
|
+
url: await tailscaleLinkUrl(
|
|
47742
|
+
options2.tailscale,
|
|
47743
|
+
port2,
|
|
47744
|
+
resolveTailnetSuffix
|
|
47745
|
+
)
|
|
47746
|
+
};
|
|
47747
|
+
}
|
|
47583
47748
|
if (!options2.ssh)
|
|
47584
|
-
throw new Error(
|
|
47749
|
+
throw new Error(
|
|
47750
|
+
"pass the peer's <url>, --tailscale <host> --port <port> or --ssh <alias> --port <port>"
|
|
47751
|
+
);
|
|
47585
47752
|
const port = parsePort("--port", options2.port);
|
|
47586
47753
|
const localPort = options2.localPort ? parsePort("--local-port", options2.localPort) : freeTunnelPort(port, others);
|
|
47587
47754
|
return { name, ssh: options2.ssh, port, localPort };
|
|
47588
47755
|
}
|
|
47756
|
+
function freeTunnelPort(port, others) {
|
|
47757
|
+
const taken = new Set(others.map((link3) => toLinkSpec(link3).ssh?.localPort));
|
|
47758
|
+
let candidate = defaultTunnelPort(port);
|
|
47759
|
+
while (taken.has(candidate)) candidate++;
|
|
47760
|
+
return candidate;
|
|
47761
|
+
}
|
|
47762
|
+
|
|
47763
|
+
// src/commands/sessions/nodes/linkNode.ts
|
|
47589
47764
|
async function linkNode(name, url, options2) {
|
|
47590
47765
|
if (name.includes(":")) throw new Error("node names cannot contain ':'");
|
|
47591
47766
|
if (name === resolveNodeName())
|
|
47592
47767
|
throw new Error(`${name} is this node; link to a different node`);
|
|
47593
47768
|
const others = readLinks().filter((link4) => link4.name !== name);
|
|
47594
|
-
const link3 = buildLink(name, url, options2, others);
|
|
47769
|
+
const link3 = await buildLink(name, url, options2, others);
|
|
47595
47770
|
await writeLinks([...others, link3]);
|
|
47596
47771
|
console.log(
|
|
47597
47772
|
chalk255.green(`Linked ${name} (${describeTarget(toLinkSpec(link3))})`)
|
|
@@ -47676,11 +47851,17 @@ async function unlinkNode(name) {
|
|
|
47676
47851
|
function registerNodes(sessions) {
|
|
47677
47852
|
const cmd = sessions.command("nodes").description("List this node and every linked node with its link state").option("--json", "Output as JSON").action(listNodes);
|
|
47678
47853
|
cmd.command("link <name> [url]").description(
|
|
47679
|
-
"Link a peer node by its web server URL, or over ssh with --ssh and --port (name must match the peer's sessions.nodeName)"
|
|
47854
|
+
"Link a peer node by its web server URL, by its Tailscale name with --tailscale and --port, or over ssh with --ssh and --port (name must match the peer's sessions.nodeName)"
|
|
47855
|
+
).option(
|
|
47856
|
+
"--tailscale <host>",
|
|
47857
|
+
"Dial the peer at https://<host>.<tailnet>.ts.net:<port> (the peer runs tailscale serve for its web server port)"
|
|
47680
47858
|
).option(
|
|
47681
47859
|
"--ssh <alias>",
|
|
47682
47860
|
"Tunnel to the peer through this ~/.ssh/config alias"
|
|
47683
|
-
).option(
|
|
47861
|
+
).option(
|
|
47862
|
+
"--port <port>",
|
|
47863
|
+
"The peer's web server port (with --tailscale or --ssh)"
|
|
47864
|
+
).option(
|
|
47684
47865
|
"--local-port <port>",
|
|
47685
47866
|
"Local end of the ssh tunnel (default: 43000 + port % 1000, bumped past other links)"
|
|
47686
47867
|
).action(linkNode);
|