@sunasteriskrnd/takumi 1.0.0-dev.24 → 1.0.0-dev.25
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 +1985 -519
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -8539,7 +8539,7 @@ var package_default;
|
|
|
8539
8539
|
var init_package = __esm(() => {
|
|
8540
8540
|
package_default = {
|
|
8541
8541
|
name: "@sunasteriskrnd/takumi",
|
|
8542
|
-
version: "1.0.0-dev.
|
|
8542
|
+
version: "1.0.0-dev.25",
|
|
8543
8543
|
description: "CLI tool for bootstrapping and managing Takumi projects",
|
|
8544
8544
|
type: "module",
|
|
8545
8545
|
repository: {
|
|
@@ -50384,14 +50384,14 @@ var exports_monorepo_resolver = {};
|
|
|
50384
50384
|
__export(exports_monorepo_resolver, {
|
|
50385
50385
|
resolveMonorepoRoot: () => resolveMonorepoRoot
|
|
50386
50386
|
});
|
|
50387
|
-
import { existsSync as
|
|
50388
|
-
import { dirname as
|
|
50387
|
+
import { existsSync as existsSync48, readFileSync as readFileSync16 } from "node:fs";
|
|
50388
|
+
import { dirname as dirname27, join as join98, resolve as resolve22 } from "node:path";
|
|
50389
50389
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
50390
50390
|
function parseMetadataAt(metadataPath) {
|
|
50391
|
-
if (!
|
|
50391
|
+
if (!existsSync48(metadataPath))
|
|
50392
50392
|
return null;
|
|
50393
50393
|
try {
|
|
50394
|
-
const raw =
|
|
50394
|
+
const raw = readFileSync16(metadataPath, "utf-8");
|
|
50395
50395
|
const parsed = JSON.parse(raw);
|
|
50396
50396
|
if (typeof parsed.name !== "string" || typeof parsed.version !== "string" || !ACCEPTED_METADATA_NAMES.has(parsed.name)) {
|
|
50397
50397
|
return null;
|
|
@@ -50402,11 +50402,11 @@ function parseMetadataAt(metadataPath) {
|
|
|
50402
50402
|
}
|
|
50403
50403
|
}
|
|
50404
50404
|
function readSourceDirFromPackageJson(candidateRoot) {
|
|
50405
|
-
const packageJsonPath =
|
|
50406
|
-
if (!
|
|
50405
|
+
const packageJsonPath = join98(candidateRoot, "package.json");
|
|
50406
|
+
if (!existsSync48(packageJsonPath))
|
|
50407
50407
|
return null;
|
|
50408
50408
|
try {
|
|
50409
|
-
const parsed = JSON.parse(
|
|
50409
|
+
const parsed = JSON.parse(readFileSync16(packageJsonPath, "utf-8"));
|
|
50410
50410
|
const kitCfg = parsed.takumi;
|
|
50411
50411
|
if (kitCfg && typeof kitCfg.sourceDir === "string" && kitCfg.sourceDir.length > 0) {
|
|
50412
50412
|
return kitCfg.sourceDir;
|
|
@@ -50425,7 +50425,7 @@ function tryReadAtCandidate(candidateRoot) {
|
|
|
50425
50425
|
};
|
|
50426
50426
|
}
|
|
50427
50427
|
const sourceDir = readSourceDirFromPackageJson(candidateRoot) ?? "claude";
|
|
50428
|
-
const sourceRoot =
|
|
50428
|
+
const sourceRoot = join98(candidateRoot, sourceDir);
|
|
50429
50429
|
const nestedMetadata = parseMetadataAt(getManifestPath(sourceRoot)) ?? parseMetadataAt(getLegacyManifestPath(sourceRoot));
|
|
50430
50430
|
if (nestedMetadata) {
|
|
50431
50431
|
return {
|
|
@@ -50438,12 +50438,12 @@ function tryReadAtCandidate(candidateRoot) {
|
|
|
50438
50438
|
return null;
|
|
50439
50439
|
}
|
|
50440
50440
|
function walkUpForMetadata(startDir, maxDepth = 5) {
|
|
50441
|
-
let current =
|
|
50441
|
+
let current = resolve22(startDir);
|
|
50442
50442
|
for (let i = 0;i < maxDepth; i++) {
|
|
50443
50443
|
const result = tryReadAtCandidate(current);
|
|
50444
50444
|
if (result)
|
|
50445
50445
|
return result;
|
|
50446
|
-
const parent =
|
|
50446
|
+
const parent = dirname27(current);
|
|
50447
50447
|
if (parent === current)
|
|
50448
50448
|
break;
|
|
50449
50449
|
current = parent;
|
|
@@ -50453,13 +50453,13 @@ function walkUpForMetadata(startDir, maxDepth = 5) {
|
|
|
50453
50453
|
function resolveMonorepoRoot() {
|
|
50454
50454
|
try {
|
|
50455
50455
|
const thisFile = fileURLToPath3(import.meta.url);
|
|
50456
|
-
const thisDir =
|
|
50456
|
+
const thisDir = dirname27(thisFile);
|
|
50457
50457
|
const result2 = walkUpForMetadata(thisDir);
|
|
50458
50458
|
if (result2)
|
|
50459
50459
|
return result2;
|
|
50460
50460
|
} catch {}
|
|
50461
50461
|
if (process.argv[1]) {
|
|
50462
|
-
const binDir =
|
|
50462
|
+
const binDir = dirname27(resolve22(process.argv[1]));
|
|
50463
50463
|
const result2 = walkUpForMetadata(binDir);
|
|
50464
50464
|
if (result2)
|
|
50465
50465
|
return result2;
|
|
@@ -51039,7 +51039,7 @@ function getPagerArgs(pagerCmd) {
|
|
|
51039
51039
|
return [];
|
|
51040
51040
|
}
|
|
51041
51041
|
async function trySystemPager(content) {
|
|
51042
|
-
return new Promise((
|
|
51042
|
+
return new Promise((resolve31) => {
|
|
51043
51043
|
const pagerCmd = process.env.PAGER || "less";
|
|
51044
51044
|
const pagerArgs = getPagerArgs(pagerCmd);
|
|
51045
51045
|
try {
|
|
@@ -51049,20 +51049,20 @@ async function trySystemPager(content) {
|
|
|
51049
51049
|
});
|
|
51050
51050
|
const timeout = setTimeout(() => {
|
|
51051
51051
|
pager.kill();
|
|
51052
|
-
|
|
51052
|
+
resolve31(false);
|
|
51053
51053
|
}, 30000);
|
|
51054
51054
|
pager.stdin.write(content);
|
|
51055
51055
|
pager.stdin.end();
|
|
51056
51056
|
pager.on("close", (code) => {
|
|
51057
51057
|
clearTimeout(timeout);
|
|
51058
|
-
|
|
51058
|
+
resolve31(code === 0);
|
|
51059
51059
|
});
|
|
51060
51060
|
pager.on("error", () => {
|
|
51061
51061
|
clearTimeout(timeout);
|
|
51062
|
-
|
|
51062
|
+
resolve31(false);
|
|
51063
51063
|
});
|
|
51064
51064
|
} catch {
|
|
51065
|
-
|
|
51065
|
+
resolve31(false);
|
|
51066
51066
|
}
|
|
51067
51067
|
});
|
|
51068
51068
|
}
|
|
@@ -51089,16 +51089,16 @@ async function basicPager(content) {
|
|
|
51089
51089
|
break;
|
|
51090
51090
|
}
|
|
51091
51091
|
const remaining = lines.length - currentLine;
|
|
51092
|
-
await new Promise((
|
|
51092
|
+
await new Promise((resolve31) => {
|
|
51093
51093
|
rl.question(`-- More (${remaining} lines) [Enter/q] --`, (answer) => {
|
|
51094
51094
|
if (answer.toLowerCase() === "q") {
|
|
51095
51095
|
rl.close();
|
|
51096
51096
|
process.exitCode = 0;
|
|
51097
|
-
|
|
51097
|
+
resolve31();
|
|
51098
51098
|
return;
|
|
51099
51099
|
}
|
|
51100
51100
|
process.stdout.write("\x1B[1A\x1B[2K");
|
|
51101
|
-
|
|
51101
|
+
resolve31();
|
|
51102
51102
|
});
|
|
51103
51103
|
});
|
|
51104
51104
|
}
|
|
@@ -53692,6 +53692,1459 @@ async function configCommand(action, keyOrOptions, valueOrOptions, options2) {
|
|
|
53692
53692
|
};
|
|
53693
53693
|
return configUICommand(uiOpts);
|
|
53694
53694
|
}
|
|
53695
|
+
// src/domains/sessions/browser-open.ts
|
|
53696
|
+
init_open();
|
|
53697
|
+
function tryOpenBrowser(target) {
|
|
53698
|
+
open_default(target).catch(() => {});
|
|
53699
|
+
}
|
|
53700
|
+
|
|
53701
|
+
// src/domains/sessions/server.ts
|
|
53702
|
+
import * as http from "node:http";
|
|
53703
|
+
|
|
53704
|
+
// src/domains/sessions/adapters/claude.ts
|
|
53705
|
+
import * as fs9 from "node:fs";
|
|
53706
|
+
import * as os4 from "node:os";
|
|
53707
|
+
import * as path7 from "node:path";
|
|
53708
|
+
|
|
53709
|
+
// src/domains/sessions/transcript-parser.ts
|
|
53710
|
+
import * as fs8 from "node:fs";
|
|
53711
|
+
|
|
53712
|
+
// src/domains/sessions/types.ts
|
|
53713
|
+
function emptyTokens() {
|
|
53714
|
+
return { input: 0, output: 0, cacheCreate: 0, cacheRead: 0 };
|
|
53715
|
+
}
|
|
53716
|
+
|
|
53717
|
+
// src/domains/sessions/transcript-parser.ts
|
|
53718
|
+
var MAX_READ_BYTES = 50 * 1024 * 1024;
|
|
53719
|
+
function safeJSON(line) {
|
|
53720
|
+
try {
|
|
53721
|
+
return JSON.parse(line);
|
|
53722
|
+
} catch {
|
|
53723
|
+
return null;
|
|
53724
|
+
}
|
|
53725
|
+
}
|
|
53726
|
+
function readNew(transcriptPath, fromOffset) {
|
|
53727
|
+
if (!transcriptPath || !fs8.existsSync(transcriptPath)) {
|
|
53728
|
+
return { records: [], newOffset: fromOffset || 0 };
|
|
53729
|
+
}
|
|
53730
|
+
if (transcriptPath.endsWith(".zst")) {
|
|
53731
|
+
return { records: [], newOffset: fromOffset || 0 };
|
|
53732
|
+
}
|
|
53733
|
+
const st = fs8.statSync(transcriptPath);
|
|
53734
|
+
const start = fromOffset || 0;
|
|
53735
|
+
if (st.size <= start) {
|
|
53736
|
+
return { records: [], newOffset: st.size };
|
|
53737
|
+
}
|
|
53738
|
+
let len = st.size - start;
|
|
53739
|
+
let truncated = false;
|
|
53740
|
+
if (len > MAX_READ_BYTES) {
|
|
53741
|
+
len = MAX_READ_BYTES;
|
|
53742
|
+
truncated = true;
|
|
53743
|
+
}
|
|
53744
|
+
const fd = fs8.openSync(transcriptPath, "r");
|
|
53745
|
+
try {
|
|
53746
|
+
const buf = Buffer.alloc(len);
|
|
53747
|
+
fs8.readSync(fd, buf, 0, len, start);
|
|
53748
|
+
const text = buf.toString("utf-8");
|
|
53749
|
+
const lines = text.split(`
|
|
53750
|
+
`).filter(Boolean);
|
|
53751
|
+
const records = lines.map(safeJSON).filter((r2) => r2 !== null);
|
|
53752
|
+
const newOffset = truncated ? start + len : st.size;
|
|
53753
|
+
return { records, newOffset };
|
|
53754
|
+
} finally {
|
|
53755
|
+
fs8.closeSync(fd);
|
|
53756
|
+
}
|
|
53757
|
+
}
|
|
53758
|
+
function addTokens(a3, b3) {
|
|
53759
|
+
return {
|
|
53760
|
+
input: (a3.input || 0) + (b3.input || 0),
|
|
53761
|
+
output: (a3.output || 0) + (b3.output || 0),
|
|
53762
|
+
cacheCreate: (a3.cacheCreate || 0) + (b3.cacheCreate || 0),
|
|
53763
|
+
cacheRead: (a3.cacheRead || 0) + (b3.cacheRead || 0)
|
|
53764
|
+
};
|
|
53765
|
+
}
|
|
53766
|
+
function tokensOfClaude(rec) {
|
|
53767
|
+
const r2 = rec;
|
|
53768
|
+
const u = r2?.message?.usage;
|
|
53769
|
+
if (!u)
|
|
53770
|
+
return null;
|
|
53771
|
+
return {
|
|
53772
|
+
input: u.input_tokens || 0,
|
|
53773
|
+
output: u.output_tokens || 0,
|
|
53774
|
+
cacheCreate: u.cache_creation_input_tokens || 0,
|
|
53775
|
+
cacheRead: u.cache_read_input_tokens || 0
|
|
53776
|
+
};
|
|
53777
|
+
}
|
|
53778
|
+
function tokensOfCodex(rec) {
|
|
53779
|
+
const r2 = rec;
|
|
53780
|
+
if (r2?.type !== "event_msg")
|
|
53781
|
+
return null;
|
|
53782
|
+
if (r2?.payload?.type !== "token_count")
|
|
53783
|
+
return null;
|
|
53784
|
+
const u = r2?.payload?.info?.last_token_usage;
|
|
53785
|
+
if (!u)
|
|
53786
|
+
return null;
|
|
53787
|
+
return {
|
|
53788
|
+
input: u.input_tokens || 0,
|
|
53789
|
+
output: (u.output_tokens || 0) + (u.reasoning_output_tokens || 0),
|
|
53790
|
+
cacheCreate: 0,
|
|
53791
|
+
cacheRead: u.cached_input_tokens || 0
|
|
53792
|
+
};
|
|
53793
|
+
}
|
|
53794
|
+
function peekFirstTimestamp(jsonlPath) {
|
|
53795
|
+
if (!fs8.existsSync(jsonlPath))
|
|
53796
|
+
return null;
|
|
53797
|
+
const { records } = readNew(jsonlPath, 0);
|
|
53798
|
+
for (const r2 of records) {
|
|
53799
|
+
const ts = r2?.timestamp;
|
|
53800
|
+
if (ts)
|
|
53801
|
+
return ts;
|
|
53802
|
+
}
|
|
53803
|
+
return null;
|
|
53804
|
+
}
|
|
53805
|
+
function peekLastTimestamp(jsonlPath) {
|
|
53806
|
+
if (!fs8.existsSync(jsonlPath))
|
|
53807
|
+
return null;
|
|
53808
|
+
const { records } = readNew(jsonlPath, 0);
|
|
53809
|
+
for (let i = records.length - 1;i >= 0; i--) {
|
|
53810
|
+
const ts = records[i]?.timestamp;
|
|
53811
|
+
if (ts)
|
|
53812
|
+
return ts;
|
|
53813
|
+
}
|
|
53814
|
+
return null;
|
|
53815
|
+
}
|
|
53816
|
+
function sumClaudeAgentTokens(jsonlPath) {
|
|
53817
|
+
const tot = emptyTokens();
|
|
53818
|
+
let model = null;
|
|
53819
|
+
if (!fs8.existsSync(jsonlPath))
|
|
53820
|
+
return { tokens: tot, model };
|
|
53821
|
+
const { records } = readNew(jsonlPath, 0);
|
|
53822
|
+
for (const rec of records) {
|
|
53823
|
+
const r2 = rec;
|
|
53824
|
+
if (r2?.type !== "assistant" && r2?.message?.role !== "assistant")
|
|
53825
|
+
continue;
|
|
53826
|
+
if (!model && r2?.message?.model)
|
|
53827
|
+
model = r2.message.model;
|
|
53828
|
+
const tok = tokensOfClaude(rec);
|
|
53829
|
+
if (!tok)
|
|
53830
|
+
continue;
|
|
53831
|
+
tot.input += tok.input;
|
|
53832
|
+
tot.output += tok.output;
|
|
53833
|
+
tot.cacheCreate += tok.cacheCreate;
|
|
53834
|
+
tot.cacheRead += tok.cacheRead;
|
|
53835
|
+
}
|
|
53836
|
+
return { tokens: tot, model };
|
|
53837
|
+
}
|
|
53838
|
+
function sumCodexAgentTokens(jsonlPath) {
|
|
53839
|
+
const tot = emptyTokens();
|
|
53840
|
+
if (!fs8.existsSync(jsonlPath))
|
|
53841
|
+
return tot;
|
|
53842
|
+
const { records } = readNew(jsonlPath, 0);
|
|
53843
|
+
for (const rec of records) {
|
|
53844
|
+
const tok = tokensOfCodex(rec);
|
|
53845
|
+
if (!tok)
|
|
53846
|
+
continue;
|
|
53847
|
+
tot.input += tok.input;
|
|
53848
|
+
tot.output += tok.output;
|
|
53849
|
+
tot.cacheCreate += tok.cacheCreate;
|
|
53850
|
+
tot.cacheRead += tok.cacheRead;
|
|
53851
|
+
}
|
|
53852
|
+
return tot;
|
|
53853
|
+
}
|
|
53854
|
+
|
|
53855
|
+
// src/domains/sessions/adapters/claude.ts
|
|
53856
|
+
var CLAUDE_ROOT = path7.join(os4.homedir(), ".claude", "projects");
|
|
53857
|
+
var MAX_PARSE_BYTES = 50 * 1024 * 1024;
|
|
53858
|
+
var HARNESS_TAGS = [
|
|
53859
|
+
"command-name",
|
|
53860
|
+
"command-message",
|
|
53861
|
+
"command-args",
|
|
53862
|
+
"ide_opened_file",
|
|
53863
|
+
"ide_selection",
|
|
53864
|
+
"task-notification",
|
|
53865
|
+
"local-command-stdout",
|
|
53866
|
+
"system-reminder"
|
|
53867
|
+
];
|
|
53868
|
+
function decodeProjectDir(name) {
|
|
53869
|
+
if (!name)
|
|
53870
|
+
return name;
|
|
53871
|
+
let p = name.replace(/-/g, "/");
|
|
53872
|
+
if (!p.startsWith("/"))
|
|
53873
|
+
p = `/${p}`;
|
|
53874
|
+
return p.replace(/\/+/g, "/");
|
|
53875
|
+
}
|
|
53876
|
+
function peekText(c2) {
|
|
53877
|
+
if (typeof c2 === "string")
|
|
53878
|
+
return c2;
|
|
53879
|
+
if (Array.isArray(c2)) {
|
|
53880
|
+
return c2.filter((it) => it && it.type === "text").map((it) => it.text || "").join(`
|
|
53881
|
+
`);
|
|
53882
|
+
}
|
|
53883
|
+
return "";
|
|
53884
|
+
}
|
|
53885
|
+
function isInterruptText(s) {
|
|
53886
|
+
return /^\s*\[Request interrupted\b/.test(String(s || ""));
|
|
53887
|
+
}
|
|
53888
|
+
function stripCommandTags(s) {
|
|
53889
|
+
let out = String(s || "");
|
|
53890
|
+
for (const tag of HARNESS_TAGS) {
|
|
53891
|
+
const re2 = new RegExp(`<${tag}>[\\s\\S]*?</${tag}>`, "g");
|
|
53892
|
+
out = out.replace(re2, " ");
|
|
53893
|
+
}
|
|
53894
|
+
return out.replace(/\s+/g, " ").trim();
|
|
53895
|
+
}
|
|
53896
|
+
function extractUserText(rec) {
|
|
53897
|
+
const msg = rec?.message;
|
|
53898
|
+
if (!msg)
|
|
53899
|
+
return "";
|
|
53900
|
+
const c2 = msg.content;
|
|
53901
|
+
if (typeof c2 === "string")
|
|
53902
|
+
return stripCommandTags(c2);
|
|
53903
|
+
if (Array.isArray(c2)) {
|
|
53904
|
+
const parts = [];
|
|
53905
|
+
for (const it of c2) {
|
|
53906
|
+
const item = it;
|
|
53907
|
+
if (item?.type === "text" && typeof item.text === "string")
|
|
53908
|
+
parts.push(item.text);
|
|
53909
|
+
}
|
|
53910
|
+
return stripCommandTags(parts.join(`
|
|
53911
|
+
`));
|
|
53912
|
+
}
|
|
53913
|
+
return "";
|
|
53914
|
+
}
|
|
53915
|
+
function parseCommandFromUser(rec) {
|
|
53916
|
+
const msg = rec?.message;
|
|
53917
|
+
if (!msg)
|
|
53918
|
+
return { slashCommand: null, args: "" };
|
|
53919
|
+
let text = "";
|
|
53920
|
+
if (typeof msg.content === "string")
|
|
53921
|
+
text = msg.content;
|
|
53922
|
+
else if (Array.isArray(msg.content)) {
|
|
53923
|
+
for (const it of msg.content) {
|
|
53924
|
+
const item = it;
|
|
53925
|
+
if (item?.type === "text" && typeof item.text === "string")
|
|
53926
|
+
text += item.text;
|
|
53927
|
+
}
|
|
53928
|
+
}
|
|
53929
|
+
const nameMatch = text.match(/<command-name>\s*\/?([^<\s]+)\s*<\/command-name>/);
|
|
53930
|
+
const argsMatch = text.match(/<command-args>([\s\S]*?)<\/command-args>/);
|
|
53931
|
+
return {
|
|
53932
|
+
slashCommand: nameMatch?.[1] ?? null,
|
|
53933
|
+
args: argsMatch?.[1]?.trim() ?? ""
|
|
53934
|
+
};
|
|
53935
|
+
}
|
|
53936
|
+
function isPromptUser(rec) {
|
|
53937
|
+
if (!rec || rec.type !== "user")
|
|
53938
|
+
return false;
|
|
53939
|
+
if (rec.isSidechain)
|
|
53940
|
+
return false;
|
|
53941
|
+
if (rec.isMeta)
|
|
53942
|
+
return false;
|
|
53943
|
+
const msg = rec.message;
|
|
53944
|
+
if (!msg)
|
|
53945
|
+
return false;
|
|
53946
|
+
if (isInterruptText(peekText(msg.content)))
|
|
53947
|
+
return false;
|
|
53948
|
+
if (typeof msg.content === "string")
|
|
53949
|
+
return msg.content.length > 0;
|
|
53950
|
+
if (Array.isArray(msg.content)) {
|
|
53951
|
+
const arr = msg.content;
|
|
53952
|
+
if (arr.some((it) => it?.type === "tool_result"))
|
|
53953
|
+
return false;
|
|
53954
|
+
return arr.some((it) => it?.type === "text");
|
|
53955
|
+
}
|
|
53956
|
+
return false;
|
|
53957
|
+
}
|
|
53958
|
+
function readSessionSummary(filePath) {
|
|
53959
|
+
const out = {
|
|
53960
|
+
startedAt: null,
|
|
53961
|
+
firstUserText: "",
|
|
53962
|
+
cwd: null,
|
|
53963
|
+
aiTitle: null
|
|
53964
|
+
};
|
|
53965
|
+
try {
|
|
53966
|
+
const st = fs9.statSync(filePath);
|
|
53967
|
+
const len = Math.min(st.size, 64 * 1024);
|
|
53968
|
+
const buf = Buffer.alloc(len);
|
|
53969
|
+
const fd = fs9.openSync(filePath, "r");
|
|
53970
|
+
try {
|
|
53971
|
+
fs9.readSync(fd, buf, 0, len, 0);
|
|
53972
|
+
} finally {
|
|
53973
|
+
fs9.closeSync(fd);
|
|
53974
|
+
}
|
|
53975
|
+
const lines = buf.toString("utf-8").split(`
|
|
53976
|
+
`);
|
|
53977
|
+
for (const line of lines) {
|
|
53978
|
+
if (!line)
|
|
53979
|
+
continue;
|
|
53980
|
+
let r2 = null;
|
|
53981
|
+
try {
|
|
53982
|
+
r2 = JSON.parse(line);
|
|
53983
|
+
} catch {
|
|
53984
|
+
continue;
|
|
53985
|
+
}
|
|
53986
|
+
if (!r2)
|
|
53987
|
+
continue;
|
|
53988
|
+
if (!out.startedAt && r2.timestamp)
|
|
53989
|
+
out.startedAt = r2.timestamp;
|
|
53990
|
+
if (!out.cwd && r2.cwd)
|
|
53991
|
+
out.cwd = r2.cwd;
|
|
53992
|
+
if (r2.type === "ai-title" && typeof r2.aiTitle === "string" && r2.aiTitle.trim()) {
|
|
53993
|
+
out.aiTitle = r2.aiTitle.trim();
|
|
53994
|
+
}
|
|
53995
|
+
if (!out.firstUserText && r2.type === "user" && !r2.isMeta && !isInterruptText(peekText(r2.message?.content))) {
|
|
53996
|
+
const cmd = parseCommandFromUser(r2);
|
|
53997
|
+
if (cmd.slashCommand) {
|
|
53998
|
+
out.firstUserText = `/${cmd.slashCommand} ${cmd.args}`.replace(/\s+/g, " ").trim().slice(0, 120);
|
|
53999
|
+
} else {
|
|
54000
|
+
const text = extractUserText(r2);
|
|
54001
|
+
if (text)
|
|
54002
|
+
out.firstUserText = text.replace(/\s+/g, " ").trim().slice(0, 120);
|
|
54003
|
+
}
|
|
54004
|
+
}
|
|
54005
|
+
}
|
|
54006
|
+
} catch {}
|
|
54007
|
+
return out;
|
|
54008
|
+
}
|
|
54009
|
+
async function listSessions(rootDir) {
|
|
54010
|
+
const root = rootDir || CLAUDE_ROOT;
|
|
54011
|
+
const out = [];
|
|
54012
|
+
let projects;
|
|
54013
|
+
try {
|
|
54014
|
+
projects = fs9.readdirSync(root);
|
|
54015
|
+
} catch {
|
|
54016
|
+
return out;
|
|
54017
|
+
}
|
|
54018
|
+
for (const proj of projects) {
|
|
54019
|
+
const projDir = path7.join(root, proj);
|
|
54020
|
+
let entries;
|
|
54021
|
+
try {
|
|
54022
|
+
entries = fs9.readdirSync(projDir);
|
|
54023
|
+
} catch {
|
|
54024
|
+
continue;
|
|
54025
|
+
}
|
|
54026
|
+
for (const entry of entries) {
|
|
54027
|
+
if (!entry.endsWith(".jsonl"))
|
|
54028
|
+
continue;
|
|
54029
|
+
const full = path7.join(projDir, entry);
|
|
54030
|
+
let st;
|
|
54031
|
+
try {
|
|
54032
|
+
st = fs9.statSync(full);
|
|
54033
|
+
} catch {
|
|
54034
|
+
continue;
|
|
54035
|
+
}
|
|
54036
|
+
const sessionId = entry.replace(/\.jsonl$/, "");
|
|
54037
|
+
const summary = readSessionSummary(full);
|
|
54038
|
+
out.push({
|
|
54039
|
+
id: sessionId,
|
|
54040
|
+
adapterName: "claude",
|
|
54041
|
+
path: full,
|
|
54042
|
+
startedAt: summary.startedAt || new Date(st.mtimeMs).toISOString(),
|
|
54043
|
+
project: summary.cwd || decodeProjectDir(proj),
|
|
54044
|
+
title: summary.aiTitle || null,
|
|
54045
|
+
summary: summary.firstUserText,
|
|
54046
|
+
sizeBytes: st.size
|
|
54047
|
+
});
|
|
54048
|
+
}
|
|
54049
|
+
}
|
|
54050
|
+
return out;
|
|
54051
|
+
}
|
|
54052
|
+
function loadSubagentIndex(parentTranscriptPath, sessionId) {
|
|
54053
|
+
const subDir = path7.join(path7.dirname(parentTranscriptPath), sessionId, "subagents");
|
|
54054
|
+
const byToolUseId = new Map;
|
|
54055
|
+
const byAgentId = new Map;
|
|
54056
|
+
let names;
|
|
54057
|
+
try {
|
|
54058
|
+
names = fs9.readdirSync(subDir);
|
|
54059
|
+
} catch {
|
|
54060
|
+
return { byToolUseId, byAgentId };
|
|
54061
|
+
}
|
|
54062
|
+
for (const name of names) {
|
|
54063
|
+
if (!name.endsWith(".meta.json"))
|
|
54064
|
+
continue;
|
|
54065
|
+
const agentId = name.replace(/^agent-/, "").replace(/\.meta\.json$/, "");
|
|
54066
|
+
let meta = {};
|
|
54067
|
+
try {
|
|
54068
|
+
meta = JSON.parse(fs9.readFileSync(path7.join(subDir, name), "utf-8"));
|
|
54069
|
+
} catch {}
|
|
54070
|
+
const jsonlPath = path7.join(subDir, `agent-${agentId}.jsonl`);
|
|
54071
|
+
const { tokens, model } = sumClaudeAgentTokens(jsonlPath);
|
|
54072
|
+
const entry = {
|
|
54073
|
+
agentId,
|
|
54074
|
+
type: meta.agentType || "unknown",
|
|
54075
|
+
description: meta.description || "",
|
|
54076
|
+
toolUseId: meta.toolUseId || null,
|
|
54077
|
+
jsonlPath,
|
|
54078
|
+
tokens,
|
|
54079
|
+
model,
|
|
54080
|
+
startedAt: peekFirstTimestamp(jsonlPath),
|
|
54081
|
+
endedAt: peekLastTimestamp(jsonlPath)
|
|
54082
|
+
};
|
|
54083
|
+
byAgentId.set(agentId, entry);
|
|
54084
|
+
if (meta.toolUseId)
|
|
54085
|
+
byToolUseId.set(meta.toolUseId, entry);
|
|
54086
|
+
}
|
|
54087
|
+
return { byToolUseId, byAgentId };
|
|
54088
|
+
}
|
|
54089
|
+
function pushTurn(state, opts) {
|
|
54090
|
+
const last = state.turns[state.turns.length - 1];
|
|
54091
|
+
if (last && !last.endedAt)
|
|
54092
|
+
last.endedAt = opts.startedAt;
|
|
54093
|
+
const id = `T${state.turns.length}`;
|
|
54094
|
+
const turn = {
|
|
54095
|
+
id,
|
|
54096
|
+
startedAt: opts.startedAt,
|
|
54097
|
+
endedAt: null,
|
|
54098
|
+
source: opts.source,
|
|
54099
|
+
slashCommand: opts.slashCommand,
|
|
54100
|
+
args: String(opts.args || "").slice(0, 120),
|
|
54101
|
+
agentIds: [],
|
|
54102
|
+
skillIds: [],
|
|
54103
|
+
slashSkillId: null
|
|
54104
|
+
};
|
|
54105
|
+
state.turns.push(turn);
|
|
54106
|
+
if (opts.slashCommand) {
|
|
54107
|
+
state.skillCounter += 1;
|
|
54108
|
+
const skillId = `sk-slash-${id}`;
|
|
54109
|
+
const skill = {
|
|
54110
|
+
id: skillId,
|
|
54111
|
+
name: opts.slashCommand,
|
|
54112
|
+
source: "slash",
|
|
54113
|
+
prefix: "/",
|
|
54114
|
+
turnId: id,
|
|
54115
|
+
startedAt: opts.startedAt,
|
|
54116
|
+
endedAt: null,
|
|
54117
|
+
status: "running",
|
|
54118
|
+
args: turn.args,
|
|
54119
|
+
tokens: emptyTokens()
|
|
54120
|
+
};
|
|
54121
|
+
state.skills[skillId] = skill;
|
|
54122
|
+
turn.slashSkillId = skillId;
|
|
54123
|
+
turn.skillIds.push(skillId);
|
|
54124
|
+
}
|
|
54125
|
+
return turn;
|
|
54126
|
+
}
|
|
54127
|
+
function handleTaskUse(state, rec, toolUse, subIdx) {
|
|
54128
|
+
const turn = state.turns[state.turns.length - 1];
|
|
54129
|
+
if (!turn)
|
|
54130
|
+
return;
|
|
54131
|
+
const inp = toolUse.input || {};
|
|
54132
|
+
const toolUseId = toolUse.id;
|
|
54133
|
+
const match2 = toolUseId ? subIdx.byToolUseId.get(toolUseId) : null;
|
|
54134
|
+
const now = rec.timestamp || new Date().toISOString();
|
|
54135
|
+
if (!match2) {
|
|
54136
|
+
const aid = (toolUseId || `unknown-${turn.agentIds.length}`).replace(/^toolu_/, "");
|
|
54137
|
+
const agent2 = {
|
|
54138
|
+
id: aid,
|
|
54139
|
+
type: inp.subagent_type || "unknown",
|
|
54140
|
+
description: inp.description || "",
|
|
54141
|
+
promptPreview: String(inp.prompt || "").slice(0, 120),
|
|
54142
|
+
turnId: turn.id,
|
|
54143
|
+
startedAt: now,
|
|
54144
|
+
endedAt: now,
|
|
54145
|
+
status: "done",
|
|
54146
|
+
tokens: emptyTokens()
|
|
54147
|
+
};
|
|
54148
|
+
state.agents[aid] = agent2;
|
|
54149
|
+
turn.agentIds.push(aid);
|
|
54150
|
+
return;
|
|
54151
|
+
}
|
|
54152
|
+
const agentId = match2.agentId;
|
|
54153
|
+
const agent = {
|
|
54154
|
+
id: agentId,
|
|
54155
|
+
type: match2.type || inp.subagent_type || "unknown",
|
|
54156
|
+
description: inp.description || match2.description || "",
|
|
54157
|
+
promptPreview: String(inp.prompt || "").slice(0, 120),
|
|
54158
|
+
turnId: turn.id,
|
|
54159
|
+
startedAt: match2.startedAt || now,
|
|
54160
|
+
endedAt: match2.endedAt || now,
|
|
54161
|
+
status: "done",
|
|
54162
|
+
tokens: match2.tokens || emptyTokens(),
|
|
54163
|
+
model: match2.model || null
|
|
54164
|
+
};
|
|
54165
|
+
state.agents[agentId] = agent;
|
|
54166
|
+
turn.agentIds.push(agentId);
|
|
54167
|
+
if (match2.jsonlPath) {
|
|
54168
|
+
try {
|
|
54169
|
+
state.agentOffsets[agentId] = fs9.statSync(match2.jsonlPath).size;
|
|
54170
|
+
} catch {
|
|
54171
|
+
state.agentOffsets[agentId] = 0;
|
|
54172
|
+
}
|
|
54173
|
+
}
|
|
54174
|
+
}
|
|
54175
|
+
function handleSkillUse(state, rec, toolUse, openSkills) {
|
|
54176
|
+
const turn = state.turns[state.turns.length - 1];
|
|
54177
|
+
if (!turn)
|
|
54178
|
+
return null;
|
|
54179
|
+
const inp = toolUse.input || {};
|
|
54180
|
+
const name = inp.skill || "unknown";
|
|
54181
|
+
state.skillCounter += 1;
|
|
54182
|
+
const skillId = `sk-tool-${state.skillCounter}`;
|
|
54183
|
+
const startedAt = rec.timestamp || new Date().toISOString();
|
|
54184
|
+
const skill = {
|
|
54185
|
+
id: skillId,
|
|
54186
|
+
name,
|
|
54187
|
+
source: "tool",
|
|
54188
|
+
turnId: turn.id,
|
|
54189
|
+
startedAt,
|
|
54190
|
+
endedAt: null,
|
|
54191
|
+
status: "running",
|
|
54192
|
+
args: String(inp.args || "").slice(0, 80),
|
|
54193
|
+
tokens: emptyTokens()
|
|
54194
|
+
};
|
|
54195
|
+
state.skills[skillId] = skill;
|
|
54196
|
+
turn.skillIds.push(skillId);
|
|
54197
|
+
openSkills.set(toolUse.id, { skillId });
|
|
54198
|
+
return skill;
|
|
54199
|
+
}
|
|
54200
|
+
function closeSkill(state, open2, endedAt) {
|
|
54201
|
+
const sk = state.skills[open2.skillId];
|
|
54202
|
+
if (!sk)
|
|
54203
|
+
return;
|
|
54204
|
+
sk.endedAt = endedAt;
|
|
54205
|
+
sk.status = "done";
|
|
54206
|
+
}
|
|
54207
|
+
function pickTurnForTimestamp(state, ts) {
|
|
54208
|
+
if (!ts)
|
|
54209
|
+
return null;
|
|
54210
|
+
let chosen = null;
|
|
54211
|
+
for (const t of state.turns) {
|
|
54212
|
+
if (String(t.startedAt) <= String(ts))
|
|
54213
|
+
chosen = t;
|
|
54214
|
+
else
|
|
54215
|
+
break;
|
|
54216
|
+
}
|
|
54217
|
+
return chosen;
|
|
54218
|
+
}
|
|
54219
|
+
function lastNonStartupTurn(state) {
|
|
54220
|
+
for (let i = state.turns.length - 1;i >= 0; i--) {
|
|
54221
|
+
const turn = state.turns[i];
|
|
54222
|
+
if (turn && turn.source !== "startup")
|
|
54223
|
+
return turn;
|
|
54224
|
+
}
|
|
54225
|
+
return null;
|
|
54226
|
+
}
|
|
54227
|
+
async function parse2(filePath) {
|
|
54228
|
+
const sessionId = path7.basename(filePath, ".jsonl");
|
|
54229
|
+
try {
|
|
54230
|
+
const st = fs9.statSync(filePath);
|
|
54231
|
+
if (st.size > MAX_PARSE_BYTES) {
|
|
54232
|
+
const mb = (st.size / (1024 * 1024)).toFixed(0);
|
|
54233
|
+
const cap = MAX_PARSE_BYTES / (1024 * 1024);
|
|
54234
|
+
throw Object.assign(new Error(`Claude transcript ${path7.basename(filePath)} is ${mb}MB (> ${cap}MB cap).`), { code: "TRANSCRIPT_TOO_LARGE" });
|
|
54235
|
+
}
|
|
54236
|
+
} catch (e2) {
|
|
54237
|
+
if (e2.code === "TRANSCRIPT_TOO_LARGE")
|
|
54238
|
+
throw e2;
|
|
54239
|
+
}
|
|
54240
|
+
const { records } = readNew(filePath, 0);
|
|
54241
|
+
const recs = records;
|
|
54242
|
+
const subIdx = loadSubagentIndex(filePath, sessionId);
|
|
54243
|
+
const firstTs = recs.find((r2) => r2?.timestamp)?.timestamp || new Date().toISOString();
|
|
54244
|
+
const state = {
|
|
54245
|
+
sessionId,
|
|
54246
|
+
schemaVersion: 2,
|
|
54247
|
+
startedAt: firstTs,
|
|
54248
|
+
transcriptPath: filePath,
|
|
54249
|
+
transcriptOffset: 0,
|
|
54250
|
+
agentOffsets: {},
|
|
54251
|
+
cwd: null,
|
|
54252
|
+
turns: [],
|
|
54253
|
+
agents: {},
|
|
54254
|
+
skills: {},
|
|
54255
|
+
skillCounter: 0,
|
|
54256
|
+
tasks: {},
|
|
54257
|
+
taskOrder: [],
|
|
54258
|
+
todos: [],
|
|
54259
|
+
todosUpdatedAt: null,
|
|
54260
|
+
mainLoopTokens: emptyTokens(),
|
|
54261
|
+
totals: emptyTokens(),
|
|
54262
|
+
hookLog: []
|
|
54263
|
+
};
|
|
54264
|
+
pushTurn(state, {
|
|
54265
|
+
source: "startup",
|
|
54266
|
+
slashCommand: null,
|
|
54267
|
+
args: "startup",
|
|
54268
|
+
startedAt: firstTs
|
|
54269
|
+
});
|
|
54270
|
+
const openSkills = new Map;
|
|
54271
|
+
let activeToolSkillId = null;
|
|
54272
|
+
for (const rec of recs) {
|
|
54273
|
+
if (!rec || typeof rec !== "object")
|
|
54274
|
+
continue;
|
|
54275
|
+
if (rec.cwd && !state.cwd)
|
|
54276
|
+
state.cwd = rec.cwd;
|
|
54277
|
+
if (rec.type === "user" && !rec.isSidechain && !rec.isMeta && isInterruptText(peekText(rec.message?.content))) {
|
|
54278
|
+
const cur = state.turns[state.turns.length - 1];
|
|
54279
|
+
if (cur && cur.source !== "startup") {
|
|
54280
|
+
cur.interrupts = cur.interrupts || [];
|
|
54281
|
+
const txt = peekText(rec.message?.content).trim();
|
|
54282
|
+
cur.interrupts.push({
|
|
54283
|
+
at: rec.timestamp || new Date().toISOString(),
|
|
54284
|
+
label: txt.replace(/^\[|\]$/g, "").slice(0, 60)
|
|
54285
|
+
});
|
|
54286
|
+
}
|
|
54287
|
+
continue;
|
|
54288
|
+
}
|
|
54289
|
+
if (isPromptUser(rec)) {
|
|
54290
|
+
activeToolSkillId = null;
|
|
54291
|
+
const { slashCommand, args } = parseCommandFromUser(rec);
|
|
54292
|
+
const text = extractUserText(rec);
|
|
54293
|
+
const argsPreview = slashCommand ? args : text.slice(0, 120);
|
|
54294
|
+
pushTurn(state, {
|
|
54295
|
+
source: slashCommand ? "slash" : "prompt",
|
|
54296
|
+
slashCommand,
|
|
54297
|
+
args: argsPreview,
|
|
54298
|
+
startedAt: rec.timestamp || new Date().toISOString()
|
|
54299
|
+
});
|
|
54300
|
+
continue;
|
|
54301
|
+
}
|
|
54302
|
+
if (rec.type === "assistant" && !rec.isSidechain) {
|
|
54303
|
+
const tok = tokensOfClaude(rec);
|
|
54304
|
+
if (tok)
|
|
54305
|
+
state.mainLoopTokens = addTokens(state.mainLoopTokens, tok);
|
|
54306
|
+
const cur = state.turns[state.turns.length - 1];
|
|
54307
|
+
if (cur && cur.source !== "startup") {
|
|
54308
|
+
cur.assistant = cur.assistant || {
|
|
54309
|
+
model: null,
|
|
54310
|
+
tokens: emptyTokens(),
|
|
54311
|
+
startedAt: null,
|
|
54312
|
+
endedAt: null
|
|
54313
|
+
};
|
|
54314
|
+
if (rec.message?.model)
|
|
54315
|
+
cur.assistant.model = rec.message.model;
|
|
54316
|
+
if (tok)
|
|
54317
|
+
cur.assistant.tokens = addTokens(cur.assistant.tokens, tok);
|
|
54318
|
+
const ts = rec.timestamp;
|
|
54319
|
+
if (ts) {
|
|
54320
|
+
if (!cur.assistant.startedAt || String(ts) < String(cur.assistant.startedAt))
|
|
54321
|
+
cur.assistant.startedAt = ts;
|
|
54322
|
+
if (!cur.assistant.endedAt || String(ts) > String(cur.assistant.endedAt))
|
|
54323
|
+
cur.assistant.endedAt = ts;
|
|
54324
|
+
}
|
|
54325
|
+
}
|
|
54326
|
+
if (tok && activeToolSkillId && state.skills[activeToolSkillId]) {
|
|
54327
|
+
const sk = state.skills[activeToolSkillId];
|
|
54328
|
+
sk.tokens = addTokens(sk.tokens, tok);
|
|
54329
|
+
}
|
|
54330
|
+
const content = rec.message?.content;
|
|
54331
|
+
if (Array.isArray(content)) {
|
|
54332
|
+
for (const it of content) {
|
|
54333
|
+
const block = it;
|
|
54334
|
+
if (!block || block.type !== "tool_use")
|
|
54335
|
+
continue;
|
|
54336
|
+
if (block.name === "Task")
|
|
54337
|
+
handleTaskUse(state, rec, block, subIdx);
|
|
54338
|
+
else if (block.name === "Skill") {
|
|
54339
|
+
const opened = handleSkillUse(state, rec, block, openSkills);
|
|
54340
|
+
if (opened)
|
|
54341
|
+
activeToolSkillId = opened.id;
|
|
54342
|
+
}
|
|
54343
|
+
}
|
|
54344
|
+
}
|
|
54345
|
+
continue;
|
|
54346
|
+
}
|
|
54347
|
+
if (rec.type === "user" && Array.isArray(rec?.message?.content)) {
|
|
54348
|
+
for (const it of rec.message.content) {
|
|
54349
|
+
if (!it || it.type !== "tool_result" || !it.tool_use_id)
|
|
54350
|
+
continue;
|
|
54351
|
+
const open2 = openSkills.get(it.tool_use_id);
|
|
54352
|
+
if (!open2)
|
|
54353
|
+
continue;
|
|
54354
|
+
closeSkill(state, open2, rec.timestamp || new Date().toISOString());
|
|
54355
|
+
openSkills.delete(it.tool_use_id);
|
|
54356
|
+
}
|
|
54357
|
+
}
|
|
54358
|
+
}
|
|
54359
|
+
for (const open2 of openSkills.values()) {
|
|
54360
|
+
closeSkill(state, open2, new Date().toISOString());
|
|
54361
|
+
}
|
|
54362
|
+
for (const t of state.turns) {
|
|
54363
|
+
if (!t.assistant)
|
|
54364
|
+
continue;
|
|
54365
|
+
for (const aid of t.agentIds || []) {
|
|
54366
|
+
const ag = state.agents[aid];
|
|
54367
|
+
if (!ag?.tokens)
|
|
54368
|
+
continue;
|
|
54369
|
+
t.assistant.tokens = addTokens(t.assistant.tokens, ag.tokens);
|
|
54370
|
+
}
|
|
54371
|
+
}
|
|
54372
|
+
for (const t of state.turns) {
|
|
54373
|
+
if (!t.assistant || !t.skillIds)
|
|
54374
|
+
continue;
|
|
54375
|
+
for (const sid of t.skillIds) {
|
|
54376
|
+
const sk = state.skills[sid];
|
|
54377
|
+
if (sk && sk.source === "slash") {
|
|
54378
|
+
sk.tokens = { ...t.assistant.tokens };
|
|
54379
|
+
}
|
|
54380
|
+
}
|
|
54381
|
+
}
|
|
54382
|
+
for (const entry of subIdx.byAgentId.values()) {
|
|
54383
|
+
if (state.agents[entry.agentId])
|
|
54384
|
+
continue;
|
|
54385
|
+
const turn = pickTurnForTimestamp(state, entry.startedAt) || lastNonStartupTurn(state) || state.turns[state.turns.length - 1];
|
|
54386
|
+
if (!turn)
|
|
54387
|
+
continue;
|
|
54388
|
+
state.agents[entry.agentId] = {
|
|
54389
|
+
id: entry.agentId,
|
|
54390
|
+
type: entry.type,
|
|
54391
|
+
description: entry.description || "",
|
|
54392
|
+
promptPreview: "",
|
|
54393
|
+
turnId: turn.id,
|
|
54394
|
+
startedAt: entry.startedAt || turn.startedAt,
|
|
54395
|
+
endedAt: entry.endedAt || turn.endedAt || new Date().toISOString(),
|
|
54396
|
+
status: "done",
|
|
54397
|
+
tokens: entry.tokens || emptyTokens(),
|
|
54398
|
+
model: entry.model || null
|
|
54399
|
+
};
|
|
54400
|
+
turn.agentIds.push(entry.agentId);
|
|
54401
|
+
}
|
|
54402
|
+
state.totals = { ...state.mainLoopTokens };
|
|
54403
|
+
for (const ag of Object.values(state.agents)) {
|
|
54404
|
+
state.totals = addTokens(state.totals, ag.tokens || emptyTokens());
|
|
54405
|
+
}
|
|
54406
|
+
const last = state.turns[state.turns.length - 1];
|
|
54407
|
+
if (last && !last.endedAt)
|
|
54408
|
+
last.endedAt = new Date().toISOString();
|
|
54409
|
+
return state;
|
|
54410
|
+
}
|
|
54411
|
+
function matches(filePath) {
|
|
54412
|
+
if (!filePath)
|
|
54413
|
+
return false;
|
|
54414
|
+
const norm = path7.resolve(filePath);
|
|
54415
|
+
return norm.includes(`${path7.sep}.claude${path7.sep}projects${path7.sep}`) && norm.endsWith(".jsonl");
|
|
54416
|
+
}
|
|
54417
|
+
var claudeAdapter = {
|
|
54418
|
+
name: "claude",
|
|
54419
|
+
matches,
|
|
54420
|
+
listSessions,
|
|
54421
|
+
parse: parse2
|
|
54422
|
+
};
|
|
54423
|
+
|
|
54424
|
+
// src/domains/sessions/adapters/codex.ts
|
|
54425
|
+
import * as fs10 from "node:fs";
|
|
54426
|
+
import * as os5 from "node:os";
|
|
54427
|
+
import * as path8 from "node:path";
|
|
54428
|
+
var CODEX_ROOT = path8.join(os5.homedir(), ".codex", "sessions");
|
|
54429
|
+
function normalizeName(n) {
|
|
54430
|
+
return String(n || "").toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
54431
|
+
}
|
|
54432
|
+
function skillDirs(cwd2) {
|
|
54433
|
+
const dirs = [path8.join(os5.homedir(), ".codex", "skills")];
|
|
54434
|
+
if (cwd2)
|
|
54435
|
+
dirs.push(path8.join(cwd2, ".codex", "skills"));
|
|
54436
|
+
return dirs;
|
|
54437
|
+
}
|
|
54438
|
+
function loadSkillCatalog(cwd2) {
|
|
54439
|
+
const out = [];
|
|
54440
|
+
const seen = new Set;
|
|
54441
|
+
for (const dir of skillDirs(cwd2)) {
|
|
54442
|
+
let names;
|
|
54443
|
+
try {
|
|
54444
|
+
names = fs10.readdirSync(dir);
|
|
54445
|
+
} catch {
|
|
54446
|
+
continue;
|
|
54447
|
+
}
|
|
54448
|
+
for (const name of names) {
|
|
54449
|
+
if (name.startsWith("."))
|
|
54450
|
+
continue;
|
|
54451
|
+
const entryPath = path8.join(dir, name);
|
|
54452
|
+
let st;
|
|
54453
|
+
try {
|
|
54454
|
+
st = fs10.statSync(entryPath);
|
|
54455
|
+
} catch {
|
|
54456
|
+
continue;
|
|
54457
|
+
}
|
|
54458
|
+
if (!st.isDirectory())
|
|
54459
|
+
continue;
|
|
54460
|
+
if (!fs10.existsSync(path8.join(entryPath, "SKILL.md")))
|
|
54461
|
+
continue;
|
|
54462
|
+
const key = normalizeName(name);
|
|
54463
|
+
if (!key || seen.has(key))
|
|
54464
|
+
continue;
|
|
54465
|
+
seen.add(key);
|
|
54466
|
+
out.push({ raw: name, normalized: key });
|
|
54467
|
+
}
|
|
54468
|
+
}
|
|
54469
|
+
return out;
|
|
54470
|
+
}
|
|
54471
|
+
function detectSkillsInPrompt(catalog, promptText) {
|
|
54472
|
+
if (!promptText || !catalog.length)
|
|
54473
|
+
return [];
|
|
54474
|
+
const matches2 = [];
|
|
54475
|
+
const seen = new Set;
|
|
54476
|
+
const re2 = /\$([A-Za-z0-9_-]+(?::[A-Za-z0-9_-]+)?)/g;
|
|
54477
|
+
for (let m2 = re2.exec(promptText);m2 !== null; m2 = re2.exec(promptText)) {
|
|
54478
|
+
const token = m2[1];
|
|
54479
|
+
if (!token)
|
|
54480
|
+
continue;
|
|
54481
|
+
const candidates = [token];
|
|
54482
|
+
const colonIdx = token.indexOf(":");
|
|
54483
|
+
if (colonIdx > -1)
|
|
54484
|
+
candidates.push(token.slice(colonIdx + 1));
|
|
54485
|
+
let hit;
|
|
54486
|
+
for (const cand of candidates) {
|
|
54487
|
+
const candNorm = normalizeName(cand);
|
|
54488
|
+
hit = catalog.find((c2) => c2.raw === cand) || catalog.find((c2) => c2.normalized === candNorm);
|
|
54489
|
+
if (hit)
|
|
54490
|
+
break;
|
|
54491
|
+
}
|
|
54492
|
+
if (!hit)
|
|
54493
|
+
continue;
|
|
54494
|
+
if (seen.has(hit.raw))
|
|
54495
|
+
continue;
|
|
54496
|
+
seen.add(hit.raw);
|
|
54497
|
+
matches2.push(hit.raw);
|
|
54498
|
+
}
|
|
54499
|
+
return matches2;
|
|
54500
|
+
}
|
|
54501
|
+
function safeJSON2(line) {
|
|
54502
|
+
try {
|
|
54503
|
+
return JSON.parse(line);
|
|
54504
|
+
} catch {
|
|
54505
|
+
return null;
|
|
54506
|
+
}
|
|
54507
|
+
}
|
|
54508
|
+
function extractUuidFromName(filePath) {
|
|
54509
|
+
const base = path8.basename(filePath, ".jsonl");
|
|
54510
|
+
const m2 = base.match(/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$/);
|
|
54511
|
+
return m2?.[1] ?? null;
|
|
54512
|
+
}
|
|
54513
|
+
function walkRolloutFiles(dir, depth, maxDepth, out) {
|
|
54514
|
+
let entries;
|
|
54515
|
+
try {
|
|
54516
|
+
entries = fs10.readdirSync(dir, { withFileTypes: true });
|
|
54517
|
+
} catch {
|
|
54518
|
+
return;
|
|
54519
|
+
}
|
|
54520
|
+
for (const e2 of entries) {
|
|
54521
|
+
const full = path8.join(dir, e2.name);
|
|
54522
|
+
if (e2.isDirectory()) {
|
|
54523
|
+
if (depth < maxDepth)
|
|
54524
|
+
walkRolloutFiles(full, depth + 1, maxDepth, out);
|
|
54525
|
+
continue;
|
|
54526
|
+
}
|
|
54527
|
+
if (!e2.isFile())
|
|
54528
|
+
continue;
|
|
54529
|
+
if (!e2.name.startsWith("rollout-") || !e2.name.endsWith(".jsonl"))
|
|
54530
|
+
continue;
|
|
54531
|
+
out.push(full);
|
|
54532
|
+
}
|
|
54533
|
+
}
|
|
54534
|
+
function collectRolloutFiles(root) {
|
|
54535
|
+
const files = [];
|
|
54536
|
+
if (!fs10.existsSync(root))
|
|
54537
|
+
return files;
|
|
54538
|
+
walkRolloutFiles(root, 0, 3, files);
|
|
54539
|
+
return files;
|
|
54540
|
+
}
|
|
54541
|
+
function readFirstSessionMeta(filePath) {
|
|
54542
|
+
try {
|
|
54543
|
+
const len = Math.min(fs10.statSync(filePath).size, 64 * 1024);
|
|
54544
|
+
const buf = Buffer.alloc(len);
|
|
54545
|
+
const fd = fs10.openSync(filePath, "r");
|
|
54546
|
+
try {
|
|
54547
|
+
fs10.readSync(fd, buf, 0, len, 0);
|
|
54548
|
+
} finally {
|
|
54549
|
+
fs10.closeSync(fd);
|
|
54550
|
+
}
|
|
54551
|
+
const firstLine = buf.toString("utf-8").split(`
|
|
54552
|
+
`)[0];
|
|
54553
|
+
const rec = firstLine ? safeJSON2(firstLine) : null;
|
|
54554
|
+
if (!rec || rec.type !== "session_meta")
|
|
54555
|
+
return null;
|
|
54556
|
+
return rec.payload || {};
|
|
54557
|
+
} catch {
|
|
54558
|
+
return null;
|
|
54559
|
+
}
|
|
54560
|
+
}
|
|
54561
|
+
function readFirstUserPrompt(filePath) {
|
|
54562
|
+
try {
|
|
54563
|
+
const len = Math.min(fs10.statSync(filePath).size, 128 * 1024);
|
|
54564
|
+
const buf = Buffer.alloc(len);
|
|
54565
|
+
const fd = fs10.openSync(filePath, "r");
|
|
54566
|
+
try {
|
|
54567
|
+
fs10.readSync(fd, buf, 0, len, 0);
|
|
54568
|
+
} finally {
|
|
54569
|
+
fs10.closeSync(fd);
|
|
54570
|
+
}
|
|
54571
|
+
const lines = buf.toString("utf-8").split(`
|
|
54572
|
+
`);
|
|
54573
|
+
for (const line of lines) {
|
|
54574
|
+
if (!line)
|
|
54575
|
+
continue;
|
|
54576
|
+
const r2 = safeJSON2(line);
|
|
54577
|
+
if (!r2)
|
|
54578
|
+
continue;
|
|
54579
|
+
if (r2.type === "event_msg" && r2.payload?.type === "user_message") {
|
|
54580
|
+
return String(r2.payload.message || "").replace(/\s+/g, " ").trim().slice(0, 120);
|
|
54581
|
+
}
|
|
54582
|
+
}
|
|
54583
|
+
} catch {}
|
|
54584
|
+
return "";
|
|
54585
|
+
}
|
|
54586
|
+
function readFirstChildModel(filePath) {
|
|
54587
|
+
try {
|
|
54588
|
+
const len = Math.min(fs10.statSync(filePath).size, 64 * 1024);
|
|
54589
|
+
const buf = Buffer.alloc(len);
|
|
54590
|
+
const fd = fs10.openSync(filePath, "r");
|
|
54591
|
+
try {
|
|
54592
|
+
fs10.readSync(fd, buf, 0, len, 0);
|
|
54593
|
+
} finally {
|
|
54594
|
+
fs10.closeSync(fd);
|
|
54595
|
+
}
|
|
54596
|
+
for (const line of buf.toString("utf-8").split(`
|
|
54597
|
+
`)) {
|
|
54598
|
+
if (!line)
|
|
54599
|
+
continue;
|
|
54600
|
+
const r2 = safeJSON2(line);
|
|
54601
|
+
if (!r2)
|
|
54602
|
+
continue;
|
|
54603
|
+
if (r2.type === "turn_context" && r2.payload?.model)
|
|
54604
|
+
return r2.payload.model;
|
|
54605
|
+
}
|
|
54606
|
+
} catch {}
|
|
54607
|
+
return null;
|
|
54608
|
+
}
|
|
54609
|
+
var _childIndex = null;
|
|
54610
|
+
function buildChildIndex(root) {
|
|
54611
|
+
if (_childIndex)
|
|
54612
|
+
return _childIndex;
|
|
54613
|
+
const map = new Map;
|
|
54614
|
+
const files = collectRolloutFiles(root);
|
|
54615
|
+
for (const f3 of files) {
|
|
54616
|
+
const id = extractUuidFromName(f3);
|
|
54617
|
+
if (id)
|
|
54618
|
+
map.set(id, f3);
|
|
54619
|
+
}
|
|
54620
|
+
_childIndex = map;
|
|
54621
|
+
return map;
|
|
54622
|
+
}
|
|
54623
|
+
function invalidateChildIndex() {
|
|
54624
|
+
_childIndex = null;
|
|
54625
|
+
}
|
|
54626
|
+
async function listSessions2(rootDir) {
|
|
54627
|
+
const root = rootDir || CODEX_ROOT;
|
|
54628
|
+
const out = [];
|
|
54629
|
+
const allFiles = collectRolloutFiles(root);
|
|
54630
|
+
for (const full of allFiles) {
|
|
54631
|
+
const meta = readFirstSessionMeta(full);
|
|
54632
|
+
if (!meta)
|
|
54633
|
+
continue;
|
|
54634
|
+
if (meta.thread_source && meta.thread_source !== "user")
|
|
54635
|
+
continue;
|
|
54636
|
+
let st;
|
|
54637
|
+
try {
|
|
54638
|
+
st = fs10.statSync(full);
|
|
54639
|
+
} catch {
|
|
54640
|
+
continue;
|
|
54641
|
+
}
|
|
54642
|
+
const summary = readFirstUserPrompt(full);
|
|
54643
|
+
const idFromName = extractUuidFromName(full);
|
|
54644
|
+
out.push({
|
|
54645
|
+
id: idFromName || meta.session_id || path8.basename(full, ".jsonl"),
|
|
54646
|
+
adapterName: "codex",
|
|
54647
|
+
path: full,
|
|
54648
|
+
startedAt: meta.timestamp || new Date(st.mtimeMs).toISOString(),
|
|
54649
|
+
project: meta.cwd || null,
|
|
54650
|
+
summary,
|
|
54651
|
+
sizeBytes: st.size
|
|
54652
|
+
});
|
|
54653
|
+
}
|
|
54654
|
+
return out;
|
|
54655
|
+
}
|
|
54656
|
+
function pushTurn2(state, opts) {
|
|
54657
|
+
const last = state.turns[state.turns.length - 1];
|
|
54658
|
+
if (last && !last.endedAt)
|
|
54659
|
+
last.endedAt = opts.startedAt;
|
|
54660
|
+
const id = `T${state.turns.length}`;
|
|
54661
|
+
const turn = {
|
|
54662
|
+
id,
|
|
54663
|
+
startedAt: opts.startedAt,
|
|
54664
|
+
endedAt: null,
|
|
54665
|
+
source: opts.source,
|
|
54666
|
+
slashCommand: null,
|
|
54667
|
+
args: String(opts.args || "").slice(0, 120),
|
|
54668
|
+
agentIds: [],
|
|
54669
|
+
skillIds: [],
|
|
54670
|
+
slashSkillId: null
|
|
54671
|
+
};
|
|
54672
|
+
state.turns.push(turn);
|
|
54673
|
+
return turn;
|
|
54674
|
+
}
|
|
54675
|
+
function addDollarSkill(state, name, ts) {
|
|
54676
|
+
const turn = state.turns[state.turns.length - 1];
|
|
54677
|
+
if (!turn)
|
|
54678
|
+
return null;
|
|
54679
|
+
state.skillCounter += 1;
|
|
54680
|
+
const id = `sk-slash-${turn.id}-${state.skillCounter}`;
|
|
54681
|
+
const startedAt = ts || new Date().toISOString();
|
|
54682
|
+
const skill = {
|
|
54683
|
+
id,
|
|
54684
|
+
name,
|
|
54685
|
+
source: "slash",
|
|
54686
|
+
prefix: "$",
|
|
54687
|
+
turnId: turn.id,
|
|
54688
|
+
startedAt,
|
|
54689
|
+
endedAt: null,
|
|
54690
|
+
status: "running",
|
|
54691
|
+
args: "",
|
|
54692
|
+
tokens: emptyTokens()
|
|
54693
|
+
};
|
|
54694
|
+
state.skills[id] = skill;
|
|
54695
|
+
if (!turn.slashSkillId)
|
|
54696
|
+
turn.slashSkillId = id;
|
|
54697
|
+
turn.skillIds.push(id);
|
|
54698
|
+
return skill;
|
|
54699
|
+
}
|
|
54700
|
+
function attachSubagent(state, info, childIndex) {
|
|
54701
|
+
const turn = state.turns[state.turns.length - 1] || pushTurn2(state, {
|
|
54702
|
+
source: "prompt",
|
|
54703
|
+
args: "spawned subagent",
|
|
54704
|
+
startedAt: info.spawnedAt
|
|
54705
|
+
});
|
|
54706
|
+
const cached = childIndex.get(info.agentId);
|
|
54707
|
+
const childPath = cached && fs10.existsSync(cached) ? cached : null;
|
|
54708
|
+
const transcriptMissing = !childPath;
|
|
54709
|
+
const description = info.nickname ? `${info.nickname}${transcriptMissing ? " (transcript missing)" : ""}` : transcriptMissing ? "(transcript missing)" : "";
|
|
54710
|
+
let tokens = emptyTokens();
|
|
54711
|
+
let model = null;
|
|
54712
|
+
if (childPath) {
|
|
54713
|
+
tokens = sumCodexAgentTokens(childPath);
|
|
54714
|
+
model = readFirstChildModel(childPath);
|
|
54715
|
+
}
|
|
54716
|
+
const ag = {
|
|
54717
|
+
id: info.agentId,
|
|
54718
|
+
type: info.agentType || "unknown",
|
|
54719
|
+
description,
|
|
54720
|
+
promptPreview: info.promptPreview || "",
|
|
54721
|
+
turnId: turn.id,
|
|
54722
|
+
startedAt: info.spawnedAt,
|
|
54723
|
+
endedAt: info.completedAt,
|
|
54724
|
+
status: "done",
|
|
54725
|
+
tokens,
|
|
54726
|
+
model,
|
|
54727
|
+
transcriptMissing
|
|
54728
|
+
};
|
|
54729
|
+
state.agents[info.agentId] = ag;
|
|
54730
|
+
turn.agentIds.push(info.agentId);
|
|
54731
|
+
}
|
|
54732
|
+
async function parse3(filePath) {
|
|
54733
|
+
const childIndex = buildChildIndex(CODEX_ROOT);
|
|
54734
|
+
const { records } = readNew(filePath, 0);
|
|
54735
|
+
const recs = records;
|
|
54736
|
+
const sessionMetaRec = recs.find((r2) => r2?.type === "session_meta");
|
|
54737
|
+
const sessionMeta = sessionMetaRec?.payload || {};
|
|
54738
|
+
const sessionId = extractUuidFromName(filePath) || sessionMeta.session_id || path8.basename(filePath, ".jsonl");
|
|
54739
|
+
const firstTs = sessionMeta.timestamp || recs.find((r2) => r2?.timestamp)?.timestamp || new Date().toISOString();
|
|
54740
|
+
const skillCatalog = loadSkillCatalog(sessionMeta.cwd || null);
|
|
54741
|
+
const state = {
|
|
54742
|
+
sessionId,
|
|
54743
|
+
schemaVersion: 2,
|
|
54744
|
+
startedAt: firstTs,
|
|
54745
|
+
transcriptPath: filePath,
|
|
54746
|
+
transcriptOffset: 0,
|
|
54747
|
+
agentOffsets: {},
|
|
54748
|
+
cwd: sessionMeta.cwd || null,
|
|
54749
|
+
turns: [],
|
|
54750
|
+
agents: {},
|
|
54751
|
+
skills: {},
|
|
54752
|
+
skillCounter: 0,
|
|
54753
|
+
tasks: {},
|
|
54754
|
+
taskOrder: [],
|
|
54755
|
+
todos: [],
|
|
54756
|
+
todosUpdatedAt: null,
|
|
54757
|
+
mainLoopTokens: emptyTokens(),
|
|
54758
|
+
totals: emptyTokens(),
|
|
54759
|
+
hookLog: []
|
|
54760
|
+
};
|
|
54761
|
+
const pendingSpawns = new Map;
|
|
54762
|
+
let lastModel = sessionMeta.model_provider || null;
|
|
54763
|
+
function attachAssistantTo(turn, rec) {
|
|
54764
|
+
if (!turn || turn.source === "startup")
|
|
54765
|
+
return;
|
|
54766
|
+
turn.assistant = turn.assistant || {
|
|
54767
|
+
model: null,
|
|
54768
|
+
tokens: emptyTokens(),
|
|
54769
|
+
startedAt: null,
|
|
54770
|
+
endedAt: null
|
|
54771
|
+
};
|
|
54772
|
+
if (lastModel)
|
|
54773
|
+
turn.assistant.model = lastModel;
|
|
54774
|
+
const tok = tokensOfCodex(rec);
|
|
54775
|
+
if (tok)
|
|
54776
|
+
turn.assistant.tokens = addTokens(turn.assistant.tokens, tok);
|
|
54777
|
+
const ts = rec.timestamp;
|
|
54778
|
+
if (ts) {
|
|
54779
|
+
if (!turn.assistant.startedAt || String(ts) < String(turn.assistant.startedAt))
|
|
54780
|
+
turn.assistant.startedAt = ts;
|
|
54781
|
+
if (!turn.assistant.endedAt || String(ts) > String(turn.assistant.endedAt))
|
|
54782
|
+
turn.assistant.endedAt = ts;
|
|
54783
|
+
}
|
|
54784
|
+
}
|
|
54785
|
+
for (const rec of recs) {
|
|
54786
|
+
if (!rec || typeof rec !== "object")
|
|
54787
|
+
continue;
|
|
54788
|
+
if (rec.type === "turn_context") {
|
|
54789
|
+
const p = rec.payload || {};
|
|
54790
|
+
if (p.model)
|
|
54791
|
+
lastModel = p.model;
|
|
54792
|
+
continue;
|
|
54793
|
+
}
|
|
54794
|
+
if (rec.type === "event_msg") {
|
|
54795
|
+
const p = rec.payload || {};
|
|
54796
|
+
if (p.type === "user_message") {
|
|
54797
|
+
const text = String(p.message || "");
|
|
54798
|
+
pushTurn2(state, {
|
|
54799
|
+
source: "prompt",
|
|
54800
|
+
args: text.slice(0, 120),
|
|
54801
|
+
startedAt: rec.timestamp || new Date().toISOString()
|
|
54802
|
+
});
|
|
54803
|
+
const hits = detectSkillsInPrompt(skillCatalog, text);
|
|
54804
|
+
for (const name of hits.slice(0, 3))
|
|
54805
|
+
addDollarSkill(state, name, rec.timestamp);
|
|
54806
|
+
} else if (p.type === "token_count") {
|
|
54807
|
+
const tok = tokensOfCodex(rec);
|
|
54808
|
+
if (tok)
|
|
54809
|
+
state.mainLoopTokens = addTokens(state.mainLoopTokens, tok);
|
|
54810
|
+
attachAssistantTo(state.turns[state.turns.length - 1], rec);
|
|
54811
|
+
} else if (p.type === "agent_message") {
|
|
54812
|
+
const cur = state.turns[state.turns.length - 1];
|
|
54813
|
+
if (cur && cur.source !== "startup") {
|
|
54814
|
+
cur.assistant = cur.assistant || {
|
|
54815
|
+
model: lastModel,
|
|
54816
|
+
tokens: emptyTokens(),
|
|
54817
|
+
startedAt: null,
|
|
54818
|
+
endedAt: null
|
|
54819
|
+
};
|
|
54820
|
+
if (lastModel)
|
|
54821
|
+
cur.assistant.model = lastModel;
|
|
54822
|
+
const ts = rec.timestamp;
|
|
54823
|
+
if (ts) {
|
|
54824
|
+
if (!cur.assistant.startedAt || String(ts) < String(cur.assistant.startedAt))
|
|
54825
|
+
cur.assistant.startedAt = ts;
|
|
54826
|
+
if (!cur.assistant.endedAt || String(ts) > String(cur.assistant.endedAt))
|
|
54827
|
+
cur.assistant.endedAt = ts;
|
|
54828
|
+
}
|
|
54829
|
+
}
|
|
54830
|
+
} else if (p.type === "task_complete") {
|
|
54831
|
+
const t = state.turns[state.turns.length - 1];
|
|
54832
|
+
if (t && !t.endedAt)
|
|
54833
|
+
t.endedAt = rec.timestamp || new Date().toISOString();
|
|
54834
|
+
}
|
|
54835
|
+
continue;
|
|
54836
|
+
}
|
|
54837
|
+
if (rec.type === "response_item") {
|
|
54838
|
+
const p = rec.payload || {};
|
|
54839
|
+
if (p.type === "function_call") {
|
|
54840
|
+
if (p.name === "spawn_agent" && p.call_id) {
|
|
54841
|
+
let argsParsed = {};
|
|
54842
|
+
try {
|
|
54843
|
+
argsParsed = JSON.parse(p.arguments || "{}");
|
|
54844
|
+
} catch {}
|
|
54845
|
+
pendingSpawns.set(p.call_id, {
|
|
54846
|
+
agentType: argsParsed.agent_type || "default",
|
|
54847
|
+
message: argsParsed.message || "",
|
|
54848
|
+
timestamp: rec.timestamp || new Date().toISOString()
|
|
54849
|
+
});
|
|
54850
|
+
}
|
|
54851
|
+
continue;
|
|
54852
|
+
}
|
|
54853
|
+
if (p.type === "function_call_output" && p.call_id) {
|
|
54854
|
+
const pending = pendingSpawns.get(p.call_id);
|
|
54855
|
+
if (!pending)
|
|
54856
|
+
continue;
|
|
54857
|
+
pendingSpawns.delete(p.call_id);
|
|
54858
|
+
let parsedOutput = {};
|
|
54859
|
+
try {
|
|
54860
|
+
parsedOutput = JSON.parse(p.output || "{}");
|
|
54861
|
+
} catch {}
|
|
54862
|
+
const agentId = parsedOutput.agent_id;
|
|
54863
|
+
const nickname = parsedOutput.nickname || "";
|
|
54864
|
+
if (!agentId)
|
|
54865
|
+
continue;
|
|
54866
|
+
attachSubagent(state, {
|
|
54867
|
+
agentId,
|
|
54868
|
+
agentType: pending.agentType,
|
|
54869
|
+
nickname,
|
|
54870
|
+
promptPreview: pending.message.slice(0, 120),
|
|
54871
|
+
spawnedAt: pending.timestamp,
|
|
54872
|
+
completedAt: rec.timestamp || pending.timestamp
|
|
54873
|
+
}, childIndex);
|
|
54874
|
+
}
|
|
54875
|
+
}
|
|
54876
|
+
}
|
|
54877
|
+
for (const t of state.turns) {
|
|
54878
|
+
if (!t.assistant)
|
|
54879
|
+
continue;
|
|
54880
|
+
for (const aid of t.agentIds || []) {
|
|
54881
|
+
const ag = state.agents[aid];
|
|
54882
|
+
if (!ag?.tokens)
|
|
54883
|
+
continue;
|
|
54884
|
+
t.assistant.tokens = addTokens(t.assistant.tokens, ag.tokens);
|
|
54885
|
+
}
|
|
54886
|
+
}
|
|
54887
|
+
for (const t of state.turns) {
|
|
54888
|
+
if (!t.assistant || !t.skillIds)
|
|
54889
|
+
continue;
|
|
54890
|
+
for (const sid of t.skillIds) {
|
|
54891
|
+
const sk = state.skills[sid];
|
|
54892
|
+
if (sk && sk.source === "slash") {
|
|
54893
|
+
sk.tokens = { ...t.assistant.tokens };
|
|
54894
|
+
}
|
|
54895
|
+
}
|
|
54896
|
+
}
|
|
54897
|
+
state.totals = { ...state.mainLoopTokens };
|
|
54898
|
+
for (const ag of Object.values(state.agents)) {
|
|
54899
|
+
state.totals = addTokens(state.totals, ag.tokens || emptyTokens());
|
|
54900
|
+
}
|
|
54901
|
+
const last = state.turns[state.turns.length - 1];
|
|
54902
|
+
if (last && !last.endedAt)
|
|
54903
|
+
last.endedAt = new Date().toISOString();
|
|
54904
|
+
return state;
|
|
54905
|
+
}
|
|
54906
|
+
function matches2(filePath) {
|
|
54907
|
+
if (!filePath)
|
|
54908
|
+
return false;
|
|
54909
|
+
const norm = path8.resolve(filePath);
|
|
54910
|
+
return norm.includes(`${path8.sep}.codex${path8.sep}sessions${path8.sep}`) && /rollout-.*\.jsonl$/.test(norm);
|
|
54911
|
+
}
|
|
54912
|
+
var codexAdapter = {
|
|
54913
|
+
name: "codex",
|
|
54914
|
+
matches: matches2,
|
|
54915
|
+
listSessions: listSessions2,
|
|
54916
|
+
parse: parse3,
|
|
54917
|
+
invalidateChildIndex
|
|
54918
|
+
};
|
|
54919
|
+
|
|
54920
|
+
// src/domains/sessions/adapters/index.ts
|
|
54921
|
+
var adapters = [claudeAdapter, codexAdapter];
|
|
54922
|
+
function resolveById(namespacedId) {
|
|
54923
|
+
if (!namespacedId)
|
|
54924
|
+
return null;
|
|
54925
|
+
const idx = namespacedId.indexOf(":");
|
|
54926
|
+
if (idx < 0)
|
|
54927
|
+
return null;
|
|
54928
|
+
const adapterName = namespacedId.slice(0, idx);
|
|
54929
|
+
const uuid = namespacedId.slice(idx + 1);
|
|
54930
|
+
const adapter = adapters.find((a3) => a3.name === adapterName);
|
|
54931
|
+
if (!adapter)
|
|
54932
|
+
return null;
|
|
54933
|
+
return { adapter, uuid, namespacedId };
|
|
54934
|
+
}
|
|
54935
|
+
|
|
54936
|
+
// src/domains/sessions/enumerate.ts
|
|
54937
|
+
var cache = null;
|
|
54938
|
+
async function list(opts = {}) {
|
|
54939
|
+
if (cache && !opts.refresh)
|
|
54940
|
+
return cache;
|
|
54941
|
+
const lists = await Promise.all(adapters.map((a3) => a3.listSessions().catch(() => [])));
|
|
54942
|
+
const merged = [];
|
|
54943
|
+
adapters.forEach((adapter, i) => {
|
|
54944
|
+
const list2 = lists[i] || [];
|
|
54945
|
+
for (const s of list2) {
|
|
54946
|
+
merged.push({ ...s, id: `${adapter.name}:${s.id}` });
|
|
54947
|
+
}
|
|
54948
|
+
});
|
|
54949
|
+
merged.sort((a3, b3) => String(b3.startedAt || "").localeCompare(String(a3.startedAt || "")));
|
|
54950
|
+
cache = merged;
|
|
54951
|
+
return cache;
|
|
54952
|
+
}
|
|
54953
|
+
function invalidate() {
|
|
54954
|
+
cache = null;
|
|
54955
|
+
for (const a3 of adapters) {
|
|
54956
|
+
if (typeof a3.invalidateChildIndex === "function")
|
|
54957
|
+
a3.invalidateChildIndex();
|
|
54958
|
+
}
|
|
54959
|
+
}
|
|
54960
|
+
|
|
54961
|
+
// src/domains/sessions/origin-allowlist.ts
|
|
54962
|
+
init_build_config();
|
|
54963
|
+
function originOf(url) {
|
|
54964
|
+
try {
|
|
54965
|
+
const u = new URL(url);
|
|
54966
|
+
return `${u.protocol}//${u.host}`;
|
|
54967
|
+
} catch {
|
|
54968
|
+
return url.replace(/\/+$/, "");
|
|
54969
|
+
}
|
|
54970
|
+
}
|
|
54971
|
+
var PLATFORM_ORIGIN = originOf(SERVER_URL);
|
|
54972
|
+
var DEFAULT_ORIGINS = [
|
|
54973
|
+
PLATFORM_ORIGIN,
|
|
54974
|
+
"http://localhost:5173",
|
|
54975
|
+
"http://localhost:4321"
|
|
54976
|
+
];
|
|
54977
|
+
var LOOPBACK_HOST_PATTERN = /^http:\/\/(localhost|127\.0\.0\.1)(:\d+)?$/;
|
|
54978
|
+
function isAllowedOrigin(origin) {
|
|
54979
|
+
if (!origin)
|
|
54980
|
+
return false;
|
|
54981
|
+
if (DEFAULT_ORIGINS.includes(origin))
|
|
54982
|
+
return true;
|
|
54983
|
+
return LOOPBACK_HOST_PATTERN.test(origin);
|
|
54984
|
+
}
|
|
54985
|
+
|
|
54986
|
+
// src/domains/sessions/server.ts
|
|
54987
|
+
var PORT_BUMP_MAX = 9;
|
|
54988
|
+
function applyCorsHeaders(req, res) {
|
|
54989
|
+
const origin = req.headers.origin;
|
|
54990
|
+
if (origin && isAllowedOrigin(origin)) {
|
|
54991
|
+
res.setHeader("Access-Control-Allow-Origin", origin);
|
|
54992
|
+
res.setHeader("Vary", "Origin");
|
|
54993
|
+
}
|
|
54994
|
+
}
|
|
54995
|
+
function sendJSON(res, code, body) {
|
|
54996
|
+
const buf = Buffer.from(JSON.stringify(body));
|
|
54997
|
+
res.writeHead(code, {
|
|
54998
|
+
"content-type": "application/json; charset=utf-8",
|
|
54999
|
+
"content-length": buf.length
|
|
55000
|
+
});
|
|
55001
|
+
res.end(buf);
|
|
55002
|
+
}
|
|
55003
|
+
function originGuard(req, res) {
|
|
55004
|
+
const origin = req.headers.origin;
|
|
55005
|
+
if (isAllowedOrigin(origin)) {
|
|
55006
|
+
applyCorsHeaders(req, res);
|
|
55007
|
+
return true;
|
|
55008
|
+
}
|
|
55009
|
+
sendJSON(res, 403, { error: "origin not allowed", origin: origin ?? null });
|
|
55010
|
+
return false;
|
|
55011
|
+
}
|
|
55012
|
+
async function route(req, res, version3) {
|
|
55013
|
+
const url = new URL(req.url || "/", "http://127.0.0.1");
|
|
55014
|
+
const pathname = url.pathname;
|
|
55015
|
+
applyCorsHeaders(req, res);
|
|
55016
|
+
if (req.method === "OPTIONS") {
|
|
55017
|
+
res.writeHead(204, {
|
|
55018
|
+
"Access-Control-Allow-Methods": "GET, OPTIONS",
|
|
55019
|
+
"Access-Control-Allow-Headers": "content-type",
|
|
55020
|
+
"Access-Control-Max-Age": "600"
|
|
55021
|
+
});
|
|
55022
|
+
res.end();
|
|
55023
|
+
return;
|
|
55024
|
+
}
|
|
55025
|
+
if (pathname === "/healthz") {
|
|
55026
|
+
sendJSON(res, 200, { ok: true, version: version3 });
|
|
55027
|
+
return;
|
|
55028
|
+
}
|
|
55029
|
+
if (!pathname.startsWith("/api/")) {
|
|
55030
|
+
sendJSON(res, 404, { error: "not found" });
|
|
55031
|
+
return;
|
|
55032
|
+
}
|
|
55033
|
+
if (!originGuard(req, res))
|
|
55034
|
+
return;
|
|
55035
|
+
if (pathname === "/api/sessions") {
|
|
55036
|
+
const refresh2 = url.searchParams.get("refresh") === "1";
|
|
55037
|
+
if (refresh2)
|
|
55038
|
+
invalidate();
|
|
55039
|
+
const list2 = await list({ refresh: refresh2 });
|
|
55040
|
+
sendJSON(res, 200, list2);
|
|
55041
|
+
return;
|
|
55042
|
+
}
|
|
55043
|
+
const m2 = pathname.match(/^\/api\/sessions\/([^/]+)\/state$/);
|
|
55044
|
+
if (m2?.[1]) {
|
|
55045
|
+
const id = decodeURIComponent(m2[1]);
|
|
55046
|
+
const resolved = resolveById(id);
|
|
55047
|
+
if (!resolved) {
|
|
55048
|
+
sendJSON(res, 404, { error: "unknown adapter or id", id });
|
|
55049
|
+
return;
|
|
55050
|
+
}
|
|
55051
|
+
const all = await list();
|
|
55052
|
+
const summary = all.find((s) => s.id === id);
|
|
55053
|
+
if (!summary) {
|
|
55054
|
+
sendJSON(res, 404, { error: "session not in list", id });
|
|
55055
|
+
return;
|
|
55056
|
+
}
|
|
55057
|
+
try {
|
|
55058
|
+
const state = await resolved.adapter.parse(summary.path);
|
|
55059
|
+
sendJSON(res, 200, state);
|
|
55060
|
+
} catch (e2) {
|
|
55061
|
+
sendJSON(res, 500, { error: String(e2.message || e2) });
|
|
55062
|
+
}
|
|
55063
|
+
return;
|
|
55064
|
+
}
|
|
55065
|
+
sendJSON(res, 404, { error: "not found" });
|
|
55066
|
+
}
|
|
55067
|
+
function start(options2 = {}) {
|
|
55068
|
+
const requested = options2.port ?? 8765;
|
|
55069
|
+
const version3 = options2.version ?? "unknown";
|
|
55070
|
+
return new Promise((resolve17, reject) => {
|
|
55071
|
+
let attempt = 0;
|
|
55072
|
+
const tryListen = (p) => {
|
|
55073
|
+
const server = http.createServer((req, res) => {
|
|
55074
|
+
Promise.resolve(route(req, res, version3)).catch((e2) => {
|
|
55075
|
+
if (res.headersSent) {
|
|
55076
|
+
try {
|
|
55077
|
+
res.end();
|
|
55078
|
+
} catch {}
|
|
55079
|
+
return;
|
|
55080
|
+
}
|
|
55081
|
+
sendJSON(res, 500, { error: String(e2.message || e2) });
|
|
55082
|
+
});
|
|
55083
|
+
});
|
|
55084
|
+
server.on("error", (err) => {
|
|
55085
|
+
if (err.code === "EADDRINUSE" && attempt < PORT_BUMP_MAX) {
|
|
55086
|
+
attempt += 1;
|
|
55087
|
+
tryListen(p + 1);
|
|
55088
|
+
return;
|
|
55089
|
+
}
|
|
55090
|
+
reject(err);
|
|
55091
|
+
});
|
|
55092
|
+
server.listen(p, "127.0.0.1", () => {
|
|
55093
|
+
const addr = server.address();
|
|
55094
|
+
const port = addr?.port ?? p;
|
|
55095
|
+
const handle = {
|
|
55096
|
+
server,
|
|
55097
|
+
port,
|
|
55098
|
+
close: () => new Promise((r2) => {
|
|
55099
|
+
server.close(() => r2());
|
|
55100
|
+
})
|
|
55101
|
+
};
|
|
55102
|
+
options2.onReady?.({ port, url: `http://127.0.0.1:${port}` });
|
|
55103
|
+
resolve17(handle);
|
|
55104
|
+
});
|
|
55105
|
+
};
|
|
55106
|
+
tryListen(requested);
|
|
55107
|
+
});
|
|
55108
|
+
}
|
|
55109
|
+
|
|
55110
|
+
// src/commands/console.ts
|
|
55111
|
+
init_build_config();
|
|
55112
|
+
init_package();
|
|
55113
|
+
function stripTrailingSlash(u) {
|
|
55114
|
+
return u.replace(/\/+$/, "");
|
|
55115
|
+
}
|
|
55116
|
+
async function consoleCommand(options2 = {}) {
|
|
55117
|
+
const requestedPort = options2.port ?? 8765;
|
|
55118
|
+
const openBrowser = !options2.noOpen;
|
|
55119
|
+
const handle = await start({
|
|
55120
|
+
port: requestedPort,
|
|
55121
|
+
version: package_default.version,
|
|
55122
|
+
onReady: ({ url }) => {
|
|
55123
|
+
console.log(`Bridge ready at ${url}`);
|
|
55124
|
+
const platformUrl = `${stripTrailingSlash(SERVER_URL)}/app/console#bridge=${url}`;
|
|
55125
|
+
if (openBrowser) {
|
|
55126
|
+
console.log(`Opening ${platformUrl}`);
|
|
55127
|
+
tryOpenBrowser(platformUrl);
|
|
55128
|
+
} else {
|
|
55129
|
+
console.log(`Open ${platformUrl} in your browser`);
|
|
55130
|
+
}
|
|
55131
|
+
}
|
|
55132
|
+
});
|
|
55133
|
+
await new Promise((resolve17) => {
|
|
55134
|
+
const shutdown = () => {
|
|
55135
|
+
console.log(`
|
|
55136
|
+
Shutting down bridge`);
|
|
55137
|
+
handle.close().finally(() => {
|
|
55138
|
+
resolve17();
|
|
55139
|
+
process.exit(0);
|
|
55140
|
+
});
|
|
55141
|
+
setTimeout(() => process.exit(0), 500).unref();
|
|
55142
|
+
};
|
|
55143
|
+
process.once("SIGINT", shutdown);
|
|
55144
|
+
process.once("SIGTERM", shutdown);
|
|
55145
|
+
});
|
|
55146
|
+
}
|
|
55147
|
+
|
|
53695
55148
|
// src/domains/health-checks/types.ts
|
|
53696
55149
|
init_zod();
|
|
53697
55150
|
var CheckStatusSchema = exports_external.enum(["pass", "warn", "fail", "info"]);
|
|
@@ -53859,7 +55312,7 @@ import { promisify as promisify11 } from "node:util";
|
|
|
53859
55312
|
// src/domains/github/gh-cli-utils.ts
|
|
53860
55313
|
init_environment();
|
|
53861
55314
|
init_logger();
|
|
53862
|
-
import { readFileSync as
|
|
55315
|
+
import { readFileSync as readFileSync8 } from "node:fs";
|
|
53863
55316
|
var MIN_GH_CLI_VERSION = "2.20.0";
|
|
53864
55317
|
var GH_COMMAND_TIMEOUT_MS = 1e4;
|
|
53865
55318
|
function compareVersions4(a3, b3) {
|
|
@@ -53880,7 +55333,7 @@ function isWSL2() {
|
|
|
53880
55333
|
if (process.platform !== "linux")
|
|
53881
55334
|
return false;
|
|
53882
55335
|
try {
|
|
53883
|
-
const release =
|
|
55336
|
+
const release = readFileSync8("/proc/version", "utf-8").toLowerCase();
|
|
53884
55337
|
return release.includes("microsoft") || release.includes("wsl");
|
|
53885
55338
|
} catch (error) {
|
|
53886
55339
|
logger.debug(`WSL detection skipped: ${error instanceof Error ? error.message : "unknown error"}`);
|
|
@@ -54044,10 +55497,10 @@ async function getCommandPath(command) {
|
|
|
54044
55497
|
const whichCmd = process.platform === "win32" ? "where" : "which";
|
|
54045
55498
|
logger.verbose(`Getting path for command: ${command}`);
|
|
54046
55499
|
const { stdout } = await execAsync2(`${whichCmd} ${command}`);
|
|
54047
|
-
const
|
|
55500
|
+
const path9 = stdout.trim().split(`
|
|
54048
55501
|
`)[0] || null;
|
|
54049
|
-
logger.verbose(`Command path resolved: ${command} -> ${
|
|
54050
|
-
return
|
|
55502
|
+
logger.verbose(`Command path resolved: ${command} -> ${path9}`);
|
|
55503
|
+
return path9;
|
|
54051
55504
|
} catch {
|
|
54052
55505
|
logger.verbose(`Failed to get path for command: ${command}`);
|
|
54053
55506
|
return null;
|
|
@@ -54102,7 +55555,7 @@ async function checkDependency(config) {
|
|
|
54102
55555
|
const exists = await commandExists(command);
|
|
54103
55556
|
if (exists) {
|
|
54104
55557
|
logger.verbose(`Found ${config.name} via command: ${command}`);
|
|
54105
|
-
const
|
|
55558
|
+
const path9 = await getCommandPath(command);
|
|
54106
55559
|
const version3 = await getCommandVersion(command, config.versionFlag, config.versionRegex);
|
|
54107
55560
|
let meetsRequirements = true;
|
|
54108
55561
|
let message;
|
|
@@ -54116,7 +55569,7 @@ async function checkDependency(config) {
|
|
|
54116
55569
|
name: config.name,
|
|
54117
55570
|
installed: true,
|
|
54118
55571
|
version: version3 || undefined,
|
|
54119
|
-
path:
|
|
55572
|
+
path: path9 || undefined,
|
|
54120
55573
|
minVersion: config.minVersion,
|
|
54121
55574
|
meetsRequirements,
|
|
54122
55575
|
message
|
|
@@ -54237,7 +55690,7 @@ var PYTHON_INSTALLERS = [
|
|
|
54237
55690
|
// src/services/package-installer/dependencies/system-installer.ts
|
|
54238
55691
|
init_logger();
|
|
54239
55692
|
import { exec as exec3 } from "node:child_process";
|
|
54240
|
-
import * as
|
|
55693
|
+
import * as fs11 from "node:fs";
|
|
54241
55694
|
import { promisify as promisify9 } from "node:util";
|
|
54242
55695
|
var execAsync3 = promisify9(exec3);
|
|
54243
55696
|
async function detectOS() {
|
|
@@ -54252,8 +55705,8 @@ async function detectOS() {
|
|
|
54252
55705
|
}
|
|
54253
55706
|
} else if (platform5 === "linux") {
|
|
54254
55707
|
try {
|
|
54255
|
-
if (
|
|
54256
|
-
const content =
|
|
55708
|
+
if (fs11.existsSync("/etc/os-release")) {
|
|
55709
|
+
const content = fs11.readFileSync("/etc/os-release", "utf-8");
|
|
54257
55710
|
const idMatch = content.match(/^ID=(.+)$/m);
|
|
54258
55711
|
info.distro = idMatch?.[1]?.replace(/"/g, "");
|
|
54259
55712
|
}
|
|
@@ -54833,10 +56286,10 @@ function getPnpmUpdateCommand(packageName, version3, registryUrl) {
|
|
|
54833
56286
|
init_logger();
|
|
54834
56287
|
init_path_resolver();
|
|
54835
56288
|
init_takumi_constants();
|
|
54836
|
-
import { existsSync as
|
|
56289
|
+
import { existsSync as existsSync35, realpathSync } from "node:fs";
|
|
54837
56290
|
import { chmod as chmod2, mkdir as mkdir18, readFile as readFile32, writeFile as writeFile22 } from "node:fs/promises";
|
|
54838
56291
|
import { platform as platform5 } from "node:os";
|
|
54839
|
-
import { join as
|
|
56292
|
+
import { join as join73 } from "node:path";
|
|
54840
56293
|
var CACHE_FILE = "install-info.json";
|
|
54841
56294
|
var CACHE_TTL = 30 * 24 * 60 * 60 * 1000;
|
|
54842
56295
|
function detectFromBinaryPath() {
|
|
@@ -54920,8 +56373,8 @@ function detectFromEnv() {
|
|
|
54920
56373
|
}
|
|
54921
56374
|
async function readCachedPm() {
|
|
54922
56375
|
try {
|
|
54923
|
-
const cacheFile =
|
|
54924
|
-
if (!
|
|
56376
|
+
const cacheFile = join73(PathResolver.getConfigDir(false), CACHE_FILE);
|
|
56377
|
+
if (!existsSync35(cacheFile)) {
|
|
54925
56378
|
return null;
|
|
54926
56379
|
}
|
|
54927
56380
|
const content = await readFile32(cacheFile, "utf-8");
|
|
@@ -54951,8 +56404,8 @@ async function saveCachedPm(pm, getVersion) {
|
|
|
54951
56404
|
return;
|
|
54952
56405
|
try {
|
|
54953
56406
|
const configDir = PathResolver.getConfigDir(false);
|
|
54954
|
-
const cacheFile =
|
|
54955
|
-
if (!
|
|
56407
|
+
const cacheFile = join73(configDir, CACHE_FILE);
|
|
56408
|
+
if (!existsSync35(configDir)) {
|
|
54956
56409
|
await mkdir18(configDir, { recursive: true });
|
|
54957
56410
|
if (platform5() !== "win32") {
|
|
54958
56411
|
await chmod2(configDir, 448);
|
|
@@ -55014,8 +56467,8 @@ async function findOwningPm() {
|
|
|
55014
56467
|
async function clearCache() {
|
|
55015
56468
|
try {
|
|
55016
56469
|
const { unlink: unlink7 } = await import("node:fs/promises");
|
|
55017
|
-
const cacheFile =
|
|
55018
|
-
if (
|
|
56470
|
+
const cacheFile = join73(PathResolver.getConfigDir(false), CACHE_FILE);
|
|
56471
|
+
if (existsSync35(cacheFile)) {
|
|
55019
56472
|
await unlink7(cacheFile);
|
|
55020
56473
|
logger.debug("Package manager cache cleared");
|
|
55021
56474
|
}
|
|
@@ -55275,23 +56728,23 @@ async function checkCliVersion() {
|
|
|
55275
56728
|
// src/domains/health-checks/checkers/claude-md-checker.ts
|
|
55276
56729
|
init_paths();
|
|
55277
56730
|
init_registry();
|
|
55278
|
-
import { existsSync as
|
|
55279
|
-
import { join as
|
|
56731
|
+
import { existsSync as existsSync36, statSync as statSync5 } from "node:fs";
|
|
56732
|
+
import { join as join74 } from "node:path";
|
|
55280
56733
|
function checkClaudeMd(setup, projectDir) {
|
|
55281
56734
|
const results = [];
|
|
55282
56735
|
const claudeCodeInstaller2 = getInstaller("claude-code");
|
|
55283
56736
|
if (claudeCodeInstaller2?.isInstalledGlobally()) {
|
|
55284
56737
|
const claudeGlobal = setup.globals.find((g2) => g2.provider === "claude-code") ?? setup.globals[0];
|
|
55285
56738
|
const globalPath = claudeGlobal?.path ?? claudeCodeInstaller2.globalRoot();
|
|
55286
|
-
const globalClaudeMd =
|
|
56739
|
+
const globalClaudeMd = join74(globalPath, "CLAUDE.md");
|
|
55287
56740
|
results.push(checkClaudeMdFile(globalClaudeMd, "Global CLAUDE.md", "sk-global-claude-md"));
|
|
55288
56741
|
}
|
|
55289
|
-
const projectClaudeMd =
|
|
56742
|
+
const projectClaudeMd = join74(getLocalClaudeDir(projectDir), "CLAUDE.md");
|
|
55290
56743
|
results.push(checkClaudeMdFile(projectClaudeMd, "Project CLAUDE.md", "sk-project-claude-md"));
|
|
55291
56744
|
return results;
|
|
55292
56745
|
}
|
|
55293
|
-
function checkClaudeMdFile(
|
|
55294
|
-
if (!
|
|
56746
|
+
function checkClaudeMdFile(path9, name, id) {
|
|
56747
|
+
if (!existsSync36(path9)) {
|
|
55295
56748
|
return {
|
|
55296
56749
|
id,
|
|
55297
56750
|
name,
|
|
@@ -55304,7 +56757,7 @@ function checkClaudeMdFile(path7, name, id) {
|
|
|
55304
56757
|
};
|
|
55305
56758
|
}
|
|
55306
56759
|
try {
|
|
55307
|
-
const stat8 =
|
|
56760
|
+
const stat8 = statSync5(path9);
|
|
55308
56761
|
const sizeKB = (stat8.size / 1024).toFixed(1);
|
|
55309
56762
|
if (stat8.size === 0) {
|
|
55310
56763
|
return {
|
|
@@ -55314,7 +56767,7 @@ function checkClaudeMdFile(path7, name, id) {
|
|
|
55314
56767
|
priority: "standard",
|
|
55315
56768
|
status: "warn",
|
|
55316
56769
|
message: "Empty (0 bytes)",
|
|
55317
|
-
details:
|
|
56770
|
+
details: path9,
|
|
55318
56771
|
suggestion: "Add project instructions to CLAUDE.md",
|
|
55319
56772
|
autoFixable: false
|
|
55320
56773
|
};
|
|
@@ -55326,7 +56779,7 @@ function checkClaudeMdFile(path7, name, id) {
|
|
|
55326
56779
|
priority: "standard",
|
|
55327
56780
|
status: "pass",
|
|
55328
56781
|
message: `Found (${sizeKB}KB)`,
|
|
55329
|
-
details:
|
|
56782
|
+
details: path9,
|
|
55330
56783
|
autoFixable: false
|
|
55331
56784
|
};
|
|
55332
56785
|
} catch {
|
|
@@ -55337,18 +56790,18 @@ function checkClaudeMdFile(path7, name, id) {
|
|
|
55337
56790
|
priority: "standard",
|
|
55338
56791
|
status: "warn",
|
|
55339
56792
|
message: "Unreadable",
|
|
55340
|
-
details:
|
|
56793
|
+
details: path9,
|
|
55341
56794
|
suggestion: "Check file permissions",
|
|
55342
56795
|
autoFixable: false
|
|
55343
56796
|
};
|
|
55344
56797
|
}
|
|
55345
56798
|
}
|
|
55346
56799
|
// src/domains/health-checks/checkers/active-plan-checker.ts
|
|
55347
|
-
import { existsSync as
|
|
55348
|
-
import { join as
|
|
56800
|
+
import { existsSync as existsSync37, readFileSync as readFileSync10 } from "node:fs";
|
|
56801
|
+
import { join as join75 } from "node:path";
|
|
55349
56802
|
function checkActivePlan(projectDir) {
|
|
55350
|
-
const activePlanPath =
|
|
55351
|
-
if (!
|
|
56803
|
+
const activePlanPath = join75(projectDir, ".claude", "active-plan");
|
|
56804
|
+
if (!existsSync37(activePlanPath)) {
|
|
55352
56805
|
return {
|
|
55353
56806
|
id: "sk-active-plan",
|
|
55354
56807
|
name: "Active Plan",
|
|
@@ -55360,9 +56813,9 @@ function checkActivePlan(projectDir) {
|
|
|
55360
56813
|
};
|
|
55361
56814
|
}
|
|
55362
56815
|
try {
|
|
55363
|
-
const targetPath =
|
|
55364
|
-
const fullPath =
|
|
55365
|
-
if (!
|
|
56816
|
+
const targetPath = readFileSync10(activePlanPath, "utf-8").trim();
|
|
56817
|
+
const fullPath = join75(projectDir, targetPath);
|
|
56818
|
+
if (!existsSync37(fullPath)) {
|
|
55366
56819
|
return {
|
|
55367
56820
|
id: "sk-active-plan",
|
|
55368
56821
|
name: "Active Plan",
|
|
@@ -55427,7 +56880,7 @@ function checkComponentCounts(setup) {
|
|
|
55427
56880
|
init_registry();
|
|
55428
56881
|
init_logger();
|
|
55429
56882
|
import { constants, access, unlink as unlink7, writeFile as writeFile23 } from "node:fs/promises";
|
|
55430
|
-
import { join as
|
|
56883
|
+
import { join as join76 } from "node:path";
|
|
55431
56884
|
|
|
55432
56885
|
// src/domains/health-checks/checkers/shared.ts
|
|
55433
56886
|
init_registry();
|
|
@@ -55502,7 +56955,7 @@ async function checkGlobalDirWritable(provider) {
|
|
|
55502
56955
|
}
|
|
55503
56956
|
const timestamp = Date.now();
|
|
55504
56957
|
const random = Math.random().toString(36).substring(2);
|
|
55505
|
-
const testFile =
|
|
56958
|
+
const testFile = join76(globalDir, `.sk-write-test-${timestamp}-${random}`);
|
|
55506
56959
|
try {
|
|
55507
56960
|
await writeFile23(testFile, "test", { encoding: "utf-8", flag: "wx" });
|
|
55508
56961
|
} catch (_error) {
|
|
@@ -55537,9 +56990,9 @@ async function checkGlobalDirWritable(provider) {
|
|
|
55537
56990
|
// src/domains/health-checks/checkers/hooks-checker.ts
|
|
55538
56991
|
init_paths();
|
|
55539
56992
|
init_registry();
|
|
55540
|
-
import { existsSync as
|
|
56993
|
+
import { existsSync as existsSync38 } from "node:fs";
|
|
55541
56994
|
import { readdir as readdir23 } from "node:fs/promises";
|
|
55542
|
-
import { join as
|
|
56995
|
+
import { join as join77 } from "node:path";
|
|
55543
56996
|
|
|
55544
56997
|
// src/domains/health-checks/utils/path-normalizer.ts
|
|
55545
56998
|
import { normalize as normalize5 } from "node:path";
|
|
@@ -55551,17 +57004,17 @@ function normalizePath(filePath) {
|
|
|
55551
57004
|
|
|
55552
57005
|
// src/domains/health-checks/checkers/hooks-checker.ts
|
|
55553
57006
|
async function checkHooksExist(projectDir) {
|
|
55554
|
-
const globalHooksDir =
|
|
55555
|
-
const projectHooksDir =
|
|
55556
|
-
const globalExists =
|
|
55557
|
-
const projectExists =
|
|
57007
|
+
const globalHooksDir = join77(getInstaller("claude-code")?.globalRoot() ?? "", "hooks");
|
|
57008
|
+
const projectHooksDir = join77(getLocalClaudeDir(projectDir), "hooks");
|
|
57009
|
+
const globalExists = existsSync38(globalHooksDir);
|
|
57010
|
+
const projectExists = existsSync38(projectHooksDir);
|
|
55558
57011
|
let hookCount = 0;
|
|
55559
57012
|
const checkedFiles = new Set;
|
|
55560
57013
|
if (globalExists) {
|
|
55561
57014
|
const files = await readdir23(globalHooksDir, { withFileTypes: false });
|
|
55562
57015
|
const hooks = files.filter((f3) => HOOK_EXTENSIONS2.some((ext2) => f3.endsWith(ext2)));
|
|
55563
57016
|
hooks.forEach((hook) => {
|
|
55564
|
-
const fullPath =
|
|
57017
|
+
const fullPath = join77(globalHooksDir, hook);
|
|
55565
57018
|
checkedFiles.add(normalizePath(fullPath));
|
|
55566
57019
|
});
|
|
55567
57020
|
}
|
|
@@ -55571,7 +57024,7 @@ async function checkHooksExist(projectDir) {
|
|
|
55571
57024
|
const files = await readdir23(projectHooksDir, { withFileTypes: false });
|
|
55572
57025
|
const hooks = files.filter((f3) => HOOK_EXTENSIONS2.some((ext2) => f3.endsWith(ext2)));
|
|
55573
57026
|
hooks.forEach((hook) => {
|
|
55574
|
-
const fullPath =
|
|
57027
|
+
const fullPath = join77(projectHooksDir, hook);
|
|
55575
57028
|
checkedFiles.add(normalizePath(fullPath));
|
|
55576
57029
|
});
|
|
55577
57030
|
}
|
|
@@ -55602,13 +57055,13 @@ async function checkHooksExist(projectDir) {
|
|
|
55602
57055
|
init_paths();
|
|
55603
57056
|
init_registry();
|
|
55604
57057
|
init_logger();
|
|
55605
|
-
import { existsSync as
|
|
57058
|
+
import { existsSync as existsSync39 } from "node:fs";
|
|
55606
57059
|
import { readFile as readFile33 } from "node:fs/promises";
|
|
55607
|
-
import { join as
|
|
57060
|
+
import { join as join78 } from "node:path";
|
|
55608
57061
|
async function checkSettingsValid(projectDir) {
|
|
55609
|
-
const globalSettings =
|
|
55610
|
-
const projectSettings =
|
|
55611
|
-
const settingsPath =
|
|
57062
|
+
const globalSettings = join78(getInstaller("claude-code")?.globalRoot() ?? "", "settings.json");
|
|
57063
|
+
const projectSettings = join78(getLocalClaudeDir(projectDir), "settings.json");
|
|
57064
|
+
const settingsPath = existsSync39(globalSettings) ? globalSettings : existsSync39(projectSettings) ? projectSettings : null;
|
|
55612
57065
|
if (!settingsPath) {
|
|
55613
57066
|
return {
|
|
55614
57067
|
id: "sk-settings-valid",
|
|
@@ -55678,14 +57131,14 @@ async function checkSettingsValid(projectDir) {
|
|
|
55678
57131
|
init_paths();
|
|
55679
57132
|
init_registry();
|
|
55680
57133
|
init_logger();
|
|
55681
|
-
import { existsSync as
|
|
57134
|
+
import { existsSync as existsSync40 } from "node:fs";
|
|
55682
57135
|
import { readFile as readFile34 } from "node:fs/promises";
|
|
55683
|
-
import { homedir as
|
|
55684
|
-
import { dirname as
|
|
57136
|
+
import { homedir as homedir24 } from "node:os";
|
|
57137
|
+
import { dirname as dirname19, join as join79, normalize as normalize6, resolve as resolve17 } from "node:path";
|
|
55685
57138
|
async function checkPathRefsValid(projectDir) {
|
|
55686
|
-
const globalClaudeMd =
|
|
55687
|
-
const projectClaudeMd =
|
|
55688
|
-
const claudeMdPath =
|
|
57139
|
+
const globalClaudeMd = join79(getInstaller("claude-code")?.globalRoot() ?? "", "CLAUDE.md");
|
|
57140
|
+
const projectClaudeMd = join79(getLocalClaudeDir(projectDir), "CLAUDE.md");
|
|
57141
|
+
const claudeMdPath = existsSync40(globalClaudeMd) ? globalClaudeMd : existsSync40(projectClaudeMd) ? projectClaudeMd : null;
|
|
55689
57142
|
if (!claudeMdPath) {
|
|
55690
57143
|
return {
|
|
55691
57144
|
id: "sk-path-refs-valid",
|
|
@@ -55712,8 +57165,8 @@ async function checkPathRefsValid(projectDir) {
|
|
|
55712
57165
|
autoFixable: false
|
|
55713
57166
|
};
|
|
55714
57167
|
}
|
|
55715
|
-
const baseDir =
|
|
55716
|
-
const home6 =
|
|
57168
|
+
const baseDir = dirname19(claudeMdPath);
|
|
57169
|
+
const home6 = homedir24();
|
|
55717
57170
|
const broken = [];
|
|
55718
57171
|
for (const ref of refs) {
|
|
55719
57172
|
let refPath;
|
|
@@ -55728,7 +57181,7 @@ async function checkPathRefsValid(projectDir) {
|
|
|
55728
57181
|
} else if (/^[A-Za-z]:/.test(ref)) {
|
|
55729
57182
|
refPath = normalize6(ref);
|
|
55730
57183
|
} else {
|
|
55731
|
-
refPath =
|
|
57184
|
+
refPath = resolve17(baseDir, ref);
|
|
55732
57185
|
}
|
|
55733
57186
|
const normalizedPath = normalize6(refPath);
|
|
55734
57187
|
const isWithinHome = normalizedPath.startsWith(home6);
|
|
@@ -55738,7 +57191,7 @@ async function checkPathRefsValid(projectDir) {
|
|
|
55738
57191
|
logger.verbose("Skipping potentially unsafe path reference", { ref, refPath });
|
|
55739
57192
|
continue;
|
|
55740
57193
|
}
|
|
55741
|
-
if (!
|
|
57194
|
+
if (!existsSync40(normalizedPath)) {
|
|
55742
57195
|
broken.push(ref);
|
|
55743
57196
|
}
|
|
55744
57197
|
}
|
|
@@ -55778,9 +57231,9 @@ async function checkPathRefsValid(projectDir) {
|
|
|
55778
57231
|
}
|
|
55779
57232
|
// src/domains/health-checks/checkers/config-completeness-checker.ts
|
|
55780
57233
|
init_paths();
|
|
55781
|
-
import { existsSync as
|
|
57234
|
+
import { existsSync as existsSync41 } from "node:fs";
|
|
55782
57235
|
import { readdir as readdir24 } from "node:fs/promises";
|
|
55783
|
-
import { join as
|
|
57236
|
+
import { join as join80 } from "node:path";
|
|
55784
57237
|
async function checkProjectConfigCompleteness(setup, projectDir) {
|
|
55785
57238
|
if (setup.globals.some((g2) => g2.path === setup.project.path)) {
|
|
55786
57239
|
return {
|
|
@@ -55797,12 +57250,12 @@ async function checkProjectConfigCompleteness(setup, projectDir) {
|
|
|
55797
57250
|
const requiredDirs = ["agents", "commands", "skills"];
|
|
55798
57251
|
const missingDirs = [];
|
|
55799
57252
|
for (const dir of requiredDirs) {
|
|
55800
|
-
const dirPath =
|
|
55801
|
-
if (!
|
|
57253
|
+
const dirPath = join80(projectClaudeDir, dir);
|
|
57254
|
+
if (!existsSync41(dirPath)) {
|
|
55802
57255
|
missingDirs.push(dir);
|
|
55803
57256
|
}
|
|
55804
57257
|
}
|
|
55805
|
-
const hasRulesOrWorkflows =
|
|
57258
|
+
const hasRulesOrWorkflows = existsSync41(join80(projectClaudeDir, "rules")) || existsSync41(join80(projectClaudeDir, "workflows"));
|
|
55806
57259
|
if (!hasRulesOrWorkflows) {
|
|
55807
57260
|
missingDirs.push("rules");
|
|
55808
57261
|
}
|
|
@@ -55899,16 +57352,16 @@ import { spawnSync as spawnSync3 } from "node:child_process";
|
|
|
55899
57352
|
// src/domains/installation/git-clone-manager.ts
|
|
55900
57353
|
init_logger();
|
|
55901
57354
|
import { execSync as execSync3 } from "node:child_process";
|
|
55902
|
-
import * as
|
|
55903
|
-
import * as
|
|
55904
|
-
import * as
|
|
57355
|
+
import * as fs12 from "node:fs";
|
|
57356
|
+
import * as os6 from "node:os";
|
|
57357
|
+
import * as path9 from "node:path";
|
|
55905
57358
|
var VALID_TAG_PATTERN = /^[a-zA-Z0-9._+\-]+$/;
|
|
55906
57359
|
|
|
55907
57360
|
class GitCloneManager {
|
|
55908
57361
|
tempBaseDir;
|
|
55909
57362
|
constructor() {
|
|
55910
57363
|
const homeDir = process.env.HOME || process.env.USERPROFILE;
|
|
55911
|
-
this.tempBaseDir = process.env.TMPDIR || process.env.TEMP || process.env.TMP || (homeDir ?
|
|
57364
|
+
this.tempBaseDir = process.env.TMPDIR || process.env.TEMP || process.env.TMP || (homeDir ? path9.join(homeDir, ".sunagentkit", "tmp") : null) || path9.join(os6.tmpdir(), ".sunagentkit", "tmp");
|
|
55912
57365
|
}
|
|
55913
57366
|
validateTag(tag) {
|
|
55914
57367
|
if (!VALID_TAG_PATTERN.test(tag)) {
|
|
@@ -55921,7 +57374,7 @@ Tags must contain only letters, numbers, dots, hyphens, underscores, and plus si
|
|
|
55921
57374
|
const { kit, tag, preferSsh = true, timeout = 60000 } = options2;
|
|
55922
57375
|
this.validateTag(tag);
|
|
55923
57376
|
try {
|
|
55924
|
-
await
|
|
57377
|
+
await fs12.promises.mkdir(this.tempBaseDir, { recursive: true });
|
|
55925
57378
|
} catch (error) {
|
|
55926
57379
|
const msg = error instanceof Error ? error.message : String(error);
|
|
55927
57380
|
throw new Error(`Failed to create temp directory: ${this.tempBaseDir}
|
|
@@ -55929,7 +57382,7 @@ Error: ${msg}
|
|
|
55929
57382
|
|
|
55930
57383
|
Check disk space and directory permissions.`);
|
|
55931
57384
|
}
|
|
55932
|
-
const tempDir = await
|
|
57385
|
+
const tempDir = await fs12.promises.mkdtemp(path9.join(this.tempBaseDir, `sk-git-${kit.repo}-`));
|
|
55933
57386
|
const url = preferSsh ? `git@github.com:${kit.owner}/${kit.repo}.git` : `https://github.com/${kit.owner}/${kit.repo}.git`;
|
|
55934
57387
|
const method = preferSsh ? "ssh" : "https";
|
|
55935
57388
|
logger.verbose("Git clone", { url, tag, tempDir, method });
|
|
@@ -55946,8 +57399,8 @@ Check disk space and directory permissions.`);
|
|
|
55946
57399
|
const stderr = shallowError?.stderr || "";
|
|
55947
57400
|
if (stderr.includes("Could not find remote branch") || stderr.includes("fatal: Remote branch") || stderr.includes("warning: Could not find remote branch")) {
|
|
55948
57401
|
logger.debug(`Shallow clone failed for tag ${tag}, trying full clone...`);
|
|
55949
|
-
await
|
|
55950
|
-
await
|
|
57402
|
+
await fs12.promises.rm(tempDir, { recursive: true, force: true }).catch(() => {});
|
|
57403
|
+
await fs12.promises.mkdir(tempDir, { recursive: true });
|
|
55951
57404
|
execSync3(`git clone --no-checkout ${quotedUrl} ${quotedDir}`, {
|
|
55952
57405
|
stdio: ["pipe", "pipe", "pipe"],
|
|
55953
57406
|
timeout,
|
|
@@ -55962,8 +57415,8 @@ Check disk space and directory permissions.`);
|
|
|
55962
57415
|
throw shallowError;
|
|
55963
57416
|
}
|
|
55964
57417
|
}
|
|
55965
|
-
const gitDir =
|
|
55966
|
-
await
|
|
57418
|
+
const gitDir = path9.join(tempDir, ".git");
|
|
57419
|
+
await fs12.promises.rm(gitDir, { recursive: true, force: true });
|
|
55967
57420
|
logger.debug(`Git clone successful: ${tempDir}`);
|
|
55968
57421
|
return {
|
|
55969
57422
|
cloneDir: tempDir,
|
|
@@ -55971,7 +57424,7 @@ Check disk space and directory permissions.`);
|
|
|
55971
57424
|
method
|
|
55972
57425
|
};
|
|
55973
57426
|
} catch (error) {
|
|
55974
|
-
await
|
|
57427
|
+
await fs12.promises.rm(tempDir, { recursive: true, force: true }).catch((err) => logger.debug(`Failed to cleanup temp dir ${tempDir}: ${err.message}`));
|
|
55975
57428
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
55976
57429
|
const stderr = error?.stderr || "";
|
|
55977
57430
|
const errorCode = error?.code;
|
|
@@ -56011,13 +57464,13 @@ Ensure you have access to the repository and your git credentials are configured
|
|
|
56011
57464
|
const homeDir = process.env.HOME || process.env.USERPROFILE;
|
|
56012
57465
|
if (!homeDir)
|
|
56013
57466
|
return false;
|
|
56014
|
-
const sshDir =
|
|
57467
|
+
const sshDir = path9.join(homeDir, ".ssh");
|
|
56015
57468
|
const keyFiles = ["id_rsa", "id_ed25519", "id_ecdsa", "id_rsa.pub", "id_ed25519.pub"];
|
|
56016
57469
|
try {
|
|
56017
|
-
if (!
|
|
57470
|
+
if (!fs12.existsSync(sshDir))
|
|
56018
57471
|
return false;
|
|
56019
57472
|
for (const keyFile of keyFiles) {
|
|
56020
|
-
if (
|
|
57473
|
+
if (fs12.existsSync(path9.join(sshDir, keyFile))) {
|
|
56021
57474
|
return true;
|
|
56022
57475
|
}
|
|
56023
57476
|
}
|
|
@@ -56240,16 +57693,16 @@ import { platform as platform7 } from "node:os";
|
|
|
56240
57693
|
init_registry();
|
|
56241
57694
|
init_environment();
|
|
56242
57695
|
import { constants as constants2, access as access2, mkdir as mkdir19, readFile as readFile35, unlink as unlink8, writeFile as writeFile24 } from "node:fs/promises";
|
|
56243
|
-
import { arch as arch2, homedir as
|
|
56244
|
-
import { join as
|
|
57696
|
+
import { arch as arch2, homedir as homedir25, platform as platform6 } from "node:os";
|
|
57697
|
+
import { join as join82, normalize as normalize7 } from "node:path";
|
|
56245
57698
|
function shouldSkipExpensiveOperations4() {
|
|
56246
57699
|
return shouldSkipExpensiveOperations();
|
|
56247
57700
|
}
|
|
56248
57701
|
async function checkPlatformDetect() {
|
|
56249
|
-
const
|
|
57702
|
+
const os7 = platform6();
|
|
56250
57703
|
const architecture = arch2();
|
|
56251
57704
|
const wslDistro = process.env.WSL_DISTRO_NAME;
|
|
56252
|
-
let message = `${
|
|
57705
|
+
let message = `${os7} (${architecture})`;
|
|
56253
57706
|
if (wslDistro)
|
|
56254
57707
|
message += ` - WSL: ${wslDistro}`;
|
|
56255
57708
|
return {
|
|
@@ -56263,7 +57716,7 @@ async function checkPlatformDetect() {
|
|
|
56263
57716
|
};
|
|
56264
57717
|
}
|
|
56265
57718
|
async function checkHomeDirResolution() {
|
|
56266
|
-
const nodeHome = normalize7(
|
|
57719
|
+
const nodeHome = normalize7(homedir25());
|
|
56267
57720
|
const rawEnvHome = getHomeDirectoryFromEnv(platform6());
|
|
56268
57721
|
const envHome = rawEnvHome ? normalize7(rawEnvHome) : "";
|
|
56269
57722
|
const match2 = nodeHome === envHome && envHome !== "";
|
|
@@ -56334,7 +57787,7 @@ async function checkGlobalDirAccess(provider) {
|
|
|
56334
57787
|
autoFixable: false
|
|
56335
57788
|
};
|
|
56336
57789
|
}
|
|
56337
|
-
const testFile =
|
|
57790
|
+
const testFile = join82(globalDir, ".sk-doctor-access-test");
|
|
56338
57791
|
try {
|
|
56339
57792
|
await mkdir19(globalDir, { recursive: true });
|
|
56340
57793
|
await writeFile24(testFile, "test", "utf-8");
|
|
@@ -56412,7 +57865,7 @@ async function checkWSLBoundary() {
|
|
|
56412
57865
|
// src/domains/health-checks/platform/windows-checker.ts
|
|
56413
57866
|
init_registry();
|
|
56414
57867
|
import { mkdir as mkdir20, symlink as symlink2, unlink as unlink9, writeFile as writeFile25 } from "node:fs/promises";
|
|
56415
|
-
import { join as
|
|
57868
|
+
import { join as join83 } from "node:path";
|
|
56416
57869
|
async function checkLongPathSupport() {
|
|
56417
57870
|
if (shouldSkipExpensiveOperations4()) {
|
|
56418
57871
|
return {
|
|
@@ -56464,8 +57917,8 @@ async function checkSymlinkSupport() {
|
|
|
56464
57917
|
};
|
|
56465
57918
|
}
|
|
56466
57919
|
const testDir = getInstaller("claude-code")?.globalRoot() ?? "";
|
|
56467
|
-
const target =
|
|
56468
|
-
const link =
|
|
57920
|
+
const target = join83(testDir, ".sk-symlink-test-target");
|
|
57921
|
+
const link = join83(testDir, ".sk-symlink-test-link");
|
|
56469
57922
|
try {
|
|
56470
57923
|
await mkdir20(testDir, { recursive: true });
|
|
56471
57924
|
await writeFile25(target, "test", "utf-8");
|
|
@@ -56721,11 +58174,11 @@ class AutoHealer {
|
|
|
56721
58174
|
duration: 0
|
|
56722
58175
|
};
|
|
56723
58176
|
}
|
|
56724
|
-
const
|
|
58177
|
+
const start2 = Date.now();
|
|
56725
58178
|
try {
|
|
56726
58179
|
const result = await Promise.race([fix.execute(), this.createTimeout()]);
|
|
56727
58180
|
const attempt = this.buildAttempt(check, fix.id, result);
|
|
56728
|
-
attempt.duration = Date.now() -
|
|
58181
|
+
attempt.duration = Date.now() - start2;
|
|
56729
58182
|
return attempt;
|
|
56730
58183
|
} catch (e2) {
|
|
56731
58184
|
const err = e2 instanceof Error ? e2.message : "Unknown error";
|
|
@@ -56736,7 +58189,7 @@ class AutoHealer {
|
|
|
56736
58189
|
success: false,
|
|
56737
58190
|
message: "Fix failed",
|
|
56738
58191
|
error: err,
|
|
56739
|
-
duration: Date.now() -
|
|
58192
|
+
duration: Date.now() - start2
|
|
56740
58193
|
};
|
|
56741
58194
|
}
|
|
56742
58195
|
}
|
|
@@ -56759,18 +58212,18 @@ class AutoHealer {
|
|
|
56759
58212
|
}
|
|
56760
58213
|
// src/domains/health-checks/report-generator.ts
|
|
56761
58214
|
import { execSync as execSync4, spawnSync as spawnSync4 } from "node:child_process";
|
|
56762
|
-
import { readFileSync as
|
|
58215
|
+
import { readFileSync as readFileSync11, unlinkSync as unlinkSync4, writeFileSync as writeFileSync6 } from "node:fs";
|
|
56763
58216
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
56764
|
-
import { dirname as
|
|
58217
|
+
import { dirname as dirname20, join as join84 } from "node:path";
|
|
56765
58218
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
56766
58219
|
init_environment();
|
|
56767
58220
|
init_logger();
|
|
56768
58221
|
init_dist2();
|
|
56769
58222
|
function getCliVersion3() {
|
|
56770
58223
|
try {
|
|
56771
|
-
const __dirname3 =
|
|
56772
|
-
const pkgPath =
|
|
56773
|
-
const pkg = JSON.parse(
|
|
58224
|
+
const __dirname3 = dirname20(fileURLToPath2(import.meta.url));
|
|
58225
|
+
const pkgPath = join84(__dirname3, "../../../package.json");
|
|
58226
|
+
const pkg = JSON.parse(readFileSync11(pkgPath, "utf-8"));
|
|
56774
58227
|
return pkg.version || "unknown";
|
|
56775
58228
|
} catch (err) {
|
|
56776
58229
|
logger.debug(`Failed to read CLI version: ${err}`);
|
|
@@ -56908,7 +58361,7 @@ class ReportGenerator {
|
|
|
56908
58361
|
return null;
|
|
56909
58362
|
}
|
|
56910
58363
|
}
|
|
56911
|
-
const tmpFile =
|
|
58364
|
+
const tmpFile = join84(tmpdir2(), `sk-report-${Date.now()}.txt`);
|
|
56912
58365
|
writeFileSync6(tmpFile, report);
|
|
56913
58366
|
try {
|
|
56914
58367
|
const result = spawnSync4("gh", ["gist", "create", tmpFile, "--desc", "Takumi Diagnostic Report"], {
|
|
@@ -56939,9 +58392,9 @@ class ReportGenerator {
|
|
|
56939
58392
|
cliVersion: getCliVersion3()
|
|
56940
58393
|
};
|
|
56941
58394
|
}
|
|
56942
|
-
scrubPath(
|
|
58395
|
+
scrubPath(path10) {
|
|
56943
58396
|
const home6 = process.env.HOME || process.env.USERPROFILE || "";
|
|
56944
|
-
return home6 ?
|
|
58397
|
+
return home6 ? path10.replace(home6, "~") : path10;
|
|
56945
58398
|
}
|
|
56946
58399
|
getStatusIcon(status2) {
|
|
56947
58400
|
switch (status2) {
|
|
@@ -57054,14 +58507,14 @@ class DoctorUIRenderer {
|
|
|
57054
58507
|
return message;
|
|
57055
58508
|
}
|
|
57056
58509
|
}
|
|
57057
|
-
shortenPath(
|
|
58510
|
+
shortenPath(path10) {
|
|
57058
58511
|
const home6 = process.env.HOME || process.env.USERPROFILE || "";
|
|
57059
|
-
let shortened = home6 ?
|
|
58512
|
+
let shortened = home6 ? path10.replace(home6, "~") : path10;
|
|
57060
58513
|
const maxLen = 50;
|
|
57061
58514
|
if (shortened.length > maxLen) {
|
|
57062
|
-
const
|
|
58515
|
+
const start2 = shortened.slice(0, 20);
|
|
57063
58516
|
const end = shortened.slice(-27);
|
|
57064
|
-
shortened = `${
|
|
58517
|
+
shortened = `${start2}...${end}`;
|
|
57065
58518
|
}
|
|
57066
58519
|
return shortened;
|
|
57067
58520
|
}
|
|
@@ -57220,14 +58673,14 @@ async function authedFetch(url, init) {
|
|
|
57220
58673
|
|
|
57221
58674
|
// src/commands/hooks/lib/detached-put.ts
|
|
57222
58675
|
import { spawn as spawn2 } from "node:child_process";
|
|
57223
|
-
import { openSync } from "node:fs";
|
|
57224
|
-
import { dirname as
|
|
58676
|
+
import { openSync as openSync4 } from "node:fs";
|
|
58677
|
+
import { dirname as dirname21, join as join85 } from "node:path";
|
|
57225
58678
|
|
|
57226
58679
|
// src/commands/hooks/lib/hook-logger.ts
|
|
57227
58680
|
import { appendFileSync } from "node:fs";
|
|
57228
58681
|
var extraLogPath = null;
|
|
57229
|
-
function setHookDebugLog(
|
|
57230
|
-
extraLogPath =
|
|
58682
|
+
function setHookDebugLog(path10) {
|
|
58683
|
+
extraLogPath = path10 && path10.trim().length > 0 ? path10 : null;
|
|
57231
58684
|
}
|
|
57232
58685
|
function formatValue(v2) {
|
|
57233
58686
|
if (v2 === null || v2 === undefined)
|
|
@@ -57268,7 +58721,7 @@ function effectiveDetachMode(flags) {
|
|
|
57268
58721
|
return flags.noDetach ? "inline" : "detached";
|
|
57269
58722
|
}
|
|
57270
58723
|
function sessionDebugLogPath(sessionDir) {
|
|
57271
|
-
return
|
|
58724
|
+
return join85(sessionDir, DETACH_DEBUG_LOG_NAME);
|
|
57272
58725
|
}
|
|
57273
58726
|
var BUNFS_PREFIX = "/$bunfs/";
|
|
57274
58727
|
function resolveInvocationPrefix() {
|
|
@@ -57296,9 +58749,9 @@ function resolveInvocationPrefix() {
|
|
|
57296
58749
|
}
|
|
57297
58750
|
function resolvePreloadScript(entryPath) {
|
|
57298
58751
|
try {
|
|
57299
|
-
const srcDir =
|
|
57300
|
-
const repoRoot =
|
|
57301
|
-
return
|
|
58752
|
+
const srcDir = dirname21(entryPath);
|
|
58753
|
+
const repoRoot = dirname21(srcDir);
|
|
58754
|
+
return join85(repoRoot, "scripts", "preload-config-override.ts");
|
|
57302
58755
|
} catch {
|
|
57303
58756
|
return null;
|
|
57304
58757
|
}
|
|
@@ -57322,7 +58775,7 @@ function buildChildStdio(job) {
|
|
|
57322
58775
|
if (!job.debug)
|
|
57323
58776
|
return "ignore";
|
|
57324
58777
|
try {
|
|
57325
|
-
const fd =
|
|
58778
|
+
const fd = openSync4(sessionDebugLogPath(job.sessionDir), "a");
|
|
57326
58779
|
return ["ignore", fd, fd];
|
|
57327
58780
|
} catch {
|
|
57328
58781
|
return "ignore";
|
|
@@ -57366,17 +58819,17 @@ function decodeJobArgv(argv) {
|
|
|
57366
58819
|
}
|
|
57367
58820
|
|
|
57368
58821
|
// src/commands/hooks/lib/throttle.ts
|
|
57369
|
-
import { promises as
|
|
58822
|
+
import { promises as fs13 } from "node:fs";
|
|
57370
58823
|
|
|
57371
58824
|
// src/commands/hooks/lib/session-paths.ts
|
|
57372
58825
|
init_paths2();
|
|
57373
|
-
import { join as
|
|
58826
|
+
import { join as join87 } from "node:path";
|
|
57374
58827
|
|
|
57375
58828
|
// src/commands/hooks/lib/project-paths.ts
|
|
57376
58829
|
init_paths2();
|
|
57377
58830
|
import { createHash as createHash8 } from "node:crypto";
|
|
57378
58831
|
import { realpathSync as realpathSync2 } from "node:fs";
|
|
57379
|
-
import { basename as
|
|
58832
|
+
import { basename as basename12, join as join86 } from "node:path";
|
|
57380
58833
|
function encodeCwd(cwd2) {
|
|
57381
58834
|
const stripped = cwd2.replace(/^\/+/, "");
|
|
57382
58835
|
const sanitized = stripped.replace(/[^a-zA-Z0-9-]/g, "-");
|
|
@@ -57392,13 +58845,13 @@ function computeProjectHash(cwd2) {
|
|
|
57392
58845
|
return createHash8("sha256").update(canonical).digest("hex").slice(0, 16);
|
|
57393
58846
|
}
|
|
57394
58847
|
function getProjectLabel(cwd2) {
|
|
57395
|
-
return
|
|
58848
|
+
return basename12(cwd2) || "";
|
|
57396
58849
|
}
|
|
57397
58850
|
function getProjectsRoot() {
|
|
57398
|
-
return
|
|
58851
|
+
return join86(getConfigDir(), "projects");
|
|
57399
58852
|
}
|
|
57400
58853
|
function getProjectDir(args) {
|
|
57401
|
-
return
|
|
58854
|
+
return join86(getProjectsRoot(), encodeCwd(args.cwd), args.agent);
|
|
57402
58855
|
}
|
|
57403
58856
|
|
|
57404
58857
|
// src/commands/hooks/lib/session-paths.ts
|
|
@@ -57410,25 +58863,25 @@ function safeSessionSegment(sessionId) {
|
|
|
57410
58863
|
return cleaned.length > 0 ? cleaned.slice(0, MAX_SESSION_ID_LEN) : null;
|
|
57411
58864
|
}
|
|
57412
58865
|
function getSessionsRoot() {
|
|
57413
|
-
return
|
|
58866
|
+
return join87(getConfigDir(), "sessions");
|
|
57414
58867
|
}
|
|
57415
58868
|
function getSessionDirV2(args) {
|
|
57416
58869
|
const segment = safeSessionSegment(args.sessionId);
|
|
57417
58870
|
if (!segment)
|
|
57418
58871
|
return null;
|
|
57419
|
-
return
|
|
58872
|
+
return join87(getProjectDir({ agent: args.agent, cwd: args.cwd }), "sessions", segment);
|
|
57420
58873
|
}
|
|
57421
58874
|
function getEventsFile(sessionDir) {
|
|
57422
|
-
return
|
|
58875
|
+
return join87(sessionDir, "events.jsonl");
|
|
57423
58876
|
}
|
|
57424
58877
|
function getSummaryFile(sessionDir) {
|
|
57425
|
-
return
|
|
58878
|
+
return join87(sessionDir, "summary.json");
|
|
57426
58879
|
}
|
|
57427
58880
|
function getLastPushFile(sessionDir) {
|
|
57428
|
-
return
|
|
58881
|
+
return join87(sessionDir, "last_push.txt");
|
|
57429
58882
|
}
|
|
57430
58883
|
function getMetaFile(sessionDir) {
|
|
57431
|
-
return
|
|
58884
|
+
return join87(sessionDir, "meta.json");
|
|
57432
58885
|
}
|
|
57433
58886
|
|
|
57434
58887
|
// src/commands/hooks/lib/throttle.ts
|
|
@@ -57436,7 +58889,7 @@ var defaultNow = () => Date.now();
|
|
|
57436
58889
|
async function readLastPush(sessionDir) {
|
|
57437
58890
|
let raw;
|
|
57438
58891
|
try {
|
|
57439
|
-
raw = await
|
|
58892
|
+
raw = await fs13.readFile(getLastPushFile(sessionDir), "utf8");
|
|
57440
58893
|
} catch {
|
|
57441
58894
|
return null;
|
|
57442
58895
|
}
|
|
@@ -57444,11 +58897,11 @@ async function readLastPush(sessionDir) {
|
|
|
57444
58897
|
return Number.isFinite(parsed) ? parsed : null;
|
|
57445
58898
|
}
|
|
57446
58899
|
async function writeLastPush(sessionDir, ts) {
|
|
57447
|
-
await
|
|
58900
|
+
await fs13.mkdir(sessionDir, { recursive: true });
|
|
57448
58901
|
const target = getLastPushFile(sessionDir);
|
|
57449
58902
|
const tmp = `${target}.tmp`;
|
|
57450
|
-
await
|
|
57451
|
-
await
|
|
58903
|
+
await fs13.writeFile(tmp, String(ts), "utf8");
|
|
58904
|
+
await fs13.rename(tmp, target);
|
|
57452
58905
|
}
|
|
57453
58906
|
async function shouldFlush(args) {
|
|
57454
58907
|
const now = args.now ?? defaultNow;
|
|
@@ -57458,7 +58911,7 @@ async function shouldFlush(args) {
|
|
|
57458
58911
|
if (now() - last >= args.intervalMs)
|
|
57459
58912
|
return true;
|
|
57460
58913
|
try {
|
|
57461
|
-
const stat8 = await
|
|
58914
|
+
const stat8 = await fs13.stat(getEventsFile(args.sessionDir));
|
|
57462
58915
|
if (stat8.size >= args.sizeBytes)
|
|
57463
58916
|
return true;
|
|
57464
58917
|
} catch {}
|
|
@@ -57500,22 +58953,22 @@ async function handleDoPut() {
|
|
|
57500
58953
|
}
|
|
57501
58954
|
|
|
57502
58955
|
// src/commands/hooks/lib/buffer.ts
|
|
57503
|
-
import { promises as
|
|
58956
|
+
import { promises as fs14 } from "node:fs";
|
|
57504
58957
|
async function appendEvent(sessionDir, event) {
|
|
57505
58958
|
try {
|
|
57506
|
-
await
|
|
58959
|
+
await fs14.mkdir(sessionDir, { recursive: true });
|
|
57507
58960
|
const line = `${JSON.stringify(event)}
|
|
57508
58961
|
`;
|
|
57509
|
-
await
|
|
58962
|
+
await fs14.appendFile(getEventsFile(sessionDir), line, "utf8");
|
|
57510
58963
|
} catch {}
|
|
57511
58964
|
}
|
|
57512
58965
|
|
|
57513
58966
|
// src/commands/hooks/lib/session-meta.ts
|
|
57514
|
-
import { promises as
|
|
58967
|
+
import { promises as fs15 } from "node:fs";
|
|
57515
58968
|
async function readMeta(sessionDir) {
|
|
57516
58969
|
let raw;
|
|
57517
58970
|
try {
|
|
57518
|
-
raw = await
|
|
58971
|
+
raw = await fs15.readFile(getMetaFile(sessionDir), "utf8");
|
|
57519
58972
|
} catch {
|
|
57520
58973
|
return null;
|
|
57521
58974
|
}
|
|
@@ -57528,17 +58981,17 @@ async function readMeta(sessionDir) {
|
|
|
57528
58981
|
async function writeMetaIfAbsent(sessionDir, meta) {
|
|
57529
58982
|
const target = getMetaFile(sessionDir);
|
|
57530
58983
|
try {
|
|
57531
|
-
await
|
|
58984
|
+
await fs15.access(target);
|
|
57532
58985
|
return;
|
|
57533
58986
|
} catch {}
|
|
57534
|
-
await
|
|
58987
|
+
await fs15.mkdir(sessionDir, { recursive: true });
|
|
57535
58988
|
const tmp = `${target}.tmp`;
|
|
57536
|
-
await
|
|
57537
|
-
await
|
|
58989
|
+
await fs15.writeFile(tmp, JSON.stringify(meta), "utf8");
|
|
58990
|
+
await fs15.rename(tmp, target);
|
|
57538
58991
|
}
|
|
57539
58992
|
|
|
57540
58993
|
// src/commands/hooks/lib/summary.ts
|
|
57541
|
-
import { promises as
|
|
58994
|
+
import { promises as fs16 } from "node:fs";
|
|
57542
58995
|
function zeroTokens() {
|
|
57543
58996
|
return { input: 0, output: 0, cache_read: 0, cache_write: 0 };
|
|
57544
58997
|
}
|
|
@@ -57573,7 +59026,7 @@ function initialSummary(args) {
|
|
|
57573
59026
|
async function readSummary(sessionDir) {
|
|
57574
59027
|
let raw;
|
|
57575
59028
|
try {
|
|
57576
|
-
raw = await
|
|
59029
|
+
raw = await fs16.readFile(getSummaryFile(sessionDir), "utf8");
|
|
57577
59030
|
} catch {
|
|
57578
59031
|
return null;
|
|
57579
59032
|
}
|
|
@@ -57584,11 +59037,11 @@ async function readSummary(sessionDir) {
|
|
|
57584
59037
|
}
|
|
57585
59038
|
}
|
|
57586
59039
|
async function writeSummary(sessionDir, summary) {
|
|
57587
|
-
await
|
|
59040
|
+
await fs16.mkdir(sessionDir, { recursive: true });
|
|
57588
59041
|
const target = getSummaryFile(sessionDir);
|
|
57589
59042
|
const tmp = `${target}.tmp`;
|
|
57590
|
-
await
|
|
57591
|
-
await
|
|
59043
|
+
await fs16.writeFile(tmp, JSON.stringify(summary), "utf8");
|
|
59044
|
+
await fs16.rename(tmp, target);
|
|
57592
59045
|
}
|
|
57593
59046
|
function isPlainObject2(value) {
|
|
57594
59047
|
return typeof value === "object" && value !== null && !Array.isArray(value) && (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null);
|
|
@@ -57665,14 +59118,14 @@ async function recordEvent(args) {
|
|
|
57665
59118
|
}
|
|
57666
59119
|
|
|
57667
59120
|
// src/commands/hooks/lib/transcript-reader.ts
|
|
57668
|
-
import { promises as
|
|
59121
|
+
import { promises as fs17 } from "node:fs";
|
|
57669
59122
|
function num(v2) {
|
|
57670
59123
|
return typeof v2 === "number" && Number.isFinite(v2) ? v2 : 0;
|
|
57671
59124
|
}
|
|
57672
59125
|
function zeroTokens2() {
|
|
57673
59126
|
return { input: 0, output: 0, cache_read: 0, cache_write: 0 };
|
|
57674
59127
|
}
|
|
57675
|
-
function
|
|
59128
|
+
function addTokens2(a3, b3) {
|
|
57676
59129
|
return {
|
|
57677
59130
|
input: a3.input + b3.input,
|
|
57678
59131
|
output: a3.output + b3.output,
|
|
@@ -57694,7 +59147,7 @@ function extractTokens(record) {
|
|
|
57694
59147
|
async function tailRead(args) {
|
|
57695
59148
|
let stat8;
|
|
57696
59149
|
try {
|
|
57697
|
-
stat8 = await
|
|
59150
|
+
stat8 = await fs17.stat(args.transcriptPath);
|
|
57698
59151
|
} catch {
|
|
57699
59152
|
return { records: [], nextOffset: args.offset };
|
|
57700
59153
|
}
|
|
@@ -57702,7 +59155,7 @@ async function tailRead(args) {
|
|
|
57702
59155
|
if (currentSize <= args.offset) {
|
|
57703
59156
|
return { records: [], nextOffset: currentSize };
|
|
57704
59157
|
}
|
|
57705
|
-
const handle = await
|
|
59158
|
+
const handle = await fs17.open(args.transcriptPath, "r");
|
|
57706
59159
|
try {
|
|
57707
59160
|
const length = currentSize - args.offset;
|
|
57708
59161
|
const buf = Buffer.alloc(length);
|
|
@@ -57736,13 +59189,13 @@ function bucketTokens(records) {
|
|
|
57736
59189
|
const key = record.agentId ?? record.toolUseID;
|
|
57737
59190
|
if (!key) {
|
|
57738
59191
|
const prev2 = mainLoopDelta;
|
|
57739
|
-
Object.assign(mainLoopDelta,
|
|
59192
|
+
Object.assign(mainLoopDelta, addTokens2(prev2, tokens));
|
|
57740
59193
|
continue;
|
|
57741
59194
|
}
|
|
57742
59195
|
const prev = subagentDeltas.get(key) ?? zeroTokens2();
|
|
57743
|
-
subagentDeltas.set(key,
|
|
59196
|
+
subagentDeltas.set(key, addTokens2(prev, tokens));
|
|
57744
59197
|
} else {
|
|
57745
|
-
Object.assign(mainLoopDelta,
|
|
59198
|
+
Object.assign(mainLoopDelta, addTokens2(mainLoopDelta, tokens));
|
|
57746
59199
|
}
|
|
57747
59200
|
}
|
|
57748
59201
|
return { mainLoopDelta, subagentDeltas };
|
|
@@ -57752,7 +59205,7 @@ function bucketTokens(records) {
|
|
|
57752
59205
|
function ensureTokens(t) {
|
|
57753
59206
|
return t ?? { input: 0, output: 0, cache_read: 0, cache_write: 0 };
|
|
57754
59207
|
}
|
|
57755
|
-
function
|
|
59208
|
+
function addTokens3(a3, b3) {
|
|
57756
59209
|
return {
|
|
57757
59210
|
input: a3.input + b3.input,
|
|
57758
59211
|
output: a3.output + b3.output,
|
|
@@ -57775,12 +59228,12 @@ async function applyTranscriptDelta(args) {
|
|
|
57775
59228
|
const { mainLoopDelta, subagentDeltas } = bucketTokens(records);
|
|
57776
59229
|
const updated = {
|
|
57777
59230
|
...args.summary,
|
|
57778
|
-
main_loop_tokens:
|
|
59231
|
+
main_loop_tokens: addTokens3(args.summary.main_loop_tokens, mainLoopDelta),
|
|
57779
59232
|
subagents: args.summary.subagents.map((rec) => {
|
|
57780
59233
|
const delta = subagentDeltas.get(rec.id);
|
|
57781
59234
|
if (!delta)
|
|
57782
59235
|
return rec;
|
|
57783
|
-
return { ...rec, tokens:
|
|
59236
|
+
return { ...rec, tokens: addTokens3(ensureTokens(rec.tokens), delta) };
|
|
57784
59237
|
}),
|
|
57785
59238
|
transcript_offset: nextOffset
|
|
57786
59239
|
};
|
|
@@ -58035,25 +59488,25 @@ init_takumi_constants();
|
|
|
58035
59488
|
|
|
58036
59489
|
// src/commands/hooks/lib/endpoint.ts
|
|
58037
59490
|
init_build_config();
|
|
58038
|
-
function
|
|
59491
|
+
function stripTrailingSlash2(u) {
|
|
58039
59492
|
return u.replace(/\/+$/, "");
|
|
58040
59493
|
}
|
|
58041
59494
|
function resolveEndpoint() {
|
|
58042
59495
|
if (!SERVER_URL)
|
|
58043
59496
|
return null;
|
|
58044
|
-
return { url:
|
|
59497
|
+
return { url: stripTrailingSlash2(SERVER_URL) };
|
|
58045
59498
|
}
|
|
58046
59499
|
|
|
58047
59500
|
// src/commands/hooks/lib/manifest-versions.ts
|
|
58048
59501
|
init_manifest_path_resolver();
|
|
58049
|
-
import { existsSync as
|
|
58050
|
-
import { homedir as
|
|
58051
|
-
import { dirname as
|
|
59502
|
+
import { existsSync as existsSync43, readFileSync as readFileSync12 } from "node:fs";
|
|
59503
|
+
import { homedir as homedir26 } from "node:os";
|
|
59504
|
+
import { dirname as dirname22, join as join88, resolve as resolve18 } from "node:path";
|
|
58052
59505
|
var PROVIDER_DIRS = [".claude", ".codex"];
|
|
58053
59506
|
var MAX_WALK = 6;
|
|
58054
|
-
function readManifestRaw(
|
|
59507
|
+
function readManifestRaw(path10) {
|
|
58055
59508
|
try {
|
|
58056
|
-
const raw =
|
|
59509
|
+
const raw = readFileSync12(path10, "utf8");
|
|
58057
59510
|
return JSON.parse(raw);
|
|
58058
59511
|
} catch {
|
|
58059
59512
|
return null;
|
|
@@ -58064,28 +59517,28 @@ function findManifestInProviderDir(providerRoot) {
|
|
|
58064
59517
|
return resolved?.path ?? null;
|
|
58065
59518
|
}
|
|
58066
59519
|
function findManifest(cwd2) {
|
|
58067
|
-
let dir =
|
|
59520
|
+
let dir = resolve18(cwd2);
|
|
58068
59521
|
for (let i = 0;i < MAX_WALK; i++) {
|
|
58069
59522
|
for (const provider of PROVIDER_DIRS) {
|
|
58070
|
-
const providerRoot =
|
|
58071
|
-
if (
|
|
58072
|
-
const
|
|
58073
|
-
if (
|
|
58074
|
-
return
|
|
59523
|
+
const providerRoot = join88(dir, provider);
|
|
59524
|
+
if (existsSync43(providerRoot)) {
|
|
59525
|
+
const path10 = findManifestInProviderDir(providerRoot);
|
|
59526
|
+
if (path10)
|
|
59527
|
+
return path10;
|
|
58075
59528
|
}
|
|
58076
59529
|
}
|
|
58077
|
-
const parent =
|
|
59530
|
+
const parent = dirname22(dir);
|
|
58078
59531
|
if (parent === dir)
|
|
58079
59532
|
break;
|
|
58080
59533
|
dir = parent;
|
|
58081
59534
|
}
|
|
58082
59535
|
const pluginRoot = process.env.CLAUDE_PLUGIN_ROOT;
|
|
58083
59536
|
if (pluginRoot) {
|
|
58084
|
-
const pluginPath = findManifestInProviderDir(
|
|
59537
|
+
const pluginPath = findManifestInProviderDir(join88(pluginRoot, ".claude"));
|
|
58085
59538
|
if (pluginPath)
|
|
58086
59539
|
return pluginPath;
|
|
58087
59540
|
}
|
|
58088
|
-
const globalPath = findManifestInProviderDir(
|
|
59541
|
+
const globalPath = findManifestInProviderDir(join88(homedir26(), ".claude"));
|
|
58089
59542
|
if (globalPath)
|
|
58090
59543
|
return globalPath;
|
|
58091
59544
|
return null;
|
|
@@ -58199,12 +59652,12 @@ async function handleSessionEnd(agent, flags = {}) {
|
|
|
58199
59652
|
...reason ? { session_end_reason: reason } : {},
|
|
58200
59653
|
session_end_raw: data
|
|
58201
59654
|
};
|
|
58202
|
-
const { promises:
|
|
58203
|
-
const { join:
|
|
58204
|
-
const target =
|
|
59655
|
+
const { promises: fs18 } = await import("node:fs");
|
|
59656
|
+
const { join: join89 } = await import("node:path");
|
|
59657
|
+
const target = join89(sessionDir, "meta.json");
|
|
58205
59658
|
const tmp = `${target}.tmp`;
|
|
58206
|
-
await
|
|
58207
|
-
await
|
|
59659
|
+
await fs18.writeFile(tmp, JSON.stringify(updated), "utf8");
|
|
59660
|
+
await fs18.rename(tmp, target);
|
|
58208
59661
|
} else if (!existingMeta) {
|
|
58209
59662
|
await writeMetaIfAbsent(sessionDir, {
|
|
58210
59663
|
agent,
|
|
@@ -58271,11 +59724,11 @@ async function handleSessionEnd(agent, flags = {}) {
|
|
|
58271
59724
|
init_auth_client();
|
|
58272
59725
|
|
|
58273
59726
|
// src/commands/hooks/lib/retention.ts
|
|
58274
|
-
import { promises as
|
|
58275
|
-
import { join as
|
|
59727
|
+
import { promises as fs18 } from "node:fs";
|
|
59728
|
+
import { join as join89 } from "node:path";
|
|
58276
59729
|
async function hasLastPush(dir) {
|
|
58277
59730
|
try {
|
|
58278
|
-
await
|
|
59731
|
+
await fs18.access(getLastPushFile(dir));
|
|
58279
59732
|
return true;
|
|
58280
59733
|
} catch {
|
|
58281
59734
|
return false;
|
|
@@ -58284,7 +59737,7 @@ async function hasLastPush(dir) {
|
|
|
58284
59737
|
async function decideDelete(dir, args) {
|
|
58285
59738
|
let mtimeMs = 0;
|
|
58286
59739
|
try {
|
|
58287
|
-
const stat8 = await
|
|
59740
|
+
const stat8 = await fs18.stat(dir);
|
|
58288
59741
|
if (!stat8.isDirectory())
|
|
58289
59742
|
return false;
|
|
58290
59743
|
mtimeMs = stat8.mtimeMs;
|
|
@@ -58301,8 +59754,8 @@ async function decideDelete(dir, args) {
|
|
|
58301
59754
|
}
|
|
58302
59755
|
async function listChildren(dir) {
|
|
58303
59756
|
try {
|
|
58304
|
-
const names = await
|
|
58305
|
-
return names.map((n) =>
|
|
59757
|
+
const names = await fs18.readdir(dir);
|
|
59758
|
+
return names.map((n) => join89(dir, n));
|
|
58306
59759
|
} catch {
|
|
58307
59760
|
return [];
|
|
58308
59761
|
}
|
|
@@ -58313,7 +59766,7 @@ async function collectV2Sessions() {
|
|
|
58313
59766
|
const sessions = [];
|
|
58314
59767
|
for (const projectDir of projects) {
|
|
58315
59768
|
for (const agentDir of await listChildren(projectDir)) {
|
|
58316
|
-
for (const sessionDir of await listChildren(
|
|
59769
|
+
for (const sessionDir of await listChildren(join89(agentDir, "sessions"))) {
|
|
58317
59770
|
sessions.push(sessionDir);
|
|
58318
59771
|
}
|
|
58319
59772
|
}
|
|
@@ -58334,7 +59787,7 @@ async function sweepRetention(args) {
|
|
|
58334
59787
|
continue;
|
|
58335
59788
|
}
|
|
58336
59789
|
try {
|
|
58337
|
-
await
|
|
59790
|
+
await fs18.rm(dir, { recursive: true, force: true });
|
|
58338
59791
|
deleted.push(dir);
|
|
58339
59792
|
} catch {}
|
|
58340
59793
|
}
|
|
@@ -58359,8 +59812,8 @@ async function warmUpToken() {
|
|
|
58359
59812
|
const token = await getValidToken();
|
|
58360
59813
|
return token ? "ok" : "none";
|
|
58361
59814
|
})(),
|
|
58362
|
-
new Promise((
|
|
58363
|
-
timer = setTimeout(() =>
|
|
59815
|
+
new Promise((resolve19) => {
|
|
59816
|
+
timer = setTimeout(() => resolve19("timeout"), TOKEN_WARMUP_TIMEOUT_MS);
|
|
58364
59817
|
})
|
|
58365
59818
|
]);
|
|
58366
59819
|
return result;
|
|
@@ -58713,8 +60166,8 @@ init_hooks_settings_merger();
|
|
|
58713
60166
|
|
|
58714
60167
|
// src/commands/portable/settings-write-with-confirm.ts
|
|
58715
60168
|
init_safe_prompts();
|
|
58716
|
-
import { existsSync as
|
|
58717
|
-
import { dirname as
|
|
60169
|
+
import { existsSync as existsSync44, mkdirSync as mkdirSync4, readFileSync as readFileSync13, renameSync as renameSync2, rmSync as rmSync3, writeFileSync as writeFileSync7 } from "node:fs";
|
|
60170
|
+
import { dirname as dirname23 } from "node:path";
|
|
58718
60171
|
|
|
58719
60172
|
// node_modules/diff/libesm/diff/base.js
|
|
58720
60173
|
class Diff {
|
|
@@ -58816,16 +60269,16 @@ class Diff {
|
|
|
58816
60269
|
}
|
|
58817
60270
|
}
|
|
58818
60271
|
}
|
|
58819
|
-
addToPath(
|
|
58820
|
-
const last =
|
|
60272
|
+
addToPath(path10, added, removed, oldPosInc, options2) {
|
|
60273
|
+
const last = path10.lastComponent;
|
|
58821
60274
|
if (last && !options2.oneChangePerToken && last.added === added && last.removed === removed) {
|
|
58822
60275
|
return {
|
|
58823
|
-
oldPos:
|
|
60276
|
+
oldPos: path10.oldPos + oldPosInc,
|
|
58824
60277
|
lastComponent: { count: last.count + 1, added, removed, previousComponent: last.previousComponent }
|
|
58825
60278
|
};
|
|
58826
60279
|
} else {
|
|
58827
60280
|
return {
|
|
58828
|
-
oldPos:
|
|
60281
|
+
oldPos: path10.oldPos + oldPosInc,
|
|
58829
60282
|
lastComponent: { count: 1, added, removed, previousComponent: last }
|
|
58830
60283
|
};
|
|
58831
60284
|
}
|
|
@@ -59403,11 +60856,11 @@ function isWin(patch) {
|
|
|
59403
60856
|
|
|
59404
60857
|
// node_modules/diff/libesm/patch/parse.js
|
|
59405
60858
|
function parsePatch(uniDiff) {
|
|
59406
|
-
const diffstr = uniDiff.split(/\n/),
|
|
60859
|
+
const diffstr = uniDiff.split(/\n/), list2 = [];
|
|
59407
60860
|
let i = 0;
|
|
59408
60861
|
function parseIndex() {
|
|
59409
60862
|
const index = {};
|
|
59410
|
-
|
|
60863
|
+
list2.push(index);
|
|
59411
60864
|
while (i < diffstr.length) {
|
|
59412
60865
|
const line = diffstr[i];
|
|
59413
60866
|
if (/^(---|\+\+\+|@@)\s/.test(line)) {
|
|
@@ -59503,11 +60956,11 @@ function parsePatch(uniDiff) {
|
|
|
59503
60956
|
while (i < diffstr.length) {
|
|
59504
60957
|
parseIndex();
|
|
59505
60958
|
}
|
|
59506
|
-
return
|
|
60959
|
+
return list2;
|
|
59507
60960
|
}
|
|
59508
60961
|
|
|
59509
60962
|
// node_modules/diff/libesm/util/distance-iterator.js
|
|
59510
|
-
function distance_iterator_default(
|
|
60963
|
+
function distance_iterator_default(start2, minLine, maxLine) {
|
|
59511
60964
|
let wantForward = true, backwardExhausted = false, forwardExhausted = false, localOffset = 1;
|
|
59512
60965
|
return function iterator() {
|
|
59513
60966
|
if (wantForward && !forwardExhausted) {
|
|
@@ -59516,8 +60969,8 @@ function distance_iterator_default(start, minLine, maxLine) {
|
|
|
59516
60969
|
} else {
|
|
59517
60970
|
wantForward = false;
|
|
59518
60971
|
}
|
|
59519
|
-
if (
|
|
59520
|
-
return
|
|
60972
|
+
if (start2 + localOffset <= maxLine) {
|
|
60973
|
+
return start2 + localOffset;
|
|
59521
60974
|
}
|
|
59522
60975
|
forwardExhausted = true;
|
|
59523
60976
|
}
|
|
@@ -59525,8 +60978,8 @@ function distance_iterator_default(start, minLine, maxLine) {
|
|
|
59525
60978
|
if (!forwardExhausted) {
|
|
59526
60979
|
wantForward = true;
|
|
59527
60980
|
}
|
|
59528
|
-
if (minLine <=
|
|
59529
|
-
return
|
|
60981
|
+
if (minLine <= start2 - localOffset) {
|
|
60982
|
+
return start2 - localOffset++;
|
|
59530
60983
|
}
|
|
59531
60984
|
backwardExhausted = true;
|
|
59532
60985
|
return iterator();
|
|
@@ -59885,12 +61338,12 @@ var EMPTY_RESULT = (status2) => ({
|
|
|
59885
61338
|
deletions: 0,
|
|
59886
61339
|
backupPath: null
|
|
59887
61340
|
});
|
|
59888
|
-
function readCurrent(
|
|
59889
|
-
if (!
|
|
61341
|
+
function readCurrent(path10) {
|
|
61342
|
+
if (!existsSync44(path10))
|
|
59890
61343
|
return { kind: "missing" };
|
|
59891
61344
|
let raw = "";
|
|
59892
61345
|
try {
|
|
59893
|
-
raw =
|
|
61346
|
+
raw = readFileSync13(path10, "utf8");
|
|
59894
61347
|
const parsed = JSON.parse(raw);
|
|
59895
61348
|
return { kind: "ok", raw, parsed };
|
|
59896
61349
|
} catch {
|
|
@@ -59916,21 +61369,21 @@ function diffStats(diff) {
|
|
|
59916
61369
|
}
|
|
59917
61370
|
return { additions, deletions };
|
|
59918
61371
|
}
|
|
59919
|
-
function atomicWrite2(
|
|
59920
|
-
mkdirSync4(
|
|
59921
|
-
const tmp = `${
|
|
61372
|
+
function atomicWrite2(path10, contents, backupPath) {
|
|
61373
|
+
mkdirSync4(dirname23(path10), { recursive: true });
|
|
61374
|
+
const tmp = `${path10}.tmp`;
|
|
59922
61375
|
try {
|
|
59923
61376
|
writeFileSync7(tmp, contents);
|
|
59924
|
-
renameSync2(tmp,
|
|
61377
|
+
renameSync2(tmp, path10);
|
|
59925
61378
|
} catch (err) {
|
|
59926
61379
|
rmSync3(tmp, { force: true });
|
|
59927
61380
|
const trailer = backupPath ? `. Backup preserved at: ${backupPath}` : "";
|
|
59928
|
-
throw new Error(`Failed to write ${
|
|
61381
|
+
throw new Error(`Failed to write ${path10}: ${err instanceof Error ? err.message : String(err)}${trailer}`);
|
|
59929
61382
|
}
|
|
59930
61383
|
}
|
|
59931
|
-
function writeBackup(
|
|
61384
|
+
function writeBackup(path10, raw) {
|
|
59932
61385
|
const timestamp = new Date().toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
59933
|
-
const backupPath = `${
|
|
61386
|
+
const backupPath = `${path10}.${timestamp}.bak`;
|
|
59934
61387
|
try {
|
|
59935
61388
|
writeFileSync7(backupPath, raw);
|
|
59936
61389
|
return backupPath;
|
|
@@ -59939,7 +61392,7 @@ function writeBackup(path8, raw) {
|
|
|
59939
61392
|
}
|
|
59940
61393
|
}
|
|
59941
61394
|
async function resolveMissingFile(options2) {
|
|
59942
|
-
const { missingFile, interactive, label, path:
|
|
61395
|
+
const { missingFile, interactive, label, path: path10 } = options2;
|
|
59943
61396
|
if (missingFile === "create")
|
|
59944
61397
|
return "proceed";
|
|
59945
61398
|
if (missingFile === "skip")
|
|
@@ -59947,7 +61400,7 @@ async function resolveMissingFile(options2) {
|
|
|
59947
61400
|
if (!interactive)
|
|
59948
61401
|
return "skip";
|
|
59949
61402
|
const result = await se({
|
|
59950
|
-
message: `${label} does not exist at ${
|
|
61403
|
+
message: `${label} does not exist at ${path10}. Create it?`,
|
|
59951
61404
|
initialValue: false
|
|
59952
61405
|
});
|
|
59953
61406
|
if (lD(result))
|
|
@@ -59955,9 +61408,9 @@ async function resolveMissingFile(options2) {
|
|
|
59955
61408
|
return result ? "proceed" : "skip";
|
|
59956
61409
|
}
|
|
59957
61410
|
async function writeSettingsWithConfirm(options2) {
|
|
59958
|
-
const { path:
|
|
61411
|
+
const { path: path10, transform, yes, dryRun, interactive, useStepUI } = options2;
|
|
59959
61412
|
const diffPrint = useStepUI ? stepLine : undefined;
|
|
59960
|
-
const current = readCurrent(
|
|
61413
|
+
const current = readCurrent(path10);
|
|
59961
61414
|
if (current.kind === "corrupt")
|
|
59962
61415
|
return EMPTY_RESULT("skipped-corrupt");
|
|
59963
61416
|
const fileMissing = current.kind === "missing";
|
|
@@ -59974,7 +61427,7 @@ async function writeSettingsWithConfirm(options2) {
|
|
|
59974
61427
|
if (before === after) {
|
|
59975
61428
|
return EMPTY_RESULT("no-changes");
|
|
59976
61429
|
}
|
|
59977
|
-
const diff = createPatch(
|
|
61430
|
+
const diff = createPatch(path10, before, after, "", "", { context: 3 });
|
|
59978
61431
|
const { additions, deletions } = diffStats(diff);
|
|
59979
61432
|
if (dryRun) {
|
|
59980
61433
|
displayDiff(diff, { color: true, print: diffPrint });
|
|
@@ -59983,15 +61436,15 @@ async function writeSettingsWithConfirm(options2) {
|
|
|
59983
61436
|
if (!yes && interactive) {
|
|
59984
61437
|
displayDiff(diff, { color: true, print: diffPrint });
|
|
59985
61438
|
const accepted = await se({
|
|
59986
|
-
message: `Apply changes to ${
|
|
61439
|
+
message: `Apply changes to ${path10}?`,
|
|
59987
61440
|
initialValue: false
|
|
59988
61441
|
});
|
|
59989
61442
|
if (lD(accepted) || !accepted) {
|
|
59990
61443
|
return { status: "user-declined", diff, additions, deletions, backupPath: null };
|
|
59991
61444
|
}
|
|
59992
61445
|
}
|
|
59993
|
-
const backupPath = fileMissing ? null : writeBackup(
|
|
59994
|
-
atomicWrite2(
|
|
61446
|
+
const backupPath = fileMissing ? null : writeBackup(path10, raw);
|
|
61447
|
+
atomicWrite2(path10, after, backupPath);
|
|
59995
61448
|
return { status: "wrote", diff, additions, deletions, backupPath };
|
|
59996
61449
|
}
|
|
59997
61450
|
|
|
@@ -60003,18 +61456,18 @@ init_dist2();
|
|
|
60003
61456
|
// src/commands/hooks/lib/agent-target-picker.ts
|
|
60004
61457
|
init_safe_prompts();
|
|
60005
61458
|
init_dist2();
|
|
60006
|
-
import { existsSync as
|
|
61459
|
+
import { existsSync as existsSync45 } from "node:fs";
|
|
60007
61460
|
|
|
60008
61461
|
// src/commands/hooks/lib/settings-path-resolver.ts
|
|
60009
61462
|
import { lstatSync as lstatSync3, realpathSync as realpathSync3 } from "node:fs";
|
|
60010
|
-
import { homedir as
|
|
60011
|
-
import { join as
|
|
61463
|
+
import { homedir as homedir27 } from "node:os";
|
|
61464
|
+
import { join as join90 } from "node:path";
|
|
60012
61465
|
function rawPath(agent, global3) {
|
|
60013
|
-
const root = global3 ?
|
|
61466
|
+
const root = global3 ? homedir27() : process.cwd();
|
|
60014
61467
|
if (agent === "claude") {
|
|
60015
|
-
return
|
|
61468
|
+
return join90(root, ".claude", "settings.json");
|
|
60016
61469
|
}
|
|
60017
|
-
return
|
|
61470
|
+
return join90(root, ".codex", "hooks.json");
|
|
60018
61471
|
}
|
|
60019
61472
|
function resolveSettingsPath(agent, options2 = {}) {
|
|
60020
61473
|
const originalPath = rawPath(agent, Boolean(options2.global));
|
|
@@ -60042,7 +61495,7 @@ function probe(global3) {
|
|
|
60042
61495
|
return {
|
|
60043
61496
|
agent,
|
|
60044
61497
|
path: location2.realPath,
|
|
60045
|
-
exists:
|
|
61498
|
+
exists: existsSync45(location2.realPath)
|
|
60046
61499
|
};
|
|
60047
61500
|
});
|
|
60048
61501
|
}
|
|
@@ -60157,8 +61610,8 @@ function buildHookSection(agent, bin, flags = {}) {
|
|
|
60157
61610
|
|
|
60158
61611
|
// src/commands/hooks/uninstall-handler.ts
|
|
60159
61612
|
init_logger();
|
|
60160
|
-
import { existsSync as
|
|
60161
|
-
import { dirname as
|
|
61613
|
+
import { existsSync as existsSync46, mkdirSync as mkdirSync5, readFileSync as readFileSync14, renameSync as renameSync3, rmSync as rmSync4, writeFileSync as writeFileSync8 } from "node:fs";
|
|
61614
|
+
import { dirname as dirname24 } from "node:path";
|
|
60162
61615
|
var AGENT_DISPLAY2 = {
|
|
60163
61616
|
claude: "Claude Code",
|
|
60164
61617
|
codex: "Codex"
|
|
@@ -60193,12 +61646,12 @@ function pruneHooksSection(hooks, agent) {
|
|
|
60193
61646
|
}
|
|
60194
61647
|
return { pruned, removed };
|
|
60195
61648
|
}
|
|
60196
|
-
function writeAtomic(
|
|
60197
|
-
mkdirSync5(
|
|
60198
|
-
const tmp = `${
|
|
61649
|
+
function writeAtomic(path10, contents) {
|
|
61650
|
+
mkdirSync5(dirname24(path10), { recursive: true });
|
|
61651
|
+
const tmp = `${path10}.tmp`;
|
|
60199
61652
|
try {
|
|
60200
61653
|
writeFileSync8(tmp, contents);
|
|
60201
|
-
renameSync3(tmp,
|
|
61654
|
+
renameSync3(tmp, path10);
|
|
60202
61655
|
} catch (err) {
|
|
60203
61656
|
rmSync4(tmp, { force: true });
|
|
60204
61657
|
throw err;
|
|
@@ -60212,12 +61665,12 @@ async function uninstallForAgent(agent, options2) {
|
|
|
60212
61665
|
removed: 0,
|
|
60213
61666
|
dryRun: Boolean(options2.dryRun)
|
|
60214
61667
|
};
|
|
60215
|
-
if (!
|
|
61668
|
+
if (!existsSync46(location2.realPath)) {
|
|
60216
61669
|
return result;
|
|
60217
61670
|
}
|
|
60218
61671
|
let parsed;
|
|
60219
61672
|
try {
|
|
60220
|
-
parsed = JSON.parse(
|
|
61673
|
+
parsed = JSON.parse(readFileSync14(location2.realPath, "utf8"));
|
|
60221
61674
|
} catch {
|
|
60222
61675
|
logger.warning(`[hooks] could not parse ${location2.realPath}; uninstall skipped to avoid clobbering`);
|
|
60223
61676
|
return result;
|
|
@@ -61684,8 +63137,8 @@ async function dispatchInstallers(ctx, targetAgents2, lifecycle) {
|
|
|
61684
63137
|
init_logger();
|
|
61685
63138
|
// src/domains/installation/download-extractor.ts
|
|
61686
63139
|
init_auth_client();
|
|
61687
|
-
import * as
|
|
61688
|
-
import * as
|
|
63140
|
+
import * as fs20 from "node:fs";
|
|
63141
|
+
import * as path10 from "node:path";
|
|
61689
63142
|
|
|
61690
63143
|
// src/domains/github/auth-prompt.ts
|
|
61691
63144
|
init_dist2();
|
|
@@ -61766,7 +63219,7 @@ init_logger();
|
|
|
61766
63219
|
init_safe_spinner();
|
|
61767
63220
|
import { mkdir as mkdir25, stat as stat10 } from "node:fs/promises";
|
|
61768
63221
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
61769
|
-
import { join as
|
|
63222
|
+
import { join as join96 } from "node:path";
|
|
61770
63223
|
|
|
61771
63224
|
// src/shared/temp-cleanup.ts
|
|
61772
63225
|
init_logger();
|
|
@@ -61785,7 +63238,7 @@ init_logger();
|
|
|
61785
63238
|
init_output_manager();
|
|
61786
63239
|
import { createWriteStream as createWriteStream2, rmSync as rmSync5 } from "node:fs";
|
|
61787
63240
|
import { mkdir as mkdir21 } from "node:fs/promises";
|
|
61788
|
-
import { join as
|
|
63241
|
+
import { join as join91 } from "node:path";
|
|
61789
63242
|
|
|
61790
63243
|
// src/shared/progress-bar.ts
|
|
61791
63244
|
init_output_manager();
|
|
@@ -61950,10 +63403,10 @@ init_types2();
|
|
|
61950
63403
|
// src/domains/installation/utils/path-security.ts
|
|
61951
63404
|
init_types2();
|
|
61952
63405
|
import { lstatSync as lstatSync4, realpathSync as realpathSync4 } from "node:fs";
|
|
61953
|
-
import { relative as relative14, resolve as
|
|
63406
|
+
import { relative as relative14, resolve as resolve19 } from "node:path";
|
|
61954
63407
|
var MAX_EXTRACTION_SIZE = 500 * 1024 * 1024;
|
|
61955
63408
|
function isPathSafe(basePath, targetPath) {
|
|
61956
|
-
const resolvedBase =
|
|
63409
|
+
const resolvedBase = resolve19(basePath);
|
|
61957
63410
|
try {
|
|
61958
63411
|
const stat8 = lstatSync4(targetPath);
|
|
61959
63412
|
if (stat8.isSymbolicLink()) {
|
|
@@ -61963,7 +63416,7 @@ function isPathSafe(basePath, targetPath) {
|
|
|
61963
63416
|
}
|
|
61964
63417
|
}
|
|
61965
63418
|
} catch {}
|
|
61966
|
-
const resolvedTarget =
|
|
63419
|
+
const resolvedTarget = resolve19(targetPath);
|
|
61967
63420
|
const relativePath = relative14(resolvedBase, resolvedTarget);
|
|
61968
63421
|
return !relativePath.startsWith("..") && !relativePath.startsWith("/") && resolvedTarget.startsWith(resolvedBase);
|
|
61969
63422
|
}
|
|
@@ -61995,7 +63448,7 @@ var MAX_DOWNLOAD_SIZE = 500 * 1024 * 1024;
|
|
|
61995
63448
|
class FileDownloader {
|
|
61996
63449
|
async downloadAsset(asset, destDir) {
|
|
61997
63450
|
try {
|
|
61998
|
-
const destPath =
|
|
63451
|
+
const destPath = join91(destDir, asset.name);
|
|
61999
63452
|
await mkdir21(destDir, { recursive: true });
|
|
62000
63453
|
output.info(`Downloading ${asset.name} (${formatBytes(asset.size)})...`);
|
|
62001
63454
|
logger.verbose("Download details", {
|
|
@@ -62051,7 +63504,7 @@ class FileDownloader {
|
|
|
62051
63504
|
}
|
|
62052
63505
|
if (downloadedSize !== totalSize) {
|
|
62053
63506
|
fileStream.end();
|
|
62054
|
-
await new Promise((
|
|
63507
|
+
await new Promise((resolve20) => fileStream.once("close", resolve20));
|
|
62055
63508
|
try {
|
|
62056
63509
|
rmSync5(destPath, { force: true });
|
|
62057
63510
|
} catch (cleanupError) {
|
|
@@ -62065,7 +63518,7 @@ class FileDownloader {
|
|
|
62065
63518
|
return destPath;
|
|
62066
63519
|
} catch (error) {
|
|
62067
63520
|
fileStream.end();
|
|
62068
|
-
await new Promise((
|
|
63521
|
+
await new Promise((resolve20) => fileStream.once("close", resolve20));
|
|
62069
63522
|
try {
|
|
62070
63523
|
rmSync5(destPath, { force: true });
|
|
62071
63524
|
} catch (cleanupError) {
|
|
@@ -62080,7 +63533,7 @@ class FileDownloader {
|
|
|
62080
63533
|
}
|
|
62081
63534
|
async downloadFile(params) {
|
|
62082
63535
|
const { url, name, size, destDir, token } = params;
|
|
62083
|
-
const destPath =
|
|
63536
|
+
const destPath = join91(destDir, name);
|
|
62084
63537
|
await mkdir21(destDir, { recursive: true });
|
|
62085
63538
|
output.info(`Downloading ${name}${size ? ` (${formatBytes(size)})` : ""}...`);
|
|
62086
63539
|
const headers = {};
|
|
@@ -62148,7 +63601,7 @@ class FileDownloader {
|
|
|
62148
63601
|
const expectedSize = Number(response.headers.get("content-length"));
|
|
62149
63602
|
if (expectedSize > 0 && downloadedSize !== expectedSize) {
|
|
62150
63603
|
fileStream.end();
|
|
62151
|
-
await new Promise((
|
|
63604
|
+
await new Promise((resolve20) => fileStream.once("close", resolve20));
|
|
62152
63605
|
try {
|
|
62153
63606
|
rmSync5(destPath, { force: true });
|
|
62154
63607
|
} catch (cleanupError) {
|
|
@@ -62166,7 +63619,7 @@ class FileDownloader {
|
|
|
62166
63619
|
return destPath;
|
|
62167
63620
|
} catch (error) {
|
|
62168
63621
|
fileStream.end();
|
|
62169
|
-
await new Promise((
|
|
63622
|
+
await new Promise((resolve20) => fileStream.once("close", resolve20));
|
|
62170
63623
|
try {
|
|
62171
63624
|
rmSync5(destPath, { force: true });
|
|
62172
63625
|
} catch (cleanupError) {
|
|
@@ -62183,7 +63636,7 @@ init_logger();
|
|
|
62183
63636
|
init_types2();
|
|
62184
63637
|
import { constants as constants3 } from "node:fs";
|
|
62185
63638
|
import { access as access3, readdir as readdir25 } from "node:fs/promises";
|
|
62186
|
-
import { join as
|
|
63639
|
+
import { join as join92 } from "node:path";
|
|
62187
63640
|
async function validateExtraction(extractDir) {
|
|
62188
63641
|
try {
|
|
62189
63642
|
const entries = await readdir25(extractDir, { encoding: "utf8" });
|
|
@@ -62193,13 +63646,13 @@ async function validateExtraction(extractDir) {
|
|
|
62193
63646
|
}
|
|
62194
63647
|
const criticalPaths = [".claude", "CLAUDE.md"];
|
|
62195
63648
|
const missingPaths = [];
|
|
62196
|
-
for (const
|
|
63649
|
+
for (const path10 of criticalPaths) {
|
|
62197
63650
|
try {
|
|
62198
|
-
await access3(
|
|
62199
|
-
logger.debug(`Found: ${
|
|
63651
|
+
await access3(join92(extractDir, path10), constants3.F_OK);
|
|
63652
|
+
logger.debug(`Found: ${path10}`);
|
|
62200
63653
|
} catch {
|
|
62201
|
-
logger.warning(`Expected path not found: ${
|
|
62202
|
-
missingPaths.push(
|
|
63654
|
+
logger.warning(`Expected path not found: ${path10}`);
|
|
63655
|
+
missingPaths.push(path10);
|
|
62203
63656
|
}
|
|
62204
63657
|
}
|
|
62205
63658
|
if (missingPaths.length > 0) {
|
|
@@ -62217,7 +63670,7 @@ async function validateExtraction(extractDir) {
|
|
|
62217
63670
|
// src/domains/installation/extraction/tar-extractor.ts
|
|
62218
63671
|
init_logger();
|
|
62219
63672
|
import { copyFile as copyFile5, mkdir as mkdir23, readdir as readdir27, rm as rm7, stat as stat8 } from "node:fs/promises";
|
|
62220
|
-
import { join as
|
|
63673
|
+
import { join as join94 } from "node:path";
|
|
62221
63674
|
|
|
62222
63675
|
// node_modules/tar/dist/esm/index.min.js
|
|
62223
63676
|
import Kr from "events";
|
|
@@ -64249,7 +65702,7 @@ var ls = Symbol("readdir");
|
|
|
64249
65702
|
var ai = Symbol("onreaddir");
|
|
64250
65703
|
var li = Symbol("pipe");
|
|
64251
65704
|
var ir = Symbol("entry");
|
|
64252
|
-
var
|
|
65705
|
+
var os7 = Symbol("entryOpt");
|
|
64253
65706
|
var ci = Symbol("writeEntryClass");
|
|
64254
65707
|
var rr = Symbol("write");
|
|
64255
65708
|
var hs = Symbol("ondrain");
|
|
@@ -64312,7 +65765,7 @@ var Et = class extends D {
|
|
|
64312
65765
|
t.resume();
|
|
64313
65766
|
else {
|
|
64314
65767
|
let i = new di(t.path, e2);
|
|
64315
|
-
i.entry = new ri(t, this[
|
|
65768
|
+
i.entry = new ri(t, this[os7](i)), i.entry.on("end", () => this[ns](i)), this[G2] += 1, this[W2].push(i);
|
|
64316
65769
|
}
|
|
64317
65770
|
this[Ft]();
|
|
64318
65771
|
}
|
|
@@ -64381,13 +65834,13 @@ var Et = class extends D {
|
|
|
64381
65834
|
}
|
|
64382
65835
|
}
|
|
64383
65836
|
}
|
|
64384
|
-
[
|
|
65837
|
+
[os7](t) {
|
|
64385
65838
|
return { onwarn: (e2, i, r2) => this.warn(e2, i, r2), noPax: this.noPax, cwd: this.cwd, absolute: t.absolute, preservePaths: this.preservePaths, maxReadSize: this.maxReadSize, strict: this.strict, portable: this.portable, linkCache: this.linkCache, statCache: this.statCache, noMtime: this.noMtime, mtime: this.mtime, prefix: this.prefix, onWriteEntry: this.onWriteEntry };
|
|
64386
65839
|
}
|
|
64387
65840
|
[ir](t) {
|
|
64388
65841
|
this[G2] += 1;
|
|
64389
65842
|
try {
|
|
64390
|
-
return new this[ci](t.path, this[
|
|
65843
|
+
return new this[ci](t.path, this[os7](t)).on("end", () => this[ns](t)).on("error", (i) => this.emit("error", i));
|
|
64391
65844
|
} catch (e2) {
|
|
64392
65845
|
this.emit("error", e2);
|
|
64393
65846
|
}
|
|
@@ -64489,7 +65942,7 @@ var Vn = 512 * 1024;
|
|
|
64489
65942
|
var $n = pr | ur | dr | mr;
|
|
64490
65943
|
var lr = !fr && typeof ar == "number" ? ar | ur | dr | mr : null;
|
|
64491
65944
|
var cs = lr !== null ? () => lr : Kn ? (s3) => s3 < Vn ? $n : "w" : () => "w";
|
|
64492
|
-
var
|
|
65945
|
+
var fs19 = (s3, t, e2) => {
|
|
64493
65946
|
try {
|
|
64494
65947
|
return mi.lchownSync(s3, t, e2);
|
|
64495
65948
|
} catch (i) {
|
|
@@ -64538,7 +65991,7 @@ var ds = (s3, t, e2, i) => {
|
|
|
64538
65991
|
});
|
|
64539
65992
|
};
|
|
64540
65993
|
var qn = (s3, t, e2, i) => {
|
|
64541
|
-
t.isDirectory() && us(Ee.resolve(s3, t.name), e2, i),
|
|
65994
|
+
t.isDirectory() && us(Ee.resolve(s3, t.name), e2, i), fs19(Ee.resolve(s3, t.name), e2, i);
|
|
64542
65995
|
};
|
|
64543
65996
|
var us = (s3, t, e2) => {
|
|
64544
65997
|
let i;
|
|
@@ -64549,12 +66002,12 @@ var us = (s3, t, e2) => {
|
|
|
64549
66002
|
if (n?.code === "ENOENT")
|
|
64550
66003
|
return;
|
|
64551
66004
|
if (n?.code === "ENOTDIR" || n?.code === "ENOTSUP")
|
|
64552
|
-
return
|
|
66005
|
+
return fs19(s3, t, e2);
|
|
64553
66006
|
throw n;
|
|
64554
66007
|
}
|
|
64555
66008
|
for (let r2 of i)
|
|
64556
66009
|
qn(s3, r2, t, e2);
|
|
64557
|
-
return
|
|
66010
|
+
return fs19(s3, t, e2);
|
|
64558
66011
|
};
|
|
64559
66012
|
var we = class extends Error {
|
|
64560
66013
|
path;
|
|
@@ -65409,20 +66862,20 @@ function normalizeZipEntryName(entryName) {
|
|
|
65409
66862
|
}
|
|
65410
66863
|
return String(entryName);
|
|
65411
66864
|
}
|
|
65412
|
-
function decodeFilePath(
|
|
65413
|
-
if (!
|
|
65414
|
-
return
|
|
66865
|
+
function decodeFilePath(path10) {
|
|
66866
|
+
if (!path10.includes("%")) {
|
|
66867
|
+
return path10;
|
|
65415
66868
|
}
|
|
65416
66869
|
try {
|
|
65417
|
-
if (/%[0-9A-F]{2}/i.test(
|
|
65418
|
-
const decoded = decodeURIComponent(
|
|
65419
|
-
logger.debug(`Decoded path: ${
|
|
66870
|
+
if (/%[0-9A-F]{2}/i.test(path10)) {
|
|
66871
|
+
const decoded = decodeURIComponent(path10);
|
|
66872
|
+
logger.debug(`Decoded path: ${path10} -> ${decoded}`);
|
|
65420
66873
|
return decoded;
|
|
65421
66874
|
}
|
|
65422
|
-
return
|
|
66875
|
+
return path10;
|
|
65423
66876
|
} catch (error) {
|
|
65424
|
-
logger.warning(`Failed to decode path "${
|
|
65425
|
-
return
|
|
66877
|
+
logger.warning(`Failed to decode path "${path10}": ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
66878
|
+
return path10;
|
|
65426
66879
|
}
|
|
65427
66880
|
}
|
|
65428
66881
|
|
|
@@ -65430,7 +66883,7 @@ function decodeFilePath(path8) {
|
|
|
65430
66883
|
init_logger();
|
|
65431
66884
|
init_types2();
|
|
65432
66885
|
import { copyFile as copyFile4, lstat as lstat6, mkdir as mkdir22, readdir as readdir26 } from "node:fs/promises";
|
|
65433
|
-
import { join as
|
|
66886
|
+
import { join as join93, relative as relative15 } from "node:path";
|
|
65434
66887
|
async function withRetry2(fn2, retries = 3) {
|
|
65435
66888
|
for (let i = 0;i < retries; i++) {
|
|
65436
66889
|
try {
|
|
@@ -65452,8 +66905,8 @@ async function moveDirectoryContents(sourceDir, destDir, shouldExclude, sizeTrac
|
|
|
65452
66905
|
await mkdir22(destDir, { recursive: true });
|
|
65453
66906
|
const entries = await readdir26(sourceDir, { encoding: "utf8" });
|
|
65454
66907
|
for (const entry of entries) {
|
|
65455
|
-
const sourcePath =
|
|
65456
|
-
const destPath =
|
|
66908
|
+
const sourcePath = join93(sourceDir, entry);
|
|
66909
|
+
const destPath = join93(destDir, entry);
|
|
65457
66910
|
const relativePath = relative15(sourceDir, sourcePath);
|
|
65458
66911
|
if (!isPathSafe(destDir, destPath)) {
|
|
65459
66912
|
logger.warning(`Skipping unsafe path: ${relativePath}`);
|
|
@@ -65480,8 +66933,8 @@ async function copyDirectory(sourceDir, destDir, shouldExclude, sizeTracker) {
|
|
|
65480
66933
|
await mkdir22(destDir, { recursive: true });
|
|
65481
66934
|
const entries = await readdir26(sourceDir, { encoding: "utf8" });
|
|
65482
66935
|
for (const entry of entries) {
|
|
65483
|
-
const sourcePath =
|
|
65484
|
-
const destPath =
|
|
66936
|
+
const sourcePath = join93(sourceDir, entry);
|
|
66937
|
+
const destPath = join93(destDir, entry);
|
|
65485
66938
|
const relativePath = relative15(sourceDir, sourcePath);
|
|
65486
66939
|
if (!isPathSafe(destDir, destPath)) {
|
|
65487
66940
|
logger.warning(`Skipping unsafe path: ${relativePath}`);
|
|
@@ -65518,12 +66971,12 @@ class TarExtractor {
|
|
|
65518
66971
|
onwarn: (code, message) => {
|
|
65519
66972
|
logger.debug(`tar warning [${code}]: ${message}`);
|
|
65520
66973
|
},
|
|
65521
|
-
filter: (
|
|
66974
|
+
filter: (path10, entry) => {
|
|
65522
66975
|
if ("type" in entry && (entry.type === "SymbolicLink" || entry.type === "Link")) {
|
|
65523
|
-
logger.debug(`Skipping symlink: ${
|
|
66976
|
+
logger.debug(`Skipping symlink: ${path10}`);
|
|
65524
66977
|
return false;
|
|
65525
66978
|
}
|
|
65526
|
-
const decodedPath = decodeFilePath(
|
|
66979
|
+
const decodedPath = decodeFilePath(path10);
|
|
65527
66980
|
const shouldInclude = !shouldExclude(decodedPath);
|
|
65528
66981
|
if (!shouldInclude) {
|
|
65529
66982
|
logger.debug(`Excluding: ${decodedPath}`);
|
|
@@ -65536,7 +66989,7 @@ class TarExtractor {
|
|
|
65536
66989
|
logger.debug(`Root entries: ${entries.join(", ")}`);
|
|
65537
66990
|
if (entries.length === 1) {
|
|
65538
66991
|
const rootEntry = entries[0];
|
|
65539
|
-
const rootPath =
|
|
66992
|
+
const rootPath = join94(tempExtractDir, rootEntry);
|
|
65540
66993
|
const rootStat = await stat8(rootPath);
|
|
65541
66994
|
if (rootStat.isDirectory()) {
|
|
65542
66995
|
const rootContents = await readdir27(rootPath, { encoding: "utf8" });
|
|
@@ -65552,7 +67005,7 @@ class TarExtractor {
|
|
|
65552
67005
|
}
|
|
65553
67006
|
} else {
|
|
65554
67007
|
await mkdir23(destDir, { recursive: true });
|
|
65555
|
-
await copyFile5(rootPath,
|
|
67008
|
+
await copyFile5(rootPath, join94(destDir, rootEntry));
|
|
65556
67009
|
}
|
|
65557
67010
|
} else {
|
|
65558
67011
|
logger.debug("Multiple root entries - moving all");
|
|
@@ -65573,7 +67026,7 @@ class TarExtractor {
|
|
|
65573
67026
|
init_logger();
|
|
65574
67027
|
import { createWriteStream as createWriteStream3 } from "node:fs";
|
|
65575
67028
|
import { chmod as chmod3, copyFile as copyFile6, mkdir as mkdir24, readdir as readdir28, rm as rm8, stat as stat9 } from "node:fs/promises";
|
|
65576
|
-
import { dirname as
|
|
67029
|
+
import { dirname as dirname25, join as join95, resolve as resolve20 } from "node:path";
|
|
65577
67030
|
import { pipeline } from "node:stream/promises";
|
|
65578
67031
|
import yauzl from "yauzl-promise";
|
|
65579
67032
|
class ZipExtractor {
|
|
@@ -65587,7 +67040,7 @@ class ZipExtractor {
|
|
|
65587
67040
|
logger.debug(`Root entries: ${entries.join(", ")}`);
|
|
65588
67041
|
if (entries.length === 1) {
|
|
65589
67042
|
const rootEntry = entries[0];
|
|
65590
|
-
const rootPath =
|
|
67043
|
+
const rootPath = join95(tempExtractDir, rootEntry);
|
|
65591
67044
|
const rootStat = await stat9(rootPath);
|
|
65592
67045
|
if (rootStat.isDirectory()) {
|
|
65593
67046
|
const rootContents = await readdir28(rootPath, { encoding: "utf8" });
|
|
@@ -65603,7 +67056,7 @@ class ZipExtractor {
|
|
|
65603
67056
|
}
|
|
65604
67057
|
} else {
|
|
65605
67058
|
await mkdir24(destDir, { recursive: true });
|
|
65606
|
-
await copyFile6(rootPath,
|
|
67059
|
+
await copyFile6(rootPath, join95(destDir, rootEntry));
|
|
65607
67060
|
}
|
|
65608
67061
|
} else {
|
|
65609
67062
|
logger.debug("Multiple root entries - moving all");
|
|
@@ -65620,13 +67073,13 @@ class ZipExtractor {
|
|
|
65620
67073
|
}
|
|
65621
67074
|
async extractToDir(archivePath, destDir) {
|
|
65622
67075
|
const zip = await yauzl.open(archivePath, { decodeStrings: false });
|
|
65623
|
-
const destRoot =
|
|
67076
|
+
const destRoot = resolve20(destDir);
|
|
65624
67077
|
let count = 0;
|
|
65625
67078
|
try {
|
|
65626
67079
|
for await (const entry of zip) {
|
|
65627
67080
|
const rawName = entry.filename;
|
|
65628
67081
|
const name = normalizeZipEntryName(rawName);
|
|
65629
|
-
const outPath =
|
|
67082
|
+
const outPath = resolve20(destRoot, name);
|
|
65630
67083
|
if (!isPathSafe(destRoot, outPath)) {
|
|
65631
67084
|
throw new Error(`Unsafe zip entry path (zip-slip): ${name}`);
|
|
65632
67085
|
}
|
|
@@ -65634,7 +67087,7 @@ class ZipExtractor {
|
|
|
65634
67087
|
await mkdir24(outPath, { recursive: true });
|
|
65635
67088
|
continue;
|
|
65636
67089
|
}
|
|
65637
|
-
await mkdir24(
|
|
67090
|
+
await mkdir24(dirname25(outPath), { recursive: true });
|
|
65638
67091
|
const readStream = await entry.openReadStream();
|
|
65639
67092
|
await pipeline(readStream, createWriteStream3(outPath));
|
|
65640
67093
|
const unixMode = entry.externalFileAttributes >>> 16 & 511;
|
|
@@ -65732,7 +67185,7 @@ class DownloadManager {
|
|
|
65732
67185
|
async createTempDir() {
|
|
65733
67186
|
const timestamp = Date.now();
|
|
65734
67187
|
const counter = DownloadManager.tempDirCounter++;
|
|
65735
|
-
const primaryTempDir =
|
|
67188
|
+
const primaryTempDir = join96(tmpdir3(), `takumi-${timestamp}-${counter}`);
|
|
65736
67189
|
try {
|
|
65737
67190
|
await mkdir25(primaryTempDir, { recursive: true });
|
|
65738
67191
|
logger.debug(`Created temp directory: ${primaryTempDir}`);
|
|
@@ -65749,7 +67202,7 @@ Solutions:
|
|
|
65749
67202
|
2. Set HOME environment variable
|
|
65750
67203
|
3. Try running from a different directory`);
|
|
65751
67204
|
}
|
|
65752
|
-
const fallbackTempDir =
|
|
67205
|
+
const fallbackTempDir = join96(homeDir, ".sunagentkit", "tmp", `takumi-${timestamp}-${counter}`);
|
|
65753
67206
|
try {
|
|
65754
67207
|
await mkdir25(fallbackTempDir, { recursive: true });
|
|
65755
67208
|
logger.debug(`Created temp directory (fallback): ${fallbackTempDir}`);
|
|
@@ -65792,9 +67245,9 @@ function buildReleaseAllowlist(layout) {
|
|
|
65792
67245
|
return [...new Set([layout.sourceDir, ...RELEASE_ROOT_ALLOWLIST])];
|
|
65793
67246
|
}
|
|
65794
67247
|
async function ensureLayoutSourceDir(projectRoot, layout, strict) {
|
|
65795
|
-
const sourceDir =
|
|
67248
|
+
const sourceDir = path10.join(projectRoot, layout.sourceDir);
|
|
65796
67249
|
try {
|
|
65797
|
-
const stat11 = await
|
|
67250
|
+
const stat11 = await fs20.promises.stat(sourceDir);
|
|
65798
67251
|
if (!stat11.isDirectory()) {
|
|
65799
67252
|
throw new Error(`Expected source directory "${layout.sourceDir}" exists but is not a directory.`);
|
|
65800
67253
|
}
|
|
@@ -65817,10 +67270,10 @@ async function materializeRuntimeLayoutInPlace(projectRoot, layout) {
|
|
|
65817
67270
|
if (layout.sourceDir === layout.runtimeDir) {
|
|
65818
67271
|
return;
|
|
65819
67272
|
}
|
|
65820
|
-
const sourceDir =
|
|
65821
|
-
const runtimeDir =
|
|
65822
|
-
await
|
|
65823
|
-
await
|
|
67273
|
+
const sourceDir = path10.join(projectRoot, layout.sourceDir);
|
|
67274
|
+
const runtimeDir = path10.join(projectRoot, layout.runtimeDir);
|
|
67275
|
+
await fs20.promises.rm(runtimeDir, { recursive: true, force: true });
|
|
67276
|
+
await fs20.promises.rename(sourceDir, runtimeDir);
|
|
65824
67277
|
}
|
|
65825
67278
|
async function stageLocalKitPathForRuntimeLayout(kitRoot, layout) {
|
|
65826
67279
|
const sourceDir = await ensureLayoutSourceDir(kitRoot, layout, false);
|
|
@@ -65830,20 +67283,20 @@ async function stageLocalKitPathForRuntimeLayout(kitRoot, layout) {
|
|
|
65830
67283
|
const downloadManager = new DownloadManager;
|
|
65831
67284
|
const tempDir = await downloadManager.createTempDir();
|
|
65832
67285
|
const extractDir = `${tempDir}/extracted`;
|
|
65833
|
-
await
|
|
65834
|
-
const entries = await
|
|
67286
|
+
await fs20.promises.mkdir(extractDir, { recursive: true });
|
|
67287
|
+
const entries = await fs20.promises.readdir(kitRoot);
|
|
65835
67288
|
const allowlist = buildReleaseAllowlist(layout);
|
|
65836
67289
|
for (const entry of entries) {
|
|
65837
67290
|
if (!allowlist.includes(entry) || entry === layout.sourceDir) {
|
|
65838
67291
|
continue;
|
|
65839
67292
|
}
|
|
65840
|
-
await
|
|
67293
|
+
await fs20.promises.cp(path10.join(kitRoot, entry), path10.join(extractDir, entry), {
|
|
65841
67294
|
recursive: true
|
|
65842
67295
|
});
|
|
65843
67296
|
}
|
|
65844
|
-
const runtimeDir =
|
|
65845
|
-
await
|
|
65846
|
-
await
|
|
67297
|
+
const runtimeDir = path10.join(extractDir, layout.runtimeDir);
|
|
67298
|
+
await fs20.promises.mkdir(path10.dirname(runtimeDir), { recursive: true });
|
|
67299
|
+
await fs20.promises.cp(sourceDir, runtimeDir, { recursive: true });
|
|
65847
67300
|
logger.verbose("Staged local kit path with runtime layout", {
|
|
65848
67301
|
kitRoot,
|
|
65849
67302
|
extractDir,
|
|
@@ -65870,14 +67323,14 @@ var MONOREPO_KIT_CONTENT = [
|
|
|
65870
67323
|
];
|
|
65871
67324
|
function resolveRepoRootForKit(kitRoot) {
|
|
65872
67325
|
try {
|
|
65873
|
-
const parent =
|
|
65874
|
-
const parentPackageJson =
|
|
65875
|
-
if (!
|
|
67326
|
+
const parent = path10.dirname(kitRoot);
|
|
67327
|
+
const parentPackageJson = path10.join(parent, "package.json");
|
|
67328
|
+
if (!fs20.existsSync(parentPackageJson))
|
|
65876
67329
|
return kitRoot;
|
|
65877
|
-
const pkg = JSON.parse(
|
|
67330
|
+
const pkg = JSON.parse(fs20.readFileSync(parentPackageJson, "utf-8"));
|
|
65878
67331
|
const kitCfg = pkg.takumi;
|
|
65879
67332
|
const sourceDir = kitCfg?.sourceDir;
|
|
65880
|
-
if (typeof sourceDir === "string" &&
|
|
67333
|
+
if (typeof sourceDir === "string" && path10.resolve(parent, sourceDir) === path10.resolve(kitRoot)) {
|
|
65881
67334
|
return parent;
|
|
65882
67335
|
}
|
|
65883
67336
|
} catch {}
|
|
@@ -65887,25 +67340,25 @@ async function stageMonorepoForInstallation(kitRoot) {
|
|
|
65887
67340
|
const downloadManager = new DownloadManager;
|
|
65888
67341
|
const tempDir = await downloadManager.createTempDir();
|
|
65889
67342
|
const extractDir = `${tempDir}/extracted`;
|
|
65890
|
-
const claudeDir =
|
|
65891
|
-
await
|
|
67343
|
+
const claudeDir = path10.join(extractDir, ".claude");
|
|
67344
|
+
await fs20.promises.mkdir(claudeDir, { recursive: true });
|
|
65892
67345
|
const repoRoot = resolveRepoRootForKit(kitRoot);
|
|
65893
|
-
const kitEntries = await
|
|
67346
|
+
const kitEntries = await fs20.promises.readdir(kitRoot);
|
|
65894
67347
|
const skipLegacyManifest = kitEntries.includes(MANIFEST_FILENAME) && kitEntries.includes(LEGACY_MANIFEST_FILENAME);
|
|
65895
67348
|
for (const entry of kitEntries) {
|
|
65896
67349
|
if (!MONOREPO_KIT_CONTENT.includes(entry))
|
|
65897
67350
|
continue;
|
|
65898
67351
|
if (skipLegacyManifest && entry === LEGACY_MANIFEST_FILENAME)
|
|
65899
67352
|
continue;
|
|
65900
|
-
const srcPath =
|
|
65901
|
-
await
|
|
67353
|
+
const srcPath = path10.join(kitRoot, entry);
|
|
67354
|
+
await fs20.promises.cp(srcPath, path10.join(claudeDir, entry), { recursive: true });
|
|
65902
67355
|
}
|
|
65903
|
-
const repoEntries = repoRoot === kitRoot ? kitEntries : await
|
|
67356
|
+
const repoEntries = repoRoot === kitRoot ? kitEntries : await fs20.promises.readdir(repoRoot);
|
|
65904
67357
|
for (const entry of repoEntries) {
|
|
65905
67358
|
if (!RELEASE_ROOT_ALLOWLIST.includes(entry))
|
|
65906
67359
|
continue;
|
|
65907
|
-
const srcPath =
|
|
65908
|
-
await
|
|
67360
|
+
const srcPath = path10.join(repoRoot, entry);
|
|
67361
|
+
await fs20.promises.cp(srcPath, path10.join(extractDir, entry), { recursive: true });
|
|
65909
67362
|
}
|
|
65910
67363
|
logger.verbose("Staged monorepo for installation", {
|
|
65911
67364
|
kitRoot,
|
|
@@ -65919,13 +67372,13 @@ async function stageMonorepoForInstallation(kitRoot) {
|
|
|
65919
67372
|
async function normalizeFullRepoExtract(dir, strict) {
|
|
65920
67373
|
const layout = resolveKitLayout(dir);
|
|
65921
67374
|
await ensureLayoutSourceDir(dir, layout, strict);
|
|
65922
|
-
const entries = await
|
|
67375
|
+
const entries = await fs20.promises.readdir(dir);
|
|
65923
67376
|
const releaseAllowlist = buildReleaseAllowlist(layout);
|
|
65924
67377
|
let removedCount = 0;
|
|
65925
67378
|
for (const entry of entries) {
|
|
65926
67379
|
if (!releaseAllowlist.includes(entry)) {
|
|
65927
|
-
const fullPath =
|
|
65928
|
-
await
|
|
67380
|
+
const fullPath = path10.join(dir, entry);
|
|
67381
|
+
await fs20.promises.rm(fullPath, { recursive: true, force: true });
|
|
65929
67382
|
removedCount++;
|
|
65930
67383
|
}
|
|
65931
67384
|
}
|
|
@@ -66038,9 +67491,9 @@ Or try: tkm init --use-git`);
|
|
|
66038
67491
|
async function useLocalKitPath(kitPath, isMonorepo) {
|
|
66039
67492
|
logger.verbose("Using local kit path", { kitPath });
|
|
66040
67493
|
output.section("Using local kit");
|
|
66041
|
-
const absolutePath =
|
|
67494
|
+
const absolutePath = path10.resolve(kitPath);
|
|
66042
67495
|
try {
|
|
66043
|
-
const stat11 = await
|
|
67496
|
+
const stat11 = await fs20.promises.stat(absolutePath);
|
|
66044
67497
|
if (!stat11.isDirectory()) {
|
|
66045
67498
|
throw new Error(`--kit-path must point to a directory, not a file.
|
|
66046
67499
|
|
|
@@ -66077,9 +67530,9 @@ Please verify the path exists and is accessible.`);
|
|
|
66077
67530
|
};
|
|
66078
67531
|
}
|
|
66079
67532
|
}
|
|
66080
|
-
const claudeDir =
|
|
67533
|
+
const claudeDir = path10.join(absolutePath, DEFAULT_KIT_LAYOUT.runtimeDir);
|
|
66081
67534
|
try {
|
|
66082
|
-
const stat11 = await
|
|
67535
|
+
const stat11 = await fs20.promises.stat(claudeDir);
|
|
66083
67536
|
if (!stat11.isDirectory()) {
|
|
66084
67537
|
logger.warning(`Warning: ${claudeDir} exists but is not a directory.
|
|
66085
67538
|
This may not be a valid Takumi installation.`);
|
|
@@ -66102,7 +67555,7 @@ function validateArchiveFormat(archivePath) {
|
|
|
66102
67555
|
const lowerPath = archivePath.toLowerCase();
|
|
66103
67556
|
const isValid2 = VALID_ARCHIVE_FORMATS.some((ext2) => lowerPath.endsWith(ext2));
|
|
66104
67557
|
if (!isValid2) {
|
|
66105
|
-
const ext2 =
|
|
67558
|
+
const ext2 = path10.extname(archivePath) || "(no extension)";
|
|
66106
67559
|
throw new Error(`Unsupported archive format: ${ext2}
|
|
66107
67560
|
|
|
66108
67561
|
` + `Supported formats: ${VALID_ARCHIVE_FORMATS.join(", ")}`);
|
|
@@ -66111,10 +67564,10 @@ function validateArchiveFormat(archivePath) {
|
|
|
66111
67564
|
async function extractLocalArchive(archivePath, exclude) {
|
|
66112
67565
|
logger.verbose("Using local archive", { archivePath });
|
|
66113
67566
|
output.section("Extracting local archive");
|
|
66114
|
-
const absolutePath =
|
|
67567
|
+
const absolutePath = path10.resolve(archivePath);
|
|
66115
67568
|
validateArchiveFormat(absolutePath);
|
|
66116
67569
|
try {
|
|
66117
|
-
const stat11 = await
|
|
67570
|
+
const stat11 = await fs20.promises.stat(absolutePath);
|
|
66118
67571
|
if (!stat11.isFile()) {
|
|
66119
67572
|
throw new Error(`--archive must point to a file, not a directory.
|
|
66120
67573
|
|
|
@@ -66245,9 +67698,9 @@ async function downloadViaWorker(release, kit, isNonInteractive2) {
|
|
|
66245
67698
|
const res = await source.fetchAsset(release.tag_name, assetName);
|
|
66246
67699
|
const downloadManager = new DownloadManager;
|
|
66247
67700
|
const tempDir = await downloadManager.createTempDir();
|
|
66248
|
-
const archivePath =
|
|
67701
|
+
const archivePath = path10.join(tempDir, assetName);
|
|
66249
67702
|
const buf = Buffer.from(await res.arrayBuffer());
|
|
66250
|
-
await
|
|
67703
|
+
await fs20.promises.writeFile(archivePath, buf);
|
|
66251
67704
|
const extractDir = `${tempDir}/extracted`;
|
|
66252
67705
|
logger.verbose("Extraction", { archivePath, extractDir });
|
|
66253
67706
|
await downloadManager.extractArchive(archivePath, extractDir);
|
|
@@ -66455,7 +67908,7 @@ Re-run with explicit base kit, e.g. --kit ${BASE_KIT} --kit ${parsed2.join(" --k
|
|
|
66455
67908
|
}
|
|
66456
67909
|
// src/commands/init/phases/selection-handler.ts
|
|
66457
67910
|
import { mkdir as mkdir26 } from "node:fs/promises";
|
|
66458
|
-
import { join as
|
|
67911
|
+
import { join as join100, resolve as resolve24 } from "node:path";
|
|
66459
67912
|
|
|
66460
67913
|
// src/commands/shared/agent-selector.ts
|
|
66461
67914
|
init_registry();
|
|
@@ -66608,8 +68061,8 @@ init_logger();
|
|
|
66608
68061
|
init_safe_spinner();
|
|
66609
68062
|
init_takumi_constants();
|
|
66610
68063
|
var import_fs_extra31 = __toESM(require_lib(), 1);
|
|
66611
|
-
import { existsSync as
|
|
66612
|
-
import { dirname as
|
|
68064
|
+
import { existsSync as existsSync49, readdirSync as readdirSync6, rmSync as rmSync6, rmdirSync as rmdirSync2, unlinkSync as unlinkSync5 } from "node:fs";
|
|
68065
|
+
import { dirname as dirname28, join as join99, resolve as resolve23 } from "node:path";
|
|
66613
68066
|
var TAKUMI_SUBDIRECTORIES = ["commands", "agents", "skills", "rules", "hooks"];
|
|
66614
68067
|
async function analyzeFreshInstallation(claudeDir) {
|
|
66615
68068
|
const metadata = await readManifest(claudeDir);
|
|
@@ -66654,15 +68107,15 @@ async function analyzeFreshInstallation(claudeDir) {
|
|
|
66654
68107
|
};
|
|
66655
68108
|
}
|
|
66656
68109
|
function cleanupEmptyDirectories2(filePath, claudeDir) {
|
|
66657
|
-
const normalizedClaudeDir =
|
|
66658
|
-
let currentDir =
|
|
68110
|
+
const normalizedClaudeDir = resolve23(claudeDir);
|
|
68111
|
+
let currentDir = resolve23(dirname28(filePath));
|
|
66659
68112
|
while (currentDir !== normalizedClaudeDir && currentDir.startsWith(normalizedClaudeDir)) {
|
|
66660
68113
|
try {
|
|
66661
|
-
const entries =
|
|
68114
|
+
const entries = readdirSync6(currentDir);
|
|
66662
68115
|
if (entries.length === 0) {
|
|
66663
68116
|
rmdirSync2(currentDir);
|
|
66664
68117
|
logger.debug(`Removed empty directory: ${currentDir}`);
|
|
66665
|
-
currentDir =
|
|
68118
|
+
currentDir = resolve23(dirname28(currentDir));
|
|
66666
68119
|
} else {
|
|
66667
68120
|
break;
|
|
66668
68121
|
}
|
|
@@ -66679,9 +68132,9 @@ async function removeFilesByOwnership(claudeDir, analysis, includeModified) {
|
|
|
66679
68132
|
const filesToRemove = includeModified ? [...analysis.ckFiles, ...analysis.ckModifiedFiles] : analysis.ckFiles;
|
|
66680
68133
|
const filesToPreserve = includeModified ? analysis.userFiles : [...analysis.ckModifiedFiles, ...analysis.userFiles];
|
|
66681
68134
|
for (const file of filesToRemove) {
|
|
66682
|
-
const fullPath =
|
|
68135
|
+
const fullPath = join99(claudeDir, file.path);
|
|
66683
68136
|
try {
|
|
66684
|
-
if (
|
|
68137
|
+
if (existsSync49(fullPath)) {
|
|
66685
68138
|
unlinkSync5(fullPath);
|
|
66686
68139
|
removedFiles.push(file.path);
|
|
66687
68140
|
logger.debug(`Removed: ${file.path}`);
|
|
@@ -66753,7 +68206,7 @@ async function removeSubdirectoriesFallback(claudeDir) {
|
|
|
66753
68206
|
const removedFiles = [];
|
|
66754
68207
|
let removedDirCount = 0;
|
|
66755
68208
|
for (const subdir of TAKUMI_SUBDIRECTORIES) {
|
|
66756
|
-
const subdirPath =
|
|
68209
|
+
const subdirPath = join99(claudeDir, subdir);
|
|
66757
68210
|
if (await import_fs_extra31.pathExists(subdirPath)) {
|
|
66758
68211
|
rmSync6(subdirPath, { recursive: true, force: true });
|
|
66759
68212
|
removedDirCount++;
|
|
@@ -66950,7 +68403,7 @@ async function handleSelection(ctx) {
|
|
|
66950
68403
|
}
|
|
66951
68404
|
}
|
|
66952
68405
|
}
|
|
66953
|
-
const resolvedDir =
|
|
68406
|
+
const resolvedDir = resolve24(targetDir);
|
|
66954
68407
|
logger.info(`Target directory: ${resolvedDir}`);
|
|
66955
68408
|
if (!ctx.options.global && isLocalSameAsGlobal(resolvedDir)) {
|
|
66956
68409
|
logger.warning("You're at HOME directory. Installing here modifies your GLOBAL Takumi.");
|
|
@@ -66978,7 +68431,7 @@ async function handleSelection(ctx) {
|
|
|
66978
68431
|
}
|
|
66979
68432
|
if (!ctx.options.fresh) {
|
|
66980
68433
|
const prefix = PathResolver.getPathPrefix(ctx.options.global);
|
|
66981
|
-
const claudeDir = prefix ?
|
|
68434
|
+
const claudeDir = prefix ? join100(resolvedDir, prefix) : resolvedDir;
|
|
66982
68435
|
try {
|
|
66983
68436
|
const existingMetadata = await readManifest(claudeDir);
|
|
66984
68437
|
if (existingMetadata?.kits) {
|
|
@@ -67011,7 +68464,7 @@ async function handleSelection(ctx) {
|
|
|
67011
68464
|
}
|
|
67012
68465
|
if (ctx.options.fresh) {
|
|
67013
68466
|
const prefix = PathResolver.getPathPrefix(ctx.options.global);
|
|
67014
|
-
const claudeDir = prefix ?
|
|
68467
|
+
const claudeDir = prefix ? join100(resolvedDir, prefix) : resolvedDir;
|
|
67015
68468
|
const canProceed = await handleFreshInstallation(claudeDir, ctx.prompts);
|
|
67016
68469
|
if (!canProceed) {
|
|
67017
68470
|
return { ...ctx, cancelled: true };
|
|
@@ -67031,7 +68484,7 @@ async function handleSelection(ctx) {
|
|
|
67031
68484
|
let currentVersion = null;
|
|
67032
68485
|
try {
|
|
67033
68486
|
const prefix = PathResolver.getPathPrefix(ctx.options.global);
|
|
67034
|
-
const claudeDir = prefix ?
|
|
68487
|
+
const claudeDir = prefix ? join100(resolvedDir, prefix) : resolvedDir;
|
|
67035
68488
|
const existingMetadata = await readManifest(claudeDir);
|
|
67036
68489
|
currentVersion = existingMetadata?.kits?.[kitType]?.version || null;
|
|
67037
68490
|
if (currentVersion) {
|
|
@@ -67119,7 +68572,7 @@ async function handleSelection(ctx) {
|
|
|
67119
68572
|
if (ctx.options.yes && !ctx.options.fresh && !ctx.options.force && releaseTag && !isOfflineMode) {
|
|
67120
68573
|
try {
|
|
67121
68574
|
const prefix = PathResolver.getPathPrefix(ctx.options.global);
|
|
67122
|
-
const claudeDir = prefix ?
|
|
68575
|
+
const claudeDir = prefix ? join100(resolvedDir, prefix) : resolvedDir;
|
|
67123
68576
|
const existingMetadata = await readManifest(claudeDir);
|
|
67124
68577
|
const installedKitVersion = existingMetadata?.kits?.[kitType]?.version;
|
|
67125
68578
|
if (installedKitVersion && versionsMatch(installedKitVersion, releaseTag)) {
|
|
@@ -67142,7 +68595,7 @@ async function handleSelection(ctx) {
|
|
|
67142
68595
|
let currentSecondaryVersion = null;
|
|
67143
68596
|
try {
|
|
67144
68597
|
const prefix = PathResolver.getPathPrefix(ctx.options.global);
|
|
67145
|
-
const claudeDir = prefix ?
|
|
68598
|
+
const claudeDir = prefix ? join100(resolvedDir, prefix) : resolvedDir;
|
|
67146
68599
|
const existingMetadata = await readManifest(claudeDir);
|
|
67147
68600
|
currentSecondaryVersion = existingMetadata?.kits?.[secondaryKit]?.version || null;
|
|
67148
68601
|
} catch {}
|
|
@@ -67226,12 +68679,12 @@ function resolveGlobalTargetDir(targetAgents2) {
|
|
|
67226
68679
|
// src/commands/init/phases/sync-handler.ts
|
|
67227
68680
|
init_paths();
|
|
67228
68681
|
import { copyFile as copyFile7, mkdir as mkdir28, open as open2, readFile as readFile39, rename as rename7, stat as stat12, unlink as unlink11, writeFile as writeFile28 } from "node:fs/promises";
|
|
67229
|
-
import { dirname as
|
|
68682
|
+
import { dirname as dirname29, join as join103, resolve as resolve25 } from "node:path";
|
|
67230
68683
|
|
|
67231
68684
|
// src/domains/sync/config-version-checker.ts
|
|
67232
68685
|
init_auth_client();
|
|
67233
68686
|
import { mkdir as mkdir27, readFile as readFile37, unlink as unlink10, writeFile as writeFile27 } from "node:fs/promises";
|
|
67234
|
-
import { join as
|
|
68687
|
+
import { join as join101 } from "node:path";
|
|
67235
68688
|
init_version_utils();
|
|
67236
68689
|
init_logger();
|
|
67237
68690
|
init_path_resolver();
|
|
@@ -67267,7 +68720,7 @@ var CACHE_FILENAME = "config-update-cache.json";
|
|
|
67267
68720
|
class ConfigVersionChecker {
|
|
67268
68721
|
static getCacheFilePath(kitType, global3) {
|
|
67269
68722
|
const cacheDir = PathResolver.getCacheDir(global3);
|
|
67270
|
-
return
|
|
68723
|
+
return join101(cacheDir, `${kitType}-${CACHE_FILENAME}`);
|
|
67271
68724
|
}
|
|
67272
68725
|
static async loadCache(kitType, global3) {
|
|
67273
68726
|
try {
|
|
@@ -67283,12 +68736,12 @@ class ConfigVersionChecker {
|
|
|
67283
68736
|
return null;
|
|
67284
68737
|
}
|
|
67285
68738
|
}
|
|
67286
|
-
static async saveCache(kitType, global3,
|
|
68739
|
+
static async saveCache(kitType, global3, cache2) {
|
|
67287
68740
|
try {
|
|
67288
68741
|
const cachePath = ConfigVersionChecker.getCacheFilePath(kitType, global3);
|
|
67289
68742
|
const cacheDir = PathResolver.getCacheDir(global3);
|
|
67290
68743
|
await mkdir27(cacheDir, { recursive: true });
|
|
67291
|
-
await writeFile27(cachePath, JSON.stringify(
|
|
68744
|
+
await writeFile27(cachePath, JSON.stringify(cache2, null, 2));
|
|
67292
68745
|
} catch (error) {
|
|
67293
68746
|
logger.debug(`Cache write failed: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
67294
68747
|
}
|
|
@@ -67323,21 +68776,21 @@ class ConfigVersionChecker {
|
|
|
67323
68776
|
return null;
|
|
67324
68777
|
}
|
|
67325
68778
|
const delay3 = baseBackoff * 2 ** attempt2;
|
|
67326
|
-
await new Promise((
|
|
68779
|
+
await new Promise((resolve25) => setTimeout(resolve25, delay3));
|
|
67327
68780
|
}
|
|
67328
68781
|
}
|
|
67329
68782
|
return null;
|
|
67330
68783
|
}
|
|
67331
68784
|
static async checkForUpdates(kitType, currentVersion, global3 = false) {
|
|
67332
68785
|
const normalizedCurrent = currentVersion.replace(/^v/, "");
|
|
67333
|
-
const
|
|
68786
|
+
const cache2 = await ConfigVersionChecker.loadCache(kitType, global3);
|
|
67334
68787
|
const now = Date.now();
|
|
67335
|
-
if (
|
|
67336
|
-
const hasUpdates = isNewerVersion(normalizedCurrent,
|
|
68788
|
+
if (cache2 && now - cache2.lastCheck < CACHE_TTL_MS) {
|
|
68789
|
+
const hasUpdates = isNewerVersion(normalizedCurrent, cache2.latestVersion);
|
|
67337
68790
|
return {
|
|
67338
68791
|
hasUpdates,
|
|
67339
68792
|
currentVersion: normalizedCurrent,
|
|
67340
|
-
latestVersion:
|
|
68793
|
+
latestVersion: cache2.latestVersion,
|
|
67341
68794
|
fromCache: true
|
|
67342
68795
|
};
|
|
67343
68796
|
}
|
|
@@ -67355,12 +68808,12 @@ class ConfigVersionChecker {
|
|
|
67355
68808
|
fromCache: false
|
|
67356
68809
|
};
|
|
67357
68810
|
}
|
|
67358
|
-
if (
|
|
67359
|
-
const hasUpdates = isNewerVersion(normalizedCurrent,
|
|
68811
|
+
if (cache2) {
|
|
68812
|
+
const hasUpdates = isNewerVersion(normalizedCurrent, cache2.latestVersion);
|
|
67360
68813
|
return {
|
|
67361
68814
|
hasUpdates,
|
|
67362
68815
|
currentVersion: normalizedCurrent,
|
|
67363
|
-
latestVersion:
|
|
68816
|
+
latestVersion: cache2.latestVersion,
|
|
67364
68817
|
fromCache: true
|
|
67365
68818
|
};
|
|
67366
68819
|
}
|
|
@@ -67387,11 +68840,11 @@ class ConfigVersionChecker {
|
|
|
67387
68840
|
init_ownership_checker();
|
|
67388
68841
|
init_logger();
|
|
67389
68842
|
import { lstat as lstat7, readFile as readFile38, readlink, realpath as realpath3, stat as stat11 } from "node:fs/promises";
|
|
67390
|
-
import { isAbsolute as isAbsolute3, join as
|
|
68843
|
+
import { isAbsolute as isAbsolute3, join as join102, normalize as normalize8, relative as relative16 } from "node:path";
|
|
67391
68844
|
var MAX_SYNC_FILE_SIZE = 10 * 1024 * 1024;
|
|
67392
68845
|
var MAX_SYMLINK_DEPTH = 20;
|
|
67393
|
-
async function validateSymlinkChain(
|
|
67394
|
-
let current =
|
|
68846
|
+
async function validateSymlinkChain(path11, basePath, maxDepth = MAX_SYMLINK_DEPTH) {
|
|
68847
|
+
let current = path11;
|
|
67395
68848
|
let depth = 0;
|
|
67396
68849
|
while (depth < maxDepth) {
|
|
67397
68850
|
try {
|
|
@@ -67399,11 +68852,11 @@ async function validateSymlinkChain(path9, basePath, maxDepth = MAX_SYMLINK_DEPT
|
|
|
67399
68852
|
if (!stats.isSymbolicLink())
|
|
67400
68853
|
break;
|
|
67401
68854
|
const target = await readlink(current);
|
|
67402
|
-
const resolvedTarget = isAbsolute3(target) ? target :
|
|
68855
|
+
const resolvedTarget = isAbsolute3(target) ? target : join102(current, "..", target);
|
|
67403
68856
|
const normalizedTarget = normalize8(resolvedTarget);
|
|
67404
68857
|
const rel = relative16(basePath, normalizedTarget);
|
|
67405
68858
|
if (rel.startsWith("..") || isAbsolute3(rel)) {
|
|
67406
|
-
throw new Error(`Symlink chain escapes base directory at depth ${depth}: ${
|
|
68859
|
+
throw new Error(`Symlink chain escapes base directory at depth ${depth}: ${path11}`);
|
|
67407
68860
|
}
|
|
67408
68861
|
current = normalizedTarget;
|
|
67409
68862
|
depth++;
|
|
@@ -67415,7 +68868,7 @@ async function validateSymlinkChain(path9, basePath, maxDepth = MAX_SYMLINK_DEPT
|
|
|
67415
68868
|
}
|
|
67416
68869
|
}
|
|
67417
68870
|
if (depth >= maxDepth) {
|
|
67418
|
-
throw new Error(`Symlink chain too deep (>${maxDepth}): ${
|
|
68871
|
+
throw new Error(`Symlink chain too deep (>${maxDepth}): ${path11}`);
|
|
67419
68872
|
}
|
|
67420
68873
|
}
|
|
67421
68874
|
async function validateSyncPath(basePath, filePath) {
|
|
@@ -67435,7 +68888,7 @@ async function validateSyncPath(basePath, filePath) {
|
|
|
67435
68888
|
if (normalized.startsWith("..") || normalized.includes("/../")) {
|
|
67436
68889
|
throw new Error(`Path traversal not allowed: ${filePath}`);
|
|
67437
68890
|
}
|
|
67438
|
-
const fullPath =
|
|
68891
|
+
const fullPath = join102(basePath, normalized);
|
|
67439
68892
|
const rel = relative16(basePath, fullPath);
|
|
67440
68893
|
if (rel.startsWith("..") || isAbsolute3(rel)) {
|
|
67441
68894
|
throw new Error(`Path escapes base directory: ${filePath}`);
|
|
@@ -67450,7 +68903,7 @@ async function validateSyncPath(basePath, filePath) {
|
|
|
67450
68903
|
}
|
|
67451
68904
|
} catch (error) {
|
|
67452
68905
|
if (error.code === "ENOENT") {
|
|
67453
|
-
const parentPath =
|
|
68906
|
+
const parentPath = join102(fullPath, "..");
|
|
67454
68907
|
try {
|
|
67455
68908
|
const resolvedBase = await realpath3(basePath);
|
|
67456
68909
|
const resolvedParent = await realpath3(parentPath);
|
|
@@ -67838,7 +69291,7 @@ async function handleSync(ctx) {
|
|
|
67838
69291
|
logger.error(`Sync not yet supported for ${targetAgent}. Only --agent claude-code supports --sync.`);
|
|
67839
69292
|
return { ...ctx, cancelled: true };
|
|
67840
69293
|
}
|
|
67841
|
-
const resolvedDir = ctx.options.global ? getClaudeDir() :
|
|
69294
|
+
const resolvedDir = ctx.options.global ? getClaudeDir() : resolve25(ctx.options.dir || ".");
|
|
67842
69295
|
const claudeDir = ctx.options.global ? resolvedDir : getLocalClaudeDir(resolvedDir);
|
|
67843
69296
|
if (!await import_fs_extra33.pathExists(claudeDir)) {
|
|
67844
69297
|
logger.error("Cannot sync: no .claude directory found");
|
|
@@ -67941,10 +69394,10 @@ function getLockTimeout() {
|
|
|
67941
69394
|
var STALE_LOCK_THRESHOLD_MS = 5 * 60 * 1000;
|
|
67942
69395
|
async function acquireSyncLock(global3) {
|
|
67943
69396
|
const cacheDir = PathResolver.getCacheDir(global3);
|
|
67944
|
-
const lockPath =
|
|
69397
|
+
const lockPath = join103(cacheDir, ".sync-lock");
|
|
67945
69398
|
const startTime = Date.now();
|
|
67946
69399
|
const lockTimeout = getLockTimeout();
|
|
67947
|
-
await mkdir28(
|
|
69400
|
+
await mkdir28(dirname29(lockPath), { recursive: true });
|
|
67948
69401
|
while (Date.now() - startTime < lockTimeout) {
|
|
67949
69402
|
try {
|
|
67950
69403
|
const handle = await open2(lockPath, "wx");
|
|
@@ -67968,7 +69421,7 @@ async function acquireSyncLock(global3) {
|
|
|
67968
69421
|
}
|
|
67969
69422
|
logger.debug(`Lock stat failed: ${statError}`);
|
|
67970
69423
|
}
|
|
67971
|
-
await new Promise((
|
|
69424
|
+
await new Promise((resolve26) => setTimeout(resolve26, 100));
|
|
67972
69425
|
continue;
|
|
67973
69426
|
}
|
|
67974
69427
|
throw err;
|
|
@@ -68022,7 +69475,7 @@ async function executeSyncMerge(ctx) {
|
|
|
68022
69475
|
try {
|
|
68023
69476
|
const sourcePath = await validateSyncPath(upstreamDir, file.path);
|
|
68024
69477
|
const targetPath = await validateSyncPath(ctx.claudeDir, file.path);
|
|
68025
|
-
const targetDir =
|
|
69478
|
+
const targetDir = join103(targetPath, "..");
|
|
68026
69479
|
try {
|
|
68027
69480
|
await mkdir28(targetDir, { recursive: true });
|
|
68028
69481
|
} catch (mkdirError) {
|
|
@@ -68193,7 +69646,7 @@ async function createBackup(claudeDir, files, backupDir) {
|
|
|
68193
69646
|
const sourcePath = await validateSyncPath(claudeDir, file.path);
|
|
68194
69647
|
if (await import_fs_extra33.pathExists(sourcePath)) {
|
|
68195
69648
|
const targetPath = await validateSyncPath(backupDir, file.path);
|
|
68196
|
-
const targetDir =
|
|
69649
|
+
const targetDir = join103(targetPath, "..");
|
|
68197
69650
|
await mkdir28(targetDir, { recursive: true });
|
|
68198
69651
|
await copyFile7(sourcePath, targetPath);
|
|
68199
69652
|
}
|
|
@@ -68219,38 +69672,38 @@ init_logger();
|
|
|
68219
69672
|
init_types2();
|
|
68220
69673
|
var import_fs_extra34 = __toESM(require_lib(), 1);
|
|
68221
69674
|
import { rename as rename8, rm as rm9 } from "node:fs/promises";
|
|
68222
|
-
import { join as
|
|
69675
|
+
import { join as join104, relative as relative17 } from "node:path";
|
|
68223
69676
|
async function collectDirsToRename(extractDir, folders) {
|
|
68224
69677
|
const dirsToRename = [];
|
|
68225
69678
|
if (folders.docs !== DEFAULT_FOLDERS.docs) {
|
|
68226
|
-
const docsPath =
|
|
69679
|
+
const docsPath = join104(extractDir, DEFAULT_FOLDERS.docs);
|
|
68227
69680
|
if (await import_fs_extra34.pathExists(docsPath)) {
|
|
68228
69681
|
dirsToRename.push({
|
|
68229
69682
|
from: docsPath,
|
|
68230
|
-
to:
|
|
69683
|
+
to: join104(extractDir, folders.docs)
|
|
68231
69684
|
});
|
|
68232
69685
|
}
|
|
68233
|
-
const claudeDocsPath =
|
|
69686
|
+
const claudeDocsPath = join104(extractDir, ".claude", DEFAULT_FOLDERS.docs);
|
|
68234
69687
|
if (await import_fs_extra34.pathExists(claudeDocsPath)) {
|
|
68235
69688
|
dirsToRename.push({
|
|
68236
69689
|
from: claudeDocsPath,
|
|
68237
|
-
to:
|
|
69690
|
+
to: join104(extractDir, ".claude", folders.docs)
|
|
68238
69691
|
});
|
|
68239
69692
|
}
|
|
68240
69693
|
}
|
|
68241
69694
|
if (folders.plans !== DEFAULT_FOLDERS.plans) {
|
|
68242
|
-
const plansPath =
|
|
69695
|
+
const plansPath = join104(extractDir, DEFAULT_FOLDERS.plans);
|
|
68243
69696
|
if (await import_fs_extra34.pathExists(plansPath)) {
|
|
68244
69697
|
dirsToRename.push({
|
|
68245
69698
|
from: plansPath,
|
|
68246
|
-
to:
|
|
69699
|
+
to: join104(extractDir, folders.plans)
|
|
68247
69700
|
});
|
|
68248
69701
|
}
|
|
68249
|
-
const claudePlansPath =
|
|
69702
|
+
const claudePlansPath = join104(extractDir, ".claude", DEFAULT_FOLDERS.plans);
|
|
68250
69703
|
if (await import_fs_extra34.pathExists(claudePlansPath)) {
|
|
68251
69704
|
dirsToRename.push({
|
|
68252
69705
|
from: claudePlansPath,
|
|
68253
|
-
to:
|
|
69706
|
+
to: join104(extractDir, ".claude", folders.plans)
|
|
68254
69707
|
});
|
|
68255
69708
|
}
|
|
68256
69709
|
}
|
|
@@ -68291,7 +69744,7 @@ async function renameFolders(dirsToRename, extractDir, options2) {
|
|
|
68291
69744
|
init_logger();
|
|
68292
69745
|
init_types2();
|
|
68293
69746
|
import { readFile as readFile40, readdir as readdir29, writeFile as writeFile29 } from "node:fs/promises";
|
|
68294
|
-
import { join as
|
|
69747
|
+
import { join as join105, relative as relative18 } from "node:path";
|
|
68295
69748
|
var TRANSFORMABLE_FILE_PATTERNS = [
|
|
68296
69749
|
".md",
|
|
68297
69750
|
".txt",
|
|
@@ -68344,7 +69797,7 @@ async function transformFileContents(dir, compiledReplacements, options2) {
|
|
|
68344
69797
|
let replacementsCount = 0;
|
|
68345
69798
|
const entries = await readdir29(dir, { withFileTypes: true });
|
|
68346
69799
|
for (const entry of entries) {
|
|
68347
|
-
const fullPath =
|
|
69800
|
+
const fullPath = join105(dir, entry.name);
|
|
68348
69801
|
if (entry.isDirectory()) {
|
|
68349
69802
|
if (entry.name === "node_modules" || entry.name === ".git") {
|
|
68350
69803
|
continue;
|
|
@@ -68362,9 +69815,9 @@ async function transformFileContents(dir, compiledReplacements, options2) {
|
|
|
68362
69815
|
let changeCount = 0;
|
|
68363
69816
|
for (const { regex: regex2, replacement } of compiledReplacements) {
|
|
68364
69817
|
regex2.lastIndex = 0;
|
|
68365
|
-
const
|
|
68366
|
-
if (
|
|
68367
|
-
changeCount +=
|
|
69818
|
+
const matches3 = newContent.match(regex2);
|
|
69819
|
+
if (matches3) {
|
|
69820
|
+
changeCount += matches3.length;
|
|
68368
69821
|
regex2.lastIndex = 0;
|
|
68369
69822
|
newContent = newContent.replace(regex2, replacement);
|
|
68370
69823
|
}
|
|
@@ -68481,7 +69934,7 @@ async function transformFolderPaths(extractDir, folders, options2 = {}) {
|
|
|
68481
69934
|
init_logger();
|
|
68482
69935
|
import { readFile as readFile41, readdir as readdir30, writeFile as writeFile30 } from "node:fs/promises";
|
|
68483
69936
|
import { platform as platform9 } from "node:os";
|
|
68484
|
-
import { extname as extname6, join as
|
|
69937
|
+
import { extname as extname6, join as join106 } from "node:path";
|
|
68485
69938
|
var IS_WINDOWS3 = platform9() === "win32";
|
|
68486
69939
|
var HOME_PREFIX = IS_WINDOWS3 ? "%USERPROFILE%" : "$HOME";
|
|
68487
69940
|
function getHomeDirPrefix() {
|
|
@@ -68582,8 +70035,8 @@ function transformContent(content) {
|
|
|
68582
70035
|
}
|
|
68583
70036
|
function shouldTransformFile3(filename) {
|
|
68584
70037
|
const ext2 = extname6(filename).toLowerCase();
|
|
68585
|
-
const
|
|
68586
|
-
return TRANSFORMABLE_EXTENSIONS3.has(ext2) || ALWAYS_TRANSFORM_FILES.has(
|
|
70038
|
+
const basename13 = filename.split("/").pop() || filename;
|
|
70039
|
+
return TRANSFORMABLE_EXTENSIONS3.has(ext2) || ALWAYS_TRANSFORM_FILES.has(basename13);
|
|
68587
70040
|
}
|
|
68588
70041
|
async function transformPathsForGlobalInstall(directory, options2 = {}) {
|
|
68589
70042
|
let filesTransformed = 0;
|
|
@@ -68593,7 +70046,7 @@ async function transformPathsForGlobalInstall(directory, options2 = {}) {
|
|
|
68593
70046
|
async function processDirectory2(dir) {
|
|
68594
70047
|
const entries = await readdir30(dir, { withFileTypes: true });
|
|
68595
70048
|
for (const entry of entries) {
|
|
68596
|
-
const fullPath =
|
|
70049
|
+
const fullPath = join106(dir, entry.name);
|
|
68597
70050
|
if (entry.isDirectory()) {
|
|
68598
70051
|
if (entry.name === "node_modules" || entry.name.startsWith(".") && entry.name !== ".claude") {
|
|
68599
70052
|
continue;
|
|
@@ -68860,20 +70313,20 @@ async function initCommand(options2) {
|
|
|
68860
70313
|
}
|
|
68861
70314
|
// src/commands/plan/plan-command.ts
|
|
68862
70315
|
init_output_manager();
|
|
68863
|
-
import { existsSync as
|
|
68864
|
-
import { dirname as
|
|
70316
|
+
import { existsSync as existsSync54, statSync as statSync7 } from "node:fs";
|
|
70317
|
+
import { dirname as dirname35, join as join110, parse as parse4, resolve as resolve29 } from "node:path";
|
|
68865
70318
|
|
|
68866
70319
|
// src/commands/plan/plan-read-handlers.ts
|
|
68867
|
-
import { existsSync as
|
|
68868
|
-
import { basename as
|
|
70320
|
+
import { existsSync as existsSync53, statSync as statSync6 } from "node:fs";
|
|
70321
|
+
import { basename as basename15, dirname as dirname34, join as join109, relative as relative19, resolve as resolve27 } from "node:path";
|
|
68869
70322
|
|
|
68870
70323
|
// src/domains/plan-parser/index.ts
|
|
68871
|
-
import { dirname as
|
|
70324
|
+
import { dirname as dirname33 } from "node:path";
|
|
68872
70325
|
|
|
68873
70326
|
// src/domains/plan-parser/plan-table-parser.ts
|
|
68874
70327
|
var import_gray_matter5 = __toESM(require_gray_matter(), 1);
|
|
68875
|
-
import { readFileSync as
|
|
68876
|
-
import { dirname as
|
|
70328
|
+
import { readFileSync as readFileSync17 } from "node:fs";
|
|
70329
|
+
import { dirname as dirname30, resolve as resolve26 } from "node:path";
|
|
68877
70330
|
function normalizeStatus(raw) {
|
|
68878
70331
|
const s3 = raw.toLowerCase().trim();
|
|
68879
70332
|
if (s3.includes("complete") || s3.includes("done") || s3.includes("✓") || s3.includes("✅")) {
|
|
@@ -68957,7 +70410,7 @@ function parseHeaderAwareTable(content, dir, options2) {
|
|
|
68957
70410
|
hasLinks = true;
|
|
68958
70411
|
linkText = linkMatch[1].trim();
|
|
68959
70412
|
name = filenameToTitle(linkText);
|
|
68960
|
-
file =
|
|
70413
|
+
file = resolve26(dir, linkMatch[2]);
|
|
68961
70414
|
} else {
|
|
68962
70415
|
name = nameRaw.replace(/\[.*?\]\(.*?\)/g, "").trim() || `Phase ${phaseId}`;
|
|
68963
70416
|
linkText = name;
|
|
@@ -68997,7 +70450,7 @@ function parseFormat1(content, dir, options2) {
|
|
|
68997
70450
|
phaseId,
|
|
68998
70451
|
name: name.trim(),
|
|
68999
70452
|
status: normalizeStatus(status2),
|
|
69000
|
-
file:
|
|
70453
|
+
file: resolve26(dir, linkPath),
|
|
69001
70454
|
linkText: linkText.trim(),
|
|
69002
70455
|
anchor
|
|
69003
70456
|
});
|
|
@@ -69017,7 +70470,7 @@ function parseFormat2(content, dir, options2) {
|
|
|
69017
70470
|
phaseId,
|
|
69018
70471
|
name: name.trim(),
|
|
69019
70472
|
status: normalizeStatus(status2),
|
|
69020
|
-
file:
|
|
70473
|
+
file: resolve26(dir, linkPath),
|
|
69021
70474
|
linkText,
|
|
69022
70475
|
anchor
|
|
69023
70476
|
});
|
|
@@ -69036,7 +70489,7 @@ function parseFormat2b(content, dir, options2) {
|
|
|
69036
70489
|
phaseId,
|
|
69037
70490
|
name: name.trim(),
|
|
69038
70491
|
status: normalizeStatus(status2),
|
|
69039
|
-
file:
|
|
70492
|
+
file: resolve26(dir, linkPath),
|
|
69040
70493
|
linkText: name.trim(),
|
|
69041
70494
|
anchor
|
|
69042
70495
|
});
|
|
@@ -69134,8 +70587,8 @@ function parseFormat4(content, planFilePath, options2) {
|
|
|
69134
70587
|
const hasCheck = /[✅✓]/.test(line);
|
|
69135
70588
|
current = { name, status: hasCheck ? "completed" : "pending" };
|
|
69136
70589
|
} else if (fileMatch && current) {
|
|
69137
|
-
const planDir =
|
|
69138
|
-
current.file =
|
|
70590
|
+
const planDir = dirname30(planFilePath);
|
|
70591
|
+
current.file = resolve26(planDir, fileMatch[1].trim());
|
|
69139
70592
|
} else if (statusMatch && current) {
|
|
69140
70593
|
current.status = normalizeStatus(statusMatch[2]);
|
|
69141
70594
|
}
|
|
@@ -69201,7 +70654,7 @@ function parseFormat6(content, dir, options2) {
|
|
|
69201
70654
|
phaseId,
|
|
69202
70655
|
name: phaseName,
|
|
69203
70656
|
status: checked.toLowerCase() === "x" ? "completed" : "pending",
|
|
69204
|
-
file:
|
|
70657
|
+
file: resolve26(dir, linkPath),
|
|
69205
70658
|
linkText: phaseName,
|
|
69206
70659
|
anchor
|
|
69207
70660
|
});
|
|
@@ -69238,31 +70691,31 @@ function parsePhasesFromBody(body, dir, options2) {
|
|
|
69238
70691
|
return parseFormat6(normalizedBody, dir, options2);
|
|
69239
70692
|
}
|
|
69240
70693
|
function parsePlanFile(planFilePath, options2) {
|
|
69241
|
-
const content =
|
|
69242
|
-
const dir =
|
|
70694
|
+
const content = readFileSync17(planFilePath, "utf8");
|
|
70695
|
+
const dir = dirname30(planFilePath);
|
|
69243
70696
|
const { data: frontmatter, content: body } = import_gray_matter5.default(content);
|
|
69244
70697
|
const phases = parsePhasesFromBody(body, dir, options2);
|
|
69245
70698
|
return { frontmatter, phases };
|
|
69246
70699
|
}
|
|
69247
70700
|
// src/domains/plan-parser/plan-scanner.ts
|
|
69248
|
-
import { existsSync as
|
|
69249
|
-
import { join as
|
|
70701
|
+
import { existsSync as existsSync50, readdirSync as readdirSync7 } from "node:fs";
|
|
70702
|
+
import { join as join107 } from "node:path";
|
|
69250
70703
|
function scanPlanDir(dir) {
|
|
69251
|
-
if (!
|
|
70704
|
+
if (!existsSync50(dir))
|
|
69252
70705
|
return [];
|
|
69253
70706
|
try {
|
|
69254
|
-
return
|
|
70707
|
+
return readdirSync7(dir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => join107(dir, entry.name, "plan.md")).filter(existsSync50);
|
|
69255
70708
|
} catch {
|
|
69256
70709
|
return [];
|
|
69257
70710
|
}
|
|
69258
70711
|
}
|
|
69259
70712
|
// src/domains/plan-parser/plan-validator.ts
|
|
69260
70713
|
var import_gray_matter6 = __toESM(require_gray_matter(), 1);
|
|
69261
|
-
import { existsSync as
|
|
69262
|
-
import { basename as
|
|
70714
|
+
import { existsSync as existsSync51, readFileSync as readFileSync18 } from "node:fs";
|
|
70715
|
+
import { basename as basename13, dirname as dirname31 } from "node:path";
|
|
69263
70716
|
function validatePlanFile(filePath, strict = false) {
|
|
69264
|
-
const content =
|
|
69265
|
-
const dir =
|
|
70717
|
+
const content = readFileSync18(filePath, "utf8");
|
|
70718
|
+
const dir = dirname31(filePath);
|
|
69266
70719
|
const issues = [];
|
|
69267
70720
|
const lines = content.split(`
|
|
69268
70721
|
`);
|
|
@@ -69298,14 +70751,14 @@ function validatePlanFile(filePath, strict = false) {
|
|
|
69298
70751
|
});
|
|
69299
70752
|
}
|
|
69300
70753
|
for (const phase of phases) {
|
|
69301
|
-
if (phase.file && !
|
|
69302
|
-
const fileBasename =
|
|
70754
|
+
if (phase.file && !existsSync51(phase.file)) {
|
|
70755
|
+
const fileBasename = basename13(phase.file);
|
|
69303
70756
|
const refLine = lines.findIndex((l2) => l2.includes(fileBasename));
|
|
69304
70757
|
issues.push({
|
|
69305
70758
|
line: refLine >= 0 ? refLine + 1 : 1,
|
|
69306
70759
|
severity: "warning",
|
|
69307
70760
|
code: "missing-phase-file",
|
|
69308
|
-
message: `Phase ${phase.phaseId} references '${
|
|
70761
|
+
message: `Phase ${phase.phaseId} references '${basename13(phase.file)}' which doesn't exist`
|
|
69309
70762
|
});
|
|
69310
70763
|
}
|
|
69311
70764
|
}
|
|
@@ -69318,9 +70771,9 @@ function validatePlanFile(filePath, strict = false) {
|
|
|
69318
70771
|
}
|
|
69319
70772
|
// src/domains/plan-parser/plan-writer.ts
|
|
69320
70773
|
var import_gray_matter7 = __toESM(require_gray_matter(), 1);
|
|
69321
|
-
import { mkdirSync as mkdirSync6, readFileSync as
|
|
69322
|
-
import { existsSync as
|
|
69323
|
-
import { basename as
|
|
70774
|
+
import { mkdirSync as mkdirSync6, readFileSync as readFileSync19, writeFileSync as writeFileSync9 } from "node:fs";
|
|
70775
|
+
import { existsSync as existsSync52 } from "node:fs";
|
|
70776
|
+
import { basename as basename14, dirname as dirname32, join as join108 } from "node:path";
|
|
69324
70777
|
function phaseNameToFilename(id, name) {
|
|
69325
70778
|
const numMatch = /^(\d+)([a-z]*)$/i.exec(id);
|
|
69326
70779
|
const num3 = numMatch ? numMatch[1] : id;
|
|
@@ -69428,12 +70881,12 @@ function scaffoldPlan(options2) {
|
|
|
69428
70881
|
mkdirSync6(dir, { recursive: true });
|
|
69429
70882
|
const resolvedPhases = resolvePhaseIds(options2.phases);
|
|
69430
70883
|
const optionsWithResolved = { ...options2, phases: resolvedPhases };
|
|
69431
|
-
const planFile =
|
|
70884
|
+
const planFile = join108(dir, "plan.md");
|
|
69432
70885
|
writeFileSync9(planFile, generatePlanMd(optionsWithResolved), "utf8");
|
|
69433
70886
|
const phaseFiles = [];
|
|
69434
70887
|
for (const phase of resolvedPhases) {
|
|
69435
70888
|
const filename = phaseNameToFilename(phase.id, phase.name);
|
|
69436
|
-
const phaseFile =
|
|
70889
|
+
const phaseFile = join108(dir, filename);
|
|
69437
70890
|
writeFileSync9(phaseFile, generatePhaseTemplate(phase), "utf8");
|
|
69438
70891
|
phaseFiles.push(phaseFile);
|
|
69439
70892
|
}
|
|
@@ -69458,7 +70911,7 @@ function isCanonicalFormat(content) {
|
|
|
69458
70911
|
return /^\|\s*phase\s*\|\s*name\s*\|\s*status\s*\|/im.test(content);
|
|
69459
70912
|
}
|
|
69460
70913
|
function updatePhaseStatus(planFile, phaseId, newStatus) {
|
|
69461
|
-
const raw =
|
|
70914
|
+
const raw = readFileSync19(planFile, "utf8").replace(/\r\n/g, `
|
|
69462
70915
|
`);
|
|
69463
70916
|
if (!isCanonicalFormat(raw)) {
|
|
69464
70917
|
console.error("[!] plan.md is not in canonical format — skipping status update");
|
|
@@ -69499,9 +70952,9 @@ function updatePhaseStatus(planFile, phaseId, newStatus) {
|
|
|
69499
70952
|
const updatedFrontmatter = { ...frontmatter, status: planStatus };
|
|
69500
70953
|
const updatedContent = import_gray_matter7.default.stringify(updatedBody, updatedFrontmatter);
|
|
69501
70954
|
writeFileSync9(planFile, updatedContent, "utf8");
|
|
69502
|
-
const planDir =
|
|
70955
|
+
const planDir = dirname32(planFile);
|
|
69503
70956
|
const phaseFilename = phaseNameFilenameFromTableRow(updatedBody, phaseId, planDir);
|
|
69504
|
-
if (phaseFilename &&
|
|
70957
|
+
if (phaseFilename && existsSync52(phaseFilename)) {
|
|
69505
70958
|
updatePhaseFileFrontmatter(phaseFilename, newStatus);
|
|
69506
70959
|
}
|
|
69507
70960
|
}
|
|
@@ -69513,25 +70966,25 @@ function phaseNameFilenameFromTableRow(body, phaseId, planDir) {
|
|
|
69513
70966
|
continue;
|
|
69514
70967
|
const linkMatch = /\[([^\]]+)\]\(\.\/([^)]+)\)/.exec(row);
|
|
69515
70968
|
if (linkMatch)
|
|
69516
|
-
return
|
|
70969
|
+
return join108(planDir, linkMatch[2]);
|
|
69517
70970
|
}
|
|
69518
70971
|
return null;
|
|
69519
70972
|
}
|
|
69520
70973
|
function updatePhaseFileFrontmatter(phaseFile, newStatus) {
|
|
69521
|
-
const raw =
|
|
70974
|
+
const raw = readFileSync19(phaseFile, "utf8");
|
|
69522
70975
|
const { data: frontmatter, content: body } = import_gray_matter7.default(raw);
|
|
69523
70976
|
const updated = { ...frontmatter, status: newStatus };
|
|
69524
70977
|
writeFileSync9(phaseFile, import_gray_matter7.default.stringify(body, updated), "utf8");
|
|
69525
70978
|
}
|
|
69526
70979
|
function addPhase(planFile, name, afterId) {
|
|
69527
|
-
const raw =
|
|
70980
|
+
const raw = readFileSync19(planFile, "utf8").replace(/\r\n/g, `
|
|
69528
70981
|
`);
|
|
69529
70982
|
if (!isCanonicalFormat(raw)) {
|
|
69530
70983
|
console.error("[!] plan.md is not in canonical format — cannot add phase");
|
|
69531
70984
|
throw new Error("Non-canonical plan.md — cannot add phase");
|
|
69532
70985
|
}
|
|
69533
70986
|
const { data: frontmatter, content: body } = import_gray_matter7.default(raw);
|
|
69534
|
-
const planDir =
|
|
70987
|
+
const planDir = dirname32(planFile);
|
|
69535
70988
|
const existingIds = [];
|
|
69536
70989
|
for (const match2 of body.matchAll(/^\|\s*(\d+[a-z]?)\s*\|/gim)) {
|
|
69537
70990
|
existingIds.push(match2[1].toLowerCase());
|
|
@@ -69560,7 +71013,7 @@ function addPhase(planFile, name, afterId) {
|
|
|
69560
71013
|
insertIdx = i;
|
|
69561
71014
|
}
|
|
69562
71015
|
if (insertIdx === -1) {
|
|
69563
|
-
throw new Error(`Phase ID "${afterId}" not found in ${
|
|
71016
|
+
throw new Error(`Phase ID "${afterId}" not found in ${basename14(planFile)}`);
|
|
69564
71017
|
}
|
|
69565
71018
|
lines.splice(insertIdx + 1, 0, newRow);
|
|
69566
71019
|
updatedBody = lines.join(`
|
|
@@ -69594,7 +71047,7 @@ function addPhase(planFile, name, afterId) {
|
|
|
69594
71047
|
`);
|
|
69595
71048
|
}
|
|
69596
71049
|
writeFileSync9(planFile, import_gray_matter7.default.stringify(updatedBody, frontmatter), "utf8");
|
|
69597
|
-
const phaseFilePath =
|
|
71050
|
+
const phaseFilePath = join108(planDir, filename);
|
|
69598
71051
|
writeFileSync9(phaseFilePath, generatePhaseTemplate({ id: phaseId, name }), "utf8");
|
|
69599
71052
|
return { phaseId, phaseFile: phaseFilePath };
|
|
69600
71053
|
}
|
|
@@ -69606,7 +71059,7 @@ function buildPlanSummary(planFile) {
|
|
|
69606
71059
|
const inProgress = phases.filter((p2) => p2.status === "in-progress").length;
|
|
69607
71060
|
const pending = phases.filter((p2) => p2.status === "pending").length;
|
|
69608
71061
|
return {
|
|
69609
|
-
planDir:
|
|
71062
|
+
planDir: dirname33(planFile),
|
|
69610
71063
|
planFile,
|
|
69611
71064
|
title: typeof frontmatter.title === "string" ? frontmatter.title : undefined,
|
|
69612
71065
|
description: typeof frontmatter.description === "string" ? frontmatter.description : undefined,
|
|
@@ -69643,7 +71096,7 @@ async function handleParse(target, options2) {
|
|
|
69643
71096
|
console.log(JSON.stringify({ file: relative19(process.cwd(), planFile), frontmatter, phases }, null, 2));
|
|
69644
71097
|
return;
|
|
69645
71098
|
}
|
|
69646
|
-
const title = typeof frontmatter.title === "string" ? frontmatter.title :
|
|
71099
|
+
const title = typeof frontmatter.title === "string" ? frontmatter.title : basename15(dirname34(planFile));
|
|
69647
71100
|
console.log();
|
|
69648
71101
|
console.log(import_picocolors25.default.bold(` Plan: ${title}`));
|
|
69649
71102
|
console.log(` File: ${planFile}`);
|
|
@@ -69697,8 +71150,8 @@ async function handleValidate(target, options2) {
|
|
|
69697
71150
|
process.exitCode = 1;
|
|
69698
71151
|
}
|
|
69699
71152
|
async function handleStatus(target, options2) {
|
|
69700
|
-
const t = target ?
|
|
69701
|
-
const plansDir = t &&
|
|
71153
|
+
const t = target ? resolve27(target) : null;
|
|
71154
|
+
const plansDir = t && existsSync53(t) && statSync6(t).isDirectory() && !existsSync53(join109(t, "plan.md")) ? t : null;
|
|
69702
71155
|
if (plansDir) {
|
|
69703
71156
|
const planFiles = scanPlanDir(plansDir);
|
|
69704
71157
|
if (planFiles.length === 0) {
|
|
@@ -69723,14 +71176,14 @@ async function handleStatus(target, options2) {
|
|
|
69723
71176
|
try {
|
|
69724
71177
|
const s3 = buildPlanSummary(pf);
|
|
69725
71178
|
const bar = progressBar(s3.completed, s3.totalPhases);
|
|
69726
|
-
const title2 = s3.title ??
|
|
71179
|
+
const title2 = s3.title ?? basename15(dirname34(pf));
|
|
69727
71180
|
console.log(` ${import_picocolors25.default.bold(title2)}`);
|
|
69728
71181
|
console.log(` ${bar}`);
|
|
69729
71182
|
if (s3.inProgress > 0)
|
|
69730
71183
|
console.log(` [~] ${s3.inProgress} in progress`);
|
|
69731
71184
|
console.log();
|
|
69732
71185
|
} catch {
|
|
69733
|
-
console.log(` [X] Failed to read: ${
|
|
71186
|
+
console.log(` [X] Failed to read: ${basename15(dirname34(pf))}`);
|
|
69734
71187
|
console.log();
|
|
69735
71188
|
}
|
|
69736
71189
|
}
|
|
@@ -69754,7 +71207,7 @@ async function handleStatus(target, options2) {
|
|
|
69754
71207
|
console.log(JSON.stringify(summary, null, 2));
|
|
69755
71208
|
return;
|
|
69756
71209
|
}
|
|
69757
|
-
const title = summary.title ??
|
|
71210
|
+
const title = summary.title ?? basename15(dirname34(planFile));
|
|
69758
71211
|
console.log();
|
|
69759
71212
|
console.log(import_picocolors25.default.bold(` ${title}`));
|
|
69760
71213
|
if (summary.status)
|
|
@@ -69780,7 +71233,7 @@ async function handleKanban(target, _options) {
|
|
|
69780
71233
|
}
|
|
69781
71234
|
|
|
69782
71235
|
// src/commands/plan/plan-write-handlers.ts
|
|
69783
|
-
import { basename as
|
|
71236
|
+
import { basename as basename16, relative as relative20, resolve as resolve28 } from "node:path";
|
|
69784
71237
|
init_output_manager();
|
|
69785
71238
|
var import_picocolors26 = __toESM(require_picocolors(), 1);
|
|
69786
71239
|
async function handleCreate(target, options2) {
|
|
@@ -69816,7 +71269,7 @@ async function handleCreate(target, options2) {
|
|
|
69816
71269
|
const result = scaffoldPlan({
|
|
69817
71270
|
title: options2.title,
|
|
69818
71271
|
phases: phaseNames.map((name) => ({ name })),
|
|
69819
|
-
dir:
|
|
71272
|
+
dir: resolve28(dir),
|
|
69820
71273
|
priority,
|
|
69821
71274
|
issue: options2.issue ? Number(options2.issue) : undefined
|
|
69822
71275
|
});
|
|
@@ -69830,10 +71283,10 @@ async function handleCreate(target, options2) {
|
|
|
69830
71283
|
}
|
|
69831
71284
|
console.log();
|
|
69832
71285
|
console.log(import_picocolors26.default.bold(` [OK] Plan created: ${options2.title}`));
|
|
69833
|
-
console.log(` Directory: ${
|
|
71286
|
+
console.log(` Directory: ${resolve28(dir)}`);
|
|
69834
71287
|
console.log(` Phases: ${result.phaseFiles.length}`);
|
|
69835
71288
|
for (const f4 of result.phaseFiles) {
|
|
69836
|
-
console.log(` [ ] ${
|
|
71289
|
+
console.log(` [ ] ${basename16(f4)}`);
|
|
69837
71290
|
}
|
|
69838
71291
|
console.log();
|
|
69839
71292
|
}
|
|
@@ -69928,23 +71381,23 @@ async function handleAddPhase(target, options2) {
|
|
|
69928
71381
|
|
|
69929
71382
|
// src/commands/plan/plan-command.ts
|
|
69930
71383
|
function resolvePlanFile(target) {
|
|
69931
|
-
const t = target ?
|
|
69932
|
-
if (
|
|
69933
|
-
const stat13 =
|
|
71384
|
+
const t = target ? resolve29(target) : process.cwd();
|
|
71385
|
+
if (existsSync54(t)) {
|
|
71386
|
+
const stat13 = statSync7(t);
|
|
69934
71387
|
if (stat13.isFile())
|
|
69935
71388
|
return t;
|
|
69936
|
-
const candidate =
|
|
69937
|
-
if (
|
|
71389
|
+
const candidate = join110(t, "plan.md");
|
|
71390
|
+
if (existsSync54(candidate))
|
|
69938
71391
|
return candidate;
|
|
69939
71392
|
}
|
|
69940
71393
|
if (!target) {
|
|
69941
71394
|
let dir = process.cwd();
|
|
69942
|
-
const root =
|
|
71395
|
+
const root = parse4(dir).root;
|
|
69943
71396
|
while (dir !== root) {
|
|
69944
|
-
const candidate =
|
|
69945
|
-
if (
|
|
71397
|
+
const candidate = join110(dir, "plan.md");
|
|
71398
|
+
if (existsSync54(candidate))
|
|
69946
71399
|
return candidate;
|
|
69947
|
-
dir =
|
|
71400
|
+
dir = dirname35(dir);
|
|
69948
71401
|
}
|
|
69949
71402
|
}
|
|
69950
71403
|
return null;
|
|
@@ -69992,7 +71445,7 @@ async function planCommand(action, target, options2) {
|
|
|
69992
71445
|
let resolvedTarget = target;
|
|
69993
71446
|
if (resolvedAction && !knownActions.has(resolvedAction)) {
|
|
69994
71447
|
const looksLikePath = resolvedAction.includes("/") || resolvedAction.includes("\\") || resolvedAction.endsWith(".md") || resolvedAction === "." || resolvedAction === "..";
|
|
69995
|
-
const existsOnDisk = !looksLikePath &&
|
|
71448
|
+
const existsOnDisk = !looksLikePath && existsSync54(resolve29(resolvedAction));
|
|
69996
71449
|
if (looksLikePath || existsOnDisk) {
|
|
69997
71450
|
resolvedTarget = resolvedAction;
|
|
69998
71451
|
resolvedAction = undefined;
|
|
@@ -70036,24 +71489,24 @@ init_logger();
|
|
|
70036
71489
|
init_logger();
|
|
70037
71490
|
|
|
70038
71491
|
// src/commands/telemetry/shared.ts
|
|
70039
|
-
import { existsSync as
|
|
70040
|
-
import { homedir as
|
|
70041
|
-
import { join as
|
|
71492
|
+
import { existsSync as existsSync55, readFileSync as readFileSync20, readdirSync as readdirSync8 } from "node:fs";
|
|
71493
|
+
import { homedir as homedir28 } from "node:os";
|
|
71494
|
+
import { join as join111 } from "node:path";
|
|
70042
71495
|
init_token_store();
|
|
70043
71496
|
init_manifest_path_resolver();
|
|
70044
71497
|
init_takumi_constants();
|
|
70045
|
-
var USER_CACHE_PATH =
|
|
70046
|
-
var EVENT_BUFFER_DIR =
|
|
70047
|
-
var RATE_STATE_PATH =
|
|
70048
|
-
var TAKUMI_MANIFEST_PATH =
|
|
70049
|
-
var LEGACY_METADATA_PATH =
|
|
71498
|
+
var USER_CACHE_PATH = join111(homedir28(), ".claude", "sk-user.json");
|
|
71499
|
+
var EVENT_BUFFER_DIR = join111(homedir28(), ".claude", "sk-events");
|
|
71500
|
+
var RATE_STATE_PATH = join111(homedir28(), ".claude", "sk-rate-state.json");
|
|
71501
|
+
var TAKUMI_MANIFEST_PATH = join111(homedir28(), ".claude", MANIFEST_FILENAME);
|
|
71502
|
+
var LEGACY_METADATA_PATH = join111(homedir28(), ".claude", LEGACY_MANIFEST_FILENAME);
|
|
70050
71503
|
var TELEMETRY_HOOK_FIELD = "hooks.telemetry";
|
|
70051
71504
|
var TOKEN_PLACEHOLDER = "__INJECT_AT_RELEASE__";
|
|
70052
71505
|
function readUserCache() {
|
|
70053
71506
|
try {
|
|
70054
|
-
if (!
|
|
71507
|
+
if (!existsSync55(USER_CACHE_PATH))
|
|
70055
71508
|
return null;
|
|
70056
|
-
const parsed = JSON.parse(
|
|
71509
|
+
const parsed = JSON.parse(readFileSync20(USER_CACHE_PATH, "utf8"));
|
|
70057
71510
|
if (!parsed || typeof parsed !== "object")
|
|
70058
71511
|
return null;
|
|
70059
71512
|
return parsed;
|
|
@@ -70063,9 +71516,9 @@ function readUserCache() {
|
|
|
70063
71516
|
}
|
|
70064
71517
|
function countBufferFiles() {
|
|
70065
71518
|
try {
|
|
70066
|
-
if (!
|
|
71519
|
+
if (!existsSync55(EVENT_BUFFER_DIR))
|
|
70067
71520
|
return 0;
|
|
70068
|
-
return
|
|
71521
|
+
return readdirSync8(EVENT_BUFFER_DIR).filter((f4) => f4.endsWith(".jsonl")).length;
|
|
70069
71522
|
} catch {
|
|
70070
71523
|
return 0;
|
|
70071
71524
|
}
|
|
@@ -70075,9 +71528,9 @@ function readTelemetryConfig() {
|
|
|
70075
71528
|
const envToken = process.env.TAKUMI_TELEMETRY_TOKEN;
|
|
70076
71529
|
let metadata = null;
|
|
70077
71530
|
try {
|
|
70078
|
-
const resolved = findManifestPathSync(
|
|
71531
|
+
const resolved = findManifestPathSync(join111(homedir28(), ".claude"));
|
|
70079
71532
|
if (resolved) {
|
|
70080
|
-
metadata = JSON.parse(
|
|
71533
|
+
metadata = JSON.parse(readFileSync20(resolved.path, "utf8"));
|
|
70081
71534
|
}
|
|
70082
71535
|
} catch {
|
|
70083
71536
|
metadata = null;
|
|
@@ -70093,16 +71546,16 @@ function readTelemetryConfig() {
|
|
|
70093
71546
|
return { endpoint, token };
|
|
70094
71547
|
}
|
|
70095
71548
|
function collectRuntimeContext() {
|
|
70096
|
-
const
|
|
71549
|
+
const cache2 = readUserCache();
|
|
70097
71550
|
const { endpoint, token } = readTelemetryConfig();
|
|
70098
71551
|
return {
|
|
70099
|
-
githubLogin: typeof
|
|
70100
|
-
cacheResolvedAt: typeof
|
|
70101
|
-
cacheSource:
|
|
71552
|
+
githubLogin: typeof cache2?.githubLogin === "string" ? cache2.githubLogin : null,
|
|
71553
|
+
cacheResolvedAt: typeof cache2?.resolvedAt === "number" ? cache2.resolvedAt : null,
|
|
71554
|
+
cacheSource: cache2?.source === "gh" || cache2?.source === "manual" ? cache2.source : null,
|
|
70102
71555
|
bufferFileCount: countBufferFiles(),
|
|
70103
71556
|
bufferDir: EVENT_BUFFER_DIR,
|
|
70104
|
-
rateStateExists:
|
|
70105
|
-
userCacheExists:
|
|
71557
|
+
rateStateExists: existsSync55(RATE_STATE_PATH),
|
|
71558
|
+
userCacheExists: existsSync55(USER_CACHE_PATH),
|
|
70106
71559
|
endpoint,
|
|
70107
71560
|
tokenConfigured: Boolean(token)
|
|
70108
71561
|
};
|
|
@@ -70252,8 +71705,8 @@ init_logger();
|
|
|
70252
71705
|
init_safe_prompts();
|
|
70253
71706
|
init_safe_spinner();
|
|
70254
71707
|
var import_fs_extra36 = __toESM(require_lib(), 1);
|
|
70255
|
-
import { readdirSync as
|
|
70256
|
-
import { join as
|
|
71708
|
+
import { readdirSync as readdirSync10, rmSync as rmSync8 } from "node:fs";
|
|
71709
|
+
import { join as join113, resolve as resolve30, sep as sep10 } from "node:path";
|
|
70257
71710
|
|
|
70258
71711
|
// src/commands/uninstall/analysis-handler.ts
|
|
70259
71712
|
init_metadata_migration();
|
|
@@ -70263,13 +71716,13 @@ init_logger();
|
|
|
70263
71716
|
init_safe_prompts();
|
|
70264
71717
|
init_takumi_constants();
|
|
70265
71718
|
var import_picocolors27 = __toESM(require_picocolors(), 1);
|
|
70266
|
-
import { existsSync as
|
|
70267
|
-
import { dirname as
|
|
71719
|
+
import { existsSync as existsSync56, readdirSync as readdirSync9, rmSync as rmSync7 } from "node:fs";
|
|
71720
|
+
import { dirname as dirname36, join as join112 } from "node:path";
|
|
70268
71721
|
function listPresentManifestNames(installPath) {
|
|
70269
71722
|
const present = [];
|
|
70270
|
-
if (
|
|
71723
|
+
if (existsSync56(getManifestPath(installPath)))
|
|
70271
71724
|
present.push(MANIFEST_FILENAME);
|
|
70272
|
-
if (
|
|
71725
|
+
if (existsSync56(getLegacyManifestPath(installPath)))
|
|
70273
71726
|
present.push(LEGACY_MANIFEST_FILENAME);
|
|
70274
71727
|
return present;
|
|
70275
71728
|
}
|
|
@@ -70287,15 +71740,15 @@ function classifyFileByOwnership(ownership, forceOverwrite, deleteReason) {
|
|
|
70287
71740
|
}
|
|
70288
71741
|
async function cleanupEmptyDirectories3(filePath, installationRoot) {
|
|
70289
71742
|
let cleaned = 0;
|
|
70290
|
-
let currentDir =
|
|
71743
|
+
let currentDir = dirname36(filePath);
|
|
70291
71744
|
while (currentDir !== installationRoot && currentDir.startsWith(installationRoot)) {
|
|
70292
71745
|
try {
|
|
70293
|
-
const entries =
|
|
71746
|
+
const entries = readdirSync9(currentDir);
|
|
70294
71747
|
if (entries.length === 0) {
|
|
70295
71748
|
rmSync7(currentDir, { recursive: true });
|
|
70296
71749
|
cleaned++;
|
|
70297
71750
|
logger.debug(`Removed empty directory: ${currentDir}`);
|
|
70298
|
-
currentDir =
|
|
71751
|
+
currentDir = dirname36(currentDir);
|
|
70299
71752
|
} else {
|
|
70300
71753
|
break;
|
|
70301
71754
|
}
|
|
@@ -70317,7 +71770,7 @@ async function analyzeInstallation(installation, forceOverwrite, kit) {
|
|
|
70317
71770
|
if (uninstallManifest.isMultiKit && kit && metadata?.kits?.[kit]) {
|
|
70318
71771
|
const kitFiles = metadata.kits[kit].files || [];
|
|
70319
71772
|
for (const trackedFile of kitFiles) {
|
|
70320
|
-
const filePath =
|
|
71773
|
+
const filePath = join112(installation.path, trackedFile.path);
|
|
70321
71774
|
if (uninstallManifest.filesToPreserve.includes(trackedFile.path)) {
|
|
70322
71775
|
result.toPreserve.push({ path: trackedFile.path, reason: "shared with other kit" });
|
|
70323
71776
|
continue;
|
|
@@ -70349,7 +71802,7 @@ async function analyzeInstallation(installation, forceOverwrite, kit) {
|
|
|
70349
71802
|
return result;
|
|
70350
71803
|
}
|
|
70351
71804
|
for (const trackedFile of allTrackedFiles) {
|
|
70352
|
-
const filePath =
|
|
71805
|
+
const filePath = join112(installation.path, trackedFile.path);
|
|
70353
71806
|
const ownershipResult = await OwnershipChecker.checkOwnership(filePath, metadata, installation.path);
|
|
70354
71807
|
if (!ownershipResult.exists)
|
|
70355
71808
|
continue;
|
|
@@ -70405,17 +71858,17 @@ async function isDirectory(filePath) {
|
|
|
70405
71858
|
}
|
|
70406
71859
|
async function isPathSafeToRemove(filePath, baseDir) {
|
|
70407
71860
|
try {
|
|
70408
|
-
const resolvedPath =
|
|
70409
|
-
const resolvedBase =
|
|
70410
|
-
if (!resolvedPath.startsWith(resolvedBase +
|
|
71861
|
+
const resolvedPath = resolve30(filePath);
|
|
71862
|
+
const resolvedBase = resolve30(baseDir);
|
|
71863
|
+
if (!resolvedPath.startsWith(resolvedBase + sep10) && resolvedPath !== resolvedBase) {
|
|
70411
71864
|
logger.debug(`Path outside installation directory: ${filePath}`);
|
|
70412
71865
|
return false;
|
|
70413
71866
|
}
|
|
70414
71867
|
const stats = await import_fs_extra36.lstat(filePath);
|
|
70415
71868
|
if (stats.isSymbolicLink()) {
|
|
70416
71869
|
const realPath = await import_fs_extra36.realpath(filePath);
|
|
70417
|
-
const resolvedReal =
|
|
70418
|
-
if (!resolvedReal.startsWith(resolvedBase +
|
|
71870
|
+
const resolvedReal = resolve30(realPath);
|
|
71871
|
+
if (!resolvedReal.startsWith(resolvedBase + sep10) && resolvedReal !== resolvedBase) {
|
|
70419
71872
|
logger.debug(`Symlink points outside installation directory: ${filePath} -> ${realPath}`);
|
|
70420
71873
|
return false;
|
|
70421
71874
|
}
|
|
@@ -70448,7 +71901,7 @@ async function removeInstallations(installations, options2) {
|
|
|
70448
71901
|
let removedCount = 0;
|
|
70449
71902
|
let cleanedDirs = 0;
|
|
70450
71903
|
for (const item of analysis.toDelete) {
|
|
70451
|
-
const filePath =
|
|
71904
|
+
const filePath = join113(installation.path, item.path);
|
|
70452
71905
|
if (!await import_fs_extra36.pathExists(filePath))
|
|
70453
71906
|
continue;
|
|
70454
71907
|
if (!await isPathSafeToRemove(filePath, installation.path)) {
|
|
@@ -70467,7 +71920,7 @@ async function removeInstallations(installations, options2) {
|
|
|
70467
71920
|
await ManifestWriter.removeKitFromManifest(installation.path, options2.kit);
|
|
70468
71921
|
}
|
|
70469
71922
|
try {
|
|
70470
|
-
const remaining =
|
|
71923
|
+
const remaining = readdirSync10(installation.path);
|
|
70471
71924
|
if (remaining.length === 0) {
|
|
70472
71925
|
rmSync8(installation.path, { recursive: true });
|
|
70473
71926
|
logger.debug(`Removed empty installation directory: ${installation.path}`);
|
|
@@ -70878,12 +72331,12 @@ async function promptKitUpdate(beta, yes, deps) {
|
|
|
70878
72331
|
args.push("--beta");
|
|
70879
72332
|
const displayCmd = `tkm ${args.join(" ")}`;
|
|
70880
72333
|
logger.info(`Running: ${displayCmd}`);
|
|
70881
|
-
const spawnFn = deps?.spawnInitFn ?? ((spawnArgs) => new Promise((
|
|
72334
|
+
const spawnFn = deps?.spawnInitFn ?? ((spawnArgs) => new Promise((resolve31) => {
|
|
70882
72335
|
const child = spawn3("tkm", spawnArgs, { stdio: "inherit", shell: true });
|
|
70883
|
-
child.on("close", (code) =>
|
|
72336
|
+
child.on("close", (code) => resolve31(code ?? 1));
|
|
70884
72337
|
child.on("error", (err) => {
|
|
70885
72338
|
logger.verbose(`Failed to spawn tkm init: ${err.message}`);
|
|
70886
|
-
|
|
72339
|
+
resolve31(1);
|
|
70887
72340
|
});
|
|
70888
72341
|
}));
|
|
70889
72342
|
const exitCode = await spawnFn(args);
|
|
@@ -71215,6 +72668,19 @@ function registerCommands(cli) {
|
|
|
71215
72668
|
cli.command("versions", "List available versions of Takumi repositories").option("--kit <kit>", "Filter by specific kit (core)").option("--limit <limit>", "Number of releases to show (default: 30)").option("--all", "Show the beta channel (prereleases only) instead of the stable channel. " + "On --use-gh, returns all release types interleaved.").option("--use-gh", "Use legacy GitHub release source (requires gh CLI)").action(async (options2) => {
|
|
71216
72669
|
await versionCommand(options2);
|
|
71217
72670
|
});
|
|
72671
|
+
cli.command("console", "Start local bridge and open session console in browser").option("--port <port>", "Bridge port (default: 8765, auto-bump on conflict)").option("--no-open", "Don't open the browser; print URL only").action(async (options2) => {
|
|
72672
|
+
let port;
|
|
72673
|
+
if (options2.port !== undefined) {
|
|
72674
|
+
const n = Number(options2.port);
|
|
72675
|
+
if (!Number.isInteger(n) || n < 0 || n > 65535) {
|
|
72676
|
+
console.error(`Invalid --port value: ${options2.port}. Expected integer 0-65535.`);
|
|
72677
|
+
process.exitCode = 1;
|
|
72678
|
+
return;
|
|
72679
|
+
}
|
|
72680
|
+
port = n;
|
|
72681
|
+
}
|
|
72682
|
+
await consoleCommand({ port, noOpen: options2.open === false });
|
|
72683
|
+
});
|
|
71218
72684
|
cli.command("doctor", "Comprehensive health check for Takumi").option("--report", "Generate shareable diagnostic report").option("--fix", "Auto-fix all fixable issues").option("--check-only", "CI mode: no prompts, exit 1 on failures").option("--json", "Output JSON format").option("--full", "Include extended priority checks (slower)").action(async (options2) => {
|
|
71219
72685
|
await doctorCommand(options2);
|
|
71220
72686
|
});
|
|
@@ -71243,8 +72709,8 @@ function registerCommands(cli) {
|
|
|
71243
72709
|
cli.command("plan [action] [target]", "Plan management: parse, validate, status, kanban, create, check, uncheck, add-phase").option("--json", "Output in JSON format").option("--strict", "Strict validation mode").option("--title <title>", "Plan title (for create)").option("--phases <phases>", "Comma-separated phase names (for create)").option("--dir <dir>", "Plan directory (for create)").option("--priority <priority>", "Priority: P1, P2, P3 (for create)").option("--issue <issue>", "GitHub issue number (for create)").option("--after <after>", "Insert after phase ID (for add-phase)").option("--start", "Mark as in-progress instead of completed (for check)").action(async (action, target, options2) => {
|
|
71244
72710
|
await planCommand(action, target, options2);
|
|
71245
72711
|
});
|
|
71246
|
-
cli.command("api [action] [service] [path]", "Interact with Takumi API and proxy services").option("--method <method>", "HTTP method for proxy requests (default: GET)").option("--body <json>", "Request body as JSON string (proxy only)").option("--query <json>", "Query params as JSON string (proxy only)").option("--key <key>", "API key to use (setup only)").option("--force", "Force re-setup even if key exists (setup only)").option("--json", "Output raw JSON instead of formatted display").option("--locale <locale>", "Locale for vidcap summary/caption (default: en)").option("--max-results <n>", "Max results for vidcap search").option("--second <s>", "Timestamp in seconds for vidcap screenshot").option("--order <order>", "Sort order for vidcap comments (time/relevance)").option("--format <fmt>", "Summary format for reviewweb (bullet/paragraph)").option("--max-length <n>", "Max summary length for reviewweb").option("--instructions <text>", "Extraction instructions for reviewweb extract").option("--template <json>", "JSON template for reviewweb extract").option("--type <type>", "Link type filter for reviewweb links (web/image/file/all)").option("--country <code>", "Country code for reviewweb SEO commands").action(async (action, service,
|
|
71247
|
-
await apiCommand(action, service,
|
|
72712
|
+
cli.command("api [action] [service] [path]", "Interact with Takumi API and proxy services").option("--method <method>", "HTTP method for proxy requests (default: GET)").option("--body <json>", "Request body as JSON string (proxy only)").option("--query <json>", "Query params as JSON string (proxy only)").option("--key <key>", "API key to use (setup only)").option("--force", "Force re-setup even if key exists (setup only)").option("--json", "Output raw JSON instead of formatted display").option("--locale <locale>", "Locale for vidcap summary/caption (default: en)").option("--max-results <n>", "Max results for vidcap search").option("--second <s>", "Timestamp in seconds for vidcap screenshot").option("--order <order>", "Sort order for vidcap comments (time/relevance)").option("--format <fmt>", "Summary format for reviewweb (bullet/paragraph)").option("--max-length <n>", "Max summary length for reviewweb").option("--instructions <text>", "Extraction instructions for reviewweb extract").option("--template <json>", "JSON template for reviewweb extract").option("--type <type>", "Link type filter for reviewweb links (web/image/file/all)").option("--country <code>", "Country code for reviewweb SEO commands").action(async (action, service, path11, options2) => {
|
|
72713
|
+
await apiCommand(action, service, path11, options2);
|
|
71248
72714
|
});
|
|
71249
72715
|
cli.command("auth [action]", "Sign in/out, refresh, and check Takumi session (login|logout|refresh|status)").option("--json", "Machine-readable JSON output (status, refresh)").option("-f, --force", "Force a token refresh even when the current token is still valid (refresh only)").action(async (action, options2 = {}) => {
|
|
71250
72716
|
switch (action) {
|
|
@@ -71279,8 +72745,8 @@ init_version_checker();
|
|
|
71279
72745
|
init_manifest_path_resolver();
|
|
71280
72746
|
init_logger();
|
|
71281
72747
|
init_types2();
|
|
71282
|
-
import { readFileSync as
|
|
71283
|
-
import { join as
|
|
72748
|
+
import { readFileSync as readFileSync21 } from "node:fs";
|
|
72749
|
+
import { join as join114 } from "node:path";
|
|
71284
72750
|
var PROVIDER_LOCAL_SUBDIRS = {
|
|
71285
72751
|
"claude-code": ".claude",
|
|
71286
72752
|
codex: ".codex"
|
|
@@ -71335,7 +72801,7 @@ async function displayVersion() {
|
|
|
71335
72801
|
const localSubdir = PROVIDER_LOCAL_SUBDIRS[provider];
|
|
71336
72802
|
if (!localSubdir)
|
|
71337
72803
|
continue;
|
|
71338
|
-
const localRoot =
|
|
72804
|
+
const localRoot = join114(process.cwd(), localSubdir);
|
|
71339
72805
|
if (localRoot === inst.globalRoot())
|
|
71340
72806
|
continue;
|
|
71341
72807
|
const resolved = findManifestPathSync(localRoot);
|
|
@@ -71345,7 +72811,7 @@ async function displayVersion() {
|
|
|
71345
72811
|
}
|
|
71346
72812
|
for (const { provider, path: metaPath } of localChecks) {
|
|
71347
72813
|
try {
|
|
71348
|
-
const rawMetadata = JSON.parse(
|
|
72814
|
+
const rawMetadata = JSON.parse(readFileSync21(metaPath, "utf-8"));
|
|
71349
72815
|
const metadata = MetadataSchema.parse(rawMetadata);
|
|
71350
72816
|
const kitsDisplay = formatInstalledKits(metadata);
|
|
71351
72817
|
if (kitsDisplay) {
|
|
@@ -71365,7 +72831,7 @@ async function displayVersion() {
|
|
|
71365
72831
|
const resolved = findManifestPathSync(installPath);
|
|
71366
72832
|
if (resolved) {
|
|
71367
72833
|
try {
|
|
71368
|
-
const rawMetadata = JSON.parse(
|
|
72834
|
+
const rawMetadata = JSON.parse(readFileSync21(resolved.path, "utf-8"));
|
|
71369
72835
|
const metadata = MetadataSchema.parse(rawMetadata);
|
|
71370
72836
|
const kitsDisplay = formatInstalledKits(metadata);
|
|
71371
72837
|
if (kitsDisplay) {
|
|
@@ -71467,18 +72933,18 @@ class Logger2 {
|
|
|
71467
72933
|
isVerbose() {
|
|
71468
72934
|
return this.verboseEnabled;
|
|
71469
72935
|
}
|
|
71470
|
-
setLogFile(
|
|
72936
|
+
setLogFile(path11) {
|
|
71471
72937
|
if (this.logFileStream) {
|
|
71472
72938
|
this.logFileStream.end();
|
|
71473
72939
|
this.logFileStream = undefined;
|
|
71474
72940
|
}
|
|
71475
|
-
if (
|
|
71476
|
-
this.logFileStream = createWriteStream4(
|
|
72941
|
+
if (path11) {
|
|
72942
|
+
this.logFileStream = createWriteStream4(path11, {
|
|
71477
72943
|
flags: "a",
|
|
71478
72944
|
mode: 384
|
|
71479
72945
|
});
|
|
71480
72946
|
this.registerExitHandler();
|
|
71481
|
-
this.verbose(`Logging to file: ${
|
|
72947
|
+
this.verbose(`Logging to file: ${path11}`);
|
|
71482
72948
|
}
|
|
71483
72949
|
}
|
|
71484
72950
|
close() {
|