@sunasteriskrnd/takumi 1.0.0-dev.24 → 1.0.0-dev.26
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 +2187 -575
- 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.26",
|
|
8543
8543
|
description: "CLI tool for bootstrapping and managing Takumi projects",
|
|
8544
8544
|
type: "module",
|
|
8545
8545
|
repository: {
|
|
@@ -13598,6 +13598,7 @@ function globalSetupToInfo(g2) {
|
|
|
13598
13598
|
};
|
|
13599
13599
|
}
|
|
13600
13600
|
async function getTakumiSetup(projectDir = process.cwd()) {
|
|
13601
|
+
const { getInstaller, listSupportedProviders } = await Promise.resolve().then(() => (init_registry(), exports_registry));
|
|
13601
13602
|
const globalResults = await Promise.all(listSupportedProviders().map(async (p) => {
|
|
13602
13603
|
const inst = getInstaller(p);
|
|
13603
13604
|
return inst ? await inst.detectGlobalSetup() : null;
|
|
@@ -13622,7 +13623,6 @@ async function getTakumiSetup(projectDir = process.cwd()) {
|
|
|
13622
13623
|
var import_fs_extra5;
|
|
13623
13624
|
var init_takumi_scanner = __esm(() => {
|
|
13624
13625
|
init_paths();
|
|
13625
|
-
init_registry();
|
|
13626
13626
|
init_skip_directories();
|
|
13627
13627
|
init_manifest_path_resolver();
|
|
13628
13628
|
import_fs_extra5 = __toESM(require_lib(), 1);
|
|
@@ -33539,10 +33539,16 @@ function mergeHooksObject(current, incoming) {
|
|
|
33539
33539
|
const merged = deduplicateMerge(existingHooks, incoming);
|
|
33540
33540
|
return { ...current, hooks: merged };
|
|
33541
33541
|
}
|
|
33542
|
+
function isMalformedHookCommand(command) {
|
|
33543
|
+
return /(\$HOME|\$\{HOME\}|\$CLAUDE_PROJECT_DIR|\$\{CLAUDE_PROJECT_DIR\}|%USERPROFILE%|%CLAUDE_PROJECT_DIR%)\/\//.test(command);
|
|
33544
|
+
}
|
|
33542
33545
|
function deduplicateMerge(existing, incoming) {
|
|
33543
33546
|
const merged = {};
|
|
33544
33547
|
for (const [event, groups] of Object.entries(existing)) {
|
|
33545
|
-
merged[event] = groups.map((g2) => ({
|
|
33548
|
+
merged[event] = groups.map((g2) => ({
|
|
33549
|
+
...g2,
|
|
33550
|
+
hooks: g2.hooks.filter((h2) => !isMalformedHookCommand(h2.command))
|
|
33551
|
+
}));
|
|
33546
33552
|
}
|
|
33547
33553
|
for (const [event, incomingGroups] of Object.entries(incoming)) {
|
|
33548
33554
|
const existingGroups = merged[event] ?? [];
|
|
@@ -33562,7 +33568,13 @@ function deduplicateMerge(existing, incoming) {
|
|
|
33562
33568
|
}
|
|
33563
33569
|
merged[event] = existingGroups;
|
|
33564
33570
|
}
|
|
33565
|
-
|
|
33571
|
+
const cleaned = {};
|
|
33572
|
+
for (const [event, groups] of Object.entries(merged)) {
|
|
33573
|
+
const nonEmpty = groups.filter((g2) => g2.hooks.length > 0);
|
|
33574
|
+
if (nonEmpty.length > 0)
|
|
33575
|
+
cleaned[event] = nonEmpty;
|
|
33576
|
+
}
|
|
33577
|
+
return cleaned;
|
|
33566
33578
|
}
|
|
33567
33579
|
var init_hooks_settings_merger = __esm(() => {
|
|
33568
33580
|
init_provider_registry();
|
|
@@ -33755,6 +33767,9 @@ function scrubHookEntry(entry, event, capabilities, pathRewrite) {
|
|
|
33755
33767
|
if (pathRewrite) {
|
|
33756
33768
|
scrubbed.command = rewriteCommandPath(scrubbed.command, pathRewrite);
|
|
33757
33769
|
}
|
|
33770
|
+
if (typeof scrubbed.timeout === "number" && scrubbed.timeout < MIN_CODEX_HOOK_TIMEOUT_SECONDS) {
|
|
33771
|
+
scrubbed.timeout = MIN_CODEX_HOOK_TIMEOUT_SECONDS;
|
|
33772
|
+
}
|
|
33758
33773
|
const eventCaps = capabilities.events[event];
|
|
33759
33774
|
if (eventCaps?.permissionDecisionValues) {
|
|
33760
33775
|
const allowed = new Set(eventCaps.permissionDecisionValues);
|
|
@@ -33773,14 +33788,17 @@ function rewriteCommandPath(command, pathRewrite) {
|
|
|
33773
33788
|
if (pathRewrite.commandSubstitutions && pathRewrite.commandSubstitutions.size > 0) {
|
|
33774
33789
|
const home4 = homedir12();
|
|
33775
33790
|
const homeForward = normalizeSlashes(home4);
|
|
33791
|
+
const projectDirForward = pathRewrite.projectDir != null ? normalizeSlashes(pathRewrite.projectDir) : null;
|
|
33792
|
+
const relFrom = (absForward, baseForward) => {
|
|
33793
|
+
if (absForward.startsWith(`${baseForward}/`))
|
|
33794
|
+
return absForward.slice(baseForward.length + 1);
|
|
33795
|
+
if (absForward === baseForward)
|
|
33796
|
+
return "";
|
|
33797
|
+
return null;
|
|
33798
|
+
};
|
|
33776
33799
|
for (const [originalAbsPath, wrapperAbsPath] of pathRewrite.commandSubstitutions) {
|
|
33777
33800
|
const originalAbsForward = normalizeSlashes(originalAbsPath);
|
|
33778
|
-
|
|
33779
|
-
if (originalAbsForward.startsWith(`${homeForward}/`)) {
|
|
33780
|
-
relFromHome = originalAbsForward.slice(homeForward.length + 1);
|
|
33781
|
-
} else if (originalAbsForward === homeForward) {
|
|
33782
|
-
relFromHome = "";
|
|
33783
|
-
}
|
|
33801
|
+
const relFromHome = relFrom(originalAbsForward, homeForward);
|
|
33784
33802
|
const candidates = [originalAbsForward, originalAbsPath];
|
|
33785
33803
|
if (relFromHome !== null && relFromHome !== "") {
|
|
33786
33804
|
candidates.push(`$HOME/${relFromHome}`);
|
|
@@ -33788,6 +33806,12 @@ function rewriteCommandPath(command, pathRewrite) {
|
|
|
33788
33806
|
candidates.push(`%USERPROFILE%/${relFromHome}`);
|
|
33789
33807
|
candidates.push(`\${HOME}/${relFromHome}`);
|
|
33790
33808
|
}
|
|
33809
|
+
const relFromProject = projectDirForward !== null ? relFrom(originalAbsForward, projectDirForward) : null;
|
|
33810
|
+
if (relFromProject !== null && relFromProject !== "") {
|
|
33811
|
+
candidates.push(`$CLAUDE_PROJECT_DIR/${relFromProject}`);
|
|
33812
|
+
candidates.push(`\${CLAUDE_PROJECT_DIR}/${relFromProject}`);
|
|
33813
|
+
candidates.push(`%CLAUDE_PROJECT_DIR%/${relFromProject}`);
|
|
33814
|
+
}
|
|
33791
33815
|
const wrapperForward = normalizeSlashes(wrapperAbsPath);
|
|
33792
33816
|
for (const candidate of candidates) {
|
|
33793
33817
|
const candidateNorm = normalizeSlashes(candidate);
|
|
@@ -33820,6 +33844,7 @@ function isRelativeCommandCandidate(candidate) {
|
|
|
33820
33844
|
function escapeRegExp(value) {
|
|
33821
33845
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
33822
33846
|
}
|
|
33847
|
+
var MIN_CODEX_HOOK_TIMEOUT_SECONDS = 10;
|
|
33823
33848
|
var init_claude_to_codex_hooks = () => {};
|
|
33824
33849
|
|
|
33825
33850
|
// src/domains/installers/codex/path-safety.ts
|
|
@@ -34371,7 +34396,8 @@ async function migrateCodexHooksSettings(options2) {
|
|
|
34371
34396
|
const wrapperPaths = [];
|
|
34372
34397
|
const commandSubstitutions = new Map;
|
|
34373
34398
|
if (targetHooksDir) {
|
|
34374
|
-
const
|
|
34399
|
+
const sourceHooksDirBase = isGlobal ? homedir14() : projectBase;
|
|
34400
|
+
const absSourceHooksDir = sourceHooksDir ? isAbsolute2(sourceHooksDir) ? sourceHooksDir : resolve12(sourceHooksDirBase, sourceHooksDir) : "";
|
|
34375
34401
|
const absTargetHooksDir = isAbsolute2(targetHooksDir) ? targetHooksDir : resolve12(projectBase, targetHooksDir);
|
|
34376
34402
|
const targetAbsolutePaths = installedHookAbsolutePaths && installedHookAbsolutePaths.length > 0 ? installedHookAbsolutePaths.filter(isCodexWrappableHookPath) : installedHookFiles.filter(isCodexWrappableHookPath).map((basenameOrPath) => basenameOrPath.includes("/") || basenameOrPath.includes("\\") ? basenameOrPath : join55(absTargetHooksDir, basenameOrPath));
|
|
34377
34403
|
const wrapperResults = generateCodexHookWrappers(targetAbsolutePaths, absTargetHooksDir, capabilities);
|
|
@@ -34395,7 +34421,8 @@ async function migrateCodexHooksSettings(options2) {
|
|
|
34395
34421
|
const converted = convertClaudeHooksToCodex(filtered, capabilities, {
|
|
34396
34422
|
sourceDir: sourceHooksDir,
|
|
34397
34423
|
targetDir: targetHooksDir || sourceHooksDir,
|
|
34398
|
-
commandSubstitutions: commandSubstitutions.size > 0 ? commandSubstitutions : undefined
|
|
34424
|
+
commandSubstitutions: commandSubstitutions.size > 0 ? commandSubstitutions : undefined,
|
|
34425
|
+
projectDir: isGlobal ? homedir14() : projectBase
|
|
34399
34426
|
});
|
|
34400
34427
|
let hooksRegistered = 0;
|
|
34401
34428
|
for (const groups of Object.values(converted)) {
|
|
@@ -34418,7 +34445,7 @@ async function migrateCodexHooksSettings(options2) {
|
|
|
34418
34445
|
}
|
|
34419
34446
|
let backupPath = null;
|
|
34420
34447
|
try {
|
|
34421
|
-
const mergeResult = await mergeHooksIntoSettings(resolvedTargetPath, converted);
|
|
34448
|
+
const mergeResult = await withCodexTargetLock2(resolvedTargetPath, () => mergeHooksIntoSettings(resolvedTargetPath, converted));
|
|
34422
34449
|
backupPath = mergeResult.backupPath;
|
|
34423
34450
|
} catch (err) {
|
|
34424
34451
|
return {
|
|
@@ -34436,7 +34463,13 @@ async function migrateCodexHooksSettings(options2) {
|
|
|
34436
34463
|
if (capabilities.requiresFeatureFlag) {
|
|
34437
34464
|
const configTomlPath = isGlobal ? join55(homedir14(), ".codex", "config.toml") : join55(projectBase, ".codex", "config.toml");
|
|
34438
34465
|
const flagResult = await ensureCodexHooksFeatureFlag(configTomlPath, isGlobal);
|
|
34439
|
-
featureFlagWritten = flagResult.status === "written" || flagResult.status === "updated";
|
|
34466
|
+
featureFlagWritten = flagResult.status === "written" || flagResult.status === "updated" || flagResult.status === "already-set";
|
|
34467
|
+
if (flagResult.status === "failed") {
|
|
34468
|
+
warnings.push({
|
|
34469
|
+
reason: "codex-feature-flag-write-failed",
|
|
34470
|
+
message: `Could not write \`[features] hooks = true\` to ${configTomlPath}${flagResult.error ? ` (${flagResult.error})` : ""}. Codex will ignore installed hooks until this flag is set. Add it manually or re-run \`tkm init -a codex\`.`
|
|
34471
|
+
});
|
|
34472
|
+
}
|
|
34440
34473
|
}
|
|
34441
34474
|
return {
|
|
34442
34475
|
status: "registered",
|
|
@@ -34460,6 +34493,7 @@ var init_hooks_merger = __esm(() => {
|
|
|
34460
34493
|
init_claude_to_codex_hooks();
|
|
34461
34494
|
init_features_flag();
|
|
34462
34495
|
init_hook_wrapper();
|
|
34496
|
+
init_path_safety();
|
|
34463
34497
|
CODEX_WRAPPABLE_HOOK_EXTENSIONS = new Set([".js", ".cjs", ".mjs", ".ts"]);
|
|
34464
34498
|
});
|
|
34465
34499
|
|
|
@@ -35985,12 +36019,25 @@ var init_installer2 = __esm(() => {
|
|
|
35985
36019
|
});
|
|
35986
36020
|
|
|
35987
36021
|
// src/domains/installers/registry.ts
|
|
36022
|
+
var exports_registry = {};
|
|
36023
|
+
__export(exports_registry, {
|
|
36024
|
+
unregisterInstaller: () => unregisterInstaller,
|
|
36025
|
+
registerInstaller: () => registerInstaller,
|
|
36026
|
+
listSupportedProviders: () => listSupportedProviders,
|
|
36027
|
+
getInstaller: () => getInstaller
|
|
36028
|
+
});
|
|
35988
36029
|
function getInstaller(provider) {
|
|
35989
36030
|
return installers[provider] ?? null;
|
|
35990
36031
|
}
|
|
35991
36032
|
function listSupportedProviders() {
|
|
35992
36033
|
return Object.keys(installers);
|
|
35993
36034
|
}
|
|
36035
|
+
function registerInstaller(installer) {
|
|
36036
|
+
installers[installer.provider] = installer;
|
|
36037
|
+
}
|
|
36038
|
+
function unregisterInstaller(provider) {
|
|
36039
|
+
delete installers[provider];
|
|
36040
|
+
}
|
|
35994
36041
|
var installers;
|
|
35995
36042
|
var init_registry = __esm(() => {
|
|
35996
36043
|
init_installer();
|
|
@@ -37485,6 +37532,24 @@ var init_kit_version_checker = __esm(() => {
|
|
|
37485
37532
|
});
|
|
37486
37533
|
|
|
37487
37534
|
// src/domains/github/npm-registry.ts
|
|
37535
|
+
function validateRegistryUrl(url) {
|
|
37536
|
+
if (!url || typeof url !== "string" || url.trim() === "") {
|
|
37537
|
+
throw new Error("Invalid registry URL: must be a non-empty string");
|
|
37538
|
+
}
|
|
37539
|
+
if (SHELL_METACHARACTERS.test(url)) {
|
|
37540
|
+
throw new Error("Invalid registry URL: contains disallowed characters");
|
|
37541
|
+
}
|
|
37542
|
+
let parsed;
|
|
37543
|
+
try {
|
|
37544
|
+
parsed = new URL(url);
|
|
37545
|
+
} catch {
|
|
37546
|
+
throw new Error(`Invalid registry URL: not a valid URL (${redactRegistryUrlForLog(url)})`);
|
|
37547
|
+
}
|
|
37548
|
+
if (parsed.protocol !== "https:" && parsed.protocol !== "http:") {
|
|
37549
|
+
throw new Error(`Invalid registry URL: unsupported protocol ${parsed.protocol}`);
|
|
37550
|
+
}
|
|
37551
|
+
return url;
|
|
37552
|
+
}
|
|
37488
37553
|
function redactRegistryUrlForLog(url) {
|
|
37489
37554
|
if (!url)
|
|
37490
37555
|
return url;
|
|
@@ -37633,9 +37698,10 @@ class NpmRegistryClient {
|
|
|
37633
37698
|
}
|
|
37634
37699
|
}
|
|
37635
37700
|
}
|
|
37636
|
-
var DEFAULT_REGISTRY_URL = "https://registry.npmjs.org", REQUEST_TIMEOUT = 5000, REDACTED_VALUE = "***";
|
|
37701
|
+
var DEFAULT_REGISTRY_URL = "https://registry.npmjs.org", REQUEST_TIMEOUT = 5000, REDACTED_VALUE = "***", SHELL_METACHARACTERS;
|
|
37637
37702
|
var init_npm_registry = __esm(() => {
|
|
37638
37703
|
init_logger();
|
|
37704
|
+
SHELL_METACHARACTERS = /[\s;|&$`<>()'"\\\n\r]/;
|
|
37639
37705
|
});
|
|
37640
37706
|
|
|
37641
37707
|
// src/domains/versioning/checking/cli-version-checker.ts
|
|
@@ -50384,14 +50450,14 @@ var exports_monorepo_resolver = {};
|
|
|
50384
50450
|
__export(exports_monorepo_resolver, {
|
|
50385
50451
|
resolveMonorepoRoot: () => resolveMonorepoRoot
|
|
50386
50452
|
});
|
|
50387
|
-
import { existsSync as
|
|
50388
|
-
import { dirname as
|
|
50453
|
+
import { existsSync as existsSync49, readFileSync as readFileSync16 } from "node:fs";
|
|
50454
|
+
import { dirname as dirname27, join as join99, resolve as resolve22 } from "node:path";
|
|
50389
50455
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
50390
50456
|
function parseMetadataAt(metadataPath) {
|
|
50391
|
-
if (!
|
|
50457
|
+
if (!existsSync49(metadataPath))
|
|
50392
50458
|
return null;
|
|
50393
50459
|
try {
|
|
50394
|
-
const raw =
|
|
50460
|
+
const raw = readFileSync16(metadataPath, "utf-8");
|
|
50395
50461
|
const parsed = JSON.parse(raw);
|
|
50396
50462
|
if (typeof parsed.name !== "string" || typeof parsed.version !== "string" || !ACCEPTED_METADATA_NAMES.has(parsed.name)) {
|
|
50397
50463
|
return null;
|
|
@@ -50402,11 +50468,11 @@ function parseMetadataAt(metadataPath) {
|
|
|
50402
50468
|
}
|
|
50403
50469
|
}
|
|
50404
50470
|
function readSourceDirFromPackageJson(candidateRoot) {
|
|
50405
|
-
const packageJsonPath =
|
|
50406
|
-
if (!
|
|
50471
|
+
const packageJsonPath = join99(candidateRoot, "package.json");
|
|
50472
|
+
if (!existsSync49(packageJsonPath))
|
|
50407
50473
|
return null;
|
|
50408
50474
|
try {
|
|
50409
|
-
const parsed = JSON.parse(
|
|
50475
|
+
const parsed = JSON.parse(readFileSync16(packageJsonPath, "utf-8"));
|
|
50410
50476
|
const kitCfg = parsed.takumi;
|
|
50411
50477
|
if (kitCfg && typeof kitCfg.sourceDir === "string" && kitCfg.sourceDir.length > 0) {
|
|
50412
50478
|
return kitCfg.sourceDir;
|
|
@@ -50425,7 +50491,7 @@ function tryReadAtCandidate(candidateRoot) {
|
|
|
50425
50491
|
};
|
|
50426
50492
|
}
|
|
50427
50493
|
const sourceDir = readSourceDirFromPackageJson(candidateRoot) ?? "claude";
|
|
50428
|
-
const sourceRoot =
|
|
50494
|
+
const sourceRoot = join99(candidateRoot, sourceDir);
|
|
50429
50495
|
const nestedMetadata = parseMetadataAt(getManifestPath(sourceRoot)) ?? parseMetadataAt(getLegacyManifestPath(sourceRoot));
|
|
50430
50496
|
if (nestedMetadata) {
|
|
50431
50497
|
return {
|
|
@@ -50438,12 +50504,12 @@ function tryReadAtCandidate(candidateRoot) {
|
|
|
50438
50504
|
return null;
|
|
50439
50505
|
}
|
|
50440
50506
|
function walkUpForMetadata(startDir, maxDepth = 5) {
|
|
50441
|
-
let current =
|
|
50507
|
+
let current = resolve22(startDir);
|
|
50442
50508
|
for (let i = 0;i < maxDepth; i++) {
|
|
50443
50509
|
const result = tryReadAtCandidate(current);
|
|
50444
50510
|
if (result)
|
|
50445
50511
|
return result;
|
|
50446
|
-
const parent =
|
|
50512
|
+
const parent = dirname27(current);
|
|
50447
50513
|
if (parent === current)
|
|
50448
50514
|
break;
|
|
50449
50515
|
current = parent;
|
|
@@ -50453,13 +50519,13 @@ function walkUpForMetadata(startDir, maxDepth = 5) {
|
|
|
50453
50519
|
function resolveMonorepoRoot() {
|
|
50454
50520
|
try {
|
|
50455
50521
|
const thisFile = fileURLToPath3(import.meta.url);
|
|
50456
|
-
const thisDir =
|
|
50522
|
+
const thisDir = dirname27(thisFile);
|
|
50457
50523
|
const result2 = walkUpForMetadata(thisDir);
|
|
50458
50524
|
if (result2)
|
|
50459
50525
|
return result2;
|
|
50460
50526
|
} catch {}
|
|
50461
50527
|
if (process.argv[1]) {
|
|
50462
|
-
const binDir =
|
|
50528
|
+
const binDir = dirname27(resolve22(process.argv[1]));
|
|
50463
50529
|
const result2 = walkUpForMetadata(binDir);
|
|
50464
50530
|
if (result2)
|
|
50465
50531
|
return result2;
|
|
@@ -51039,7 +51105,7 @@ function getPagerArgs(pagerCmd) {
|
|
|
51039
51105
|
return [];
|
|
51040
51106
|
}
|
|
51041
51107
|
async function trySystemPager(content) {
|
|
51042
|
-
return new Promise((
|
|
51108
|
+
return new Promise((resolve31) => {
|
|
51043
51109
|
const pagerCmd = process.env.PAGER || "less";
|
|
51044
51110
|
const pagerArgs = getPagerArgs(pagerCmd);
|
|
51045
51111
|
try {
|
|
@@ -51049,20 +51115,20 @@ async function trySystemPager(content) {
|
|
|
51049
51115
|
});
|
|
51050
51116
|
const timeout = setTimeout(() => {
|
|
51051
51117
|
pager.kill();
|
|
51052
|
-
|
|
51118
|
+
resolve31(false);
|
|
51053
51119
|
}, 30000);
|
|
51054
51120
|
pager.stdin.write(content);
|
|
51055
51121
|
pager.stdin.end();
|
|
51056
51122
|
pager.on("close", (code) => {
|
|
51057
51123
|
clearTimeout(timeout);
|
|
51058
|
-
|
|
51124
|
+
resolve31(code === 0);
|
|
51059
51125
|
});
|
|
51060
51126
|
pager.on("error", () => {
|
|
51061
51127
|
clearTimeout(timeout);
|
|
51062
|
-
|
|
51128
|
+
resolve31(false);
|
|
51063
51129
|
});
|
|
51064
51130
|
} catch {
|
|
51065
|
-
|
|
51131
|
+
resolve31(false);
|
|
51066
51132
|
}
|
|
51067
51133
|
});
|
|
51068
51134
|
}
|
|
@@ -51089,16 +51155,16 @@ async function basicPager(content) {
|
|
|
51089
51155
|
break;
|
|
51090
51156
|
}
|
|
51091
51157
|
const remaining = lines.length - currentLine;
|
|
51092
|
-
await new Promise((
|
|
51158
|
+
await new Promise((resolve31) => {
|
|
51093
51159
|
rl.question(`-- More (${remaining} lines) [Enter/q] --`, (answer) => {
|
|
51094
51160
|
if (answer.toLowerCase() === "q") {
|
|
51095
51161
|
rl.close();
|
|
51096
51162
|
process.exitCode = 0;
|
|
51097
|
-
|
|
51163
|
+
resolve31();
|
|
51098
51164
|
return;
|
|
51099
51165
|
}
|
|
51100
51166
|
process.stdout.write("\x1B[1A\x1B[2K");
|
|
51101
|
-
|
|
51167
|
+
resolve31();
|
|
51102
51168
|
});
|
|
51103
51169
|
});
|
|
51104
51170
|
}
|
|
@@ -53692,6 +53758,1459 @@ async function configCommand(action, keyOrOptions, valueOrOptions, options2) {
|
|
|
53692
53758
|
};
|
|
53693
53759
|
return configUICommand(uiOpts);
|
|
53694
53760
|
}
|
|
53761
|
+
// src/domains/sessions/browser-open.ts
|
|
53762
|
+
init_open();
|
|
53763
|
+
function tryOpenBrowser(target) {
|
|
53764
|
+
open_default(target).catch(() => {});
|
|
53765
|
+
}
|
|
53766
|
+
|
|
53767
|
+
// src/domains/sessions/server.ts
|
|
53768
|
+
import * as http from "node:http";
|
|
53769
|
+
|
|
53770
|
+
// src/domains/sessions/adapters/claude.ts
|
|
53771
|
+
import * as fs9 from "node:fs";
|
|
53772
|
+
import * as os4 from "node:os";
|
|
53773
|
+
import * as path7 from "node:path";
|
|
53774
|
+
|
|
53775
|
+
// src/domains/sessions/transcript-parser.ts
|
|
53776
|
+
import * as fs8 from "node:fs";
|
|
53777
|
+
|
|
53778
|
+
// src/domains/sessions/types.ts
|
|
53779
|
+
function emptyTokens() {
|
|
53780
|
+
return { input: 0, output: 0, cacheCreate: 0, cacheRead: 0 };
|
|
53781
|
+
}
|
|
53782
|
+
|
|
53783
|
+
// src/domains/sessions/transcript-parser.ts
|
|
53784
|
+
var MAX_READ_BYTES = 50 * 1024 * 1024;
|
|
53785
|
+
function safeJSON(line) {
|
|
53786
|
+
try {
|
|
53787
|
+
return JSON.parse(line);
|
|
53788
|
+
} catch {
|
|
53789
|
+
return null;
|
|
53790
|
+
}
|
|
53791
|
+
}
|
|
53792
|
+
function readNew(transcriptPath, fromOffset) {
|
|
53793
|
+
if (!transcriptPath || !fs8.existsSync(transcriptPath)) {
|
|
53794
|
+
return { records: [], newOffset: fromOffset || 0 };
|
|
53795
|
+
}
|
|
53796
|
+
if (transcriptPath.endsWith(".zst")) {
|
|
53797
|
+
return { records: [], newOffset: fromOffset || 0 };
|
|
53798
|
+
}
|
|
53799
|
+
const st = fs8.statSync(transcriptPath);
|
|
53800
|
+
const start = fromOffset || 0;
|
|
53801
|
+
if (st.size <= start) {
|
|
53802
|
+
return { records: [], newOffset: st.size };
|
|
53803
|
+
}
|
|
53804
|
+
let len = st.size - start;
|
|
53805
|
+
let truncated = false;
|
|
53806
|
+
if (len > MAX_READ_BYTES) {
|
|
53807
|
+
len = MAX_READ_BYTES;
|
|
53808
|
+
truncated = true;
|
|
53809
|
+
}
|
|
53810
|
+
const fd = fs8.openSync(transcriptPath, "r");
|
|
53811
|
+
try {
|
|
53812
|
+
const buf = Buffer.alloc(len);
|
|
53813
|
+
fs8.readSync(fd, buf, 0, len, start);
|
|
53814
|
+
const text = buf.toString("utf-8");
|
|
53815
|
+
const lines = text.split(`
|
|
53816
|
+
`).filter(Boolean);
|
|
53817
|
+
const records = lines.map(safeJSON).filter((r2) => r2 !== null);
|
|
53818
|
+
const newOffset = truncated ? start + len : st.size;
|
|
53819
|
+
return { records, newOffset };
|
|
53820
|
+
} finally {
|
|
53821
|
+
fs8.closeSync(fd);
|
|
53822
|
+
}
|
|
53823
|
+
}
|
|
53824
|
+
function addTokens(a3, b3) {
|
|
53825
|
+
return {
|
|
53826
|
+
input: (a3.input || 0) + (b3.input || 0),
|
|
53827
|
+
output: (a3.output || 0) + (b3.output || 0),
|
|
53828
|
+
cacheCreate: (a3.cacheCreate || 0) + (b3.cacheCreate || 0),
|
|
53829
|
+
cacheRead: (a3.cacheRead || 0) + (b3.cacheRead || 0)
|
|
53830
|
+
};
|
|
53831
|
+
}
|
|
53832
|
+
function tokensOfClaude(rec) {
|
|
53833
|
+
const r2 = rec;
|
|
53834
|
+
const u = r2?.message?.usage;
|
|
53835
|
+
if (!u)
|
|
53836
|
+
return null;
|
|
53837
|
+
return {
|
|
53838
|
+
input: u.input_tokens || 0,
|
|
53839
|
+
output: u.output_tokens || 0,
|
|
53840
|
+
cacheCreate: u.cache_creation_input_tokens || 0,
|
|
53841
|
+
cacheRead: u.cache_read_input_tokens || 0
|
|
53842
|
+
};
|
|
53843
|
+
}
|
|
53844
|
+
function tokensOfCodex(rec) {
|
|
53845
|
+
const r2 = rec;
|
|
53846
|
+
if (r2?.type !== "event_msg")
|
|
53847
|
+
return null;
|
|
53848
|
+
if (r2?.payload?.type !== "token_count")
|
|
53849
|
+
return null;
|
|
53850
|
+
const u = r2?.payload?.info?.last_token_usage;
|
|
53851
|
+
if (!u)
|
|
53852
|
+
return null;
|
|
53853
|
+
return {
|
|
53854
|
+
input: u.input_tokens || 0,
|
|
53855
|
+
output: (u.output_tokens || 0) + (u.reasoning_output_tokens || 0),
|
|
53856
|
+
cacheCreate: 0,
|
|
53857
|
+
cacheRead: u.cached_input_tokens || 0
|
|
53858
|
+
};
|
|
53859
|
+
}
|
|
53860
|
+
function peekFirstTimestamp(jsonlPath) {
|
|
53861
|
+
if (!fs8.existsSync(jsonlPath))
|
|
53862
|
+
return null;
|
|
53863
|
+
const { records } = readNew(jsonlPath, 0);
|
|
53864
|
+
for (const r2 of records) {
|
|
53865
|
+
const ts = r2?.timestamp;
|
|
53866
|
+
if (ts)
|
|
53867
|
+
return ts;
|
|
53868
|
+
}
|
|
53869
|
+
return null;
|
|
53870
|
+
}
|
|
53871
|
+
function peekLastTimestamp(jsonlPath) {
|
|
53872
|
+
if (!fs8.existsSync(jsonlPath))
|
|
53873
|
+
return null;
|
|
53874
|
+
const { records } = readNew(jsonlPath, 0);
|
|
53875
|
+
for (let i = records.length - 1;i >= 0; i--) {
|
|
53876
|
+
const ts = records[i]?.timestamp;
|
|
53877
|
+
if (ts)
|
|
53878
|
+
return ts;
|
|
53879
|
+
}
|
|
53880
|
+
return null;
|
|
53881
|
+
}
|
|
53882
|
+
function sumClaudeAgentTokens(jsonlPath) {
|
|
53883
|
+
const tot = emptyTokens();
|
|
53884
|
+
let model = null;
|
|
53885
|
+
if (!fs8.existsSync(jsonlPath))
|
|
53886
|
+
return { tokens: tot, model };
|
|
53887
|
+
const { records } = readNew(jsonlPath, 0);
|
|
53888
|
+
for (const rec of records) {
|
|
53889
|
+
const r2 = rec;
|
|
53890
|
+
if (r2?.type !== "assistant" && r2?.message?.role !== "assistant")
|
|
53891
|
+
continue;
|
|
53892
|
+
if (!model && r2?.message?.model)
|
|
53893
|
+
model = r2.message.model;
|
|
53894
|
+
const tok = tokensOfClaude(rec);
|
|
53895
|
+
if (!tok)
|
|
53896
|
+
continue;
|
|
53897
|
+
tot.input += tok.input;
|
|
53898
|
+
tot.output += tok.output;
|
|
53899
|
+
tot.cacheCreate += tok.cacheCreate;
|
|
53900
|
+
tot.cacheRead += tok.cacheRead;
|
|
53901
|
+
}
|
|
53902
|
+
return { tokens: tot, model };
|
|
53903
|
+
}
|
|
53904
|
+
function sumCodexAgentTokens(jsonlPath) {
|
|
53905
|
+
const tot = emptyTokens();
|
|
53906
|
+
if (!fs8.existsSync(jsonlPath))
|
|
53907
|
+
return tot;
|
|
53908
|
+
const { records } = readNew(jsonlPath, 0);
|
|
53909
|
+
for (const rec of records) {
|
|
53910
|
+
const tok = tokensOfCodex(rec);
|
|
53911
|
+
if (!tok)
|
|
53912
|
+
continue;
|
|
53913
|
+
tot.input += tok.input;
|
|
53914
|
+
tot.output += tok.output;
|
|
53915
|
+
tot.cacheCreate += tok.cacheCreate;
|
|
53916
|
+
tot.cacheRead += tok.cacheRead;
|
|
53917
|
+
}
|
|
53918
|
+
return tot;
|
|
53919
|
+
}
|
|
53920
|
+
|
|
53921
|
+
// src/domains/sessions/adapters/claude.ts
|
|
53922
|
+
var CLAUDE_ROOT = path7.join(os4.homedir(), ".claude", "projects");
|
|
53923
|
+
var MAX_PARSE_BYTES = 50 * 1024 * 1024;
|
|
53924
|
+
var HARNESS_TAGS = [
|
|
53925
|
+
"command-name",
|
|
53926
|
+
"command-message",
|
|
53927
|
+
"command-args",
|
|
53928
|
+
"ide_opened_file",
|
|
53929
|
+
"ide_selection",
|
|
53930
|
+
"task-notification",
|
|
53931
|
+
"local-command-stdout",
|
|
53932
|
+
"system-reminder"
|
|
53933
|
+
];
|
|
53934
|
+
function decodeProjectDir(name) {
|
|
53935
|
+
if (!name)
|
|
53936
|
+
return name;
|
|
53937
|
+
let p = name.replace(/-/g, "/");
|
|
53938
|
+
if (!p.startsWith("/"))
|
|
53939
|
+
p = `/${p}`;
|
|
53940
|
+
return p.replace(/\/+/g, "/");
|
|
53941
|
+
}
|
|
53942
|
+
function peekText(c2) {
|
|
53943
|
+
if (typeof c2 === "string")
|
|
53944
|
+
return c2;
|
|
53945
|
+
if (Array.isArray(c2)) {
|
|
53946
|
+
return c2.filter((it) => it && it.type === "text").map((it) => it.text || "").join(`
|
|
53947
|
+
`);
|
|
53948
|
+
}
|
|
53949
|
+
return "";
|
|
53950
|
+
}
|
|
53951
|
+
function isInterruptText(s) {
|
|
53952
|
+
return /^\s*\[Request interrupted\b/.test(String(s || ""));
|
|
53953
|
+
}
|
|
53954
|
+
function stripCommandTags(s) {
|
|
53955
|
+
let out = String(s || "");
|
|
53956
|
+
for (const tag of HARNESS_TAGS) {
|
|
53957
|
+
const re2 = new RegExp(`<${tag}>[\\s\\S]*?</${tag}>`, "g");
|
|
53958
|
+
out = out.replace(re2, " ");
|
|
53959
|
+
}
|
|
53960
|
+
return out.replace(/\s+/g, " ").trim();
|
|
53961
|
+
}
|
|
53962
|
+
function extractUserText(rec) {
|
|
53963
|
+
const msg = rec?.message;
|
|
53964
|
+
if (!msg)
|
|
53965
|
+
return "";
|
|
53966
|
+
const c2 = msg.content;
|
|
53967
|
+
if (typeof c2 === "string")
|
|
53968
|
+
return stripCommandTags(c2);
|
|
53969
|
+
if (Array.isArray(c2)) {
|
|
53970
|
+
const parts = [];
|
|
53971
|
+
for (const it of c2) {
|
|
53972
|
+
const item = it;
|
|
53973
|
+
if (item?.type === "text" && typeof item.text === "string")
|
|
53974
|
+
parts.push(item.text);
|
|
53975
|
+
}
|
|
53976
|
+
return stripCommandTags(parts.join(`
|
|
53977
|
+
`));
|
|
53978
|
+
}
|
|
53979
|
+
return "";
|
|
53980
|
+
}
|
|
53981
|
+
function parseCommandFromUser(rec) {
|
|
53982
|
+
const msg = rec?.message;
|
|
53983
|
+
if (!msg)
|
|
53984
|
+
return { slashCommand: null, args: "" };
|
|
53985
|
+
let text = "";
|
|
53986
|
+
if (typeof msg.content === "string")
|
|
53987
|
+
text = msg.content;
|
|
53988
|
+
else if (Array.isArray(msg.content)) {
|
|
53989
|
+
for (const it of msg.content) {
|
|
53990
|
+
const item = it;
|
|
53991
|
+
if (item?.type === "text" && typeof item.text === "string")
|
|
53992
|
+
text += item.text;
|
|
53993
|
+
}
|
|
53994
|
+
}
|
|
53995
|
+
const nameMatch = text.match(/<command-name>\s*\/?([^<\s]+)\s*<\/command-name>/);
|
|
53996
|
+
const argsMatch = text.match(/<command-args>([\s\S]*?)<\/command-args>/);
|
|
53997
|
+
return {
|
|
53998
|
+
slashCommand: nameMatch?.[1] ?? null,
|
|
53999
|
+
args: argsMatch?.[1]?.trim() ?? ""
|
|
54000
|
+
};
|
|
54001
|
+
}
|
|
54002
|
+
function isPromptUser(rec) {
|
|
54003
|
+
if (!rec || rec.type !== "user")
|
|
54004
|
+
return false;
|
|
54005
|
+
if (rec.isSidechain)
|
|
54006
|
+
return false;
|
|
54007
|
+
if (rec.isMeta)
|
|
54008
|
+
return false;
|
|
54009
|
+
const msg = rec.message;
|
|
54010
|
+
if (!msg)
|
|
54011
|
+
return false;
|
|
54012
|
+
if (isInterruptText(peekText(msg.content)))
|
|
54013
|
+
return false;
|
|
54014
|
+
if (typeof msg.content === "string")
|
|
54015
|
+
return msg.content.length > 0;
|
|
54016
|
+
if (Array.isArray(msg.content)) {
|
|
54017
|
+
const arr = msg.content;
|
|
54018
|
+
if (arr.some((it) => it?.type === "tool_result"))
|
|
54019
|
+
return false;
|
|
54020
|
+
return arr.some((it) => it?.type === "text");
|
|
54021
|
+
}
|
|
54022
|
+
return false;
|
|
54023
|
+
}
|
|
54024
|
+
function readSessionSummary(filePath) {
|
|
54025
|
+
const out = {
|
|
54026
|
+
startedAt: null,
|
|
54027
|
+
firstUserText: "",
|
|
54028
|
+
cwd: null,
|
|
54029
|
+
aiTitle: null
|
|
54030
|
+
};
|
|
54031
|
+
try {
|
|
54032
|
+
const st = fs9.statSync(filePath);
|
|
54033
|
+
const len = Math.min(st.size, 64 * 1024);
|
|
54034
|
+
const buf = Buffer.alloc(len);
|
|
54035
|
+
const fd = fs9.openSync(filePath, "r");
|
|
54036
|
+
try {
|
|
54037
|
+
fs9.readSync(fd, buf, 0, len, 0);
|
|
54038
|
+
} finally {
|
|
54039
|
+
fs9.closeSync(fd);
|
|
54040
|
+
}
|
|
54041
|
+
const lines = buf.toString("utf-8").split(`
|
|
54042
|
+
`);
|
|
54043
|
+
for (const line of lines) {
|
|
54044
|
+
if (!line)
|
|
54045
|
+
continue;
|
|
54046
|
+
let r2 = null;
|
|
54047
|
+
try {
|
|
54048
|
+
r2 = JSON.parse(line);
|
|
54049
|
+
} catch {
|
|
54050
|
+
continue;
|
|
54051
|
+
}
|
|
54052
|
+
if (!r2)
|
|
54053
|
+
continue;
|
|
54054
|
+
if (!out.startedAt && r2.timestamp)
|
|
54055
|
+
out.startedAt = r2.timestamp;
|
|
54056
|
+
if (!out.cwd && r2.cwd)
|
|
54057
|
+
out.cwd = r2.cwd;
|
|
54058
|
+
if (r2.type === "ai-title" && typeof r2.aiTitle === "string" && r2.aiTitle.trim()) {
|
|
54059
|
+
out.aiTitle = r2.aiTitle.trim();
|
|
54060
|
+
}
|
|
54061
|
+
if (!out.firstUserText && r2.type === "user" && !r2.isMeta && !isInterruptText(peekText(r2.message?.content))) {
|
|
54062
|
+
const cmd = parseCommandFromUser(r2);
|
|
54063
|
+
if (cmd.slashCommand) {
|
|
54064
|
+
out.firstUserText = `/${cmd.slashCommand} ${cmd.args}`.replace(/\s+/g, " ").trim().slice(0, 120);
|
|
54065
|
+
} else {
|
|
54066
|
+
const text = extractUserText(r2);
|
|
54067
|
+
if (text)
|
|
54068
|
+
out.firstUserText = text.replace(/\s+/g, " ").trim().slice(0, 120);
|
|
54069
|
+
}
|
|
54070
|
+
}
|
|
54071
|
+
}
|
|
54072
|
+
} catch {}
|
|
54073
|
+
return out;
|
|
54074
|
+
}
|
|
54075
|
+
async function listSessions(rootDir) {
|
|
54076
|
+
const root = rootDir || CLAUDE_ROOT;
|
|
54077
|
+
const out = [];
|
|
54078
|
+
let projects;
|
|
54079
|
+
try {
|
|
54080
|
+
projects = fs9.readdirSync(root);
|
|
54081
|
+
} catch {
|
|
54082
|
+
return out;
|
|
54083
|
+
}
|
|
54084
|
+
for (const proj of projects) {
|
|
54085
|
+
const projDir = path7.join(root, proj);
|
|
54086
|
+
let entries;
|
|
54087
|
+
try {
|
|
54088
|
+
entries = fs9.readdirSync(projDir);
|
|
54089
|
+
} catch {
|
|
54090
|
+
continue;
|
|
54091
|
+
}
|
|
54092
|
+
for (const entry of entries) {
|
|
54093
|
+
if (!entry.endsWith(".jsonl"))
|
|
54094
|
+
continue;
|
|
54095
|
+
const full = path7.join(projDir, entry);
|
|
54096
|
+
let st;
|
|
54097
|
+
try {
|
|
54098
|
+
st = fs9.statSync(full);
|
|
54099
|
+
} catch {
|
|
54100
|
+
continue;
|
|
54101
|
+
}
|
|
54102
|
+
const sessionId = entry.replace(/\.jsonl$/, "");
|
|
54103
|
+
const summary = readSessionSummary(full);
|
|
54104
|
+
out.push({
|
|
54105
|
+
id: sessionId,
|
|
54106
|
+
adapterName: "claude",
|
|
54107
|
+
path: full,
|
|
54108
|
+
startedAt: summary.startedAt || new Date(st.mtimeMs).toISOString(),
|
|
54109
|
+
project: summary.cwd || decodeProjectDir(proj),
|
|
54110
|
+
title: summary.aiTitle || null,
|
|
54111
|
+
summary: summary.firstUserText,
|
|
54112
|
+
sizeBytes: st.size
|
|
54113
|
+
});
|
|
54114
|
+
}
|
|
54115
|
+
}
|
|
54116
|
+
return out;
|
|
54117
|
+
}
|
|
54118
|
+
function loadSubagentIndex(parentTranscriptPath, sessionId) {
|
|
54119
|
+
const subDir = path7.join(path7.dirname(parentTranscriptPath), sessionId, "subagents");
|
|
54120
|
+
const byToolUseId = new Map;
|
|
54121
|
+
const byAgentId = new Map;
|
|
54122
|
+
let names;
|
|
54123
|
+
try {
|
|
54124
|
+
names = fs9.readdirSync(subDir);
|
|
54125
|
+
} catch {
|
|
54126
|
+
return { byToolUseId, byAgentId };
|
|
54127
|
+
}
|
|
54128
|
+
for (const name of names) {
|
|
54129
|
+
if (!name.endsWith(".meta.json"))
|
|
54130
|
+
continue;
|
|
54131
|
+
const agentId = name.replace(/^agent-/, "").replace(/\.meta\.json$/, "");
|
|
54132
|
+
let meta = {};
|
|
54133
|
+
try {
|
|
54134
|
+
meta = JSON.parse(fs9.readFileSync(path7.join(subDir, name), "utf-8"));
|
|
54135
|
+
} catch {}
|
|
54136
|
+
const jsonlPath = path7.join(subDir, `agent-${agentId}.jsonl`);
|
|
54137
|
+
const { tokens, model } = sumClaudeAgentTokens(jsonlPath);
|
|
54138
|
+
const entry = {
|
|
54139
|
+
agentId,
|
|
54140
|
+
type: meta.agentType || "unknown",
|
|
54141
|
+
description: meta.description || "",
|
|
54142
|
+
toolUseId: meta.toolUseId || null,
|
|
54143
|
+
jsonlPath,
|
|
54144
|
+
tokens,
|
|
54145
|
+
model,
|
|
54146
|
+
startedAt: peekFirstTimestamp(jsonlPath),
|
|
54147
|
+
endedAt: peekLastTimestamp(jsonlPath)
|
|
54148
|
+
};
|
|
54149
|
+
byAgentId.set(agentId, entry);
|
|
54150
|
+
if (meta.toolUseId)
|
|
54151
|
+
byToolUseId.set(meta.toolUseId, entry);
|
|
54152
|
+
}
|
|
54153
|
+
return { byToolUseId, byAgentId };
|
|
54154
|
+
}
|
|
54155
|
+
function pushTurn(state, opts) {
|
|
54156
|
+
const last = state.turns[state.turns.length - 1];
|
|
54157
|
+
if (last && !last.endedAt)
|
|
54158
|
+
last.endedAt = opts.startedAt;
|
|
54159
|
+
const id = `T${state.turns.length}`;
|
|
54160
|
+
const turn = {
|
|
54161
|
+
id,
|
|
54162
|
+
startedAt: opts.startedAt,
|
|
54163
|
+
endedAt: null,
|
|
54164
|
+
source: opts.source,
|
|
54165
|
+
slashCommand: opts.slashCommand,
|
|
54166
|
+
args: String(opts.args || "").slice(0, 120),
|
|
54167
|
+
agentIds: [],
|
|
54168
|
+
skillIds: [],
|
|
54169
|
+
slashSkillId: null
|
|
54170
|
+
};
|
|
54171
|
+
state.turns.push(turn);
|
|
54172
|
+
if (opts.slashCommand) {
|
|
54173
|
+
state.skillCounter += 1;
|
|
54174
|
+
const skillId = `sk-slash-${id}`;
|
|
54175
|
+
const skill = {
|
|
54176
|
+
id: skillId,
|
|
54177
|
+
name: opts.slashCommand,
|
|
54178
|
+
source: "slash",
|
|
54179
|
+
prefix: "/",
|
|
54180
|
+
turnId: id,
|
|
54181
|
+
startedAt: opts.startedAt,
|
|
54182
|
+
endedAt: null,
|
|
54183
|
+
status: "running",
|
|
54184
|
+
args: turn.args,
|
|
54185
|
+
tokens: emptyTokens()
|
|
54186
|
+
};
|
|
54187
|
+
state.skills[skillId] = skill;
|
|
54188
|
+
turn.slashSkillId = skillId;
|
|
54189
|
+
turn.skillIds.push(skillId);
|
|
54190
|
+
}
|
|
54191
|
+
return turn;
|
|
54192
|
+
}
|
|
54193
|
+
function handleTaskUse(state, rec, toolUse, subIdx) {
|
|
54194
|
+
const turn = state.turns[state.turns.length - 1];
|
|
54195
|
+
if (!turn)
|
|
54196
|
+
return;
|
|
54197
|
+
const inp = toolUse.input || {};
|
|
54198
|
+
const toolUseId = toolUse.id;
|
|
54199
|
+
const match2 = toolUseId ? subIdx.byToolUseId.get(toolUseId) : null;
|
|
54200
|
+
const now = rec.timestamp || new Date().toISOString();
|
|
54201
|
+
if (!match2) {
|
|
54202
|
+
const aid = (toolUseId || `unknown-${turn.agentIds.length}`).replace(/^toolu_/, "");
|
|
54203
|
+
const agent2 = {
|
|
54204
|
+
id: aid,
|
|
54205
|
+
type: inp.subagent_type || "unknown",
|
|
54206
|
+
description: inp.description || "",
|
|
54207
|
+
promptPreview: String(inp.prompt || "").slice(0, 120),
|
|
54208
|
+
turnId: turn.id,
|
|
54209
|
+
startedAt: now,
|
|
54210
|
+
endedAt: now,
|
|
54211
|
+
status: "done",
|
|
54212
|
+
tokens: emptyTokens()
|
|
54213
|
+
};
|
|
54214
|
+
state.agents[aid] = agent2;
|
|
54215
|
+
turn.agentIds.push(aid);
|
|
54216
|
+
return;
|
|
54217
|
+
}
|
|
54218
|
+
const agentId = match2.agentId;
|
|
54219
|
+
const agent = {
|
|
54220
|
+
id: agentId,
|
|
54221
|
+
type: match2.type || inp.subagent_type || "unknown",
|
|
54222
|
+
description: inp.description || match2.description || "",
|
|
54223
|
+
promptPreview: String(inp.prompt || "").slice(0, 120),
|
|
54224
|
+
turnId: turn.id,
|
|
54225
|
+
startedAt: match2.startedAt || now,
|
|
54226
|
+
endedAt: match2.endedAt || now,
|
|
54227
|
+
status: "done",
|
|
54228
|
+
tokens: match2.tokens || emptyTokens(),
|
|
54229
|
+
model: match2.model || null
|
|
54230
|
+
};
|
|
54231
|
+
state.agents[agentId] = agent;
|
|
54232
|
+
turn.agentIds.push(agentId);
|
|
54233
|
+
if (match2.jsonlPath) {
|
|
54234
|
+
try {
|
|
54235
|
+
state.agentOffsets[agentId] = fs9.statSync(match2.jsonlPath).size;
|
|
54236
|
+
} catch {
|
|
54237
|
+
state.agentOffsets[agentId] = 0;
|
|
54238
|
+
}
|
|
54239
|
+
}
|
|
54240
|
+
}
|
|
54241
|
+
function handleSkillUse(state, rec, toolUse, openSkills) {
|
|
54242
|
+
const turn = state.turns[state.turns.length - 1];
|
|
54243
|
+
if (!turn)
|
|
54244
|
+
return null;
|
|
54245
|
+
const inp = toolUse.input || {};
|
|
54246
|
+
const name = inp.skill || "unknown";
|
|
54247
|
+
state.skillCounter += 1;
|
|
54248
|
+
const skillId = `sk-tool-${state.skillCounter}`;
|
|
54249
|
+
const startedAt = rec.timestamp || new Date().toISOString();
|
|
54250
|
+
const skill = {
|
|
54251
|
+
id: skillId,
|
|
54252
|
+
name,
|
|
54253
|
+
source: "tool",
|
|
54254
|
+
turnId: turn.id,
|
|
54255
|
+
startedAt,
|
|
54256
|
+
endedAt: null,
|
|
54257
|
+
status: "running",
|
|
54258
|
+
args: String(inp.args || "").slice(0, 80),
|
|
54259
|
+
tokens: emptyTokens()
|
|
54260
|
+
};
|
|
54261
|
+
state.skills[skillId] = skill;
|
|
54262
|
+
turn.skillIds.push(skillId);
|
|
54263
|
+
openSkills.set(toolUse.id, { skillId });
|
|
54264
|
+
return skill;
|
|
54265
|
+
}
|
|
54266
|
+
function closeSkill(state, open2, endedAt) {
|
|
54267
|
+
const sk = state.skills[open2.skillId];
|
|
54268
|
+
if (!sk)
|
|
54269
|
+
return;
|
|
54270
|
+
sk.endedAt = endedAt;
|
|
54271
|
+
sk.status = "done";
|
|
54272
|
+
}
|
|
54273
|
+
function pickTurnForTimestamp(state, ts) {
|
|
54274
|
+
if (!ts)
|
|
54275
|
+
return null;
|
|
54276
|
+
let chosen = null;
|
|
54277
|
+
for (const t of state.turns) {
|
|
54278
|
+
if (String(t.startedAt) <= String(ts))
|
|
54279
|
+
chosen = t;
|
|
54280
|
+
else
|
|
54281
|
+
break;
|
|
54282
|
+
}
|
|
54283
|
+
return chosen;
|
|
54284
|
+
}
|
|
54285
|
+
function lastNonStartupTurn(state) {
|
|
54286
|
+
for (let i = state.turns.length - 1;i >= 0; i--) {
|
|
54287
|
+
const turn = state.turns[i];
|
|
54288
|
+
if (turn && turn.source !== "startup")
|
|
54289
|
+
return turn;
|
|
54290
|
+
}
|
|
54291
|
+
return null;
|
|
54292
|
+
}
|
|
54293
|
+
async function parse2(filePath) {
|
|
54294
|
+
const sessionId = path7.basename(filePath, ".jsonl");
|
|
54295
|
+
try {
|
|
54296
|
+
const st = fs9.statSync(filePath);
|
|
54297
|
+
if (st.size > MAX_PARSE_BYTES) {
|
|
54298
|
+
const mb = (st.size / (1024 * 1024)).toFixed(0);
|
|
54299
|
+
const cap = MAX_PARSE_BYTES / (1024 * 1024);
|
|
54300
|
+
throw Object.assign(new Error(`Claude transcript ${path7.basename(filePath)} is ${mb}MB (> ${cap}MB cap).`), { code: "TRANSCRIPT_TOO_LARGE" });
|
|
54301
|
+
}
|
|
54302
|
+
} catch (e2) {
|
|
54303
|
+
if (e2.code === "TRANSCRIPT_TOO_LARGE")
|
|
54304
|
+
throw e2;
|
|
54305
|
+
}
|
|
54306
|
+
const { records } = readNew(filePath, 0);
|
|
54307
|
+
const recs = records;
|
|
54308
|
+
const subIdx = loadSubagentIndex(filePath, sessionId);
|
|
54309
|
+
const firstTs = recs.find((r2) => r2?.timestamp)?.timestamp || new Date().toISOString();
|
|
54310
|
+
const state = {
|
|
54311
|
+
sessionId,
|
|
54312
|
+
schemaVersion: 2,
|
|
54313
|
+
startedAt: firstTs,
|
|
54314
|
+
transcriptPath: filePath,
|
|
54315
|
+
transcriptOffset: 0,
|
|
54316
|
+
agentOffsets: {},
|
|
54317
|
+
cwd: null,
|
|
54318
|
+
turns: [],
|
|
54319
|
+
agents: {},
|
|
54320
|
+
skills: {},
|
|
54321
|
+
skillCounter: 0,
|
|
54322
|
+
tasks: {},
|
|
54323
|
+
taskOrder: [],
|
|
54324
|
+
todos: [],
|
|
54325
|
+
todosUpdatedAt: null,
|
|
54326
|
+
mainLoopTokens: emptyTokens(),
|
|
54327
|
+
totals: emptyTokens(),
|
|
54328
|
+
hookLog: []
|
|
54329
|
+
};
|
|
54330
|
+
pushTurn(state, {
|
|
54331
|
+
source: "startup",
|
|
54332
|
+
slashCommand: null,
|
|
54333
|
+
args: "startup",
|
|
54334
|
+
startedAt: firstTs
|
|
54335
|
+
});
|
|
54336
|
+
const openSkills = new Map;
|
|
54337
|
+
let activeToolSkillId = null;
|
|
54338
|
+
for (const rec of recs) {
|
|
54339
|
+
if (!rec || typeof rec !== "object")
|
|
54340
|
+
continue;
|
|
54341
|
+
if (rec.cwd && !state.cwd)
|
|
54342
|
+
state.cwd = rec.cwd;
|
|
54343
|
+
if (rec.type === "user" && !rec.isSidechain && !rec.isMeta && isInterruptText(peekText(rec.message?.content))) {
|
|
54344
|
+
const cur = state.turns[state.turns.length - 1];
|
|
54345
|
+
if (cur && cur.source !== "startup") {
|
|
54346
|
+
cur.interrupts = cur.interrupts || [];
|
|
54347
|
+
const txt = peekText(rec.message?.content).trim();
|
|
54348
|
+
cur.interrupts.push({
|
|
54349
|
+
at: rec.timestamp || new Date().toISOString(),
|
|
54350
|
+
label: txt.replace(/^\[|\]$/g, "").slice(0, 60)
|
|
54351
|
+
});
|
|
54352
|
+
}
|
|
54353
|
+
continue;
|
|
54354
|
+
}
|
|
54355
|
+
if (isPromptUser(rec)) {
|
|
54356
|
+
activeToolSkillId = null;
|
|
54357
|
+
const { slashCommand, args } = parseCommandFromUser(rec);
|
|
54358
|
+
const text = extractUserText(rec);
|
|
54359
|
+
const argsPreview = slashCommand ? args : text.slice(0, 120);
|
|
54360
|
+
pushTurn(state, {
|
|
54361
|
+
source: slashCommand ? "slash" : "prompt",
|
|
54362
|
+
slashCommand,
|
|
54363
|
+
args: argsPreview,
|
|
54364
|
+
startedAt: rec.timestamp || new Date().toISOString()
|
|
54365
|
+
});
|
|
54366
|
+
continue;
|
|
54367
|
+
}
|
|
54368
|
+
if (rec.type === "assistant" && !rec.isSidechain) {
|
|
54369
|
+
const tok = tokensOfClaude(rec);
|
|
54370
|
+
if (tok)
|
|
54371
|
+
state.mainLoopTokens = addTokens(state.mainLoopTokens, tok);
|
|
54372
|
+
const cur = state.turns[state.turns.length - 1];
|
|
54373
|
+
if (cur && cur.source !== "startup") {
|
|
54374
|
+
cur.assistant = cur.assistant || {
|
|
54375
|
+
model: null,
|
|
54376
|
+
tokens: emptyTokens(),
|
|
54377
|
+
startedAt: null,
|
|
54378
|
+
endedAt: null
|
|
54379
|
+
};
|
|
54380
|
+
if (rec.message?.model)
|
|
54381
|
+
cur.assistant.model = rec.message.model;
|
|
54382
|
+
if (tok)
|
|
54383
|
+
cur.assistant.tokens = addTokens(cur.assistant.tokens, tok);
|
|
54384
|
+
const ts = rec.timestamp;
|
|
54385
|
+
if (ts) {
|
|
54386
|
+
if (!cur.assistant.startedAt || String(ts) < String(cur.assistant.startedAt))
|
|
54387
|
+
cur.assistant.startedAt = ts;
|
|
54388
|
+
if (!cur.assistant.endedAt || String(ts) > String(cur.assistant.endedAt))
|
|
54389
|
+
cur.assistant.endedAt = ts;
|
|
54390
|
+
}
|
|
54391
|
+
}
|
|
54392
|
+
if (tok && activeToolSkillId && state.skills[activeToolSkillId]) {
|
|
54393
|
+
const sk = state.skills[activeToolSkillId];
|
|
54394
|
+
sk.tokens = addTokens(sk.tokens, tok);
|
|
54395
|
+
}
|
|
54396
|
+
const content = rec.message?.content;
|
|
54397
|
+
if (Array.isArray(content)) {
|
|
54398
|
+
for (const it of content) {
|
|
54399
|
+
const block = it;
|
|
54400
|
+
if (!block || block.type !== "tool_use")
|
|
54401
|
+
continue;
|
|
54402
|
+
if (block.name === "Task")
|
|
54403
|
+
handleTaskUse(state, rec, block, subIdx);
|
|
54404
|
+
else if (block.name === "Skill") {
|
|
54405
|
+
const opened = handleSkillUse(state, rec, block, openSkills);
|
|
54406
|
+
if (opened)
|
|
54407
|
+
activeToolSkillId = opened.id;
|
|
54408
|
+
}
|
|
54409
|
+
}
|
|
54410
|
+
}
|
|
54411
|
+
continue;
|
|
54412
|
+
}
|
|
54413
|
+
if (rec.type === "user" && Array.isArray(rec?.message?.content)) {
|
|
54414
|
+
for (const it of rec.message.content) {
|
|
54415
|
+
if (!it || it.type !== "tool_result" || !it.tool_use_id)
|
|
54416
|
+
continue;
|
|
54417
|
+
const open2 = openSkills.get(it.tool_use_id);
|
|
54418
|
+
if (!open2)
|
|
54419
|
+
continue;
|
|
54420
|
+
closeSkill(state, open2, rec.timestamp || new Date().toISOString());
|
|
54421
|
+
openSkills.delete(it.tool_use_id);
|
|
54422
|
+
}
|
|
54423
|
+
}
|
|
54424
|
+
}
|
|
54425
|
+
for (const open2 of openSkills.values()) {
|
|
54426
|
+
closeSkill(state, open2, new Date().toISOString());
|
|
54427
|
+
}
|
|
54428
|
+
for (const t of state.turns) {
|
|
54429
|
+
if (!t.assistant)
|
|
54430
|
+
continue;
|
|
54431
|
+
for (const aid of t.agentIds || []) {
|
|
54432
|
+
const ag = state.agents[aid];
|
|
54433
|
+
if (!ag?.tokens)
|
|
54434
|
+
continue;
|
|
54435
|
+
t.assistant.tokens = addTokens(t.assistant.tokens, ag.tokens);
|
|
54436
|
+
}
|
|
54437
|
+
}
|
|
54438
|
+
for (const t of state.turns) {
|
|
54439
|
+
if (!t.assistant || !t.skillIds)
|
|
54440
|
+
continue;
|
|
54441
|
+
for (const sid of t.skillIds) {
|
|
54442
|
+
const sk = state.skills[sid];
|
|
54443
|
+
if (sk && sk.source === "slash") {
|
|
54444
|
+
sk.tokens = { ...t.assistant.tokens };
|
|
54445
|
+
}
|
|
54446
|
+
}
|
|
54447
|
+
}
|
|
54448
|
+
for (const entry of subIdx.byAgentId.values()) {
|
|
54449
|
+
if (state.agents[entry.agentId])
|
|
54450
|
+
continue;
|
|
54451
|
+
const turn = pickTurnForTimestamp(state, entry.startedAt) || lastNonStartupTurn(state) || state.turns[state.turns.length - 1];
|
|
54452
|
+
if (!turn)
|
|
54453
|
+
continue;
|
|
54454
|
+
state.agents[entry.agentId] = {
|
|
54455
|
+
id: entry.agentId,
|
|
54456
|
+
type: entry.type,
|
|
54457
|
+
description: entry.description || "",
|
|
54458
|
+
promptPreview: "",
|
|
54459
|
+
turnId: turn.id,
|
|
54460
|
+
startedAt: entry.startedAt || turn.startedAt,
|
|
54461
|
+
endedAt: entry.endedAt || turn.endedAt || new Date().toISOString(),
|
|
54462
|
+
status: "done",
|
|
54463
|
+
tokens: entry.tokens || emptyTokens(),
|
|
54464
|
+
model: entry.model || null
|
|
54465
|
+
};
|
|
54466
|
+
turn.agentIds.push(entry.agentId);
|
|
54467
|
+
}
|
|
54468
|
+
state.totals = { ...state.mainLoopTokens };
|
|
54469
|
+
for (const ag of Object.values(state.agents)) {
|
|
54470
|
+
state.totals = addTokens(state.totals, ag.tokens || emptyTokens());
|
|
54471
|
+
}
|
|
54472
|
+
const last = state.turns[state.turns.length - 1];
|
|
54473
|
+
if (last && !last.endedAt)
|
|
54474
|
+
last.endedAt = new Date().toISOString();
|
|
54475
|
+
return state;
|
|
54476
|
+
}
|
|
54477
|
+
function matches(filePath) {
|
|
54478
|
+
if (!filePath)
|
|
54479
|
+
return false;
|
|
54480
|
+
const norm = path7.resolve(filePath);
|
|
54481
|
+
return norm.includes(`${path7.sep}.claude${path7.sep}projects${path7.sep}`) && norm.endsWith(".jsonl");
|
|
54482
|
+
}
|
|
54483
|
+
var claudeAdapter = {
|
|
54484
|
+
name: "claude",
|
|
54485
|
+
matches,
|
|
54486
|
+
listSessions,
|
|
54487
|
+
parse: parse2
|
|
54488
|
+
};
|
|
54489
|
+
|
|
54490
|
+
// src/domains/sessions/adapters/codex.ts
|
|
54491
|
+
import * as fs10 from "node:fs";
|
|
54492
|
+
import * as os5 from "node:os";
|
|
54493
|
+
import * as path8 from "node:path";
|
|
54494
|
+
var CODEX_ROOT = path8.join(os5.homedir(), ".codex", "sessions");
|
|
54495
|
+
function normalizeName(n) {
|
|
54496
|
+
return String(n || "").toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
54497
|
+
}
|
|
54498
|
+
function skillDirs(cwd2) {
|
|
54499
|
+
const dirs = [path8.join(os5.homedir(), ".codex", "skills")];
|
|
54500
|
+
if (cwd2)
|
|
54501
|
+
dirs.push(path8.join(cwd2, ".codex", "skills"));
|
|
54502
|
+
return dirs;
|
|
54503
|
+
}
|
|
54504
|
+
function loadSkillCatalog(cwd2) {
|
|
54505
|
+
const out = [];
|
|
54506
|
+
const seen = new Set;
|
|
54507
|
+
for (const dir of skillDirs(cwd2)) {
|
|
54508
|
+
let names;
|
|
54509
|
+
try {
|
|
54510
|
+
names = fs10.readdirSync(dir);
|
|
54511
|
+
} catch {
|
|
54512
|
+
continue;
|
|
54513
|
+
}
|
|
54514
|
+
for (const name of names) {
|
|
54515
|
+
if (name.startsWith("."))
|
|
54516
|
+
continue;
|
|
54517
|
+
const entryPath = path8.join(dir, name);
|
|
54518
|
+
let st;
|
|
54519
|
+
try {
|
|
54520
|
+
st = fs10.statSync(entryPath);
|
|
54521
|
+
} catch {
|
|
54522
|
+
continue;
|
|
54523
|
+
}
|
|
54524
|
+
if (!st.isDirectory())
|
|
54525
|
+
continue;
|
|
54526
|
+
if (!fs10.existsSync(path8.join(entryPath, "SKILL.md")))
|
|
54527
|
+
continue;
|
|
54528
|
+
const key = normalizeName(name);
|
|
54529
|
+
if (!key || seen.has(key))
|
|
54530
|
+
continue;
|
|
54531
|
+
seen.add(key);
|
|
54532
|
+
out.push({ raw: name, normalized: key });
|
|
54533
|
+
}
|
|
54534
|
+
}
|
|
54535
|
+
return out;
|
|
54536
|
+
}
|
|
54537
|
+
function detectSkillsInPrompt(catalog, promptText) {
|
|
54538
|
+
if (!promptText || !catalog.length)
|
|
54539
|
+
return [];
|
|
54540
|
+
const matches2 = [];
|
|
54541
|
+
const seen = new Set;
|
|
54542
|
+
const re2 = /\$([A-Za-z0-9_-]+(?::[A-Za-z0-9_-]+)?)/g;
|
|
54543
|
+
for (let m2 = re2.exec(promptText);m2 !== null; m2 = re2.exec(promptText)) {
|
|
54544
|
+
const token = m2[1];
|
|
54545
|
+
if (!token)
|
|
54546
|
+
continue;
|
|
54547
|
+
const candidates = [token];
|
|
54548
|
+
const colonIdx = token.indexOf(":");
|
|
54549
|
+
if (colonIdx > -1)
|
|
54550
|
+
candidates.push(token.slice(colonIdx + 1));
|
|
54551
|
+
let hit;
|
|
54552
|
+
for (const cand of candidates) {
|
|
54553
|
+
const candNorm = normalizeName(cand);
|
|
54554
|
+
hit = catalog.find((c2) => c2.raw === cand) || catalog.find((c2) => c2.normalized === candNorm);
|
|
54555
|
+
if (hit)
|
|
54556
|
+
break;
|
|
54557
|
+
}
|
|
54558
|
+
if (!hit)
|
|
54559
|
+
continue;
|
|
54560
|
+
if (seen.has(hit.raw))
|
|
54561
|
+
continue;
|
|
54562
|
+
seen.add(hit.raw);
|
|
54563
|
+
matches2.push(hit.raw);
|
|
54564
|
+
}
|
|
54565
|
+
return matches2;
|
|
54566
|
+
}
|
|
54567
|
+
function safeJSON2(line) {
|
|
54568
|
+
try {
|
|
54569
|
+
return JSON.parse(line);
|
|
54570
|
+
} catch {
|
|
54571
|
+
return null;
|
|
54572
|
+
}
|
|
54573
|
+
}
|
|
54574
|
+
function extractUuidFromName(filePath) {
|
|
54575
|
+
const base = path8.basename(filePath, ".jsonl");
|
|
54576
|
+
const m2 = base.match(/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$/);
|
|
54577
|
+
return m2?.[1] ?? null;
|
|
54578
|
+
}
|
|
54579
|
+
function walkRolloutFiles(dir, depth, maxDepth, out) {
|
|
54580
|
+
let entries;
|
|
54581
|
+
try {
|
|
54582
|
+
entries = fs10.readdirSync(dir, { withFileTypes: true });
|
|
54583
|
+
} catch {
|
|
54584
|
+
return;
|
|
54585
|
+
}
|
|
54586
|
+
for (const e2 of entries) {
|
|
54587
|
+
const full = path8.join(dir, e2.name);
|
|
54588
|
+
if (e2.isDirectory()) {
|
|
54589
|
+
if (depth < maxDepth)
|
|
54590
|
+
walkRolloutFiles(full, depth + 1, maxDepth, out);
|
|
54591
|
+
continue;
|
|
54592
|
+
}
|
|
54593
|
+
if (!e2.isFile())
|
|
54594
|
+
continue;
|
|
54595
|
+
if (!e2.name.startsWith("rollout-") || !e2.name.endsWith(".jsonl"))
|
|
54596
|
+
continue;
|
|
54597
|
+
out.push(full);
|
|
54598
|
+
}
|
|
54599
|
+
}
|
|
54600
|
+
function collectRolloutFiles(root) {
|
|
54601
|
+
const files = [];
|
|
54602
|
+
if (!fs10.existsSync(root))
|
|
54603
|
+
return files;
|
|
54604
|
+
walkRolloutFiles(root, 0, 3, files);
|
|
54605
|
+
return files;
|
|
54606
|
+
}
|
|
54607
|
+
function readFirstSessionMeta(filePath) {
|
|
54608
|
+
try {
|
|
54609
|
+
const len = Math.min(fs10.statSync(filePath).size, 64 * 1024);
|
|
54610
|
+
const buf = Buffer.alloc(len);
|
|
54611
|
+
const fd = fs10.openSync(filePath, "r");
|
|
54612
|
+
try {
|
|
54613
|
+
fs10.readSync(fd, buf, 0, len, 0);
|
|
54614
|
+
} finally {
|
|
54615
|
+
fs10.closeSync(fd);
|
|
54616
|
+
}
|
|
54617
|
+
const firstLine = buf.toString("utf-8").split(`
|
|
54618
|
+
`)[0];
|
|
54619
|
+
const rec = firstLine ? safeJSON2(firstLine) : null;
|
|
54620
|
+
if (!rec || rec.type !== "session_meta")
|
|
54621
|
+
return null;
|
|
54622
|
+
return rec.payload || {};
|
|
54623
|
+
} catch {
|
|
54624
|
+
return null;
|
|
54625
|
+
}
|
|
54626
|
+
}
|
|
54627
|
+
function readFirstUserPrompt(filePath) {
|
|
54628
|
+
try {
|
|
54629
|
+
const len = Math.min(fs10.statSync(filePath).size, 128 * 1024);
|
|
54630
|
+
const buf = Buffer.alloc(len);
|
|
54631
|
+
const fd = fs10.openSync(filePath, "r");
|
|
54632
|
+
try {
|
|
54633
|
+
fs10.readSync(fd, buf, 0, len, 0);
|
|
54634
|
+
} finally {
|
|
54635
|
+
fs10.closeSync(fd);
|
|
54636
|
+
}
|
|
54637
|
+
const lines = buf.toString("utf-8").split(`
|
|
54638
|
+
`);
|
|
54639
|
+
for (const line of lines) {
|
|
54640
|
+
if (!line)
|
|
54641
|
+
continue;
|
|
54642
|
+
const r2 = safeJSON2(line);
|
|
54643
|
+
if (!r2)
|
|
54644
|
+
continue;
|
|
54645
|
+
if (r2.type === "event_msg" && r2.payload?.type === "user_message") {
|
|
54646
|
+
return String(r2.payload.message || "").replace(/\s+/g, " ").trim().slice(0, 120);
|
|
54647
|
+
}
|
|
54648
|
+
}
|
|
54649
|
+
} catch {}
|
|
54650
|
+
return "";
|
|
54651
|
+
}
|
|
54652
|
+
function readFirstChildModel(filePath) {
|
|
54653
|
+
try {
|
|
54654
|
+
const len = Math.min(fs10.statSync(filePath).size, 64 * 1024);
|
|
54655
|
+
const buf = Buffer.alloc(len);
|
|
54656
|
+
const fd = fs10.openSync(filePath, "r");
|
|
54657
|
+
try {
|
|
54658
|
+
fs10.readSync(fd, buf, 0, len, 0);
|
|
54659
|
+
} finally {
|
|
54660
|
+
fs10.closeSync(fd);
|
|
54661
|
+
}
|
|
54662
|
+
for (const line of buf.toString("utf-8").split(`
|
|
54663
|
+
`)) {
|
|
54664
|
+
if (!line)
|
|
54665
|
+
continue;
|
|
54666
|
+
const r2 = safeJSON2(line);
|
|
54667
|
+
if (!r2)
|
|
54668
|
+
continue;
|
|
54669
|
+
if (r2.type === "turn_context" && r2.payload?.model)
|
|
54670
|
+
return r2.payload.model;
|
|
54671
|
+
}
|
|
54672
|
+
} catch {}
|
|
54673
|
+
return null;
|
|
54674
|
+
}
|
|
54675
|
+
var _childIndex = null;
|
|
54676
|
+
function buildChildIndex(root) {
|
|
54677
|
+
if (_childIndex)
|
|
54678
|
+
return _childIndex;
|
|
54679
|
+
const map = new Map;
|
|
54680
|
+
const files = collectRolloutFiles(root);
|
|
54681
|
+
for (const f3 of files) {
|
|
54682
|
+
const id = extractUuidFromName(f3);
|
|
54683
|
+
if (id)
|
|
54684
|
+
map.set(id, f3);
|
|
54685
|
+
}
|
|
54686
|
+
_childIndex = map;
|
|
54687
|
+
return map;
|
|
54688
|
+
}
|
|
54689
|
+
function invalidateChildIndex() {
|
|
54690
|
+
_childIndex = null;
|
|
54691
|
+
}
|
|
54692
|
+
async function listSessions2(rootDir) {
|
|
54693
|
+
const root = rootDir || CODEX_ROOT;
|
|
54694
|
+
const out = [];
|
|
54695
|
+
const allFiles = collectRolloutFiles(root);
|
|
54696
|
+
for (const full of allFiles) {
|
|
54697
|
+
const meta = readFirstSessionMeta(full);
|
|
54698
|
+
if (!meta)
|
|
54699
|
+
continue;
|
|
54700
|
+
if (meta.thread_source && meta.thread_source !== "user")
|
|
54701
|
+
continue;
|
|
54702
|
+
let st;
|
|
54703
|
+
try {
|
|
54704
|
+
st = fs10.statSync(full);
|
|
54705
|
+
} catch {
|
|
54706
|
+
continue;
|
|
54707
|
+
}
|
|
54708
|
+
const summary = readFirstUserPrompt(full);
|
|
54709
|
+
const idFromName = extractUuidFromName(full);
|
|
54710
|
+
out.push({
|
|
54711
|
+
id: idFromName || meta.session_id || path8.basename(full, ".jsonl"),
|
|
54712
|
+
adapterName: "codex",
|
|
54713
|
+
path: full,
|
|
54714
|
+
startedAt: meta.timestamp || new Date(st.mtimeMs).toISOString(),
|
|
54715
|
+
project: meta.cwd || null,
|
|
54716
|
+
summary,
|
|
54717
|
+
sizeBytes: st.size
|
|
54718
|
+
});
|
|
54719
|
+
}
|
|
54720
|
+
return out;
|
|
54721
|
+
}
|
|
54722
|
+
function pushTurn2(state, opts) {
|
|
54723
|
+
const last = state.turns[state.turns.length - 1];
|
|
54724
|
+
if (last && !last.endedAt)
|
|
54725
|
+
last.endedAt = opts.startedAt;
|
|
54726
|
+
const id = `T${state.turns.length}`;
|
|
54727
|
+
const turn = {
|
|
54728
|
+
id,
|
|
54729
|
+
startedAt: opts.startedAt,
|
|
54730
|
+
endedAt: null,
|
|
54731
|
+
source: opts.source,
|
|
54732
|
+
slashCommand: null,
|
|
54733
|
+
args: String(opts.args || "").slice(0, 120),
|
|
54734
|
+
agentIds: [],
|
|
54735
|
+
skillIds: [],
|
|
54736
|
+
slashSkillId: null
|
|
54737
|
+
};
|
|
54738
|
+
state.turns.push(turn);
|
|
54739
|
+
return turn;
|
|
54740
|
+
}
|
|
54741
|
+
function addDollarSkill(state, name, ts) {
|
|
54742
|
+
const turn = state.turns[state.turns.length - 1];
|
|
54743
|
+
if (!turn)
|
|
54744
|
+
return null;
|
|
54745
|
+
state.skillCounter += 1;
|
|
54746
|
+
const id = `sk-slash-${turn.id}-${state.skillCounter}`;
|
|
54747
|
+
const startedAt = ts || new Date().toISOString();
|
|
54748
|
+
const skill = {
|
|
54749
|
+
id,
|
|
54750
|
+
name,
|
|
54751
|
+
source: "slash",
|
|
54752
|
+
prefix: "$",
|
|
54753
|
+
turnId: turn.id,
|
|
54754
|
+
startedAt,
|
|
54755
|
+
endedAt: null,
|
|
54756
|
+
status: "running",
|
|
54757
|
+
args: "",
|
|
54758
|
+
tokens: emptyTokens()
|
|
54759
|
+
};
|
|
54760
|
+
state.skills[id] = skill;
|
|
54761
|
+
if (!turn.slashSkillId)
|
|
54762
|
+
turn.slashSkillId = id;
|
|
54763
|
+
turn.skillIds.push(id);
|
|
54764
|
+
return skill;
|
|
54765
|
+
}
|
|
54766
|
+
function attachSubagent(state, info, childIndex) {
|
|
54767
|
+
const turn = state.turns[state.turns.length - 1] || pushTurn2(state, {
|
|
54768
|
+
source: "prompt",
|
|
54769
|
+
args: "spawned subagent",
|
|
54770
|
+
startedAt: info.spawnedAt
|
|
54771
|
+
});
|
|
54772
|
+
const cached = childIndex.get(info.agentId);
|
|
54773
|
+
const childPath = cached && fs10.existsSync(cached) ? cached : null;
|
|
54774
|
+
const transcriptMissing = !childPath;
|
|
54775
|
+
const description = info.nickname ? `${info.nickname}${transcriptMissing ? " (transcript missing)" : ""}` : transcriptMissing ? "(transcript missing)" : "";
|
|
54776
|
+
let tokens = emptyTokens();
|
|
54777
|
+
let model = null;
|
|
54778
|
+
if (childPath) {
|
|
54779
|
+
tokens = sumCodexAgentTokens(childPath);
|
|
54780
|
+
model = readFirstChildModel(childPath);
|
|
54781
|
+
}
|
|
54782
|
+
const ag = {
|
|
54783
|
+
id: info.agentId,
|
|
54784
|
+
type: info.agentType || "unknown",
|
|
54785
|
+
description,
|
|
54786
|
+
promptPreview: info.promptPreview || "",
|
|
54787
|
+
turnId: turn.id,
|
|
54788
|
+
startedAt: info.spawnedAt,
|
|
54789
|
+
endedAt: info.completedAt,
|
|
54790
|
+
status: "done",
|
|
54791
|
+
tokens,
|
|
54792
|
+
model,
|
|
54793
|
+
transcriptMissing
|
|
54794
|
+
};
|
|
54795
|
+
state.agents[info.agentId] = ag;
|
|
54796
|
+
turn.agentIds.push(info.agentId);
|
|
54797
|
+
}
|
|
54798
|
+
async function parse3(filePath) {
|
|
54799
|
+
const childIndex = buildChildIndex(CODEX_ROOT);
|
|
54800
|
+
const { records } = readNew(filePath, 0);
|
|
54801
|
+
const recs = records;
|
|
54802
|
+
const sessionMetaRec = recs.find((r2) => r2?.type === "session_meta");
|
|
54803
|
+
const sessionMeta = sessionMetaRec?.payload || {};
|
|
54804
|
+
const sessionId = extractUuidFromName(filePath) || sessionMeta.session_id || path8.basename(filePath, ".jsonl");
|
|
54805
|
+
const firstTs = sessionMeta.timestamp || recs.find((r2) => r2?.timestamp)?.timestamp || new Date().toISOString();
|
|
54806
|
+
const skillCatalog = loadSkillCatalog(sessionMeta.cwd || null);
|
|
54807
|
+
const state = {
|
|
54808
|
+
sessionId,
|
|
54809
|
+
schemaVersion: 2,
|
|
54810
|
+
startedAt: firstTs,
|
|
54811
|
+
transcriptPath: filePath,
|
|
54812
|
+
transcriptOffset: 0,
|
|
54813
|
+
agentOffsets: {},
|
|
54814
|
+
cwd: sessionMeta.cwd || null,
|
|
54815
|
+
turns: [],
|
|
54816
|
+
agents: {},
|
|
54817
|
+
skills: {},
|
|
54818
|
+
skillCounter: 0,
|
|
54819
|
+
tasks: {},
|
|
54820
|
+
taskOrder: [],
|
|
54821
|
+
todos: [],
|
|
54822
|
+
todosUpdatedAt: null,
|
|
54823
|
+
mainLoopTokens: emptyTokens(),
|
|
54824
|
+
totals: emptyTokens(),
|
|
54825
|
+
hookLog: []
|
|
54826
|
+
};
|
|
54827
|
+
const pendingSpawns = new Map;
|
|
54828
|
+
let lastModel = sessionMeta.model_provider || null;
|
|
54829
|
+
function attachAssistantTo(turn, rec) {
|
|
54830
|
+
if (!turn || turn.source === "startup")
|
|
54831
|
+
return;
|
|
54832
|
+
turn.assistant = turn.assistant || {
|
|
54833
|
+
model: null,
|
|
54834
|
+
tokens: emptyTokens(),
|
|
54835
|
+
startedAt: null,
|
|
54836
|
+
endedAt: null
|
|
54837
|
+
};
|
|
54838
|
+
if (lastModel)
|
|
54839
|
+
turn.assistant.model = lastModel;
|
|
54840
|
+
const tok = tokensOfCodex(rec);
|
|
54841
|
+
if (tok)
|
|
54842
|
+
turn.assistant.tokens = addTokens(turn.assistant.tokens, tok);
|
|
54843
|
+
const ts = rec.timestamp;
|
|
54844
|
+
if (ts) {
|
|
54845
|
+
if (!turn.assistant.startedAt || String(ts) < String(turn.assistant.startedAt))
|
|
54846
|
+
turn.assistant.startedAt = ts;
|
|
54847
|
+
if (!turn.assistant.endedAt || String(ts) > String(turn.assistant.endedAt))
|
|
54848
|
+
turn.assistant.endedAt = ts;
|
|
54849
|
+
}
|
|
54850
|
+
}
|
|
54851
|
+
for (const rec of recs) {
|
|
54852
|
+
if (!rec || typeof rec !== "object")
|
|
54853
|
+
continue;
|
|
54854
|
+
if (rec.type === "turn_context") {
|
|
54855
|
+
const p = rec.payload || {};
|
|
54856
|
+
if (p.model)
|
|
54857
|
+
lastModel = p.model;
|
|
54858
|
+
continue;
|
|
54859
|
+
}
|
|
54860
|
+
if (rec.type === "event_msg") {
|
|
54861
|
+
const p = rec.payload || {};
|
|
54862
|
+
if (p.type === "user_message") {
|
|
54863
|
+
const text = String(p.message || "");
|
|
54864
|
+
pushTurn2(state, {
|
|
54865
|
+
source: "prompt",
|
|
54866
|
+
args: text.slice(0, 120),
|
|
54867
|
+
startedAt: rec.timestamp || new Date().toISOString()
|
|
54868
|
+
});
|
|
54869
|
+
const hits = detectSkillsInPrompt(skillCatalog, text);
|
|
54870
|
+
for (const name of hits.slice(0, 3))
|
|
54871
|
+
addDollarSkill(state, name, rec.timestamp);
|
|
54872
|
+
} else if (p.type === "token_count") {
|
|
54873
|
+
const tok = tokensOfCodex(rec);
|
|
54874
|
+
if (tok)
|
|
54875
|
+
state.mainLoopTokens = addTokens(state.mainLoopTokens, tok);
|
|
54876
|
+
attachAssistantTo(state.turns[state.turns.length - 1], rec);
|
|
54877
|
+
} else if (p.type === "agent_message") {
|
|
54878
|
+
const cur = state.turns[state.turns.length - 1];
|
|
54879
|
+
if (cur && cur.source !== "startup") {
|
|
54880
|
+
cur.assistant = cur.assistant || {
|
|
54881
|
+
model: lastModel,
|
|
54882
|
+
tokens: emptyTokens(),
|
|
54883
|
+
startedAt: null,
|
|
54884
|
+
endedAt: null
|
|
54885
|
+
};
|
|
54886
|
+
if (lastModel)
|
|
54887
|
+
cur.assistant.model = lastModel;
|
|
54888
|
+
const ts = rec.timestamp;
|
|
54889
|
+
if (ts) {
|
|
54890
|
+
if (!cur.assistant.startedAt || String(ts) < String(cur.assistant.startedAt))
|
|
54891
|
+
cur.assistant.startedAt = ts;
|
|
54892
|
+
if (!cur.assistant.endedAt || String(ts) > String(cur.assistant.endedAt))
|
|
54893
|
+
cur.assistant.endedAt = ts;
|
|
54894
|
+
}
|
|
54895
|
+
}
|
|
54896
|
+
} else if (p.type === "task_complete") {
|
|
54897
|
+
const t = state.turns[state.turns.length - 1];
|
|
54898
|
+
if (t && !t.endedAt)
|
|
54899
|
+
t.endedAt = rec.timestamp || new Date().toISOString();
|
|
54900
|
+
}
|
|
54901
|
+
continue;
|
|
54902
|
+
}
|
|
54903
|
+
if (rec.type === "response_item") {
|
|
54904
|
+
const p = rec.payload || {};
|
|
54905
|
+
if (p.type === "function_call") {
|
|
54906
|
+
if (p.name === "spawn_agent" && p.call_id) {
|
|
54907
|
+
let argsParsed = {};
|
|
54908
|
+
try {
|
|
54909
|
+
argsParsed = JSON.parse(p.arguments || "{}");
|
|
54910
|
+
} catch {}
|
|
54911
|
+
pendingSpawns.set(p.call_id, {
|
|
54912
|
+
agentType: argsParsed.agent_type || "default",
|
|
54913
|
+
message: argsParsed.message || "",
|
|
54914
|
+
timestamp: rec.timestamp || new Date().toISOString()
|
|
54915
|
+
});
|
|
54916
|
+
}
|
|
54917
|
+
continue;
|
|
54918
|
+
}
|
|
54919
|
+
if (p.type === "function_call_output" && p.call_id) {
|
|
54920
|
+
const pending = pendingSpawns.get(p.call_id);
|
|
54921
|
+
if (!pending)
|
|
54922
|
+
continue;
|
|
54923
|
+
pendingSpawns.delete(p.call_id);
|
|
54924
|
+
let parsedOutput = {};
|
|
54925
|
+
try {
|
|
54926
|
+
parsedOutput = JSON.parse(p.output || "{}");
|
|
54927
|
+
} catch {}
|
|
54928
|
+
const agentId = parsedOutput.agent_id;
|
|
54929
|
+
const nickname = parsedOutput.nickname || "";
|
|
54930
|
+
if (!agentId)
|
|
54931
|
+
continue;
|
|
54932
|
+
attachSubagent(state, {
|
|
54933
|
+
agentId,
|
|
54934
|
+
agentType: pending.agentType,
|
|
54935
|
+
nickname,
|
|
54936
|
+
promptPreview: pending.message.slice(0, 120),
|
|
54937
|
+
spawnedAt: pending.timestamp,
|
|
54938
|
+
completedAt: rec.timestamp || pending.timestamp
|
|
54939
|
+
}, childIndex);
|
|
54940
|
+
}
|
|
54941
|
+
}
|
|
54942
|
+
}
|
|
54943
|
+
for (const t of state.turns) {
|
|
54944
|
+
if (!t.assistant)
|
|
54945
|
+
continue;
|
|
54946
|
+
for (const aid of t.agentIds || []) {
|
|
54947
|
+
const ag = state.agents[aid];
|
|
54948
|
+
if (!ag?.tokens)
|
|
54949
|
+
continue;
|
|
54950
|
+
t.assistant.tokens = addTokens(t.assistant.tokens, ag.tokens);
|
|
54951
|
+
}
|
|
54952
|
+
}
|
|
54953
|
+
for (const t of state.turns) {
|
|
54954
|
+
if (!t.assistant || !t.skillIds)
|
|
54955
|
+
continue;
|
|
54956
|
+
for (const sid of t.skillIds) {
|
|
54957
|
+
const sk = state.skills[sid];
|
|
54958
|
+
if (sk && sk.source === "slash") {
|
|
54959
|
+
sk.tokens = { ...t.assistant.tokens };
|
|
54960
|
+
}
|
|
54961
|
+
}
|
|
54962
|
+
}
|
|
54963
|
+
state.totals = { ...state.mainLoopTokens };
|
|
54964
|
+
for (const ag of Object.values(state.agents)) {
|
|
54965
|
+
state.totals = addTokens(state.totals, ag.tokens || emptyTokens());
|
|
54966
|
+
}
|
|
54967
|
+
const last = state.turns[state.turns.length - 1];
|
|
54968
|
+
if (last && !last.endedAt)
|
|
54969
|
+
last.endedAt = new Date().toISOString();
|
|
54970
|
+
return state;
|
|
54971
|
+
}
|
|
54972
|
+
function matches2(filePath) {
|
|
54973
|
+
if (!filePath)
|
|
54974
|
+
return false;
|
|
54975
|
+
const norm = path8.resolve(filePath);
|
|
54976
|
+
return norm.includes(`${path8.sep}.codex${path8.sep}sessions${path8.sep}`) && /rollout-.*\.jsonl$/.test(norm);
|
|
54977
|
+
}
|
|
54978
|
+
var codexAdapter = {
|
|
54979
|
+
name: "codex",
|
|
54980
|
+
matches: matches2,
|
|
54981
|
+
listSessions: listSessions2,
|
|
54982
|
+
parse: parse3,
|
|
54983
|
+
invalidateChildIndex
|
|
54984
|
+
};
|
|
54985
|
+
|
|
54986
|
+
// src/domains/sessions/adapters/index.ts
|
|
54987
|
+
var adapters = [claudeAdapter, codexAdapter];
|
|
54988
|
+
function resolveById(namespacedId) {
|
|
54989
|
+
if (!namespacedId)
|
|
54990
|
+
return null;
|
|
54991
|
+
const idx = namespacedId.indexOf(":");
|
|
54992
|
+
if (idx < 0)
|
|
54993
|
+
return null;
|
|
54994
|
+
const adapterName = namespacedId.slice(0, idx);
|
|
54995
|
+
const uuid = namespacedId.slice(idx + 1);
|
|
54996
|
+
const adapter = adapters.find((a3) => a3.name === adapterName);
|
|
54997
|
+
if (!adapter)
|
|
54998
|
+
return null;
|
|
54999
|
+
return { adapter, uuid, namespacedId };
|
|
55000
|
+
}
|
|
55001
|
+
|
|
55002
|
+
// src/domains/sessions/enumerate.ts
|
|
55003
|
+
var cache = null;
|
|
55004
|
+
async function list(opts = {}) {
|
|
55005
|
+
if (cache && !opts.refresh)
|
|
55006
|
+
return cache;
|
|
55007
|
+
const lists = await Promise.all(adapters.map((a3) => a3.listSessions().catch(() => [])));
|
|
55008
|
+
const merged = [];
|
|
55009
|
+
adapters.forEach((adapter, i) => {
|
|
55010
|
+
const list2 = lists[i] || [];
|
|
55011
|
+
for (const s of list2) {
|
|
55012
|
+
merged.push({ ...s, id: `${adapter.name}:${s.id}` });
|
|
55013
|
+
}
|
|
55014
|
+
});
|
|
55015
|
+
merged.sort((a3, b3) => String(b3.startedAt || "").localeCompare(String(a3.startedAt || "")));
|
|
55016
|
+
cache = merged;
|
|
55017
|
+
return cache;
|
|
55018
|
+
}
|
|
55019
|
+
function invalidate() {
|
|
55020
|
+
cache = null;
|
|
55021
|
+
for (const a3 of adapters) {
|
|
55022
|
+
if (typeof a3.invalidateChildIndex === "function")
|
|
55023
|
+
a3.invalidateChildIndex();
|
|
55024
|
+
}
|
|
55025
|
+
}
|
|
55026
|
+
|
|
55027
|
+
// src/domains/sessions/origin-allowlist.ts
|
|
55028
|
+
init_build_config();
|
|
55029
|
+
function originOf(url) {
|
|
55030
|
+
try {
|
|
55031
|
+
const u = new URL(url);
|
|
55032
|
+
return `${u.protocol}//${u.host}`;
|
|
55033
|
+
} catch {
|
|
55034
|
+
return url.replace(/\/+$/, "");
|
|
55035
|
+
}
|
|
55036
|
+
}
|
|
55037
|
+
var PLATFORM_ORIGIN = originOf(SERVER_URL);
|
|
55038
|
+
var DEFAULT_ORIGINS = [
|
|
55039
|
+
PLATFORM_ORIGIN,
|
|
55040
|
+
"http://localhost:5173",
|
|
55041
|
+
"http://localhost:4321"
|
|
55042
|
+
];
|
|
55043
|
+
var LOOPBACK_HOST_PATTERN = /^http:\/\/(localhost|127\.0\.0\.1)(:\d+)?$/;
|
|
55044
|
+
function isAllowedOrigin(origin) {
|
|
55045
|
+
if (!origin)
|
|
55046
|
+
return false;
|
|
55047
|
+
if (DEFAULT_ORIGINS.includes(origin))
|
|
55048
|
+
return true;
|
|
55049
|
+
return LOOPBACK_HOST_PATTERN.test(origin);
|
|
55050
|
+
}
|
|
55051
|
+
|
|
55052
|
+
// src/domains/sessions/server.ts
|
|
55053
|
+
var PORT_BUMP_MAX = 9;
|
|
55054
|
+
function applyCorsHeaders(req, res) {
|
|
55055
|
+
const origin = req.headers.origin;
|
|
55056
|
+
if (origin && isAllowedOrigin(origin)) {
|
|
55057
|
+
res.setHeader("Access-Control-Allow-Origin", origin);
|
|
55058
|
+
res.setHeader("Vary", "Origin");
|
|
55059
|
+
}
|
|
55060
|
+
}
|
|
55061
|
+
function sendJSON(res, code, body) {
|
|
55062
|
+
const buf = Buffer.from(JSON.stringify(body));
|
|
55063
|
+
res.writeHead(code, {
|
|
55064
|
+
"content-type": "application/json; charset=utf-8",
|
|
55065
|
+
"content-length": buf.length
|
|
55066
|
+
});
|
|
55067
|
+
res.end(buf);
|
|
55068
|
+
}
|
|
55069
|
+
function originGuard(req, res) {
|
|
55070
|
+
const origin = req.headers.origin;
|
|
55071
|
+
if (isAllowedOrigin(origin)) {
|
|
55072
|
+
applyCorsHeaders(req, res);
|
|
55073
|
+
return true;
|
|
55074
|
+
}
|
|
55075
|
+
sendJSON(res, 403, { error: "origin not allowed", origin: origin ?? null });
|
|
55076
|
+
return false;
|
|
55077
|
+
}
|
|
55078
|
+
async function route(req, res, version3) {
|
|
55079
|
+
const url = new URL(req.url || "/", "http://127.0.0.1");
|
|
55080
|
+
const pathname = url.pathname;
|
|
55081
|
+
applyCorsHeaders(req, res);
|
|
55082
|
+
if (req.method === "OPTIONS") {
|
|
55083
|
+
res.writeHead(204, {
|
|
55084
|
+
"Access-Control-Allow-Methods": "GET, OPTIONS",
|
|
55085
|
+
"Access-Control-Allow-Headers": "content-type",
|
|
55086
|
+
"Access-Control-Max-Age": "600"
|
|
55087
|
+
});
|
|
55088
|
+
res.end();
|
|
55089
|
+
return;
|
|
55090
|
+
}
|
|
55091
|
+
if (pathname === "/healthz") {
|
|
55092
|
+
sendJSON(res, 200, { ok: true, version: version3 });
|
|
55093
|
+
return;
|
|
55094
|
+
}
|
|
55095
|
+
if (!pathname.startsWith("/api/")) {
|
|
55096
|
+
sendJSON(res, 404, { error: "not found" });
|
|
55097
|
+
return;
|
|
55098
|
+
}
|
|
55099
|
+
if (!originGuard(req, res))
|
|
55100
|
+
return;
|
|
55101
|
+
if (pathname === "/api/sessions") {
|
|
55102
|
+
const refresh2 = url.searchParams.get("refresh") === "1";
|
|
55103
|
+
if (refresh2)
|
|
55104
|
+
invalidate();
|
|
55105
|
+
const list2 = await list({ refresh: refresh2 });
|
|
55106
|
+
sendJSON(res, 200, list2);
|
|
55107
|
+
return;
|
|
55108
|
+
}
|
|
55109
|
+
const m2 = pathname.match(/^\/api\/sessions\/([^/]+)\/state$/);
|
|
55110
|
+
if (m2?.[1]) {
|
|
55111
|
+
const id = decodeURIComponent(m2[1]);
|
|
55112
|
+
const resolved = resolveById(id);
|
|
55113
|
+
if (!resolved) {
|
|
55114
|
+
sendJSON(res, 404, { error: "unknown adapter or id", id });
|
|
55115
|
+
return;
|
|
55116
|
+
}
|
|
55117
|
+
const all = await list();
|
|
55118
|
+
const summary = all.find((s) => s.id === id);
|
|
55119
|
+
if (!summary) {
|
|
55120
|
+
sendJSON(res, 404, { error: "session not in list", id });
|
|
55121
|
+
return;
|
|
55122
|
+
}
|
|
55123
|
+
try {
|
|
55124
|
+
const state = await resolved.adapter.parse(summary.path);
|
|
55125
|
+
sendJSON(res, 200, state);
|
|
55126
|
+
} catch (e2) {
|
|
55127
|
+
sendJSON(res, 500, { error: String(e2.message || e2) });
|
|
55128
|
+
}
|
|
55129
|
+
return;
|
|
55130
|
+
}
|
|
55131
|
+
sendJSON(res, 404, { error: "not found" });
|
|
55132
|
+
}
|
|
55133
|
+
function start(options2 = {}) {
|
|
55134
|
+
const requested = options2.port ?? 8765;
|
|
55135
|
+
const version3 = options2.version ?? "unknown";
|
|
55136
|
+
return new Promise((resolve17, reject) => {
|
|
55137
|
+
let attempt = 0;
|
|
55138
|
+
const tryListen = (p) => {
|
|
55139
|
+
const server = http.createServer((req, res) => {
|
|
55140
|
+
Promise.resolve(route(req, res, version3)).catch((e2) => {
|
|
55141
|
+
if (res.headersSent) {
|
|
55142
|
+
try {
|
|
55143
|
+
res.end();
|
|
55144
|
+
} catch {}
|
|
55145
|
+
return;
|
|
55146
|
+
}
|
|
55147
|
+
sendJSON(res, 500, { error: String(e2.message || e2) });
|
|
55148
|
+
});
|
|
55149
|
+
});
|
|
55150
|
+
server.on("error", (err) => {
|
|
55151
|
+
if (err.code === "EADDRINUSE" && attempt < PORT_BUMP_MAX) {
|
|
55152
|
+
attempt += 1;
|
|
55153
|
+
tryListen(p + 1);
|
|
55154
|
+
return;
|
|
55155
|
+
}
|
|
55156
|
+
reject(err);
|
|
55157
|
+
});
|
|
55158
|
+
server.listen(p, "127.0.0.1", () => {
|
|
55159
|
+
const addr = server.address();
|
|
55160
|
+
const port = addr?.port ?? p;
|
|
55161
|
+
const handle = {
|
|
55162
|
+
server,
|
|
55163
|
+
port,
|
|
55164
|
+
close: () => new Promise((r2) => {
|
|
55165
|
+
server.close(() => r2());
|
|
55166
|
+
})
|
|
55167
|
+
};
|
|
55168
|
+
options2.onReady?.({ port, url: `http://127.0.0.1:${port}` });
|
|
55169
|
+
resolve17(handle);
|
|
55170
|
+
});
|
|
55171
|
+
};
|
|
55172
|
+
tryListen(requested);
|
|
55173
|
+
});
|
|
55174
|
+
}
|
|
55175
|
+
|
|
55176
|
+
// src/commands/console.ts
|
|
55177
|
+
init_build_config();
|
|
55178
|
+
init_package();
|
|
55179
|
+
function stripTrailingSlash(u) {
|
|
55180
|
+
return u.replace(/\/+$/, "");
|
|
55181
|
+
}
|
|
55182
|
+
async function consoleCommand(options2 = {}) {
|
|
55183
|
+
const requestedPort = options2.port ?? 8765;
|
|
55184
|
+
const openBrowser = !options2.noOpen;
|
|
55185
|
+
const handle = await start({
|
|
55186
|
+
port: requestedPort,
|
|
55187
|
+
version: package_default.version,
|
|
55188
|
+
onReady: ({ url }) => {
|
|
55189
|
+
console.log(`Bridge ready at ${url}`);
|
|
55190
|
+
const platformUrl = `${stripTrailingSlash(SERVER_URL)}/app/console#bridge=${url}`;
|
|
55191
|
+
if (openBrowser) {
|
|
55192
|
+
console.log(`Opening ${platformUrl}`);
|
|
55193
|
+
tryOpenBrowser(platformUrl);
|
|
55194
|
+
} else {
|
|
55195
|
+
console.log(`Open ${platformUrl} in your browser`);
|
|
55196
|
+
}
|
|
55197
|
+
}
|
|
55198
|
+
});
|
|
55199
|
+
await new Promise((resolve17) => {
|
|
55200
|
+
const shutdown = () => {
|
|
55201
|
+
console.log(`
|
|
55202
|
+
Shutting down bridge`);
|
|
55203
|
+
handle.close().finally(() => {
|
|
55204
|
+
resolve17();
|
|
55205
|
+
process.exit(0);
|
|
55206
|
+
});
|
|
55207
|
+
setTimeout(() => process.exit(0), 500).unref();
|
|
55208
|
+
};
|
|
55209
|
+
process.once("SIGINT", shutdown);
|
|
55210
|
+
process.once("SIGTERM", shutdown);
|
|
55211
|
+
});
|
|
55212
|
+
}
|
|
55213
|
+
|
|
53695
55214
|
// src/domains/health-checks/types.ts
|
|
53696
55215
|
init_zod();
|
|
53697
55216
|
var CheckStatusSchema = exports_external.enum(["pass", "warn", "fail", "info"]);
|
|
@@ -53859,7 +55378,7 @@ import { promisify as promisify11 } from "node:util";
|
|
|
53859
55378
|
// src/domains/github/gh-cli-utils.ts
|
|
53860
55379
|
init_environment();
|
|
53861
55380
|
init_logger();
|
|
53862
|
-
import { readFileSync as
|
|
55381
|
+
import { readFileSync as readFileSync8 } from "node:fs";
|
|
53863
55382
|
var MIN_GH_CLI_VERSION = "2.20.0";
|
|
53864
55383
|
var GH_COMMAND_TIMEOUT_MS = 1e4;
|
|
53865
55384
|
function compareVersions4(a3, b3) {
|
|
@@ -53880,7 +55399,7 @@ function isWSL2() {
|
|
|
53880
55399
|
if (process.platform !== "linux")
|
|
53881
55400
|
return false;
|
|
53882
55401
|
try {
|
|
53883
|
-
const release =
|
|
55402
|
+
const release = readFileSync8("/proc/version", "utf-8").toLowerCase();
|
|
53884
55403
|
return release.includes("microsoft") || release.includes("wsl");
|
|
53885
55404
|
} catch (error) {
|
|
53886
55405
|
logger.debug(`WSL detection skipped: ${error instanceof Error ? error.message : "unknown error"}`);
|
|
@@ -54044,10 +55563,10 @@ async function getCommandPath(command) {
|
|
|
54044
55563
|
const whichCmd = process.platform === "win32" ? "where" : "which";
|
|
54045
55564
|
logger.verbose(`Getting path for command: ${command}`);
|
|
54046
55565
|
const { stdout } = await execAsync2(`${whichCmd} ${command}`);
|
|
54047
|
-
const
|
|
55566
|
+
const path9 = stdout.trim().split(`
|
|
54048
55567
|
`)[0] || null;
|
|
54049
|
-
logger.verbose(`Command path resolved: ${command} -> ${
|
|
54050
|
-
return
|
|
55568
|
+
logger.verbose(`Command path resolved: ${command} -> ${path9}`);
|
|
55569
|
+
return path9;
|
|
54051
55570
|
} catch {
|
|
54052
55571
|
logger.verbose(`Failed to get path for command: ${command}`);
|
|
54053
55572
|
return null;
|
|
@@ -54102,7 +55621,7 @@ async function checkDependency(config) {
|
|
|
54102
55621
|
const exists = await commandExists(command);
|
|
54103
55622
|
if (exists) {
|
|
54104
55623
|
logger.verbose(`Found ${config.name} via command: ${command}`);
|
|
54105
|
-
const
|
|
55624
|
+
const path9 = await getCommandPath(command);
|
|
54106
55625
|
const version3 = await getCommandVersion(command, config.versionFlag, config.versionRegex);
|
|
54107
55626
|
let meetsRequirements = true;
|
|
54108
55627
|
let message;
|
|
@@ -54116,7 +55635,7 @@ async function checkDependency(config) {
|
|
|
54116
55635
|
name: config.name,
|
|
54117
55636
|
installed: true,
|
|
54118
55637
|
version: version3 || undefined,
|
|
54119
|
-
path:
|
|
55638
|
+
path: path9 || undefined,
|
|
54120
55639
|
minVersion: config.minVersion,
|
|
54121
55640
|
meetsRequirements,
|
|
54122
55641
|
message
|
|
@@ -54237,7 +55756,7 @@ var PYTHON_INSTALLERS = [
|
|
|
54237
55756
|
// src/services/package-installer/dependencies/system-installer.ts
|
|
54238
55757
|
init_logger();
|
|
54239
55758
|
import { exec as exec3 } from "node:child_process";
|
|
54240
|
-
import * as
|
|
55759
|
+
import * as fs11 from "node:fs";
|
|
54241
55760
|
import { promisify as promisify9 } from "node:util";
|
|
54242
55761
|
var execAsync3 = promisify9(exec3);
|
|
54243
55762
|
async function detectOS() {
|
|
@@ -54252,8 +55771,8 @@ async function detectOS() {
|
|
|
54252
55771
|
}
|
|
54253
55772
|
} else if (platform5 === "linux") {
|
|
54254
55773
|
try {
|
|
54255
|
-
if (
|
|
54256
|
-
const content =
|
|
55774
|
+
if (fs11.existsSync("/etc/os-release")) {
|
|
55775
|
+
const content = fs11.readFileSync("/etc/os-release", "utf-8");
|
|
54257
55776
|
const idMatch = content.match(/^ID=(.+)$/m);
|
|
54258
55777
|
info.distro = idMatch?.[1]?.replace(/"/g, "");
|
|
54259
55778
|
}
|
|
@@ -54833,10 +56352,10 @@ function getPnpmUpdateCommand(packageName, version3, registryUrl) {
|
|
|
54833
56352
|
init_logger();
|
|
54834
56353
|
init_path_resolver();
|
|
54835
56354
|
init_takumi_constants();
|
|
54836
|
-
import { existsSync as
|
|
56355
|
+
import { existsSync as existsSync35, realpathSync } from "node:fs";
|
|
54837
56356
|
import { chmod as chmod2, mkdir as mkdir18, readFile as readFile32, writeFile as writeFile22 } from "node:fs/promises";
|
|
54838
56357
|
import { platform as platform5 } from "node:os";
|
|
54839
|
-
import { join as
|
|
56358
|
+
import { join as join73 } from "node:path";
|
|
54840
56359
|
var CACHE_FILE = "install-info.json";
|
|
54841
56360
|
var CACHE_TTL = 30 * 24 * 60 * 60 * 1000;
|
|
54842
56361
|
function detectFromBinaryPath() {
|
|
@@ -54920,8 +56439,8 @@ function detectFromEnv() {
|
|
|
54920
56439
|
}
|
|
54921
56440
|
async function readCachedPm() {
|
|
54922
56441
|
try {
|
|
54923
|
-
const cacheFile =
|
|
54924
|
-
if (!
|
|
56442
|
+
const cacheFile = join73(PathResolver.getConfigDir(false), CACHE_FILE);
|
|
56443
|
+
if (!existsSync35(cacheFile)) {
|
|
54925
56444
|
return null;
|
|
54926
56445
|
}
|
|
54927
56446
|
const content = await readFile32(cacheFile, "utf-8");
|
|
@@ -54951,8 +56470,8 @@ async function saveCachedPm(pm, getVersion) {
|
|
|
54951
56470
|
return;
|
|
54952
56471
|
try {
|
|
54953
56472
|
const configDir = PathResolver.getConfigDir(false);
|
|
54954
|
-
const cacheFile =
|
|
54955
|
-
if (!
|
|
56473
|
+
const cacheFile = join73(configDir, CACHE_FILE);
|
|
56474
|
+
if (!existsSync35(configDir)) {
|
|
54956
56475
|
await mkdir18(configDir, { recursive: true });
|
|
54957
56476
|
if (platform5() !== "win32") {
|
|
54958
56477
|
await chmod2(configDir, 448);
|
|
@@ -55014,8 +56533,8 @@ async function findOwningPm() {
|
|
|
55014
56533
|
async function clearCache() {
|
|
55015
56534
|
try {
|
|
55016
56535
|
const { unlink: unlink7 } = await import("node:fs/promises");
|
|
55017
|
-
const cacheFile =
|
|
55018
|
-
if (
|
|
56536
|
+
const cacheFile = join73(PathResolver.getConfigDir(false), CACHE_FILE);
|
|
56537
|
+
if (existsSync35(cacheFile)) {
|
|
55019
56538
|
await unlink7(cacheFile);
|
|
55020
56539
|
logger.debug("Package manager cache cleared");
|
|
55021
56540
|
}
|
|
@@ -55275,23 +56794,23 @@ async function checkCliVersion() {
|
|
|
55275
56794
|
// src/domains/health-checks/checkers/claude-md-checker.ts
|
|
55276
56795
|
init_paths();
|
|
55277
56796
|
init_registry();
|
|
55278
|
-
import { existsSync as
|
|
55279
|
-
import { join as
|
|
56797
|
+
import { existsSync as existsSync36, statSync as statSync5 } from "node:fs";
|
|
56798
|
+
import { join as join74 } from "node:path";
|
|
55280
56799
|
function checkClaudeMd(setup, projectDir) {
|
|
55281
56800
|
const results = [];
|
|
55282
56801
|
const claudeCodeInstaller2 = getInstaller("claude-code");
|
|
55283
56802
|
if (claudeCodeInstaller2?.isInstalledGlobally()) {
|
|
55284
56803
|
const claudeGlobal = setup.globals.find((g2) => g2.provider === "claude-code") ?? setup.globals[0];
|
|
55285
56804
|
const globalPath = claudeGlobal?.path ?? claudeCodeInstaller2.globalRoot();
|
|
55286
|
-
const globalClaudeMd =
|
|
56805
|
+
const globalClaudeMd = join74(globalPath, "CLAUDE.md");
|
|
55287
56806
|
results.push(checkClaudeMdFile(globalClaudeMd, "Global CLAUDE.md", "sk-global-claude-md"));
|
|
55288
56807
|
}
|
|
55289
|
-
const projectClaudeMd =
|
|
56808
|
+
const projectClaudeMd = join74(getLocalClaudeDir(projectDir), "CLAUDE.md");
|
|
55290
56809
|
results.push(checkClaudeMdFile(projectClaudeMd, "Project CLAUDE.md", "sk-project-claude-md"));
|
|
55291
56810
|
return results;
|
|
55292
56811
|
}
|
|
55293
|
-
function checkClaudeMdFile(
|
|
55294
|
-
if (!
|
|
56812
|
+
function checkClaudeMdFile(path9, name, id) {
|
|
56813
|
+
if (!existsSync36(path9)) {
|
|
55295
56814
|
return {
|
|
55296
56815
|
id,
|
|
55297
56816
|
name,
|
|
@@ -55304,7 +56823,7 @@ function checkClaudeMdFile(path7, name, id) {
|
|
|
55304
56823
|
};
|
|
55305
56824
|
}
|
|
55306
56825
|
try {
|
|
55307
|
-
const stat8 =
|
|
56826
|
+
const stat8 = statSync5(path9);
|
|
55308
56827
|
const sizeKB = (stat8.size / 1024).toFixed(1);
|
|
55309
56828
|
if (stat8.size === 0) {
|
|
55310
56829
|
return {
|
|
@@ -55314,7 +56833,7 @@ function checkClaudeMdFile(path7, name, id) {
|
|
|
55314
56833
|
priority: "standard",
|
|
55315
56834
|
status: "warn",
|
|
55316
56835
|
message: "Empty (0 bytes)",
|
|
55317
|
-
details:
|
|
56836
|
+
details: path9,
|
|
55318
56837
|
suggestion: "Add project instructions to CLAUDE.md",
|
|
55319
56838
|
autoFixable: false
|
|
55320
56839
|
};
|
|
@@ -55326,7 +56845,7 @@ function checkClaudeMdFile(path7, name, id) {
|
|
|
55326
56845
|
priority: "standard",
|
|
55327
56846
|
status: "pass",
|
|
55328
56847
|
message: `Found (${sizeKB}KB)`,
|
|
55329
|
-
details:
|
|
56848
|
+
details: path9,
|
|
55330
56849
|
autoFixable: false
|
|
55331
56850
|
};
|
|
55332
56851
|
} catch {
|
|
@@ -55337,18 +56856,18 @@ function checkClaudeMdFile(path7, name, id) {
|
|
|
55337
56856
|
priority: "standard",
|
|
55338
56857
|
status: "warn",
|
|
55339
56858
|
message: "Unreadable",
|
|
55340
|
-
details:
|
|
56859
|
+
details: path9,
|
|
55341
56860
|
suggestion: "Check file permissions",
|
|
55342
56861
|
autoFixable: false
|
|
55343
56862
|
};
|
|
55344
56863
|
}
|
|
55345
56864
|
}
|
|
55346
56865
|
// src/domains/health-checks/checkers/active-plan-checker.ts
|
|
55347
|
-
import { existsSync as
|
|
55348
|
-
import { join as
|
|
56866
|
+
import { existsSync as existsSync37, readFileSync as readFileSync10 } from "node:fs";
|
|
56867
|
+
import { join as join75 } from "node:path";
|
|
55349
56868
|
function checkActivePlan(projectDir) {
|
|
55350
|
-
const activePlanPath =
|
|
55351
|
-
if (!
|
|
56869
|
+
const activePlanPath = join75(projectDir, ".claude", "active-plan");
|
|
56870
|
+
if (!existsSync37(activePlanPath)) {
|
|
55352
56871
|
return {
|
|
55353
56872
|
id: "sk-active-plan",
|
|
55354
56873
|
name: "Active Plan",
|
|
@@ -55360,9 +56879,9 @@ function checkActivePlan(projectDir) {
|
|
|
55360
56879
|
};
|
|
55361
56880
|
}
|
|
55362
56881
|
try {
|
|
55363
|
-
const targetPath =
|
|
55364
|
-
const fullPath =
|
|
55365
|
-
if (!
|
|
56882
|
+
const targetPath = readFileSync10(activePlanPath, "utf-8").trim();
|
|
56883
|
+
const fullPath = join75(projectDir, targetPath);
|
|
56884
|
+
if (!existsSync37(fullPath)) {
|
|
55366
56885
|
return {
|
|
55367
56886
|
id: "sk-active-plan",
|
|
55368
56887
|
name: "Active Plan",
|
|
@@ -55427,7 +56946,7 @@ function checkComponentCounts(setup) {
|
|
|
55427
56946
|
init_registry();
|
|
55428
56947
|
init_logger();
|
|
55429
56948
|
import { constants, access, unlink as unlink7, writeFile as writeFile23 } from "node:fs/promises";
|
|
55430
|
-
import { join as
|
|
56949
|
+
import { join as join76 } from "node:path";
|
|
55431
56950
|
|
|
55432
56951
|
// src/domains/health-checks/checkers/shared.ts
|
|
55433
56952
|
init_registry();
|
|
@@ -55502,7 +57021,7 @@ async function checkGlobalDirWritable(provider) {
|
|
|
55502
57021
|
}
|
|
55503
57022
|
const timestamp = Date.now();
|
|
55504
57023
|
const random = Math.random().toString(36).substring(2);
|
|
55505
|
-
const testFile =
|
|
57024
|
+
const testFile = join76(globalDir, `.sk-write-test-${timestamp}-${random}`);
|
|
55506
57025
|
try {
|
|
55507
57026
|
await writeFile23(testFile, "test", { encoding: "utf-8", flag: "wx" });
|
|
55508
57027
|
} catch (_error) {
|
|
@@ -55537,9 +57056,9 @@ async function checkGlobalDirWritable(provider) {
|
|
|
55537
57056
|
// src/domains/health-checks/checkers/hooks-checker.ts
|
|
55538
57057
|
init_paths();
|
|
55539
57058
|
init_registry();
|
|
55540
|
-
import { existsSync as
|
|
57059
|
+
import { existsSync as existsSync38 } from "node:fs";
|
|
55541
57060
|
import { readdir as readdir23 } from "node:fs/promises";
|
|
55542
|
-
import { join as
|
|
57061
|
+
import { join as join77 } from "node:path";
|
|
55543
57062
|
|
|
55544
57063
|
// src/domains/health-checks/utils/path-normalizer.ts
|
|
55545
57064
|
import { normalize as normalize5 } from "node:path";
|
|
@@ -55551,17 +57070,17 @@ function normalizePath(filePath) {
|
|
|
55551
57070
|
|
|
55552
57071
|
// src/domains/health-checks/checkers/hooks-checker.ts
|
|
55553
57072
|
async function checkHooksExist(projectDir) {
|
|
55554
|
-
const globalHooksDir =
|
|
55555
|
-
const projectHooksDir =
|
|
55556
|
-
const globalExists =
|
|
55557
|
-
const projectExists =
|
|
57073
|
+
const globalHooksDir = join77(getInstaller("claude-code")?.globalRoot() ?? "", "hooks");
|
|
57074
|
+
const projectHooksDir = join77(getLocalClaudeDir(projectDir), "hooks");
|
|
57075
|
+
const globalExists = existsSync38(globalHooksDir);
|
|
57076
|
+
const projectExists = existsSync38(projectHooksDir);
|
|
55558
57077
|
let hookCount = 0;
|
|
55559
57078
|
const checkedFiles = new Set;
|
|
55560
57079
|
if (globalExists) {
|
|
55561
57080
|
const files = await readdir23(globalHooksDir, { withFileTypes: false });
|
|
55562
57081
|
const hooks = files.filter((f3) => HOOK_EXTENSIONS2.some((ext2) => f3.endsWith(ext2)));
|
|
55563
57082
|
hooks.forEach((hook) => {
|
|
55564
|
-
const fullPath =
|
|
57083
|
+
const fullPath = join77(globalHooksDir, hook);
|
|
55565
57084
|
checkedFiles.add(normalizePath(fullPath));
|
|
55566
57085
|
});
|
|
55567
57086
|
}
|
|
@@ -55571,7 +57090,7 @@ async function checkHooksExist(projectDir) {
|
|
|
55571
57090
|
const files = await readdir23(projectHooksDir, { withFileTypes: false });
|
|
55572
57091
|
const hooks = files.filter((f3) => HOOK_EXTENSIONS2.some((ext2) => f3.endsWith(ext2)));
|
|
55573
57092
|
hooks.forEach((hook) => {
|
|
55574
|
-
const fullPath =
|
|
57093
|
+
const fullPath = join77(projectHooksDir, hook);
|
|
55575
57094
|
checkedFiles.add(normalizePath(fullPath));
|
|
55576
57095
|
});
|
|
55577
57096
|
}
|
|
@@ -55598,17 +57117,102 @@ async function checkHooksExist(projectDir) {
|
|
|
55598
57117
|
autoFixable: false
|
|
55599
57118
|
};
|
|
55600
57119
|
}
|
|
57120
|
+
// src/domains/health-checks/checkers/codex-hook-health-checker.ts
|
|
57121
|
+
init_registry();
|
|
57122
|
+
import { existsSync as existsSync39 } from "node:fs";
|
|
57123
|
+
import { readFile as readFile33 } from "node:fs/promises";
|
|
57124
|
+
import { join as join78 } from "node:path";
|
|
57125
|
+
async function checkCodexHooksHealth() {
|
|
57126
|
+
const codex = getInstaller("codex");
|
|
57127
|
+
if (!codex?.isInstalledGlobally())
|
|
57128
|
+
return [];
|
|
57129
|
+
const codexRoot = codex.globalRoot();
|
|
57130
|
+
const configTomlPath = join78(codexRoot, "config.toml");
|
|
57131
|
+
const hooksJsonPath = join78(codexRoot, "hooks.json");
|
|
57132
|
+
if (!existsSync39(hooksJsonPath))
|
|
57133
|
+
return [];
|
|
57134
|
+
const results = [];
|
|
57135
|
+
const flagPresent = existsSync39(configTomlPath) ? /(^|\n)\s*hooks\s*=\s*true/.test(await readFile33(configTomlPath, "utf8")) : false;
|
|
57136
|
+
results.push(flagPresent ? {
|
|
57137
|
+
id: "codex-hooks-feature-flag",
|
|
57138
|
+
name: "Codex hooks feature flag",
|
|
57139
|
+
group: "takumi",
|
|
57140
|
+
priority: "critical",
|
|
57141
|
+
status: "pass",
|
|
57142
|
+
message: "[features] hooks = true present",
|
|
57143
|
+
details: configTomlPath,
|
|
57144
|
+
autoFixable: false
|
|
57145
|
+
} : {
|
|
57146
|
+
id: "codex-hooks-feature-flag",
|
|
57147
|
+
name: "Codex hooks feature flag",
|
|
57148
|
+
group: "takumi",
|
|
57149
|
+
priority: "critical",
|
|
57150
|
+
status: "fail",
|
|
57151
|
+
message: "[features] hooks = true missing — Codex ignores all hooks. Add it to config.toml or run `tkm init -a codex`.",
|
|
57152
|
+
details: configTomlPath,
|
|
57153
|
+
autoFixable: false
|
|
57154
|
+
});
|
|
57155
|
+
const missing = await collectMissingWrapperTargets(hooksJsonPath);
|
|
57156
|
+
results.push(missing.length === 0 ? {
|
|
57157
|
+
id: "codex-hooks-command-targets",
|
|
57158
|
+
name: "Codex hook command targets",
|
|
57159
|
+
group: "takumi",
|
|
57160
|
+
priority: "standard",
|
|
57161
|
+
status: "pass",
|
|
57162
|
+
message: "All hook commands point to existing wrappers",
|
|
57163
|
+
details: hooksJsonPath,
|
|
57164
|
+
autoFixable: false
|
|
57165
|
+
} : {
|
|
57166
|
+
id: "codex-hooks-command-targets",
|
|
57167
|
+
name: "Codex hook command targets",
|
|
57168
|
+
group: "takumi",
|
|
57169
|
+
priority: "standard",
|
|
57170
|
+
status: "fail",
|
|
57171
|
+
message: `${missing.length} hook command(s) point to a missing wrapper. Re-run \`tkm init -a codex\` to regenerate.`,
|
|
57172
|
+
details: missing.join(", "),
|
|
57173
|
+
autoFixable: false
|
|
57174
|
+
});
|
|
57175
|
+
return results;
|
|
57176
|
+
}
|
|
57177
|
+
async function collectMissingWrapperTargets(hooksJsonPath) {
|
|
57178
|
+
let parsed;
|
|
57179
|
+
try {
|
|
57180
|
+
parsed = JSON.parse(await readFile33(hooksJsonPath, "utf8"));
|
|
57181
|
+
} catch {
|
|
57182
|
+
return [];
|
|
57183
|
+
}
|
|
57184
|
+
const hooks = parsed?.hooks;
|
|
57185
|
+
if (!hooks || typeof hooks !== "object")
|
|
57186
|
+
return [];
|
|
57187
|
+
const missing = [];
|
|
57188
|
+
const nodeCmd = /\bnode\s+"([^"]+\.cjs)"/;
|
|
57189
|
+
for (const groups of Object.values(hooks)) {
|
|
57190
|
+
if (!Array.isArray(groups))
|
|
57191
|
+
continue;
|
|
57192
|
+
for (const group of groups) {
|
|
57193
|
+
for (const entry of group?.hooks ?? []) {
|
|
57194
|
+
const command = entry?.command;
|
|
57195
|
+
if (typeof command !== "string")
|
|
57196
|
+
continue;
|
|
57197
|
+
const m2 = command.match(nodeCmd);
|
|
57198
|
+
if (m2 && !existsSync39(m2[1]))
|
|
57199
|
+
missing.push(m2[1]);
|
|
57200
|
+
}
|
|
57201
|
+
}
|
|
57202
|
+
}
|
|
57203
|
+
return missing;
|
|
57204
|
+
}
|
|
55601
57205
|
// src/domains/health-checks/checkers/settings-checker.ts
|
|
55602
57206
|
init_paths();
|
|
55603
57207
|
init_registry();
|
|
55604
57208
|
init_logger();
|
|
55605
|
-
import { existsSync as
|
|
55606
|
-
import { readFile as
|
|
55607
|
-
import { join as
|
|
57209
|
+
import { existsSync as existsSync40 } from "node:fs";
|
|
57210
|
+
import { readFile as readFile34 } from "node:fs/promises";
|
|
57211
|
+
import { join as join79 } from "node:path";
|
|
55608
57212
|
async function checkSettingsValid(projectDir) {
|
|
55609
|
-
const globalSettings =
|
|
55610
|
-
const projectSettings =
|
|
55611
|
-
const settingsPath =
|
|
57213
|
+
const globalSettings = join79(getInstaller("claude-code")?.globalRoot() ?? "", "settings.json");
|
|
57214
|
+
const projectSettings = join79(getLocalClaudeDir(projectDir), "settings.json");
|
|
57215
|
+
const settingsPath = existsSync40(globalSettings) ? globalSettings : existsSync40(projectSettings) ? projectSettings : null;
|
|
55612
57216
|
if (!settingsPath) {
|
|
55613
57217
|
return {
|
|
55614
57218
|
id: "sk-settings-valid",
|
|
@@ -55621,7 +57225,7 @@ async function checkSettingsValid(projectDir) {
|
|
|
55621
57225
|
};
|
|
55622
57226
|
}
|
|
55623
57227
|
try {
|
|
55624
|
-
const content = await
|
|
57228
|
+
const content = await readFile34(settingsPath, "utf-8");
|
|
55625
57229
|
JSON.parse(content);
|
|
55626
57230
|
return {
|
|
55627
57231
|
id: "sk-settings-valid",
|
|
@@ -55678,14 +57282,14 @@ async function checkSettingsValid(projectDir) {
|
|
|
55678
57282
|
init_paths();
|
|
55679
57283
|
init_registry();
|
|
55680
57284
|
init_logger();
|
|
55681
|
-
import { existsSync as
|
|
55682
|
-
import { readFile as
|
|
55683
|
-
import { homedir as
|
|
55684
|
-
import { dirname as
|
|
57285
|
+
import { existsSync as existsSync41 } from "node:fs";
|
|
57286
|
+
import { readFile as readFile35 } from "node:fs/promises";
|
|
57287
|
+
import { homedir as homedir24 } from "node:os";
|
|
57288
|
+
import { dirname as dirname19, join as join80, normalize as normalize6, resolve as resolve17 } from "node:path";
|
|
55685
57289
|
async function checkPathRefsValid(projectDir) {
|
|
55686
|
-
const globalClaudeMd =
|
|
55687
|
-
const projectClaudeMd =
|
|
55688
|
-
const claudeMdPath =
|
|
57290
|
+
const globalClaudeMd = join80(getInstaller("claude-code")?.globalRoot() ?? "", "CLAUDE.md");
|
|
57291
|
+
const projectClaudeMd = join80(getLocalClaudeDir(projectDir), "CLAUDE.md");
|
|
57292
|
+
const claudeMdPath = existsSync41(globalClaudeMd) ? globalClaudeMd : existsSync41(projectClaudeMd) ? projectClaudeMd : null;
|
|
55689
57293
|
if (!claudeMdPath) {
|
|
55690
57294
|
return {
|
|
55691
57295
|
id: "sk-path-refs-valid",
|
|
@@ -55698,7 +57302,7 @@ async function checkPathRefsValid(projectDir) {
|
|
|
55698
57302
|
};
|
|
55699
57303
|
}
|
|
55700
57304
|
try {
|
|
55701
|
-
const content = await
|
|
57305
|
+
const content = await readFile35(claudeMdPath, "utf-8");
|
|
55702
57306
|
const refPattern = /@([^\s\)]+)/g;
|
|
55703
57307
|
const refs = [...content.matchAll(refPattern)].map((m2) => m2[1]);
|
|
55704
57308
|
if (refs.length === 0) {
|
|
@@ -55712,8 +57316,8 @@ async function checkPathRefsValid(projectDir) {
|
|
|
55712
57316
|
autoFixable: false
|
|
55713
57317
|
};
|
|
55714
57318
|
}
|
|
55715
|
-
const baseDir =
|
|
55716
|
-
const home6 =
|
|
57319
|
+
const baseDir = dirname19(claudeMdPath);
|
|
57320
|
+
const home6 = homedir24();
|
|
55717
57321
|
const broken = [];
|
|
55718
57322
|
for (const ref of refs) {
|
|
55719
57323
|
let refPath;
|
|
@@ -55728,7 +57332,7 @@ async function checkPathRefsValid(projectDir) {
|
|
|
55728
57332
|
} else if (/^[A-Za-z]:/.test(ref)) {
|
|
55729
57333
|
refPath = normalize6(ref);
|
|
55730
57334
|
} else {
|
|
55731
|
-
refPath =
|
|
57335
|
+
refPath = resolve17(baseDir, ref);
|
|
55732
57336
|
}
|
|
55733
57337
|
const normalizedPath = normalize6(refPath);
|
|
55734
57338
|
const isWithinHome = normalizedPath.startsWith(home6);
|
|
@@ -55738,7 +57342,7 @@ async function checkPathRefsValid(projectDir) {
|
|
|
55738
57342
|
logger.verbose("Skipping potentially unsafe path reference", { ref, refPath });
|
|
55739
57343
|
continue;
|
|
55740
57344
|
}
|
|
55741
|
-
if (!
|
|
57345
|
+
if (!existsSync41(normalizedPath)) {
|
|
55742
57346
|
broken.push(ref);
|
|
55743
57347
|
}
|
|
55744
57348
|
}
|
|
@@ -55778,9 +57382,9 @@ async function checkPathRefsValid(projectDir) {
|
|
|
55778
57382
|
}
|
|
55779
57383
|
// src/domains/health-checks/checkers/config-completeness-checker.ts
|
|
55780
57384
|
init_paths();
|
|
55781
|
-
import { existsSync as
|
|
57385
|
+
import { existsSync as existsSync42 } from "node:fs";
|
|
55782
57386
|
import { readdir as readdir24 } from "node:fs/promises";
|
|
55783
|
-
import { join as
|
|
57387
|
+
import { join as join81 } from "node:path";
|
|
55784
57388
|
async function checkProjectConfigCompleteness(setup, projectDir) {
|
|
55785
57389
|
if (setup.globals.some((g2) => g2.path === setup.project.path)) {
|
|
55786
57390
|
return {
|
|
@@ -55797,12 +57401,12 @@ async function checkProjectConfigCompleteness(setup, projectDir) {
|
|
|
55797
57401
|
const requiredDirs = ["agents", "commands", "skills"];
|
|
55798
57402
|
const missingDirs = [];
|
|
55799
57403
|
for (const dir of requiredDirs) {
|
|
55800
|
-
const dirPath =
|
|
55801
|
-
if (!
|
|
57404
|
+
const dirPath = join81(projectClaudeDir, dir);
|
|
57405
|
+
if (!existsSync42(dirPath)) {
|
|
55802
57406
|
missingDirs.push(dir);
|
|
55803
57407
|
}
|
|
55804
57408
|
}
|
|
55805
|
-
const hasRulesOrWorkflows =
|
|
57409
|
+
const hasRulesOrWorkflows = existsSync42(join81(projectClaudeDir, "rules")) || existsSync42(join81(projectClaudeDir, "workflows"));
|
|
55806
57410
|
if (!hasRulesOrWorkflows) {
|
|
55807
57411
|
missingDirs.push("rules");
|
|
55808
57412
|
}
|
|
@@ -55882,6 +57486,8 @@ class TakumiChecker {
|
|
|
55882
57486
|
}
|
|
55883
57487
|
logger.verbose("TakumiChecker: Checking hooks directory");
|
|
55884
57488
|
results.push(await checkHooksExist(this.projectDir));
|
|
57489
|
+
logger.verbose("TakumiChecker: Checking Codex hook health");
|
|
57490
|
+
results.push(...await checkCodexHooksHealth());
|
|
55885
57491
|
logger.verbose("TakumiChecker: Checking settings.json validity");
|
|
55886
57492
|
results.push(await checkSettingsValid(this.projectDir));
|
|
55887
57493
|
logger.verbose("TakumiChecker: Checking path references");
|
|
@@ -55899,16 +57505,16 @@ import { spawnSync as spawnSync3 } from "node:child_process";
|
|
|
55899
57505
|
// src/domains/installation/git-clone-manager.ts
|
|
55900
57506
|
init_logger();
|
|
55901
57507
|
import { execSync as execSync3 } from "node:child_process";
|
|
55902
|
-
import * as
|
|
55903
|
-
import * as
|
|
55904
|
-
import * as
|
|
57508
|
+
import * as fs12 from "node:fs";
|
|
57509
|
+
import * as os6 from "node:os";
|
|
57510
|
+
import * as path9 from "node:path";
|
|
55905
57511
|
var VALID_TAG_PATTERN = /^[a-zA-Z0-9._+\-]+$/;
|
|
55906
57512
|
|
|
55907
57513
|
class GitCloneManager {
|
|
55908
57514
|
tempBaseDir;
|
|
55909
57515
|
constructor() {
|
|
55910
57516
|
const homeDir = process.env.HOME || process.env.USERPROFILE;
|
|
55911
|
-
this.tempBaseDir = process.env.TMPDIR || process.env.TEMP || process.env.TMP || (homeDir ?
|
|
57517
|
+
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
57518
|
}
|
|
55913
57519
|
validateTag(tag) {
|
|
55914
57520
|
if (!VALID_TAG_PATTERN.test(tag)) {
|
|
@@ -55921,7 +57527,7 @@ Tags must contain only letters, numbers, dots, hyphens, underscores, and plus si
|
|
|
55921
57527
|
const { kit, tag, preferSsh = true, timeout = 60000 } = options2;
|
|
55922
57528
|
this.validateTag(tag);
|
|
55923
57529
|
try {
|
|
55924
|
-
await
|
|
57530
|
+
await fs12.promises.mkdir(this.tempBaseDir, { recursive: true });
|
|
55925
57531
|
} catch (error) {
|
|
55926
57532
|
const msg = error instanceof Error ? error.message : String(error);
|
|
55927
57533
|
throw new Error(`Failed to create temp directory: ${this.tempBaseDir}
|
|
@@ -55929,7 +57535,7 @@ Error: ${msg}
|
|
|
55929
57535
|
|
|
55930
57536
|
Check disk space and directory permissions.`);
|
|
55931
57537
|
}
|
|
55932
|
-
const tempDir = await
|
|
57538
|
+
const tempDir = await fs12.promises.mkdtemp(path9.join(this.tempBaseDir, `sk-git-${kit.repo}-`));
|
|
55933
57539
|
const url = preferSsh ? `git@github.com:${kit.owner}/${kit.repo}.git` : `https://github.com/${kit.owner}/${kit.repo}.git`;
|
|
55934
57540
|
const method = preferSsh ? "ssh" : "https";
|
|
55935
57541
|
logger.verbose("Git clone", { url, tag, tempDir, method });
|
|
@@ -55946,8 +57552,8 @@ Check disk space and directory permissions.`);
|
|
|
55946
57552
|
const stderr = shallowError?.stderr || "";
|
|
55947
57553
|
if (stderr.includes("Could not find remote branch") || stderr.includes("fatal: Remote branch") || stderr.includes("warning: Could not find remote branch")) {
|
|
55948
57554
|
logger.debug(`Shallow clone failed for tag ${tag}, trying full clone...`);
|
|
55949
|
-
await
|
|
55950
|
-
await
|
|
57555
|
+
await fs12.promises.rm(tempDir, { recursive: true, force: true }).catch(() => {});
|
|
57556
|
+
await fs12.promises.mkdir(tempDir, { recursive: true });
|
|
55951
57557
|
execSync3(`git clone --no-checkout ${quotedUrl} ${quotedDir}`, {
|
|
55952
57558
|
stdio: ["pipe", "pipe", "pipe"],
|
|
55953
57559
|
timeout,
|
|
@@ -55962,8 +57568,8 @@ Check disk space and directory permissions.`);
|
|
|
55962
57568
|
throw shallowError;
|
|
55963
57569
|
}
|
|
55964
57570
|
}
|
|
55965
|
-
const gitDir =
|
|
55966
|
-
await
|
|
57571
|
+
const gitDir = path9.join(tempDir, ".git");
|
|
57572
|
+
await fs12.promises.rm(gitDir, { recursive: true, force: true });
|
|
55967
57573
|
logger.debug(`Git clone successful: ${tempDir}`);
|
|
55968
57574
|
return {
|
|
55969
57575
|
cloneDir: tempDir,
|
|
@@ -55971,7 +57577,7 @@ Check disk space and directory permissions.`);
|
|
|
55971
57577
|
method
|
|
55972
57578
|
};
|
|
55973
57579
|
} catch (error) {
|
|
55974
|
-
await
|
|
57580
|
+
await fs12.promises.rm(tempDir, { recursive: true, force: true }).catch((err) => logger.debug(`Failed to cleanup temp dir ${tempDir}: ${err.message}`));
|
|
55975
57581
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
55976
57582
|
const stderr = error?.stderr || "";
|
|
55977
57583
|
const errorCode = error?.code;
|
|
@@ -56011,13 +57617,13 @@ Ensure you have access to the repository and your git credentials are configured
|
|
|
56011
57617
|
const homeDir = process.env.HOME || process.env.USERPROFILE;
|
|
56012
57618
|
if (!homeDir)
|
|
56013
57619
|
return false;
|
|
56014
|
-
const sshDir =
|
|
57620
|
+
const sshDir = path9.join(homeDir, ".ssh");
|
|
56015
57621
|
const keyFiles = ["id_rsa", "id_ed25519", "id_ecdsa", "id_rsa.pub", "id_ed25519.pub"];
|
|
56016
57622
|
try {
|
|
56017
|
-
if (!
|
|
57623
|
+
if (!fs12.existsSync(sshDir))
|
|
56018
57624
|
return false;
|
|
56019
57625
|
for (const keyFile of keyFiles) {
|
|
56020
|
-
if (
|
|
57626
|
+
if (fs12.existsSync(path9.join(sshDir, keyFile))) {
|
|
56021
57627
|
return true;
|
|
56022
57628
|
}
|
|
56023
57629
|
}
|
|
@@ -56239,17 +57845,17 @@ import { platform as platform7 } from "node:os";
|
|
|
56239
57845
|
// src/domains/health-checks/platform/environment-checker.ts
|
|
56240
57846
|
init_registry();
|
|
56241
57847
|
init_environment();
|
|
56242
|
-
import { constants as constants2, access as access2, mkdir as mkdir19, readFile as
|
|
56243
|
-
import { arch as arch2, homedir as
|
|
56244
|
-
import { join as
|
|
57848
|
+
import { constants as constants2, access as access2, mkdir as mkdir19, readFile as readFile36, unlink as unlink8, writeFile as writeFile24 } from "node:fs/promises";
|
|
57849
|
+
import { arch as arch2, homedir as homedir25, platform as platform6 } from "node:os";
|
|
57850
|
+
import { join as join83, normalize as normalize7 } from "node:path";
|
|
56245
57851
|
function shouldSkipExpensiveOperations4() {
|
|
56246
57852
|
return shouldSkipExpensiveOperations();
|
|
56247
57853
|
}
|
|
56248
57854
|
async function checkPlatformDetect() {
|
|
56249
|
-
const
|
|
57855
|
+
const os7 = platform6();
|
|
56250
57856
|
const architecture = arch2();
|
|
56251
57857
|
const wslDistro = process.env.WSL_DISTRO_NAME;
|
|
56252
|
-
let message = `${
|
|
57858
|
+
let message = `${os7} (${architecture})`;
|
|
56253
57859
|
if (wslDistro)
|
|
56254
57860
|
message += ` - WSL: ${wslDistro}`;
|
|
56255
57861
|
return {
|
|
@@ -56263,7 +57869,7 @@ async function checkPlatformDetect() {
|
|
|
56263
57869
|
};
|
|
56264
57870
|
}
|
|
56265
57871
|
async function checkHomeDirResolution() {
|
|
56266
|
-
const nodeHome = normalize7(
|
|
57872
|
+
const nodeHome = normalize7(homedir25());
|
|
56267
57873
|
const rawEnvHome = getHomeDirectoryFromEnv(platform6());
|
|
56268
57874
|
const envHome = rawEnvHome ? normalize7(rawEnvHome) : "";
|
|
56269
57875
|
const match2 = nodeHome === envHome && envHome !== "";
|
|
@@ -56334,11 +57940,11 @@ async function checkGlobalDirAccess(provider) {
|
|
|
56334
57940
|
autoFixable: false
|
|
56335
57941
|
};
|
|
56336
57942
|
}
|
|
56337
|
-
const testFile =
|
|
57943
|
+
const testFile = join83(globalDir, ".sk-doctor-access-test");
|
|
56338
57944
|
try {
|
|
56339
57945
|
await mkdir19(globalDir, { recursive: true });
|
|
56340
57946
|
await writeFile24(testFile, "test", "utf-8");
|
|
56341
|
-
const content = await
|
|
57947
|
+
const content = await readFile36(testFile, "utf-8");
|
|
56342
57948
|
await unlink8(testFile);
|
|
56343
57949
|
if (content !== "test")
|
|
56344
57950
|
throw new Error("Read mismatch");
|
|
@@ -56412,7 +58018,7 @@ async function checkWSLBoundary() {
|
|
|
56412
58018
|
// src/domains/health-checks/platform/windows-checker.ts
|
|
56413
58019
|
init_registry();
|
|
56414
58020
|
import { mkdir as mkdir20, symlink as symlink2, unlink as unlink9, writeFile as writeFile25 } from "node:fs/promises";
|
|
56415
|
-
import { join as
|
|
58021
|
+
import { join as join84 } from "node:path";
|
|
56416
58022
|
async function checkLongPathSupport() {
|
|
56417
58023
|
if (shouldSkipExpensiveOperations4()) {
|
|
56418
58024
|
return {
|
|
@@ -56464,8 +58070,8 @@ async function checkSymlinkSupport() {
|
|
|
56464
58070
|
};
|
|
56465
58071
|
}
|
|
56466
58072
|
const testDir = getInstaller("claude-code")?.globalRoot() ?? "";
|
|
56467
|
-
const target =
|
|
56468
|
-
const link =
|
|
58073
|
+
const target = join84(testDir, ".sk-symlink-test-target");
|
|
58074
|
+
const link = join84(testDir, ".sk-symlink-test-link");
|
|
56469
58075
|
try {
|
|
56470
58076
|
await mkdir20(testDir, { recursive: true });
|
|
56471
58077
|
await writeFile25(target, "test", "utf-8");
|
|
@@ -56721,11 +58327,11 @@ class AutoHealer {
|
|
|
56721
58327
|
duration: 0
|
|
56722
58328
|
};
|
|
56723
58329
|
}
|
|
56724
|
-
const
|
|
58330
|
+
const start2 = Date.now();
|
|
56725
58331
|
try {
|
|
56726
58332
|
const result = await Promise.race([fix.execute(), this.createTimeout()]);
|
|
56727
58333
|
const attempt = this.buildAttempt(check, fix.id, result);
|
|
56728
|
-
attempt.duration = Date.now() -
|
|
58334
|
+
attempt.duration = Date.now() - start2;
|
|
56729
58335
|
return attempt;
|
|
56730
58336
|
} catch (e2) {
|
|
56731
58337
|
const err = e2 instanceof Error ? e2.message : "Unknown error";
|
|
@@ -56736,7 +58342,7 @@ class AutoHealer {
|
|
|
56736
58342
|
success: false,
|
|
56737
58343
|
message: "Fix failed",
|
|
56738
58344
|
error: err,
|
|
56739
|
-
duration: Date.now() -
|
|
58345
|
+
duration: Date.now() - start2
|
|
56740
58346
|
};
|
|
56741
58347
|
}
|
|
56742
58348
|
}
|
|
@@ -56759,18 +58365,18 @@ class AutoHealer {
|
|
|
56759
58365
|
}
|
|
56760
58366
|
// src/domains/health-checks/report-generator.ts
|
|
56761
58367
|
import { execSync as execSync4, spawnSync as spawnSync4 } from "node:child_process";
|
|
56762
|
-
import { readFileSync as
|
|
58368
|
+
import { readFileSync as readFileSync11, unlinkSync as unlinkSync4, writeFileSync as writeFileSync6 } from "node:fs";
|
|
56763
58369
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
56764
|
-
import { dirname as
|
|
58370
|
+
import { dirname as dirname20, join as join85 } from "node:path";
|
|
56765
58371
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
56766
58372
|
init_environment();
|
|
56767
58373
|
init_logger();
|
|
56768
58374
|
init_dist2();
|
|
56769
58375
|
function getCliVersion3() {
|
|
56770
58376
|
try {
|
|
56771
|
-
const __dirname3 =
|
|
56772
|
-
const pkgPath =
|
|
56773
|
-
const pkg = JSON.parse(
|
|
58377
|
+
const __dirname3 = dirname20(fileURLToPath2(import.meta.url));
|
|
58378
|
+
const pkgPath = join85(__dirname3, "../../../package.json");
|
|
58379
|
+
const pkg = JSON.parse(readFileSync11(pkgPath, "utf-8"));
|
|
56774
58380
|
return pkg.version || "unknown";
|
|
56775
58381
|
} catch (err) {
|
|
56776
58382
|
logger.debug(`Failed to read CLI version: ${err}`);
|
|
@@ -56908,7 +58514,7 @@ class ReportGenerator {
|
|
|
56908
58514
|
return null;
|
|
56909
58515
|
}
|
|
56910
58516
|
}
|
|
56911
|
-
const tmpFile =
|
|
58517
|
+
const tmpFile = join85(tmpdir2(), `sk-report-${Date.now()}.txt`);
|
|
56912
58518
|
writeFileSync6(tmpFile, report);
|
|
56913
58519
|
try {
|
|
56914
58520
|
const result = spawnSync4("gh", ["gist", "create", tmpFile, "--desc", "Takumi Diagnostic Report"], {
|
|
@@ -56939,9 +58545,9 @@ class ReportGenerator {
|
|
|
56939
58545
|
cliVersion: getCliVersion3()
|
|
56940
58546
|
};
|
|
56941
58547
|
}
|
|
56942
|
-
scrubPath(
|
|
58548
|
+
scrubPath(path10) {
|
|
56943
58549
|
const home6 = process.env.HOME || process.env.USERPROFILE || "";
|
|
56944
|
-
return home6 ?
|
|
58550
|
+
return home6 ? path10.replace(home6, "~") : path10;
|
|
56945
58551
|
}
|
|
56946
58552
|
getStatusIcon(status2) {
|
|
56947
58553
|
switch (status2) {
|
|
@@ -57054,14 +58660,14 @@ class DoctorUIRenderer {
|
|
|
57054
58660
|
return message;
|
|
57055
58661
|
}
|
|
57056
58662
|
}
|
|
57057
|
-
shortenPath(
|
|
58663
|
+
shortenPath(path10) {
|
|
57058
58664
|
const home6 = process.env.HOME || process.env.USERPROFILE || "";
|
|
57059
|
-
let shortened = home6 ?
|
|
58665
|
+
let shortened = home6 ? path10.replace(home6, "~") : path10;
|
|
57060
58666
|
const maxLen = 50;
|
|
57061
58667
|
if (shortened.length > maxLen) {
|
|
57062
|
-
const
|
|
58668
|
+
const start2 = shortened.slice(0, 20);
|
|
57063
58669
|
const end = shortened.slice(-27);
|
|
57064
|
-
shortened = `${
|
|
58670
|
+
shortened = `${start2}...${end}`;
|
|
57065
58671
|
}
|
|
57066
58672
|
return shortened;
|
|
57067
58673
|
}
|
|
@@ -57220,14 +58826,14 @@ async function authedFetch(url, init) {
|
|
|
57220
58826
|
|
|
57221
58827
|
// src/commands/hooks/lib/detached-put.ts
|
|
57222
58828
|
import { spawn as spawn2 } from "node:child_process";
|
|
57223
|
-
import { openSync } from "node:fs";
|
|
57224
|
-
import { dirname as
|
|
58829
|
+
import { openSync as openSync4 } from "node:fs";
|
|
58830
|
+
import { dirname as dirname21, join as join86 } from "node:path";
|
|
57225
58831
|
|
|
57226
58832
|
// src/commands/hooks/lib/hook-logger.ts
|
|
57227
58833
|
import { appendFileSync } from "node:fs";
|
|
57228
58834
|
var extraLogPath = null;
|
|
57229
|
-
function setHookDebugLog(
|
|
57230
|
-
extraLogPath =
|
|
58835
|
+
function setHookDebugLog(path10) {
|
|
58836
|
+
extraLogPath = path10 && path10.trim().length > 0 ? path10 : null;
|
|
57231
58837
|
}
|
|
57232
58838
|
function formatValue(v2) {
|
|
57233
58839
|
if (v2 === null || v2 === undefined)
|
|
@@ -57268,7 +58874,7 @@ function effectiveDetachMode(flags) {
|
|
|
57268
58874
|
return flags.noDetach ? "inline" : "detached";
|
|
57269
58875
|
}
|
|
57270
58876
|
function sessionDebugLogPath(sessionDir) {
|
|
57271
|
-
return
|
|
58877
|
+
return join86(sessionDir, DETACH_DEBUG_LOG_NAME);
|
|
57272
58878
|
}
|
|
57273
58879
|
var BUNFS_PREFIX = "/$bunfs/";
|
|
57274
58880
|
function resolveInvocationPrefix() {
|
|
@@ -57296,9 +58902,9 @@ function resolveInvocationPrefix() {
|
|
|
57296
58902
|
}
|
|
57297
58903
|
function resolvePreloadScript(entryPath) {
|
|
57298
58904
|
try {
|
|
57299
|
-
const srcDir =
|
|
57300
|
-
const repoRoot =
|
|
57301
|
-
return
|
|
58905
|
+
const srcDir = dirname21(entryPath);
|
|
58906
|
+
const repoRoot = dirname21(srcDir);
|
|
58907
|
+
return join86(repoRoot, "scripts", "preload-config-override.ts");
|
|
57302
58908
|
} catch {
|
|
57303
58909
|
return null;
|
|
57304
58910
|
}
|
|
@@ -57322,7 +58928,7 @@ function buildChildStdio(job) {
|
|
|
57322
58928
|
if (!job.debug)
|
|
57323
58929
|
return "ignore";
|
|
57324
58930
|
try {
|
|
57325
|
-
const fd =
|
|
58931
|
+
const fd = openSync4(sessionDebugLogPath(job.sessionDir), "a");
|
|
57326
58932
|
return ["ignore", fd, fd];
|
|
57327
58933
|
} catch {
|
|
57328
58934
|
return "ignore";
|
|
@@ -57366,17 +58972,17 @@ function decodeJobArgv(argv) {
|
|
|
57366
58972
|
}
|
|
57367
58973
|
|
|
57368
58974
|
// src/commands/hooks/lib/throttle.ts
|
|
57369
|
-
import { promises as
|
|
58975
|
+
import { promises as fs13 } from "node:fs";
|
|
57370
58976
|
|
|
57371
58977
|
// src/commands/hooks/lib/session-paths.ts
|
|
57372
58978
|
init_paths2();
|
|
57373
|
-
import { join as
|
|
58979
|
+
import { join as join88 } from "node:path";
|
|
57374
58980
|
|
|
57375
58981
|
// src/commands/hooks/lib/project-paths.ts
|
|
57376
58982
|
init_paths2();
|
|
57377
58983
|
import { createHash as createHash8 } from "node:crypto";
|
|
57378
58984
|
import { realpathSync as realpathSync2 } from "node:fs";
|
|
57379
|
-
import { basename as
|
|
58985
|
+
import { basename as basename12, join as join87 } from "node:path";
|
|
57380
58986
|
function encodeCwd(cwd2) {
|
|
57381
58987
|
const stripped = cwd2.replace(/^\/+/, "");
|
|
57382
58988
|
const sanitized = stripped.replace(/[^a-zA-Z0-9-]/g, "-");
|
|
@@ -57392,13 +58998,13 @@ function computeProjectHash(cwd2) {
|
|
|
57392
58998
|
return createHash8("sha256").update(canonical).digest("hex").slice(0, 16);
|
|
57393
58999
|
}
|
|
57394
59000
|
function getProjectLabel(cwd2) {
|
|
57395
|
-
return
|
|
59001
|
+
return basename12(cwd2) || "";
|
|
57396
59002
|
}
|
|
57397
59003
|
function getProjectsRoot() {
|
|
57398
|
-
return
|
|
59004
|
+
return join87(getConfigDir(), "projects");
|
|
57399
59005
|
}
|
|
57400
59006
|
function getProjectDir(args) {
|
|
57401
|
-
return
|
|
59007
|
+
return join87(getProjectsRoot(), encodeCwd(args.cwd), args.agent);
|
|
57402
59008
|
}
|
|
57403
59009
|
|
|
57404
59010
|
// src/commands/hooks/lib/session-paths.ts
|
|
@@ -57410,25 +59016,25 @@ function safeSessionSegment(sessionId) {
|
|
|
57410
59016
|
return cleaned.length > 0 ? cleaned.slice(0, MAX_SESSION_ID_LEN) : null;
|
|
57411
59017
|
}
|
|
57412
59018
|
function getSessionsRoot() {
|
|
57413
|
-
return
|
|
59019
|
+
return join88(getConfigDir(), "sessions");
|
|
57414
59020
|
}
|
|
57415
59021
|
function getSessionDirV2(args) {
|
|
57416
59022
|
const segment = safeSessionSegment(args.sessionId);
|
|
57417
59023
|
if (!segment)
|
|
57418
59024
|
return null;
|
|
57419
|
-
return
|
|
59025
|
+
return join88(getProjectDir({ agent: args.agent, cwd: args.cwd }), "sessions", segment);
|
|
57420
59026
|
}
|
|
57421
59027
|
function getEventsFile(sessionDir) {
|
|
57422
|
-
return
|
|
59028
|
+
return join88(sessionDir, "events.jsonl");
|
|
57423
59029
|
}
|
|
57424
59030
|
function getSummaryFile(sessionDir) {
|
|
57425
|
-
return
|
|
59031
|
+
return join88(sessionDir, "summary.json");
|
|
57426
59032
|
}
|
|
57427
59033
|
function getLastPushFile(sessionDir) {
|
|
57428
|
-
return
|
|
59034
|
+
return join88(sessionDir, "last_push.txt");
|
|
57429
59035
|
}
|
|
57430
59036
|
function getMetaFile(sessionDir) {
|
|
57431
|
-
return
|
|
59037
|
+
return join88(sessionDir, "meta.json");
|
|
57432
59038
|
}
|
|
57433
59039
|
|
|
57434
59040
|
// src/commands/hooks/lib/throttle.ts
|
|
@@ -57436,7 +59042,7 @@ var defaultNow = () => Date.now();
|
|
|
57436
59042
|
async function readLastPush(sessionDir) {
|
|
57437
59043
|
let raw;
|
|
57438
59044
|
try {
|
|
57439
|
-
raw = await
|
|
59045
|
+
raw = await fs13.readFile(getLastPushFile(sessionDir), "utf8");
|
|
57440
59046
|
} catch {
|
|
57441
59047
|
return null;
|
|
57442
59048
|
}
|
|
@@ -57444,11 +59050,11 @@ async function readLastPush(sessionDir) {
|
|
|
57444
59050
|
return Number.isFinite(parsed) ? parsed : null;
|
|
57445
59051
|
}
|
|
57446
59052
|
async function writeLastPush(sessionDir, ts) {
|
|
57447
|
-
await
|
|
59053
|
+
await fs13.mkdir(sessionDir, { recursive: true });
|
|
57448
59054
|
const target = getLastPushFile(sessionDir);
|
|
57449
59055
|
const tmp = `${target}.tmp`;
|
|
57450
|
-
await
|
|
57451
|
-
await
|
|
59056
|
+
await fs13.writeFile(tmp, String(ts), "utf8");
|
|
59057
|
+
await fs13.rename(tmp, target);
|
|
57452
59058
|
}
|
|
57453
59059
|
async function shouldFlush(args) {
|
|
57454
59060
|
const now = args.now ?? defaultNow;
|
|
@@ -57458,7 +59064,7 @@ async function shouldFlush(args) {
|
|
|
57458
59064
|
if (now() - last >= args.intervalMs)
|
|
57459
59065
|
return true;
|
|
57460
59066
|
try {
|
|
57461
|
-
const stat8 = await
|
|
59067
|
+
const stat8 = await fs13.stat(getEventsFile(args.sessionDir));
|
|
57462
59068
|
if (stat8.size >= args.sizeBytes)
|
|
57463
59069
|
return true;
|
|
57464
59070
|
} catch {}
|
|
@@ -57500,22 +59106,22 @@ async function handleDoPut() {
|
|
|
57500
59106
|
}
|
|
57501
59107
|
|
|
57502
59108
|
// src/commands/hooks/lib/buffer.ts
|
|
57503
|
-
import { promises as
|
|
59109
|
+
import { promises as fs14 } from "node:fs";
|
|
57504
59110
|
async function appendEvent(sessionDir, event) {
|
|
57505
59111
|
try {
|
|
57506
|
-
await
|
|
59112
|
+
await fs14.mkdir(sessionDir, { recursive: true });
|
|
57507
59113
|
const line = `${JSON.stringify(event)}
|
|
57508
59114
|
`;
|
|
57509
|
-
await
|
|
59115
|
+
await fs14.appendFile(getEventsFile(sessionDir), line, "utf8");
|
|
57510
59116
|
} catch {}
|
|
57511
59117
|
}
|
|
57512
59118
|
|
|
57513
59119
|
// src/commands/hooks/lib/session-meta.ts
|
|
57514
|
-
import { promises as
|
|
59120
|
+
import { promises as fs15 } from "node:fs";
|
|
57515
59121
|
async function readMeta(sessionDir) {
|
|
57516
59122
|
let raw;
|
|
57517
59123
|
try {
|
|
57518
|
-
raw = await
|
|
59124
|
+
raw = await fs15.readFile(getMetaFile(sessionDir), "utf8");
|
|
57519
59125
|
} catch {
|
|
57520
59126
|
return null;
|
|
57521
59127
|
}
|
|
@@ -57528,17 +59134,17 @@ async function readMeta(sessionDir) {
|
|
|
57528
59134
|
async function writeMetaIfAbsent(sessionDir, meta) {
|
|
57529
59135
|
const target = getMetaFile(sessionDir);
|
|
57530
59136
|
try {
|
|
57531
|
-
await
|
|
59137
|
+
await fs15.access(target);
|
|
57532
59138
|
return;
|
|
57533
59139
|
} catch {}
|
|
57534
|
-
await
|
|
59140
|
+
await fs15.mkdir(sessionDir, { recursive: true });
|
|
57535
59141
|
const tmp = `${target}.tmp`;
|
|
57536
|
-
await
|
|
57537
|
-
await
|
|
59142
|
+
await fs15.writeFile(tmp, JSON.stringify(meta), "utf8");
|
|
59143
|
+
await fs15.rename(tmp, target);
|
|
57538
59144
|
}
|
|
57539
59145
|
|
|
57540
59146
|
// src/commands/hooks/lib/summary.ts
|
|
57541
|
-
import { promises as
|
|
59147
|
+
import { promises as fs16 } from "node:fs";
|
|
57542
59148
|
function zeroTokens() {
|
|
57543
59149
|
return { input: 0, output: 0, cache_read: 0, cache_write: 0 };
|
|
57544
59150
|
}
|
|
@@ -57573,7 +59179,7 @@ function initialSummary(args) {
|
|
|
57573
59179
|
async function readSummary(sessionDir) {
|
|
57574
59180
|
let raw;
|
|
57575
59181
|
try {
|
|
57576
|
-
raw = await
|
|
59182
|
+
raw = await fs16.readFile(getSummaryFile(sessionDir), "utf8");
|
|
57577
59183
|
} catch {
|
|
57578
59184
|
return null;
|
|
57579
59185
|
}
|
|
@@ -57584,11 +59190,11 @@ async function readSummary(sessionDir) {
|
|
|
57584
59190
|
}
|
|
57585
59191
|
}
|
|
57586
59192
|
async function writeSummary(sessionDir, summary) {
|
|
57587
|
-
await
|
|
59193
|
+
await fs16.mkdir(sessionDir, { recursive: true });
|
|
57588
59194
|
const target = getSummaryFile(sessionDir);
|
|
57589
59195
|
const tmp = `${target}.tmp`;
|
|
57590
|
-
await
|
|
57591
|
-
await
|
|
59196
|
+
await fs16.writeFile(tmp, JSON.stringify(summary), "utf8");
|
|
59197
|
+
await fs16.rename(tmp, target);
|
|
57592
59198
|
}
|
|
57593
59199
|
function isPlainObject2(value) {
|
|
57594
59200
|
return typeof value === "object" && value !== null && !Array.isArray(value) && (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null);
|
|
@@ -57665,14 +59271,14 @@ async function recordEvent(args) {
|
|
|
57665
59271
|
}
|
|
57666
59272
|
|
|
57667
59273
|
// src/commands/hooks/lib/transcript-reader.ts
|
|
57668
|
-
import { promises as
|
|
59274
|
+
import { promises as fs17 } from "node:fs";
|
|
57669
59275
|
function num(v2) {
|
|
57670
59276
|
return typeof v2 === "number" && Number.isFinite(v2) ? v2 : 0;
|
|
57671
59277
|
}
|
|
57672
59278
|
function zeroTokens2() {
|
|
57673
59279
|
return { input: 0, output: 0, cache_read: 0, cache_write: 0 };
|
|
57674
59280
|
}
|
|
57675
|
-
function
|
|
59281
|
+
function addTokens2(a3, b3) {
|
|
57676
59282
|
return {
|
|
57677
59283
|
input: a3.input + b3.input,
|
|
57678
59284
|
output: a3.output + b3.output,
|
|
@@ -57694,7 +59300,7 @@ function extractTokens(record) {
|
|
|
57694
59300
|
async function tailRead(args) {
|
|
57695
59301
|
let stat8;
|
|
57696
59302
|
try {
|
|
57697
|
-
stat8 = await
|
|
59303
|
+
stat8 = await fs17.stat(args.transcriptPath);
|
|
57698
59304
|
} catch {
|
|
57699
59305
|
return { records: [], nextOffset: args.offset };
|
|
57700
59306
|
}
|
|
@@ -57702,7 +59308,7 @@ async function tailRead(args) {
|
|
|
57702
59308
|
if (currentSize <= args.offset) {
|
|
57703
59309
|
return { records: [], nextOffset: currentSize };
|
|
57704
59310
|
}
|
|
57705
|
-
const handle = await
|
|
59311
|
+
const handle = await fs17.open(args.transcriptPath, "r");
|
|
57706
59312
|
try {
|
|
57707
59313
|
const length = currentSize - args.offset;
|
|
57708
59314
|
const buf = Buffer.alloc(length);
|
|
@@ -57736,13 +59342,13 @@ function bucketTokens(records) {
|
|
|
57736
59342
|
const key = record.agentId ?? record.toolUseID;
|
|
57737
59343
|
if (!key) {
|
|
57738
59344
|
const prev2 = mainLoopDelta;
|
|
57739
|
-
Object.assign(mainLoopDelta,
|
|
59345
|
+
Object.assign(mainLoopDelta, addTokens2(prev2, tokens));
|
|
57740
59346
|
continue;
|
|
57741
59347
|
}
|
|
57742
59348
|
const prev = subagentDeltas.get(key) ?? zeroTokens2();
|
|
57743
|
-
subagentDeltas.set(key,
|
|
59349
|
+
subagentDeltas.set(key, addTokens2(prev, tokens));
|
|
57744
59350
|
} else {
|
|
57745
|
-
Object.assign(mainLoopDelta,
|
|
59351
|
+
Object.assign(mainLoopDelta, addTokens2(mainLoopDelta, tokens));
|
|
57746
59352
|
}
|
|
57747
59353
|
}
|
|
57748
59354
|
return { mainLoopDelta, subagentDeltas };
|
|
@@ -57752,7 +59358,7 @@ function bucketTokens(records) {
|
|
|
57752
59358
|
function ensureTokens(t) {
|
|
57753
59359
|
return t ?? { input: 0, output: 0, cache_read: 0, cache_write: 0 };
|
|
57754
59360
|
}
|
|
57755
|
-
function
|
|
59361
|
+
function addTokens3(a3, b3) {
|
|
57756
59362
|
return {
|
|
57757
59363
|
input: a3.input + b3.input,
|
|
57758
59364
|
output: a3.output + b3.output,
|
|
@@ -57775,12 +59381,12 @@ async function applyTranscriptDelta(args) {
|
|
|
57775
59381
|
const { mainLoopDelta, subagentDeltas } = bucketTokens(records);
|
|
57776
59382
|
const updated = {
|
|
57777
59383
|
...args.summary,
|
|
57778
|
-
main_loop_tokens:
|
|
59384
|
+
main_loop_tokens: addTokens3(args.summary.main_loop_tokens, mainLoopDelta),
|
|
57779
59385
|
subagents: args.summary.subagents.map((rec) => {
|
|
57780
59386
|
const delta = subagentDeltas.get(rec.id);
|
|
57781
59387
|
if (!delta)
|
|
57782
59388
|
return rec;
|
|
57783
|
-
return { ...rec, tokens:
|
|
59389
|
+
return { ...rec, tokens: addTokens3(ensureTokens(rec.tokens), delta) };
|
|
57784
59390
|
}),
|
|
57785
59391
|
transcript_offset: nextOffset
|
|
57786
59392
|
};
|
|
@@ -58035,25 +59641,25 @@ init_takumi_constants();
|
|
|
58035
59641
|
|
|
58036
59642
|
// src/commands/hooks/lib/endpoint.ts
|
|
58037
59643
|
init_build_config();
|
|
58038
|
-
function
|
|
59644
|
+
function stripTrailingSlash2(u) {
|
|
58039
59645
|
return u.replace(/\/+$/, "");
|
|
58040
59646
|
}
|
|
58041
59647
|
function resolveEndpoint() {
|
|
58042
59648
|
if (!SERVER_URL)
|
|
58043
59649
|
return null;
|
|
58044
|
-
return { url:
|
|
59650
|
+
return { url: stripTrailingSlash2(SERVER_URL) };
|
|
58045
59651
|
}
|
|
58046
59652
|
|
|
58047
59653
|
// src/commands/hooks/lib/manifest-versions.ts
|
|
58048
59654
|
init_manifest_path_resolver();
|
|
58049
|
-
import { existsSync as
|
|
58050
|
-
import { homedir as
|
|
58051
|
-
import { dirname as
|
|
59655
|
+
import { existsSync as existsSync44, readFileSync as readFileSync12 } from "node:fs";
|
|
59656
|
+
import { homedir as homedir26 } from "node:os";
|
|
59657
|
+
import { dirname as dirname22, join as join89, resolve as resolve18 } from "node:path";
|
|
58052
59658
|
var PROVIDER_DIRS = [".claude", ".codex"];
|
|
58053
59659
|
var MAX_WALK = 6;
|
|
58054
|
-
function readManifestRaw(
|
|
59660
|
+
function readManifestRaw(path10) {
|
|
58055
59661
|
try {
|
|
58056
|
-
const raw =
|
|
59662
|
+
const raw = readFileSync12(path10, "utf8");
|
|
58057
59663
|
return JSON.parse(raw);
|
|
58058
59664
|
} catch {
|
|
58059
59665
|
return null;
|
|
@@ -58064,28 +59670,28 @@ function findManifestInProviderDir(providerRoot) {
|
|
|
58064
59670
|
return resolved?.path ?? null;
|
|
58065
59671
|
}
|
|
58066
59672
|
function findManifest(cwd2) {
|
|
58067
|
-
let dir =
|
|
59673
|
+
let dir = resolve18(cwd2);
|
|
58068
59674
|
for (let i = 0;i < MAX_WALK; i++) {
|
|
58069
59675
|
for (const provider of PROVIDER_DIRS) {
|
|
58070
|
-
const providerRoot =
|
|
58071
|
-
if (
|
|
58072
|
-
const
|
|
58073
|
-
if (
|
|
58074
|
-
return
|
|
59676
|
+
const providerRoot = join89(dir, provider);
|
|
59677
|
+
if (existsSync44(providerRoot)) {
|
|
59678
|
+
const path10 = findManifestInProviderDir(providerRoot);
|
|
59679
|
+
if (path10)
|
|
59680
|
+
return path10;
|
|
58075
59681
|
}
|
|
58076
59682
|
}
|
|
58077
|
-
const parent =
|
|
59683
|
+
const parent = dirname22(dir);
|
|
58078
59684
|
if (parent === dir)
|
|
58079
59685
|
break;
|
|
58080
59686
|
dir = parent;
|
|
58081
59687
|
}
|
|
58082
59688
|
const pluginRoot = process.env.CLAUDE_PLUGIN_ROOT;
|
|
58083
59689
|
if (pluginRoot) {
|
|
58084
|
-
const pluginPath = findManifestInProviderDir(
|
|
59690
|
+
const pluginPath = findManifestInProviderDir(join89(pluginRoot, ".claude"));
|
|
58085
59691
|
if (pluginPath)
|
|
58086
59692
|
return pluginPath;
|
|
58087
59693
|
}
|
|
58088
|
-
const globalPath = findManifestInProviderDir(
|
|
59694
|
+
const globalPath = findManifestInProviderDir(join89(homedir26(), ".claude"));
|
|
58089
59695
|
if (globalPath)
|
|
58090
59696
|
return globalPath;
|
|
58091
59697
|
return null;
|
|
@@ -58199,12 +59805,12 @@ async function handleSessionEnd(agent, flags = {}) {
|
|
|
58199
59805
|
...reason ? { session_end_reason: reason } : {},
|
|
58200
59806
|
session_end_raw: data
|
|
58201
59807
|
};
|
|
58202
|
-
const { promises:
|
|
58203
|
-
const { join:
|
|
58204
|
-
const target =
|
|
59808
|
+
const { promises: fs18 } = await import("node:fs");
|
|
59809
|
+
const { join: join90 } = await import("node:path");
|
|
59810
|
+
const target = join90(sessionDir, "meta.json");
|
|
58205
59811
|
const tmp = `${target}.tmp`;
|
|
58206
|
-
await
|
|
58207
|
-
await
|
|
59812
|
+
await fs18.writeFile(tmp, JSON.stringify(updated), "utf8");
|
|
59813
|
+
await fs18.rename(tmp, target);
|
|
58208
59814
|
} else if (!existingMeta) {
|
|
58209
59815
|
await writeMetaIfAbsent(sessionDir, {
|
|
58210
59816
|
agent,
|
|
@@ -58271,11 +59877,11 @@ async function handleSessionEnd(agent, flags = {}) {
|
|
|
58271
59877
|
init_auth_client();
|
|
58272
59878
|
|
|
58273
59879
|
// src/commands/hooks/lib/retention.ts
|
|
58274
|
-
import { promises as
|
|
58275
|
-
import { join as
|
|
59880
|
+
import { promises as fs18 } from "node:fs";
|
|
59881
|
+
import { join as join90 } from "node:path";
|
|
58276
59882
|
async function hasLastPush(dir) {
|
|
58277
59883
|
try {
|
|
58278
|
-
await
|
|
59884
|
+
await fs18.access(getLastPushFile(dir));
|
|
58279
59885
|
return true;
|
|
58280
59886
|
} catch {
|
|
58281
59887
|
return false;
|
|
@@ -58284,7 +59890,7 @@ async function hasLastPush(dir) {
|
|
|
58284
59890
|
async function decideDelete(dir, args) {
|
|
58285
59891
|
let mtimeMs = 0;
|
|
58286
59892
|
try {
|
|
58287
|
-
const stat8 = await
|
|
59893
|
+
const stat8 = await fs18.stat(dir);
|
|
58288
59894
|
if (!stat8.isDirectory())
|
|
58289
59895
|
return false;
|
|
58290
59896
|
mtimeMs = stat8.mtimeMs;
|
|
@@ -58301,8 +59907,8 @@ async function decideDelete(dir, args) {
|
|
|
58301
59907
|
}
|
|
58302
59908
|
async function listChildren(dir) {
|
|
58303
59909
|
try {
|
|
58304
|
-
const names = await
|
|
58305
|
-
return names.map((n) =>
|
|
59910
|
+
const names = await fs18.readdir(dir);
|
|
59911
|
+
return names.map((n) => join90(dir, n));
|
|
58306
59912
|
} catch {
|
|
58307
59913
|
return [];
|
|
58308
59914
|
}
|
|
@@ -58313,7 +59919,7 @@ async function collectV2Sessions() {
|
|
|
58313
59919
|
const sessions = [];
|
|
58314
59920
|
for (const projectDir of projects) {
|
|
58315
59921
|
for (const agentDir of await listChildren(projectDir)) {
|
|
58316
|
-
for (const sessionDir of await listChildren(
|
|
59922
|
+
for (const sessionDir of await listChildren(join90(agentDir, "sessions"))) {
|
|
58317
59923
|
sessions.push(sessionDir);
|
|
58318
59924
|
}
|
|
58319
59925
|
}
|
|
@@ -58334,7 +59940,7 @@ async function sweepRetention(args) {
|
|
|
58334
59940
|
continue;
|
|
58335
59941
|
}
|
|
58336
59942
|
try {
|
|
58337
|
-
await
|
|
59943
|
+
await fs18.rm(dir, { recursive: true, force: true });
|
|
58338
59944
|
deleted.push(dir);
|
|
58339
59945
|
} catch {}
|
|
58340
59946
|
}
|
|
@@ -58359,8 +59965,8 @@ async function warmUpToken() {
|
|
|
58359
59965
|
const token = await getValidToken();
|
|
58360
59966
|
return token ? "ok" : "none";
|
|
58361
59967
|
})(),
|
|
58362
|
-
new Promise((
|
|
58363
|
-
timer = setTimeout(() =>
|
|
59968
|
+
new Promise((resolve19) => {
|
|
59969
|
+
timer = setTimeout(() => resolve19("timeout"), TOKEN_WARMUP_TIMEOUT_MS);
|
|
58364
59970
|
})
|
|
58365
59971
|
]);
|
|
58366
59972
|
return result;
|
|
@@ -58713,8 +60319,8 @@ init_hooks_settings_merger();
|
|
|
58713
60319
|
|
|
58714
60320
|
// src/commands/portable/settings-write-with-confirm.ts
|
|
58715
60321
|
init_safe_prompts();
|
|
58716
|
-
import { existsSync as
|
|
58717
|
-
import { dirname as
|
|
60322
|
+
import { existsSync as existsSync45, mkdirSync as mkdirSync4, readFileSync as readFileSync13, renameSync as renameSync2, rmSync as rmSync3, writeFileSync as writeFileSync7 } from "node:fs";
|
|
60323
|
+
import { dirname as dirname23 } from "node:path";
|
|
58718
60324
|
|
|
58719
60325
|
// node_modules/diff/libesm/diff/base.js
|
|
58720
60326
|
class Diff {
|
|
@@ -58816,16 +60422,16 @@ class Diff {
|
|
|
58816
60422
|
}
|
|
58817
60423
|
}
|
|
58818
60424
|
}
|
|
58819
|
-
addToPath(
|
|
58820
|
-
const last =
|
|
60425
|
+
addToPath(path10, added, removed, oldPosInc, options2) {
|
|
60426
|
+
const last = path10.lastComponent;
|
|
58821
60427
|
if (last && !options2.oneChangePerToken && last.added === added && last.removed === removed) {
|
|
58822
60428
|
return {
|
|
58823
|
-
oldPos:
|
|
60429
|
+
oldPos: path10.oldPos + oldPosInc,
|
|
58824
60430
|
lastComponent: { count: last.count + 1, added, removed, previousComponent: last.previousComponent }
|
|
58825
60431
|
};
|
|
58826
60432
|
} else {
|
|
58827
60433
|
return {
|
|
58828
|
-
oldPos:
|
|
60434
|
+
oldPos: path10.oldPos + oldPosInc,
|
|
58829
60435
|
lastComponent: { count: 1, added, removed, previousComponent: last }
|
|
58830
60436
|
};
|
|
58831
60437
|
}
|
|
@@ -59403,11 +61009,11 @@ function isWin(patch) {
|
|
|
59403
61009
|
|
|
59404
61010
|
// node_modules/diff/libesm/patch/parse.js
|
|
59405
61011
|
function parsePatch(uniDiff) {
|
|
59406
|
-
const diffstr = uniDiff.split(/\n/),
|
|
61012
|
+
const diffstr = uniDiff.split(/\n/), list2 = [];
|
|
59407
61013
|
let i = 0;
|
|
59408
61014
|
function parseIndex() {
|
|
59409
61015
|
const index = {};
|
|
59410
|
-
|
|
61016
|
+
list2.push(index);
|
|
59411
61017
|
while (i < diffstr.length) {
|
|
59412
61018
|
const line = diffstr[i];
|
|
59413
61019
|
if (/^(---|\+\+\+|@@)\s/.test(line)) {
|
|
@@ -59503,11 +61109,11 @@ function parsePatch(uniDiff) {
|
|
|
59503
61109
|
while (i < diffstr.length) {
|
|
59504
61110
|
parseIndex();
|
|
59505
61111
|
}
|
|
59506
|
-
return
|
|
61112
|
+
return list2;
|
|
59507
61113
|
}
|
|
59508
61114
|
|
|
59509
61115
|
// node_modules/diff/libesm/util/distance-iterator.js
|
|
59510
|
-
function distance_iterator_default(
|
|
61116
|
+
function distance_iterator_default(start2, minLine, maxLine) {
|
|
59511
61117
|
let wantForward = true, backwardExhausted = false, forwardExhausted = false, localOffset = 1;
|
|
59512
61118
|
return function iterator() {
|
|
59513
61119
|
if (wantForward && !forwardExhausted) {
|
|
@@ -59516,8 +61122,8 @@ function distance_iterator_default(start, minLine, maxLine) {
|
|
|
59516
61122
|
} else {
|
|
59517
61123
|
wantForward = false;
|
|
59518
61124
|
}
|
|
59519
|
-
if (
|
|
59520
|
-
return
|
|
61125
|
+
if (start2 + localOffset <= maxLine) {
|
|
61126
|
+
return start2 + localOffset;
|
|
59521
61127
|
}
|
|
59522
61128
|
forwardExhausted = true;
|
|
59523
61129
|
}
|
|
@@ -59525,8 +61131,8 @@ function distance_iterator_default(start, minLine, maxLine) {
|
|
|
59525
61131
|
if (!forwardExhausted) {
|
|
59526
61132
|
wantForward = true;
|
|
59527
61133
|
}
|
|
59528
|
-
if (minLine <=
|
|
59529
|
-
return
|
|
61134
|
+
if (minLine <= start2 - localOffset) {
|
|
61135
|
+
return start2 - localOffset++;
|
|
59530
61136
|
}
|
|
59531
61137
|
backwardExhausted = true;
|
|
59532
61138
|
return iterator();
|
|
@@ -59885,12 +61491,12 @@ var EMPTY_RESULT = (status2) => ({
|
|
|
59885
61491
|
deletions: 0,
|
|
59886
61492
|
backupPath: null
|
|
59887
61493
|
});
|
|
59888
|
-
function readCurrent(
|
|
59889
|
-
if (!
|
|
61494
|
+
function readCurrent(path10) {
|
|
61495
|
+
if (!existsSync45(path10))
|
|
59890
61496
|
return { kind: "missing" };
|
|
59891
61497
|
let raw = "";
|
|
59892
61498
|
try {
|
|
59893
|
-
raw =
|
|
61499
|
+
raw = readFileSync13(path10, "utf8");
|
|
59894
61500
|
const parsed = JSON.parse(raw);
|
|
59895
61501
|
return { kind: "ok", raw, parsed };
|
|
59896
61502
|
} catch {
|
|
@@ -59916,21 +61522,21 @@ function diffStats(diff) {
|
|
|
59916
61522
|
}
|
|
59917
61523
|
return { additions, deletions };
|
|
59918
61524
|
}
|
|
59919
|
-
function atomicWrite2(
|
|
59920
|
-
mkdirSync4(
|
|
59921
|
-
const tmp = `${
|
|
61525
|
+
function atomicWrite2(path10, contents, backupPath) {
|
|
61526
|
+
mkdirSync4(dirname23(path10), { recursive: true });
|
|
61527
|
+
const tmp = `${path10}.tmp`;
|
|
59922
61528
|
try {
|
|
59923
61529
|
writeFileSync7(tmp, contents);
|
|
59924
|
-
renameSync2(tmp,
|
|
61530
|
+
renameSync2(tmp, path10);
|
|
59925
61531
|
} catch (err) {
|
|
59926
61532
|
rmSync3(tmp, { force: true });
|
|
59927
61533
|
const trailer = backupPath ? `. Backup preserved at: ${backupPath}` : "";
|
|
59928
|
-
throw new Error(`Failed to write ${
|
|
61534
|
+
throw new Error(`Failed to write ${path10}: ${err instanceof Error ? err.message : String(err)}${trailer}`);
|
|
59929
61535
|
}
|
|
59930
61536
|
}
|
|
59931
|
-
function writeBackup(
|
|
61537
|
+
function writeBackup(path10, raw) {
|
|
59932
61538
|
const timestamp = new Date().toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
59933
|
-
const backupPath = `${
|
|
61539
|
+
const backupPath = `${path10}.${timestamp}.bak`;
|
|
59934
61540
|
try {
|
|
59935
61541
|
writeFileSync7(backupPath, raw);
|
|
59936
61542
|
return backupPath;
|
|
@@ -59939,7 +61545,7 @@ function writeBackup(path8, raw) {
|
|
|
59939
61545
|
}
|
|
59940
61546
|
}
|
|
59941
61547
|
async function resolveMissingFile(options2) {
|
|
59942
|
-
const { missingFile, interactive, label, path:
|
|
61548
|
+
const { missingFile, interactive, label, path: path10 } = options2;
|
|
59943
61549
|
if (missingFile === "create")
|
|
59944
61550
|
return "proceed";
|
|
59945
61551
|
if (missingFile === "skip")
|
|
@@ -59947,7 +61553,7 @@ async function resolveMissingFile(options2) {
|
|
|
59947
61553
|
if (!interactive)
|
|
59948
61554
|
return "skip";
|
|
59949
61555
|
const result = await se({
|
|
59950
|
-
message: `${label} does not exist at ${
|
|
61556
|
+
message: `${label} does not exist at ${path10}. Create it?`,
|
|
59951
61557
|
initialValue: false
|
|
59952
61558
|
});
|
|
59953
61559
|
if (lD(result))
|
|
@@ -59955,9 +61561,9 @@ async function resolveMissingFile(options2) {
|
|
|
59955
61561
|
return result ? "proceed" : "skip";
|
|
59956
61562
|
}
|
|
59957
61563
|
async function writeSettingsWithConfirm(options2) {
|
|
59958
|
-
const { path:
|
|
61564
|
+
const { path: path10, transform, yes, dryRun, interactive, useStepUI } = options2;
|
|
59959
61565
|
const diffPrint = useStepUI ? stepLine : undefined;
|
|
59960
|
-
const current = readCurrent(
|
|
61566
|
+
const current = readCurrent(path10);
|
|
59961
61567
|
if (current.kind === "corrupt")
|
|
59962
61568
|
return EMPTY_RESULT("skipped-corrupt");
|
|
59963
61569
|
const fileMissing = current.kind === "missing";
|
|
@@ -59974,7 +61580,7 @@ async function writeSettingsWithConfirm(options2) {
|
|
|
59974
61580
|
if (before === after) {
|
|
59975
61581
|
return EMPTY_RESULT("no-changes");
|
|
59976
61582
|
}
|
|
59977
|
-
const diff = createPatch(
|
|
61583
|
+
const diff = createPatch(path10, before, after, "", "", { context: 3 });
|
|
59978
61584
|
const { additions, deletions } = diffStats(diff);
|
|
59979
61585
|
if (dryRun) {
|
|
59980
61586
|
displayDiff(diff, { color: true, print: diffPrint });
|
|
@@ -59983,15 +61589,15 @@ async function writeSettingsWithConfirm(options2) {
|
|
|
59983
61589
|
if (!yes && interactive) {
|
|
59984
61590
|
displayDiff(diff, { color: true, print: diffPrint });
|
|
59985
61591
|
const accepted = await se({
|
|
59986
|
-
message: `Apply changes to ${
|
|
61592
|
+
message: `Apply changes to ${path10}?`,
|
|
59987
61593
|
initialValue: false
|
|
59988
61594
|
});
|
|
59989
61595
|
if (lD(accepted) || !accepted) {
|
|
59990
61596
|
return { status: "user-declined", diff, additions, deletions, backupPath: null };
|
|
59991
61597
|
}
|
|
59992
61598
|
}
|
|
59993
|
-
const backupPath = fileMissing ? null : writeBackup(
|
|
59994
|
-
atomicWrite2(
|
|
61599
|
+
const backupPath = fileMissing ? null : writeBackup(path10, raw);
|
|
61600
|
+
atomicWrite2(path10, after, backupPath);
|
|
59995
61601
|
return { status: "wrote", diff, additions, deletions, backupPath };
|
|
59996
61602
|
}
|
|
59997
61603
|
|
|
@@ -60003,18 +61609,18 @@ init_dist2();
|
|
|
60003
61609
|
// src/commands/hooks/lib/agent-target-picker.ts
|
|
60004
61610
|
init_safe_prompts();
|
|
60005
61611
|
init_dist2();
|
|
60006
|
-
import { existsSync as
|
|
61612
|
+
import { existsSync as existsSync46 } from "node:fs";
|
|
60007
61613
|
|
|
60008
61614
|
// src/commands/hooks/lib/settings-path-resolver.ts
|
|
60009
61615
|
import { lstatSync as lstatSync3, realpathSync as realpathSync3 } from "node:fs";
|
|
60010
|
-
import { homedir as
|
|
60011
|
-
import { join as
|
|
61616
|
+
import { homedir as homedir27 } from "node:os";
|
|
61617
|
+
import { join as join91 } from "node:path";
|
|
60012
61618
|
function rawPath(agent, global3) {
|
|
60013
|
-
const root = global3 ?
|
|
61619
|
+
const root = global3 ? homedir27() : process.cwd();
|
|
60014
61620
|
if (agent === "claude") {
|
|
60015
|
-
return
|
|
61621
|
+
return join91(root, ".claude", "settings.json");
|
|
60016
61622
|
}
|
|
60017
|
-
return
|
|
61623
|
+
return join91(root, ".codex", "hooks.json");
|
|
60018
61624
|
}
|
|
60019
61625
|
function resolveSettingsPath(agent, options2 = {}) {
|
|
60020
61626
|
const originalPath = rawPath(agent, Boolean(options2.global));
|
|
@@ -60042,7 +61648,7 @@ function probe(global3) {
|
|
|
60042
61648
|
return {
|
|
60043
61649
|
agent,
|
|
60044
61650
|
path: location2.realPath,
|
|
60045
|
-
exists:
|
|
61651
|
+
exists: existsSync46(location2.realPath)
|
|
60046
61652
|
};
|
|
60047
61653
|
});
|
|
60048
61654
|
}
|
|
@@ -60087,7 +61693,7 @@ async function promptHookAgentTargets(options2) {
|
|
|
60087
61693
|
|
|
60088
61694
|
// src/commands/hooks/lib/entry-builder.ts
|
|
60089
61695
|
init_capabilities();
|
|
60090
|
-
var TIMEOUT_SECONDS =
|
|
61696
|
+
var TIMEOUT_SECONDS = 10;
|
|
60091
61697
|
var DEFAULT_HOOK_BIN = "tkm";
|
|
60092
61698
|
var CLAUDE_SESSION_START_MATCHER = "startup|resume|clear|compact";
|
|
60093
61699
|
var HOOK_EVENT_TO_CLAUDE_EVENT = {
|
|
@@ -60157,8 +61763,8 @@ function buildHookSection(agent, bin, flags = {}) {
|
|
|
60157
61763
|
|
|
60158
61764
|
// src/commands/hooks/uninstall-handler.ts
|
|
60159
61765
|
init_logger();
|
|
60160
|
-
import { existsSync as
|
|
60161
|
-
import { dirname as
|
|
61766
|
+
import { existsSync as existsSync47, mkdirSync as mkdirSync5, readFileSync as readFileSync14, renameSync as renameSync3, rmSync as rmSync4, writeFileSync as writeFileSync8 } from "node:fs";
|
|
61767
|
+
import { dirname as dirname24 } from "node:path";
|
|
60162
61768
|
var AGENT_DISPLAY2 = {
|
|
60163
61769
|
claude: "Claude Code",
|
|
60164
61770
|
codex: "Codex"
|
|
@@ -60193,12 +61799,12 @@ function pruneHooksSection(hooks, agent) {
|
|
|
60193
61799
|
}
|
|
60194
61800
|
return { pruned, removed };
|
|
60195
61801
|
}
|
|
60196
|
-
function writeAtomic(
|
|
60197
|
-
mkdirSync5(
|
|
60198
|
-
const tmp = `${
|
|
61802
|
+
function writeAtomic(path10, contents) {
|
|
61803
|
+
mkdirSync5(dirname24(path10), { recursive: true });
|
|
61804
|
+
const tmp = `${path10}.tmp`;
|
|
60199
61805
|
try {
|
|
60200
61806
|
writeFileSync8(tmp, contents);
|
|
60201
|
-
renameSync3(tmp,
|
|
61807
|
+
renameSync3(tmp, path10);
|
|
60202
61808
|
} catch (err) {
|
|
60203
61809
|
rmSync4(tmp, { force: true });
|
|
60204
61810
|
throw err;
|
|
@@ -60212,12 +61818,12 @@ async function uninstallForAgent(agent, options2) {
|
|
|
60212
61818
|
removed: 0,
|
|
60213
61819
|
dryRun: Boolean(options2.dryRun)
|
|
60214
61820
|
};
|
|
60215
|
-
if (!
|
|
61821
|
+
if (!existsSync47(location2.realPath)) {
|
|
60216
61822
|
return result;
|
|
60217
61823
|
}
|
|
60218
61824
|
let parsed;
|
|
60219
61825
|
try {
|
|
60220
|
-
parsed = JSON.parse(
|
|
61826
|
+
parsed = JSON.parse(readFileSync14(location2.realPath, "utf8"));
|
|
60221
61827
|
} catch {
|
|
60222
61828
|
logger.warning(`[hooks] could not parse ${location2.realPath}; uninstall skipped to avoid clobbering`);
|
|
60223
61829
|
return result;
|
|
@@ -61684,8 +63290,8 @@ async function dispatchInstallers(ctx, targetAgents2, lifecycle) {
|
|
|
61684
63290
|
init_logger();
|
|
61685
63291
|
// src/domains/installation/download-extractor.ts
|
|
61686
63292
|
init_auth_client();
|
|
61687
|
-
import * as
|
|
61688
|
-
import * as
|
|
63293
|
+
import * as fs20 from "node:fs";
|
|
63294
|
+
import * as path10 from "node:path";
|
|
61689
63295
|
|
|
61690
63296
|
// src/domains/github/auth-prompt.ts
|
|
61691
63297
|
init_dist2();
|
|
@@ -61766,7 +63372,7 @@ init_logger();
|
|
|
61766
63372
|
init_safe_spinner();
|
|
61767
63373
|
import { mkdir as mkdir25, stat as stat10 } from "node:fs/promises";
|
|
61768
63374
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
61769
|
-
import { join as
|
|
63375
|
+
import { join as join97 } from "node:path";
|
|
61770
63376
|
|
|
61771
63377
|
// src/shared/temp-cleanup.ts
|
|
61772
63378
|
init_logger();
|
|
@@ -61785,7 +63391,7 @@ init_logger();
|
|
|
61785
63391
|
init_output_manager();
|
|
61786
63392
|
import { createWriteStream as createWriteStream2, rmSync as rmSync5 } from "node:fs";
|
|
61787
63393
|
import { mkdir as mkdir21 } from "node:fs/promises";
|
|
61788
|
-
import { join as
|
|
63394
|
+
import { join as join92 } from "node:path";
|
|
61789
63395
|
|
|
61790
63396
|
// src/shared/progress-bar.ts
|
|
61791
63397
|
init_output_manager();
|
|
@@ -61950,10 +63556,10 @@ init_types2();
|
|
|
61950
63556
|
// src/domains/installation/utils/path-security.ts
|
|
61951
63557
|
init_types2();
|
|
61952
63558
|
import { lstatSync as lstatSync4, realpathSync as realpathSync4 } from "node:fs";
|
|
61953
|
-
import { relative as relative14, resolve as
|
|
63559
|
+
import { relative as relative14, resolve as resolve19 } from "node:path";
|
|
61954
63560
|
var MAX_EXTRACTION_SIZE = 500 * 1024 * 1024;
|
|
61955
63561
|
function isPathSafe(basePath, targetPath) {
|
|
61956
|
-
const resolvedBase =
|
|
63562
|
+
const resolvedBase = resolve19(basePath);
|
|
61957
63563
|
try {
|
|
61958
63564
|
const stat8 = lstatSync4(targetPath);
|
|
61959
63565
|
if (stat8.isSymbolicLink()) {
|
|
@@ -61963,7 +63569,7 @@ function isPathSafe(basePath, targetPath) {
|
|
|
61963
63569
|
}
|
|
61964
63570
|
}
|
|
61965
63571
|
} catch {}
|
|
61966
|
-
const resolvedTarget =
|
|
63572
|
+
const resolvedTarget = resolve19(targetPath);
|
|
61967
63573
|
const relativePath = relative14(resolvedBase, resolvedTarget);
|
|
61968
63574
|
return !relativePath.startsWith("..") && !relativePath.startsWith("/") && resolvedTarget.startsWith(resolvedBase);
|
|
61969
63575
|
}
|
|
@@ -61995,7 +63601,7 @@ var MAX_DOWNLOAD_SIZE = 500 * 1024 * 1024;
|
|
|
61995
63601
|
class FileDownloader {
|
|
61996
63602
|
async downloadAsset(asset, destDir) {
|
|
61997
63603
|
try {
|
|
61998
|
-
const destPath =
|
|
63604
|
+
const destPath = join92(destDir, asset.name);
|
|
61999
63605
|
await mkdir21(destDir, { recursive: true });
|
|
62000
63606
|
output.info(`Downloading ${asset.name} (${formatBytes(asset.size)})...`);
|
|
62001
63607
|
logger.verbose("Download details", {
|
|
@@ -62051,7 +63657,7 @@ class FileDownloader {
|
|
|
62051
63657
|
}
|
|
62052
63658
|
if (downloadedSize !== totalSize) {
|
|
62053
63659
|
fileStream.end();
|
|
62054
|
-
await new Promise((
|
|
63660
|
+
await new Promise((resolve20) => fileStream.once("close", resolve20));
|
|
62055
63661
|
try {
|
|
62056
63662
|
rmSync5(destPath, { force: true });
|
|
62057
63663
|
} catch (cleanupError) {
|
|
@@ -62065,7 +63671,7 @@ class FileDownloader {
|
|
|
62065
63671
|
return destPath;
|
|
62066
63672
|
} catch (error) {
|
|
62067
63673
|
fileStream.end();
|
|
62068
|
-
await new Promise((
|
|
63674
|
+
await new Promise((resolve20) => fileStream.once("close", resolve20));
|
|
62069
63675
|
try {
|
|
62070
63676
|
rmSync5(destPath, { force: true });
|
|
62071
63677
|
} catch (cleanupError) {
|
|
@@ -62080,7 +63686,7 @@ class FileDownloader {
|
|
|
62080
63686
|
}
|
|
62081
63687
|
async downloadFile(params) {
|
|
62082
63688
|
const { url, name, size, destDir, token } = params;
|
|
62083
|
-
const destPath =
|
|
63689
|
+
const destPath = join92(destDir, name);
|
|
62084
63690
|
await mkdir21(destDir, { recursive: true });
|
|
62085
63691
|
output.info(`Downloading ${name}${size ? ` (${formatBytes(size)})` : ""}...`);
|
|
62086
63692
|
const headers = {};
|
|
@@ -62148,7 +63754,7 @@ class FileDownloader {
|
|
|
62148
63754
|
const expectedSize = Number(response.headers.get("content-length"));
|
|
62149
63755
|
if (expectedSize > 0 && downloadedSize !== expectedSize) {
|
|
62150
63756
|
fileStream.end();
|
|
62151
|
-
await new Promise((
|
|
63757
|
+
await new Promise((resolve20) => fileStream.once("close", resolve20));
|
|
62152
63758
|
try {
|
|
62153
63759
|
rmSync5(destPath, { force: true });
|
|
62154
63760
|
} catch (cleanupError) {
|
|
@@ -62166,7 +63772,7 @@ class FileDownloader {
|
|
|
62166
63772
|
return destPath;
|
|
62167
63773
|
} catch (error) {
|
|
62168
63774
|
fileStream.end();
|
|
62169
|
-
await new Promise((
|
|
63775
|
+
await new Promise((resolve20) => fileStream.once("close", resolve20));
|
|
62170
63776
|
try {
|
|
62171
63777
|
rmSync5(destPath, { force: true });
|
|
62172
63778
|
} catch (cleanupError) {
|
|
@@ -62183,7 +63789,7 @@ init_logger();
|
|
|
62183
63789
|
init_types2();
|
|
62184
63790
|
import { constants as constants3 } from "node:fs";
|
|
62185
63791
|
import { access as access3, readdir as readdir25 } from "node:fs/promises";
|
|
62186
|
-
import { join as
|
|
63792
|
+
import { join as join93 } from "node:path";
|
|
62187
63793
|
async function validateExtraction(extractDir) {
|
|
62188
63794
|
try {
|
|
62189
63795
|
const entries = await readdir25(extractDir, { encoding: "utf8" });
|
|
@@ -62193,13 +63799,13 @@ async function validateExtraction(extractDir) {
|
|
|
62193
63799
|
}
|
|
62194
63800
|
const criticalPaths = [".claude", "CLAUDE.md"];
|
|
62195
63801
|
const missingPaths = [];
|
|
62196
|
-
for (const
|
|
63802
|
+
for (const path10 of criticalPaths) {
|
|
62197
63803
|
try {
|
|
62198
|
-
await access3(
|
|
62199
|
-
logger.debug(`Found: ${
|
|
63804
|
+
await access3(join93(extractDir, path10), constants3.F_OK);
|
|
63805
|
+
logger.debug(`Found: ${path10}`);
|
|
62200
63806
|
} catch {
|
|
62201
|
-
logger.warning(`Expected path not found: ${
|
|
62202
|
-
missingPaths.push(
|
|
63807
|
+
logger.warning(`Expected path not found: ${path10}`);
|
|
63808
|
+
missingPaths.push(path10);
|
|
62203
63809
|
}
|
|
62204
63810
|
}
|
|
62205
63811
|
if (missingPaths.length > 0) {
|
|
@@ -62217,7 +63823,7 @@ async function validateExtraction(extractDir) {
|
|
|
62217
63823
|
// src/domains/installation/extraction/tar-extractor.ts
|
|
62218
63824
|
init_logger();
|
|
62219
63825
|
import { copyFile as copyFile5, mkdir as mkdir23, readdir as readdir27, rm as rm7, stat as stat8 } from "node:fs/promises";
|
|
62220
|
-
import { join as
|
|
63826
|
+
import { join as join95 } from "node:path";
|
|
62221
63827
|
|
|
62222
63828
|
// node_modules/tar/dist/esm/index.min.js
|
|
62223
63829
|
import Kr from "events";
|
|
@@ -64249,7 +65855,7 @@ var ls = Symbol("readdir");
|
|
|
64249
65855
|
var ai = Symbol("onreaddir");
|
|
64250
65856
|
var li = Symbol("pipe");
|
|
64251
65857
|
var ir = Symbol("entry");
|
|
64252
|
-
var
|
|
65858
|
+
var os7 = Symbol("entryOpt");
|
|
64253
65859
|
var ci = Symbol("writeEntryClass");
|
|
64254
65860
|
var rr = Symbol("write");
|
|
64255
65861
|
var hs = Symbol("ondrain");
|
|
@@ -64312,7 +65918,7 @@ var Et = class extends D {
|
|
|
64312
65918
|
t.resume();
|
|
64313
65919
|
else {
|
|
64314
65920
|
let i = new di(t.path, e2);
|
|
64315
|
-
i.entry = new ri(t, this[
|
|
65921
|
+
i.entry = new ri(t, this[os7](i)), i.entry.on("end", () => this[ns](i)), this[G2] += 1, this[W2].push(i);
|
|
64316
65922
|
}
|
|
64317
65923
|
this[Ft]();
|
|
64318
65924
|
}
|
|
@@ -64381,13 +65987,13 @@ var Et = class extends D {
|
|
|
64381
65987
|
}
|
|
64382
65988
|
}
|
|
64383
65989
|
}
|
|
64384
|
-
[
|
|
65990
|
+
[os7](t) {
|
|
64385
65991
|
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
65992
|
}
|
|
64387
65993
|
[ir](t) {
|
|
64388
65994
|
this[G2] += 1;
|
|
64389
65995
|
try {
|
|
64390
|
-
return new this[ci](t.path, this[
|
|
65996
|
+
return new this[ci](t.path, this[os7](t)).on("end", () => this[ns](t)).on("error", (i) => this.emit("error", i));
|
|
64391
65997
|
} catch (e2) {
|
|
64392
65998
|
this.emit("error", e2);
|
|
64393
65999
|
}
|
|
@@ -64489,7 +66095,7 @@ var Vn = 512 * 1024;
|
|
|
64489
66095
|
var $n = pr | ur | dr | mr;
|
|
64490
66096
|
var lr = !fr && typeof ar == "number" ? ar | ur | dr | mr : null;
|
|
64491
66097
|
var cs = lr !== null ? () => lr : Kn ? (s3) => s3 < Vn ? $n : "w" : () => "w";
|
|
64492
|
-
var
|
|
66098
|
+
var fs19 = (s3, t, e2) => {
|
|
64493
66099
|
try {
|
|
64494
66100
|
return mi.lchownSync(s3, t, e2);
|
|
64495
66101
|
} catch (i) {
|
|
@@ -64538,7 +66144,7 @@ var ds = (s3, t, e2, i) => {
|
|
|
64538
66144
|
});
|
|
64539
66145
|
};
|
|
64540
66146
|
var qn = (s3, t, e2, i) => {
|
|
64541
|
-
t.isDirectory() && us(Ee.resolve(s3, t.name), e2, i),
|
|
66147
|
+
t.isDirectory() && us(Ee.resolve(s3, t.name), e2, i), fs19(Ee.resolve(s3, t.name), e2, i);
|
|
64542
66148
|
};
|
|
64543
66149
|
var us = (s3, t, e2) => {
|
|
64544
66150
|
let i;
|
|
@@ -64549,12 +66155,12 @@ var us = (s3, t, e2) => {
|
|
|
64549
66155
|
if (n?.code === "ENOENT")
|
|
64550
66156
|
return;
|
|
64551
66157
|
if (n?.code === "ENOTDIR" || n?.code === "ENOTSUP")
|
|
64552
|
-
return
|
|
66158
|
+
return fs19(s3, t, e2);
|
|
64553
66159
|
throw n;
|
|
64554
66160
|
}
|
|
64555
66161
|
for (let r2 of i)
|
|
64556
66162
|
qn(s3, r2, t, e2);
|
|
64557
|
-
return
|
|
66163
|
+
return fs19(s3, t, e2);
|
|
64558
66164
|
};
|
|
64559
66165
|
var we = class extends Error {
|
|
64560
66166
|
path;
|
|
@@ -65409,20 +67015,20 @@ function normalizeZipEntryName(entryName) {
|
|
|
65409
67015
|
}
|
|
65410
67016
|
return String(entryName);
|
|
65411
67017
|
}
|
|
65412
|
-
function decodeFilePath(
|
|
65413
|
-
if (!
|
|
65414
|
-
return
|
|
67018
|
+
function decodeFilePath(path10) {
|
|
67019
|
+
if (!path10.includes("%")) {
|
|
67020
|
+
return path10;
|
|
65415
67021
|
}
|
|
65416
67022
|
try {
|
|
65417
|
-
if (/%[0-9A-F]{2}/i.test(
|
|
65418
|
-
const decoded = decodeURIComponent(
|
|
65419
|
-
logger.debug(`Decoded path: ${
|
|
67023
|
+
if (/%[0-9A-F]{2}/i.test(path10)) {
|
|
67024
|
+
const decoded = decodeURIComponent(path10);
|
|
67025
|
+
logger.debug(`Decoded path: ${path10} -> ${decoded}`);
|
|
65420
67026
|
return decoded;
|
|
65421
67027
|
}
|
|
65422
|
-
return
|
|
67028
|
+
return path10;
|
|
65423
67029
|
} catch (error) {
|
|
65424
|
-
logger.warning(`Failed to decode path "${
|
|
65425
|
-
return
|
|
67030
|
+
logger.warning(`Failed to decode path "${path10}": ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
67031
|
+
return path10;
|
|
65426
67032
|
}
|
|
65427
67033
|
}
|
|
65428
67034
|
|
|
@@ -65430,7 +67036,7 @@ function decodeFilePath(path8) {
|
|
|
65430
67036
|
init_logger();
|
|
65431
67037
|
init_types2();
|
|
65432
67038
|
import { copyFile as copyFile4, lstat as lstat6, mkdir as mkdir22, readdir as readdir26 } from "node:fs/promises";
|
|
65433
|
-
import { join as
|
|
67039
|
+
import { join as join94, relative as relative15 } from "node:path";
|
|
65434
67040
|
async function withRetry2(fn2, retries = 3) {
|
|
65435
67041
|
for (let i = 0;i < retries; i++) {
|
|
65436
67042
|
try {
|
|
@@ -65452,8 +67058,8 @@ async function moveDirectoryContents(sourceDir, destDir, shouldExclude, sizeTrac
|
|
|
65452
67058
|
await mkdir22(destDir, { recursive: true });
|
|
65453
67059
|
const entries = await readdir26(sourceDir, { encoding: "utf8" });
|
|
65454
67060
|
for (const entry of entries) {
|
|
65455
|
-
const sourcePath =
|
|
65456
|
-
const destPath =
|
|
67061
|
+
const sourcePath = join94(sourceDir, entry);
|
|
67062
|
+
const destPath = join94(destDir, entry);
|
|
65457
67063
|
const relativePath = relative15(sourceDir, sourcePath);
|
|
65458
67064
|
if (!isPathSafe(destDir, destPath)) {
|
|
65459
67065
|
logger.warning(`Skipping unsafe path: ${relativePath}`);
|
|
@@ -65480,8 +67086,8 @@ async function copyDirectory(sourceDir, destDir, shouldExclude, sizeTracker) {
|
|
|
65480
67086
|
await mkdir22(destDir, { recursive: true });
|
|
65481
67087
|
const entries = await readdir26(sourceDir, { encoding: "utf8" });
|
|
65482
67088
|
for (const entry of entries) {
|
|
65483
|
-
const sourcePath =
|
|
65484
|
-
const destPath =
|
|
67089
|
+
const sourcePath = join94(sourceDir, entry);
|
|
67090
|
+
const destPath = join94(destDir, entry);
|
|
65485
67091
|
const relativePath = relative15(sourceDir, sourcePath);
|
|
65486
67092
|
if (!isPathSafe(destDir, destPath)) {
|
|
65487
67093
|
logger.warning(`Skipping unsafe path: ${relativePath}`);
|
|
@@ -65518,12 +67124,12 @@ class TarExtractor {
|
|
|
65518
67124
|
onwarn: (code, message) => {
|
|
65519
67125
|
logger.debug(`tar warning [${code}]: ${message}`);
|
|
65520
67126
|
},
|
|
65521
|
-
filter: (
|
|
67127
|
+
filter: (path10, entry) => {
|
|
65522
67128
|
if ("type" in entry && (entry.type === "SymbolicLink" || entry.type === "Link")) {
|
|
65523
|
-
logger.debug(`Skipping symlink: ${
|
|
67129
|
+
logger.debug(`Skipping symlink: ${path10}`);
|
|
65524
67130
|
return false;
|
|
65525
67131
|
}
|
|
65526
|
-
const decodedPath = decodeFilePath(
|
|
67132
|
+
const decodedPath = decodeFilePath(path10);
|
|
65527
67133
|
const shouldInclude = !shouldExclude(decodedPath);
|
|
65528
67134
|
if (!shouldInclude) {
|
|
65529
67135
|
logger.debug(`Excluding: ${decodedPath}`);
|
|
@@ -65536,7 +67142,7 @@ class TarExtractor {
|
|
|
65536
67142
|
logger.debug(`Root entries: ${entries.join(", ")}`);
|
|
65537
67143
|
if (entries.length === 1) {
|
|
65538
67144
|
const rootEntry = entries[0];
|
|
65539
|
-
const rootPath =
|
|
67145
|
+
const rootPath = join95(tempExtractDir, rootEntry);
|
|
65540
67146
|
const rootStat = await stat8(rootPath);
|
|
65541
67147
|
if (rootStat.isDirectory()) {
|
|
65542
67148
|
const rootContents = await readdir27(rootPath, { encoding: "utf8" });
|
|
@@ -65552,7 +67158,7 @@ class TarExtractor {
|
|
|
65552
67158
|
}
|
|
65553
67159
|
} else {
|
|
65554
67160
|
await mkdir23(destDir, { recursive: true });
|
|
65555
|
-
await copyFile5(rootPath,
|
|
67161
|
+
await copyFile5(rootPath, join95(destDir, rootEntry));
|
|
65556
67162
|
}
|
|
65557
67163
|
} else {
|
|
65558
67164
|
logger.debug("Multiple root entries - moving all");
|
|
@@ -65573,7 +67179,7 @@ class TarExtractor {
|
|
|
65573
67179
|
init_logger();
|
|
65574
67180
|
import { createWriteStream as createWriteStream3 } from "node:fs";
|
|
65575
67181
|
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
|
|
67182
|
+
import { dirname as dirname25, join as join96, resolve as resolve20 } from "node:path";
|
|
65577
67183
|
import { pipeline } from "node:stream/promises";
|
|
65578
67184
|
import yauzl from "yauzl-promise";
|
|
65579
67185
|
class ZipExtractor {
|
|
@@ -65587,7 +67193,7 @@ class ZipExtractor {
|
|
|
65587
67193
|
logger.debug(`Root entries: ${entries.join(", ")}`);
|
|
65588
67194
|
if (entries.length === 1) {
|
|
65589
67195
|
const rootEntry = entries[0];
|
|
65590
|
-
const rootPath =
|
|
67196
|
+
const rootPath = join96(tempExtractDir, rootEntry);
|
|
65591
67197
|
const rootStat = await stat9(rootPath);
|
|
65592
67198
|
if (rootStat.isDirectory()) {
|
|
65593
67199
|
const rootContents = await readdir28(rootPath, { encoding: "utf8" });
|
|
@@ -65603,7 +67209,7 @@ class ZipExtractor {
|
|
|
65603
67209
|
}
|
|
65604
67210
|
} else {
|
|
65605
67211
|
await mkdir24(destDir, { recursive: true });
|
|
65606
|
-
await copyFile6(rootPath,
|
|
67212
|
+
await copyFile6(rootPath, join96(destDir, rootEntry));
|
|
65607
67213
|
}
|
|
65608
67214
|
} else {
|
|
65609
67215
|
logger.debug("Multiple root entries - moving all");
|
|
@@ -65620,13 +67226,13 @@ class ZipExtractor {
|
|
|
65620
67226
|
}
|
|
65621
67227
|
async extractToDir(archivePath, destDir) {
|
|
65622
67228
|
const zip = await yauzl.open(archivePath, { decodeStrings: false });
|
|
65623
|
-
const destRoot =
|
|
67229
|
+
const destRoot = resolve20(destDir);
|
|
65624
67230
|
let count = 0;
|
|
65625
67231
|
try {
|
|
65626
67232
|
for await (const entry of zip) {
|
|
65627
67233
|
const rawName = entry.filename;
|
|
65628
67234
|
const name = normalizeZipEntryName(rawName);
|
|
65629
|
-
const outPath =
|
|
67235
|
+
const outPath = resolve20(destRoot, name);
|
|
65630
67236
|
if (!isPathSafe(destRoot, outPath)) {
|
|
65631
67237
|
throw new Error(`Unsafe zip entry path (zip-slip): ${name}`);
|
|
65632
67238
|
}
|
|
@@ -65634,7 +67240,7 @@ class ZipExtractor {
|
|
|
65634
67240
|
await mkdir24(outPath, { recursive: true });
|
|
65635
67241
|
continue;
|
|
65636
67242
|
}
|
|
65637
|
-
await mkdir24(
|
|
67243
|
+
await mkdir24(dirname25(outPath), { recursive: true });
|
|
65638
67244
|
const readStream = await entry.openReadStream();
|
|
65639
67245
|
await pipeline(readStream, createWriteStream3(outPath));
|
|
65640
67246
|
const unixMode = entry.externalFileAttributes >>> 16 & 511;
|
|
@@ -65732,7 +67338,7 @@ class DownloadManager {
|
|
|
65732
67338
|
async createTempDir() {
|
|
65733
67339
|
const timestamp = Date.now();
|
|
65734
67340
|
const counter = DownloadManager.tempDirCounter++;
|
|
65735
|
-
const primaryTempDir =
|
|
67341
|
+
const primaryTempDir = join97(tmpdir3(), `takumi-${timestamp}-${counter}`);
|
|
65736
67342
|
try {
|
|
65737
67343
|
await mkdir25(primaryTempDir, { recursive: true });
|
|
65738
67344
|
logger.debug(`Created temp directory: ${primaryTempDir}`);
|
|
@@ -65749,7 +67355,7 @@ Solutions:
|
|
|
65749
67355
|
2. Set HOME environment variable
|
|
65750
67356
|
3. Try running from a different directory`);
|
|
65751
67357
|
}
|
|
65752
|
-
const fallbackTempDir =
|
|
67358
|
+
const fallbackTempDir = join97(homeDir, ".sunagentkit", "tmp", `takumi-${timestamp}-${counter}`);
|
|
65753
67359
|
try {
|
|
65754
67360
|
await mkdir25(fallbackTempDir, { recursive: true });
|
|
65755
67361
|
logger.debug(`Created temp directory (fallback): ${fallbackTempDir}`);
|
|
@@ -65792,9 +67398,9 @@ function buildReleaseAllowlist(layout) {
|
|
|
65792
67398
|
return [...new Set([layout.sourceDir, ...RELEASE_ROOT_ALLOWLIST])];
|
|
65793
67399
|
}
|
|
65794
67400
|
async function ensureLayoutSourceDir(projectRoot, layout, strict) {
|
|
65795
|
-
const sourceDir =
|
|
67401
|
+
const sourceDir = path10.join(projectRoot, layout.sourceDir);
|
|
65796
67402
|
try {
|
|
65797
|
-
const stat11 = await
|
|
67403
|
+
const stat11 = await fs20.promises.stat(sourceDir);
|
|
65798
67404
|
if (!stat11.isDirectory()) {
|
|
65799
67405
|
throw new Error(`Expected source directory "${layout.sourceDir}" exists but is not a directory.`);
|
|
65800
67406
|
}
|
|
@@ -65817,10 +67423,10 @@ async function materializeRuntimeLayoutInPlace(projectRoot, layout) {
|
|
|
65817
67423
|
if (layout.sourceDir === layout.runtimeDir) {
|
|
65818
67424
|
return;
|
|
65819
67425
|
}
|
|
65820
|
-
const sourceDir =
|
|
65821
|
-
const runtimeDir =
|
|
65822
|
-
await
|
|
65823
|
-
await
|
|
67426
|
+
const sourceDir = path10.join(projectRoot, layout.sourceDir);
|
|
67427
|
+
const runtimeDir = path10.join(projectRoot, layout.runtimeDir);
|
|
67428
|
+
await fs20.promises.rm(runtimeDir, { recursive: true, force: true });
|
|
67429
|
+
await fs20.promises.rename(sourceDir, runtimeDir);
|
|
65824
67430
|
}
|
|
65825
67431
|
async function stageLocalKitPathForRuntimeLayout(kitRoot, layout) {
|
|
65826
67432
|
const sourceDir = await ensureLayoutSourceDir(kitRoot, layout, false);
|
|
@@ -65830,20 +67436,20 @@ async function stageLocalKitPathForRuntimeLayout(kitRoot, layout) {
|
|
|
65830
67436
|
const downloadManager = new DownloadManager;
|
|
65831
67437
|
const tempDir = await downloadManager.createTempDir();
|
|
65832
67438
|
const extractDir = `${tempDir}/extracted`;
|
|
65833
|
-
await
|
|
65834
|
-
const entries = await
|
|
67439
|
+
await fs20.promises.mkdir(extractDir, { recursive: true });
|
|
67440
|
+
const entries = await fs20.promises.readdir(kitRoot);
|
|
65835
67441
|
const allowlist = buildReleaseAllowlist(layout);
|
|
65836
67442
|
for (const entry of entries) {
|
|
65837
67443
|
if (!allowlist.includes(entry) || entry === layout.sourceDir) {
|
|
65838
67444
|
continue;
|
|
65839
67445
|
}
|
|
65840
|
-
await
|
|
67446
|
+
await fs20.promises.cp(path10.join(kitRoot, entry), path10.join(extractDir, entry), {
|
|
65841
67447
|
recursive: true
|
|
65842
67448
|
});
|
|
65843
67449
|
}
|
|
65844
|
-
const runtimeDir =
|
|
65845
|
-
await
|
|
65846
|
-
await
|
|
67450
|
+
const runtimeDir = path10.join(extractDir, layout.runtimeDir);
|
|
67451
|
+
await fs20.promises.mkdir(path10.dirname(runtimeDir), { recursive: true });
|
|
67452
|
+
await fs20.promises.cp(sourceDir, runtimeDir, { recursive: true });
|
|
65847
67453
|
logger.verbose("Staged local kit path with runtime layout", {
|
|
65848
67454
|
kitRoot,
|
|
65849
67455
|
extractDir,
|
|
@@ -65870,14 +67476,14 @@ var MONOREPO_KIT_CONTENT = [
|
|
|
65870
67476
|
];
|
|
65871
67477
|
function resolveRepoRootForKit(kitRoot) {
|
|
65872
67478
|
try {
|
|
65873
|
-
const parent =
|
|
65874
|
-
const parentPackageJson =
|
|
65875
|
-
if (!
|
|
67479
|
+
const parent = path10.dirname(kitRoot);
|
|
67480
|
+
const parentPackageJson = path10.join(parent, "package.json");
|
|
67481
|
+
if (!fs20.existsSync(parentPackageJson))
|
|
65876
67482
|
return kitRoot;
|
|
65877
|
-
const pkg = JSON.parse(
|
|
67483
|
+
const pkg = JSON.parse(fs20.readFileSync(parentPackageJson, "utf-8"));
|
|
65878
67484
|
const kitCfg = pkg.takumi;
|
|
65879
67485
|
const sourceDir = kitCfg?.sourceDir;
|
|
65880
|
-
if (typeof sourceDir === "string" &&
|
|
67486
|
+
if (typeof sourceDir === "string" && path10.resolve(parent, sourceDir) === path10.resolve(kitRoot)) {
|
|
65881
67487
|
return parent;
|
|
65882
67488
|
}
|
|
65883
67489
|
} catch {}
|
|
@@ -65887,25 +67493,25 @@ async function stageMonorepoForInstallation(kitRoot) {
|
|
|
65887
67493
|
const downloadManager = new DownloadManager;
|
|
65888
67494
|
const tempDir = await downloadManager.createTempDir();
|
|
65889
67495
|
const extractDir = `${tempDir}/extracted`;
|
|
65890
|
-
const claudeDir =
|
|
65891
|
-
await
|
|
67496
|
+
const claudeDir = path10.join(extractDir, ".claude");
|
|
67497
|
+
await fs20.promises.mkdir(claudeDir, { recursive: true });
|
|
65892
67498
|
const repoRoot = resolveRepoRootForKit(kitRoot);
|
|
65893
|
-
const kitEntries = await
|
|
67499
|
+
const kitEntries = await fs20.promises.readdir(kitRoot);
|
|
65894
67500
|
const skipLegacyManifest = kitEntries.includes(MANIFEST_FILENAME) && kitEntries.includes(LEGACY_MANIFEST_FILENAME);
|
|
65895
67501
|
for (const entry of kitEntries) {
|
|
65896
67502
|
if (!MONOREPO_KIT_CONTENT.includes(entry))
|
|
65897
67503
|
continue;
|
|
65898
67504
|
if (skipLegacyManifest && entry === LEGACY_MANIFEST_FILENAME)
|
|
65899
67505
|
continue;
|
|
65900
|
-
const srcPath =
|
|
65901
|
-
await
|
|
67506
|
+
const srcPath = path10.join(kitRoot, entry);
|
|
67507
|
+
await fs20.promises.cp(srcPath, path10.join(claudeDir, entry), { recursive: true });
|
|
65902
67508
|
}
|
|
65903
|
-
const repoEntries = repoRoot === kitRoot ? kitEntries : await
|
|
67509
|
+
const repoEntries = repoRoot === kitRoot ? kitEntries : await fs20.promises.readdir(repoRoot);
|
|
65904
67510
|
for (const entry of repoEntries) {
|
|
65905
67511
|
if (!RELEASE_ROOT_ALLOWLIST.includes(entry))
|
|
65906
67512
|
continue;
|
|
65907
|
-
const srcPath =
|
|
65908
|
-
await
|
|
67513
|
+
const srcPath = path10.join(repoRoot, entry);
|
|
67514
|
+
await fs20.promises.cp(srcPath, path10.join(extractDir, entry), { recursive: true });
|
|
65909
67515
|
}
|
|
65910
67516
|
logger.verbose("Staged monorepo for installation", {
|
|
65911
67517
|
kitRoot,
|
|
@@ -65919,13 +67525,13 @@ async function stageMonorepoForInstallation(kitRoot) {
|
|
|
65919
67525
|
async function normalizeFullRepoExtract(dir, strict) {
|
|
65920
67526
|
const layout = resolveKitLayout(dir);
|
|
65921
67527
|
await ensureLayoutSourceDir(dir, layout, strict);
|
|
65922
|
-
const entries = await
|
|
67528
|
+
const entries = await fs20.promises.readdir(dir);
|
|
65923
67529
|
const releaseAllowlist = buildReleaseAllowlist(layout);
|
|
65924
67530
|
let removedCount = 0;
|
|
65925
67531
|
for (const entry of entries) {
|
|
65926
67532
|
if (!releaseAllowlist.includes(entry)) {
|
|
65927
|
-
const fullPath =
|
|
65928
|
-
await
|
|
67533
|
+
const fullPath = path10.join(dir, entry);
|
|
67534
|
+
await fs20.promises.rm(fullPath, { recursive: true, force: true });
|
|
65929
67535
|
removedCount++;
|
|
65930
67536
|
}
|
|
65931
67537
|
}
|
|
@@ -66038,9 +67644,9 @@ Or try: tkm init --use-git`);
|
|
|
66038
67644
|
async function useLocalKitPath(kitPath, isMonorepo) {
|
|
66039
67645
|
logger.verbose("Using local kit path", { kitPath });
|
|
66040
67646
|
output.section("Using local kit");
|
|
66041
|
-
const absolutePath =
|
|
67647
|
+
const absolutePath = path10.resolve(kitPath);
|
|
66042
67648
|
try {
|
|
66043
|
-
const stat11 = await
|
|
67649
|
+
const stat11 = await fs20.promises.stat(absolutePath);
|
|
66044
67650
|
if (!stat11.isDirectory()) {
|
|
66045
67651
|
throw new Error(`--kit-path must point to a directory, not a file.
|
|
66046
67652
|
|
|
@@ -66077,9 +67683,9 @@ Please verify the path exists and is accessible.`);
|
|
|
66077
67683
|
};
|
|
66078
67684
|
}
|
|
66079
67685
|
}
|
|
66080
|
-
const claudeDir =
|
|
67686
|
+
const claudeDir = path10.join(absolutePath, DEFAULT_KIT_LAYOUT.runtimeDir);
|
|
66081
67687
|
try {
|
|
66082
|
-
const stat11 = await
|
|
67688
|
+
const stat11 = await fs20.promises.stat(claudeDir);
|
|
66083
67689
|
if (!stat11.isDirectory()) {
|
|
66084
67690
|
logger.warning(`Warning: ${claudeDir} exists but is not a directory.
|
|
66085
67691
|
This may not be a valid Takumi installation.`);
|
|
@@ -66102,7 +67708,7 @@ function validateArchiveFormat(archivePath) {
|
|
|
66102
67708
|
const lowerPath = archivePath.toLowerCase();
|
|
66103
67709
|
const isValid2 = VALID_ARCHIVE_FORMATS.some((ext2) => lowerPath.endsWith(ext2));
|
|
66104
67710
|
if (!isValid2) {
|
|
66105
|
-
const ext2 =
|
|
67711
|
+
const ext2 = path10.extname(archivePath) || "(no extension)";
|
|
66106
67712
|
throw new Error(`Unsupported archive format: ${ext2}
|
|
66107
67713
|
|
|
66108
67714
|
` + `Supported formats: ${VALID_ARCHIVE_FORMATS.join(", ")}`);
|
|
@@ -66111,10 +67717,10 @@ function validateArchiveFormat(archivePath) {
|
|
|
66111
67717
|
async function extractLocalArchive(archivePath, exclude) {
|
|
66112
67718
|
logger.verbose("Using local archive", { archivePath });
|
|
66113
67719
|
output.section("Extracting local archive");
|
|
66114
|
-
const absolutePath =
|
|
67720
|
+
const absolutePath = path10.resolve(archivePath);
|
|
66115
67721
|
validateArchiveFormat(absolutePath);
|
|
66116
67722
|
try {
|
|
66117
|
-
const stat11 = await
|
|
67723
|
+
const stat11 = await fs20.promises.stat(absolutePath);
|
|
66118
67724
|
if (!stat11.isFile()) {
|
|
66119
67725
|
throw new Error(`--archive must point to a file, not a directory.
|
|
66120
67726
|
|
|
@@ -66245,9 +67851,9 @@ async function downloadViaWorker(release, kit, isNonInteractive2) {
|
|
|
66245
67851
|
const res = await source.fetchAsset(release.tag_name, assetName);
|
|
66246
67852
|
const downloadManager = new DownloadManager;
|
|
66247
67853
|
const tempDir = await downloadManager.createTempDir();
|
|
66248
|
-
const archivePath =
|
|
67854
|
+
const archivePath = path10.join(tempDir, assetName);
|
|
66249
67855
|
const buf = Buffer.from(await res.arrayBuffer());
|
|
66250
|
-
await
|
|
67856
|
+
await fs20.promises.writeFile(archivePath, buf);
|
|
66251
67857
|
const extractDir = `${tempDir}/extracted`;
|
|
66252
67858
|
logger.verbose("Extraction", { archivePath, extractDir });
|
|
66253
67859
|
await downloadManager.extractArchive(archivePath, extractDir);
|
|
@@ -66455,7 +68061,7 @@ Re-run with explicit base kit, e.g. --kit ${BASE_KIT} --kit ${parsed2.join(" --k
|
|
|
66455
68061
|
}
|
|
66456
68062
|
// src/commands/init/phases/selection-handler.ts
|
|
66457
68063
|
import { mkdir as mkdir26 } from "node:fs/promises";
|
|
66458
|
-
import { join as
|
|
68064
|
+
import { join as join101, resolve as resolve24 } from "node:path";
|
|
66459
68065
|
|
|
66460
68066
|
// src/commands/shared/agent-selector.ts
|
|
66461
68067
|
init_registry();
|
|
@@ -66608,8 +68214,8 @@ init_logger();
|
|
|
66608
68214
|
init_safe_spinner();
|
|
66609
68215
|
init_takumi_constants();
|
|
66610
68216
|
var import_fs_extra31 = __toESM(require_lib(), 1);
|
|
66611
|
-
import { existsSync as
|
|
66612
|
-
import { dirname as
|
|
68217
|
+
import { existsSync as existsSync50, readdirSync as readdirSync6, rmSync as rmSync6, rmdirSync as rmdirSync2, unlinkSync as unlinkSync5 } from "node:fs";
|
|
68218
|
+
import { dirname as dirname28, join as join100, resolve as resolve23 } from "node:path";
|
|
66613
68219
|
var TAKUMI_SUBDIRECTORIES = ["commands", "agents", "skills", "rules", "hooks"];
|
|
66614
68220
|
async function analyzeFreshInstallation(claudeDir) {
|
|
66615
68221
|
const metadata = await readManifest(claudeDir);
|
|
@@ -66654,15 +68260,15 @@ async function analyzeFreshInstallation(claudeDir) {
|
|
|
66654
68260
|
};
|
|
66655
68261
|
}
|
|
66656
68262
|
function cleanupEmptyDirectories2(filePath, claudeDir) {
|
|
66657
|
-
const normalizedClaudeDir =
|
|
66658
|
-
let currentDir =
|
|
68263
|
+
const normalizedClaudeDir = resolve23(claudeDir);
|
|
68264
|
+
let currentDir = resolve23(dirname28(filePath));
|
|
66659
68265
|
while (currentDir !== normalizedClaudeDir && currentDir.startsWith(normalizedClaudeDir)) {
|
|
66660
68266
|
try {
|
|
66661
|
-
const entries =
|
|
68267
|
+
const entries = readdirSync6(currentDir);
|
|
66662
68268
|
if (entries.length === 0) {
|
|
66663
68269
|
rmdirSync2(currentDir);
|
|
66664
68270
|
logger.debug(`Removed empty directory: ${currentDir}`);
|
|
66665
|
-
currentDir =
|
|
68271
|
+
currentDir = resolve23(dirname28(currentDir));
|
|
66666
68272
|
} else {
|
|
66667
68273
|
break;
|
|
66668
68274
|
}
|
|
@@ -66679,9 +68285,9 @@ async function removeFilesByOwnership(claudeDir, analysis, includeModified) {
|
|
|
66679
68285
|
const filesToRemove = includeModified ? [...analysis.ckFiles, ...analysis.ckModifiedFiles] : analysis.ckFiles;
|
|
66680
68286
|
const filesToPreserve = includeModified ? analysis.userFiles : [...analysis.ckModifiedFiles, ...analysis.userFiles];
|
|
66681
68287
|
for (const file of filesToRemove) {
|
|
66682
|
-
const fullPath =
|
|
68288
|
+
const fullPath = join100(claudeDir, file.path);
|
|
66683
68289
|
try {
|
|
66684
|
-
if (
|
|
68290
|
+
if (existsSync50(fullPath)) {
|
|
66685
68291
|
unlinkSync5(fullPath);
|
|
66686
68292
|
removedFiles.push(file.path);
|
|
66687
68293
|
logger.debug(`Removed: ${file.path}`);
|
|
@@ -66753,7 +68359,7 @@ async function removeSubdirectoriesFallback(claudeDir) {
|
|
|
66753
68359
|
const removedFiles = [];
|
|
66754
68360
|
let removedDirCount = 0;
|
|
66755
68361
|
for (const subdir of TAKUMI_SUBDIRECTORIES) {
|
|
66756
|
-
const subdirPath =
|
|
68362
|
+
const subdirPath = join100(claudeDir, subdir);
|
|
66757
68363
|
if (await import_fs_extra31.pathExists(subdirPath)) {
|
|
66758
68364
|
rmSync6(subdirPath, { recursive: true, force: true });
|
|
66759
68365
|
removedDirCount++;
|
|
@@ -66950,7 +68556,7 @@ async function handleSelection(ctx) {
|
|
|
66950
68556
|
}
|
|
66951
68557
|
}
|
|
66952
68558
|
}
|
|
66953
|
-
const resolvedDir =
|
|
68559
|
+
const resolvedDir = resolve24(targetDir);
|
|
66954
68560
|
logger.info(`Target directory: ${resolvedDir}`);
|
|
66955
68561
|
if (!ctx.options.global && isLocalSameAsGlobal(resolvedDir)) {
|
|
66956
68562
|
logger.warning("You're at HOME directory. Installing here modifies your GLOBAL Takumi.");
|
|
@@ -66978,7 +68584,7 @@ async function handleSelection(ctx) {
|
|
|
66978
68584
|
}
|
|
66979
68585
|
if (!ctx.options.fresh) {
|
|
66980
68586
|
const prefix = PathResolver.getPathPrefix(ctx.options.global);
|
|
66981
|
-
const claudeDir = prefix ?
|
|
68587
|
+
const claudeDir = prefix ? join101(resolvedDir, prefix) : resolvedDir;
|
|
66982
68588
|
try {
|
|
66983
68589
|
const existingMetadata = await readManifest(claudeDir);
|
|
66984
68590
|
if (existingMetadata?.kits) {
|
|
@@ -67011,7 +68617,7 @@ async function handleSelection(ctx) {
|
|
|
67011
68617
|
}
|
|
67012
68618
|
if (ctx.options.fresh) {
|
|
67013
68619
|
const prefix = PathResolver.getPathPrefix(ctx.options.global);
|
|
67014
|
-
const claudeDir = prefix ?
|
|
68620
|
+
const claudeDir = prefix ? join101(resolvedDir, prefix) : resolvedDir;
|
|
67015
68621
|
const canProceed = await handleFreshInstallation(claudeDir, ctx.prompts);
|
|
67016
68622
|
if (!canProceed) {
|
|
67017
68623
|
return { ...ctx, cancelled: true };
|
|
@@ -67031,7 +68637,7 @@ async function handleSelection(ctx) {
|
|
|
67031
68637
|
let currentVersion = null;
|
|
67032
68638
|
try {
|
|
67033
68639
|
const prefix = PathResolver.getPathPrefix(ctx.options.global);
|
|
67034
|
-
const claudeDir = prefix ?
|
|
68640
|
+
const claudeDir = prefix ? join101(resolvedDir, prefix) : resolvedDir;
|
|
67035
68641
|
const existingMetadata = await readManifest(claudeDir);
|
|
67036
68642
|
currentVersion = existingMetadata?.kits?.[kitType]?.version || null;
|
|
67037
68643
|
if (currentVersion) {
|
|
@@ -67119,7 +68725,7 @@ async function handleSelection(ctx) {
|
|
|
67119
68725
|
if (ctx.options.yes && !ctx.options.fresh && !ctx.options.force && releaseTag && !isOfflineMode) {
|
|
67120
68726
|
try {
|
|
67121
68727
|
const prefix = PathResolver.getPathPrefix(ctx.options.global);
|
|
67122
|
-
const claudeDir = prefix ?
|
|
68728
|
+
const claudeDir = prefix ? join101(resolvedDir, prefix) : resolvedDir;
|
|
67123
68729
|
const existingMetadata = await readManifest(claudeDir);
|
|
67124
68730
|
const installedKitVersion = existingMetadata?.kits?.[kitType]?.version;
|
|
67125
68731
|
if (installedKitVersion && versionsMatch(installedKitVersion, releaseTag)) {
|
|
@@ -67142,7 +68748,7 @@ async function handleSelection(ctx) {
|
|
|
67142
68748
|
let currentSecondaryVersion = null;
|
|
67143
68749
|
try {
|
|
67144
68750
|
const prefix = PathResolver.getPathPrefix(ctx.options.global);
|
|
67145
|
-
const claudeDir = prefix ?
|
|
68751
|
+
const claudeDir = prefix ? join101(resolvedDir, prefix) : resolvedDir;
|
|
67146
68752
|
const existingMetadata = await readManifest(claudeDir);
|
|
67147
68753
|
currentSecondaryVersion = existingMetadata?.kits?.[secondaryKit]?.version || null;
|
|
67148
68754
|
} catch {}
|
|
@@ -67225,13 +68831,13 @@ function resolveGlobalTargetDir(targetAgents2) {
|
|
|
67225
68831
|
}
|
|
67226
68832
|
// src/commands/init/phases/sync-handler.ts
|
|
67227
68833
|
init_paths();
|
|
67228
|
-
import { copyFile as copyFile7, mkdir as mkdir28, open as open2, readFile as
|
|
67229
|
-
import { dirname as
|
|
68834
|
+
import { copyFile as copyFile7, mkdir as mkdir28, open as open2, readFile as readFile40, rename as rename7, stat as stat12, unlink as unlink11, writeFile as writeFile28 } from "node:fs/promises";
|
|
68835
|
+
import { dirname as dirname29, join as join104, resolve as resolve25 } from "node:path";
|
|
67230
68836
|
|
|
67231
68837
|
// src/domains/sync/config-version-checker.ts
|
|
67232
68838
|
init_auth_client();
|
|
67233
|
-
import { mkdir as mkdir27, readFile as
|
|
67234
|
-
import { join as
|
|
68839
|
+
import { mkdir as mkdir27, readFile as readFile38, unlink as unlink10, writeFile as writeFile27 } from "node:fs/promises";
|
|
68840
|
+
import { join as join102 } from "node:path";
|
|
67235
68841
|
init_version_utils();
|
|
67236
68842
|
init_logger();
|
|
67237
68843
|
init_path_resolver();
|
|
@@ -67267,12 +68873,12 @@ var CACHE_FILENAME = "config-update-cache.json";
|
|
|
67267
68873
|
class ConfigVersionChecker {
|
|
67268
68874
|
static getCacheFilePath(kitType, global3) {
|
|
67269
68875
|
const cacheDir = PathResolver.getCacheDir(global3);
|
|
67270
|
-
return
|
|
68876
|
+
return join102(cacheDir, `${kitType}-${CACHE_FILENAME}`);
|
|
67271
68877
|
}
|
|
67272
68878
|
static async loadCache(kitType, global3) {
|
|
67273
68879
|
try {
|
|
67274
68880
|
const cachePath = ConfigVersionChecker.getCacheFilePath(kitType, global3);
|
|
67275
|
-
const data = await
|
|
68881
|
+
const data = await readFile38(cachePath, "utf8");
|
|
67276
68882
|
const parsed = JSON.parse(data);
|
|
67277
68883
|
if (typeof parsed !== "object" || parsed === null || typeof parsed.lastCheck !== "number" || typeof parsed.latestVersion !== "string" || !parsed.latestVersion || parsed.lastCheck < 0 || parsed.lastCheck > Date.now() + 7 * 24 * 60 * 60 * 1000) {
|
|
67278
68884
|
logger.debug("Invalid cache structure, ignoring");
|
|
@@ -67283,12 +68889,12 @@ class ConfigVersionChecker {
|
|
|
67283
68889
|
return null;
|
|
67284
68890
|
}
|
|
67285
68891
|
}
|
|
67286
|
-
static async saveCache(kitType, global3,
|
|
68892
|
+
static async saveCache(kitType, global3, cache2) {
|
|
67287
68893
|
try {
|
|
67288
68894
|
const cachePath = ConfigVersionChecker.getCacheFilePath(kitType, global3);
|
|
67289
68895
|
const cacheDir = PathResolver.getCacheDir(global3);
|
|
67290
68896
|
await mkdir27(cacheDir, { recursive: true });
|
|
67291
|
-
await writeFile27(cachePath, JSON.stringify(
|
|
68897
|
+
await writeFile27(cachePath, JSON.stringify(cache2, null, 2));
|
|
67292
68898
|
} catch (error) {
|
|
67293
68899
|
logger.debug(`Cache write failed: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
67294
68900
|
}
|
|
@@ -67323,21 +68929,21 @@ class ConfigVersionChecker {
|
|
|
67323
68929
|
return null;
|
|
67324
68930
|
}
|
|
67325
68931
|
const delay3 = baseBackoff * 2 ** attempt2;
|
|
67326
|
-
await new Promise((
|
|
68932
|
+
await new Promise((resolve25) => setTimeout(resolve25, delay3));
|
|
67327
68933
|
}
|
|
67328
68934
|
}
|
|
67329
68935
|
return null;
|
|
67330
68936
|
}
|
|
67331
68937
|
static async checkForUpdates(kitType, currentVersion, global3 = false) {
|
|
67332
68938
|
const normalizedCurrent = currentVersion.replace(/^v/, "");
|
|
67333
|
-
const
|
|
68939
|
+
const cache2 = await ConfigVersionChecker.loadCache(kitType, global3);
|
|
67334
68940
|
const now = Date.now();
|
|
67335
|
-
if (
|
|
67336
|
-
const hasUpdates = isNewerVersion(normalizedCurrent,
|
|
68941
|
+
if (cache2 && now - cache2.lastCheck < CACHE_TTL_MS) {
|
|
68942
|
+
const hasUpdates = isNewerVersion(normalizedCurrent, cache2.latestVersion);
|
|
67337
68943
|
return {
|
|
67338
68944
|
hasUpdates,
|
|
67339
68945
|
currentVersion: normalizedCurrent,
|
|
67340
|
-
latestVersion:
|
|
68946
|
+
latestVersion: cache2.latestVersion,
|
|
67341
68947
|
fromCache: true
|
|
67342
68948
|
};
|
|
67343
68949
|
}
|
|
@@ -67355,12 +68961,12 @@ class ConfigVersionChecker {
|
|
|
67355
68961
|
fromCache: false
|
|
67356
68962
|
};
|
|
67357
68963
|
}
|
|
67358
|
-
if (
|
|
67359
|
-
const hasUpdates = isNewerVersion(normalizedCurrent,
|
|
68964
|
+
if (cache2) {
|
|
68965
|
+
const hasUpdates = isNewerVersion(normalizedCurrent, cache2.latestVersion);
|
|
67360
68966
|
return {
|
|
67361
68967
|
hasUpdates,
|
|
67362
68968
|
currentVersion: normalizedCurrent,
|
|
67363
|
-
latestVersion:
|
|
68969
|
+
latestVersion: cache2.latestVersion,
|
|
67364
68970
|
fromCache: true
|
|
67365
68971
|
};
|
|
67366
68972
|
}
|
|
@@ -67386,12 +68992,12 @@ class ConfigVersionChecker {
|
|
|
67386
68992
|
// src/domains/sync/sync-engine.ts
|
|
67387
68993
|
init_ownership_checker();
|
|
67388
68994
|
init_logger();
|
|
67389
|
-
import { lstat as lstat7, readFile as
|
|
67390
|
-
import { isAbsolute as isAbsolute3, join as
|
|
68995
|
+
import { lstat as lstat7, readFile as readFile39, readlink, realpath as realpath3, stat as stat11 } from "node:fs/promises";
|
|
68996
|
+
import { isAbsolute as isAbsolute3, join as join103, normalize as normalize8, relative as relative16 } from "node:path";
|
|
67391
68997
|
var MAX_SYNC_FILE_SIZE = 10 * 1024 * 1024;
|
|
67392
68998
|
var MAX_SYMLINK_DEPTH = 20;
|
|
67393
|
-
async function validateSymlinkChain(
|
|
67394
|
-
let current =
|
|
68999
|
+
async function validateSymlinkChain(path11, basePath, maxDepth = MAX_SYMLINK_DEPTH) {
|
|
69000
|
+
let current = path11;
|
|
67395
69001
|
let depth = 0;
|
|
67396
69002
|
while (depth < maxDepth) {
|
|
67397
69003
|
try {
|
|
@@ -67399,11 +69005,11 @@ async function validateSymlinkChain(path9, basePath, maxDepth = MAX_SYMLINK_DEPT
|
|
|
67399
69005
|
if (!stats.isSymbolicLink())
|
|
67400
69006
|
break;
|
|
67401
69007
|
const target = await readlink(current);
|
|
67402
|
-
const resolvedTarget = isAbsolute3(target) ? target :
|
|
69008
|
+
const resolvedTarget = isAbsolute3(target) ? target : join103(current, "..", target);
|
|
67403
69009
|
const normalizedTarget = normalize8(resolvedTarget);
|
|
67404
69010
|
const rel = relative16(basePath, normalizedTarget);
|
|
67405
69011
|
if (rel.startsWith("..") || isAbsolute3(rel)) {
|
|
67406
|
-
throw new Error(`Symlink chain escapes base directory at depth ${depth}: ${
|
|
69012
|
+
throw new Error(`Symlink chain escapes base directory at depth ${depth}: ${path11}`);
|
|
67407
69013
|
}
|
|
67408
69014
|
current = normalizedTarget;
|
|
67409
69015
|
depth++;
|
|
@@ -67415,7 +69021,7 @@ async function validateSymlinkChain(path9, basePath, maxDepth = MAX_SYMLINK_DEPT
|
|
|
67415
69021
|
}
|
|
67416
69022
|
}
|
|
67417
69023
|
if (depth >= maxDepth) {
|
|
67418
|
-
throw new Error(`Symlink chain too deep (>${maxDepth}): ${
|
|
69024
|
+
throw new Error(`Symlink chain too deep (>${maxDepth}): ${path11}`);
|
|
67419
69025
|
}
|
|
67420
69026
|
}
|
|
67421
69027
|
async function validateSyncPath(basePath, filePath) {
|
|
@@ -67435,7 +69041,7 @@ async function validateSyncPath(basePath, filePath) {
|
|
|
67435
69041
|
if (normalized.startsWith("..") || normalized.includes("/../")) {
|
|
67436
69042
|
throw new Error(`Path traversal not allowed: ${filePath}`);
|
|
67437
69043
|
}
|
|
67438
|
-
const fullPath =
|
|
69044
|
+
const fullPath = join103(basePath, normalized);
|
|
67439
69045
|
const rel = relative16(basePath, fullPath);
|
|
67440
69046
|
if (rel.startsWith("..") || isAbsolute3(rel)) {
|
|
67441
69047
|
throw new Error(`Path escapes base directory: ${filePath}`);
|
|
@@ -67450,7 +69056,7 @@ async function validateSyncPath(basePath, filePath) {
|
|
|
67450
69056
|
}
|
|
67451
69057
|
} catch (error) {
|
|
67452
69058
|
if (error.code === "ENOENT") {
|
|
67453
|
-
const parentPath =
|
|
69059
|
+
const parentPath = join103(fullPath, "..");
|
|
67454
69060
|
try {
|
|
67455
69061
|
const resolvedBase = await realpath3(basePath);
|
|
67456
69062
|
const resolvedParent = await realpath3(parentPath);
|
|
@@ -67621,7 +69227,7 @@ class SyncEngine {
|
|
|
67621
69227
|
if (lstats.size > MAX_SYNC_FILE_SIZE) {
|
|
67622
69228
|
throw new Error(`File too large for sync (${Math.round(lstats.size / 1024 / 1024)}MB > ${MAX_SYNC_FILE_SIZE / 1024 / 1024}MB limit)`);
|
|
67623
69229
|
}
|
|
67624
|
-
const buffer = await
|
|
69230
|
+
const buffer = await readFile39(filePath);
|
|
67625
69231
|
if (buffer.includes(0)) {
|
|
67626
69232
|
return { content: "", isBinary: true };
|
|
67627
69233
|
}
|
|
@@ -67838,7 +69444,7 @@ async function handleSync(ctx) {
|
|
|
67838
69444
|
logger.error(`Sync not yet supported for ${targetAgent}. Only --agent claude-code supports --sync.`);
|
|
67839
69445
|
return { ...ctx, cancelled: true };
|
|
67840
69446
|
}
|
|
67841
|
-
const resolvedDir = ctx.options.global ? getClaudeDir() :
|
|
69447
|
+
const resolvedDir = ctx.options.global ? getClaudeDir() : resolve25(ctx.options.dir || ".");
|
|
67842
69448
|
const claudeDir = ctx.options.global ? resolvedDir : getLocalClaudeDir(resolvedDir);
|
|
67843
69449
|
if (!await import_fs_extra33.pathExists(claudeDir)) {
|
|
67844
69450
|
logger.error("Cannot sync: no .claude directory found");
|
|
@@ -67941,10 +69547,10 @@ function getLockTimeout() {
|
|
|
67941
69547
|
var STALE_LOCK_THRESHOLD_MS = 5 * 60 * 1000;
|
|
67942
69548
|
async function acquireSyncLock(global3) {
|
|
67943
69549
|
const cacheDir = PathResolver.getCacheDir(global3);
|
|
67944
|
-
const lockPath =
|
|
69550
|
+
const lockPath = join104(cacheDir, ".sync-lock");
|
|
67945
69551
|
const startTime = Date.now();
|
|
67946
69552
|
const lockTimeout = getLockTimeout();
|
|
67947
|
-
await mkdir28(
|
|
69553
|
+
await mkdir28(dirname29(lockPath), { recursive: true });
|
|
67948
69554
|
while (Date.now() - startTime < lockTimeout) {
|
|
67949
69555
|
try {
|
|
67950
69556
|
const handle = await open2(lockPath, "wx");
|
|
@@ -67968,7 +69574,7 @@ async function acquireSyncLock(global3) {
|
|
|
67968
69574
|
}
|
|
67969
69575
|
logger.debug(`Lock stat failed: ${statError}`);
|
|
67970
69576
|
}
|
|
67971
|
-
await new Promise((
|
|
69577
|
+
await new Promise((resolve26) => setTimeout(resolve26, 100));
|
|
67972
69578
|
continue;
|
|
67973
69579
|
}
|
|
67974
69580
|
throw err;
|
|
@@ -67992,7 +69598,7 @@ async function executeSyncMerge(ctx) {
|
|
|
67992
69598
|
try {
|
|
67993
69599
|
const sourceManifest = await findManifestPath(upstreamDir);
|
|
67994
69600
|
if (sourceManifest) {
|
|
67995
|
-
const content = await
|
|
69601
|
+
const content = await readFile40(sourceManifest.path, "utf-8");
|
|
67996
69602
|
const sourceMetadata = JSON.parse(content);
|
|
67997
69603
|
deletions = sourceMetadata.deletions || [];
|
|
67998
69604
|
}
|
|
@@ -68022,7 +69628,7 @@ async function executeSyncMerge(ctx) {
|
|
|
68022
69628
|
try {
|
|
68023
69629
|
const sourcePath = await validateSyncPath(upstreamDir, file.path);
|
|
68024
69630
|
const targetPath = await validateSyncPath(ctx.claudeDir, file.path);
|
|
68025
|
-
const targetDir =
|
|
69631
|
+
const targetDir = join104(targetPath, "..");
|
|
68026
69632
|
try {
|
|
68027
69633
|
await mkdir28(targetDir, { recursive: true });
|
|
68028
69634
|
} catch (mkdirError) {
|
|
@@ -68193,7 +69799,7 @@ async function createBackup(claudeDir, files, backupDir) {
|
|
|
68193
69799
|
const sourcePath = await validateSyncPath(claudeDir, file.path);
|
|
68194
69800
|
if (await import_fs_extra33.pathExists(sourcePath)) {
|
|
68195
69801
|
const targetPath = await validateSyncPath(backupDir, file.path);
|
|
68196
|
-
const targetDir =
|
|
69802
|
+
const targetDir = join104(targetPath, "..");
|
|
68197
69803
|
await mkdir28(targetDir, { recursive: true });
|
|
68198
69804
|
await copyFile7(sourcePath, targetPath);
|
|
68199
69805
|
}
|
|
@@ -68219,38 +69825,38 @@ init_logger();
|
|
|
68219
69825
|
init_types2();
|
|
68220
69826
|
var import_fs_extra34 = __toESM(require_lib(), 1);
|
|
68221
69827
|
import { rename as rename8, rm as rm9 } from "node:fs/promises";
|
|
68222
|
-
import { join as
|
|
69828
|
+
import { join as join105, relative as relative17 } from "node:path";
|
|
68223
69829
|
async function collectDirsToRename(extractDir, folders) {
|
|
68224
69830
|
const dirsToRename = [];
|
|
68225
69831
|
if (folders.docs !== DEFAULT_FOLDERS.docs) {
|
|
68226
|
-
const docsPath =
|
|
69832
|
+
const docsPath = join105(extractDir, DEFAULT_FOLDERS.docs);
|
|
68227
69833
|
if (await import_fs_extra34.pathExists(docsPath)) {
|
|
68228
69834
|
dirsToRename.push({
|
|
68229
69835
|
from: docsPath,
|
|
68230
|
-
to:
|
|
69836
|
+
to: join105(extractDir, folders.docs)
|
|
68231
69837
|
});
|
|
68232
69838
|
}
|
|
68233
|
-
const claudeDocsPath =
|
|
69839
|
+
const claudeDocsPath = join105(extractDir, ".claude", DEFAULT_FOLDERS.docs);
|
|
68234
69840
|
if (await import_fs_extra34.pathExists(claudeDocsPath)) {
|
|
68235
69841
|
dirsToRename.push({
|
|
68236
69842
|
from: claudeDocsPath,
|
|
68237
|
-
to:
|
|
69843
|
+
to: join105(extractDir, ".claude", folders.docs)
|
|
68238
69844
|
});
|
|
68239
69845
|
}
|
|
68240
69846
|
}
|
|
68241
69847
|
if (folders.plans !== DEFAULT_FOLDERS.plans) {
|
|
68242
|
-
const plansPath =
|
|
69848
|
+
const plansPath = join105(extractDir, DEFAULT_FOLDERS.plans);
|
|
68243
69849
|
if (await import_fs_extra34.pathExists(plansPath)) {
|
|
68244
69850
|
dirsToRename.push({
|
|
68245
69851
|
from: plansPath,
|
|
68246
|
-
to:
|
|
69852
|
+
to: join105(extractDir, folders.plans)
|
|
68247
69853
|
});
|
|
68248
69854
|
}
|
|
68249
|
-
const claudePlansPath =
|
|
69855
|
+
const claudePlansPath = join105(extractDir, ".claude", DEFAULT_FOLDERS.plans);
|
|
68250
69856
|
if (await import_fs_extra34.pathExists(claudePlansPath)) {
|
|
68251
69857
|
dirsToRename.push({
|
|
68252
69858
|
from: claudePlansPath,
|
|
68253
|
-
to:
|
|
69859
|
+
to: join105(extractDir, ".claude", folders.plans)
|
|
68254
69860
|
});
|
|
68255
69861
|
}
|
|
68256
69862
|
}
|
|
@@ -68290,8 +69896,8 @@ async function renameFolders(dirsToRename, extractDir, options2) {
|
|
|
68290
69896
|
// src/services/transformers/folder-transform/path-replacer.ts
|
|
68291
69897
|
init_logger();
|
|
68292
69898
|
init_types2();
|
|
68293
|
-
import { readFile as
|
|
68294
|
-
import { join as
|
|
69899
|
+
import { readFile as readFile41, readdir as readdir29, writeFile as writeFile29 } from "node:fs/promises";
|
|
69900
|
+
import { join as join106, relative as relative18 } from "node:path";
|
|
68295
69901
|
var TRANSFORMABLE_FILE_PATTERNS = [
|
|
68296
69902
|
".md",
|
|
68297
69903
|
".txt",
|
|
@@ -68344,7 +69950,7 @@ async function transformFileContents(dir, compiledReplacements, options2) {
|
|
|
68344
69950
|
let replacementsCount = 0;
|
|
68345
69951
|
const entries = await readdir29(dir, { withFileTypes: true });
|
|
68346
69952
|
for (const entry of entries) {
|
|
68347
|
-
const fullPath =
|
|
69953
|
+
const fullPath = join106(dir, entry.name);
|
|
68348
69954
|
if (entry.isDirectory()) {
|
|
68349
69955
|
if (entry.name === "node_modules" || entry.name === ".git") {
|
|
68350
69956
|
continue;
|
|
@@ -68357,14 +69963,14 @@ async function transformFileContents(dir, compiledReplacements, options2) {
|
|
|
68357
69963
|
if (!shouldTransform)
|
|
68358
69964
|
continue;
|
|
68359
69965
|
try {
|
|
68360
|
-
const content = await
|
|
69966
|
+
const content = await readFile41(fullPath, "utf-8");
|
|
68361
69967
|
let newContent = content;
|
|
68362
69968
|
let changeCount = 0;
|
|
68363
69969
|
for (const { regex: regex2, replacement } of compiledReplacements) {
|
|
68364
69970
|
regex2.lastIndex = 0;
|
|
68365
|
-
const
|
|
68366
|
-
if (
|
|
68367
|
-
changeCount +=
|
|
69971
|
+
const matches3 = newContent.match(regex2);
|
|
69972
|
+
if (matches3) {
|
|
69973
|
+
changeCount += matches3.length;
|
|
68368
69974
|
regex2.lastIndex = 0;
|
|
68369
69975
|
newContent = newContent.replace(regex2, replacement);
|
|
68370
69976
|
}
|
|
@@ -68479,11 +70085,11 @@ async function transformFolderPaths(extractDir, folders, options2 = {}) {
|
|
|
68479
70085
|
|
|
68480
70086
|
// src/services/transformers/global-path-transformer.ts
|
|
68481
70087
|
init_logger();
|
|
68482
|
-
import { readFile as
|
|
70088
|
+
import { readFile as readFile42, readdir as readdir30, writeFile as writeFile30 } from "node:fs/promises";
|
|
68483
70089
|
import { platform as platform9 } from "node:os";
|
|
68484
|
-
import { extname as extname6, join as
|
|
70090
|
+
import { extname as extname6, join as join107 } from "node:path";
|
|
68485
70091
|
var IS_WINDOWS3 = platform9() === "win32";
|
|
68486
|
-
var HOME_PREFIX =
|
|
70092
|
+
var HOME_PREFIX = "$HOME";
|
|
68487
70093
|
function getHomeDirPrefix() {
|
|
68488
70094
|
return HOME_PREFIX;
|
|
68489
70095
|
}
|
|
@@ -68506,24 +70112,14 @@ function transformContent(content) {
|
|
|
68506
70112
|
let transformed = content;
|
|
68507
70113
|
const homePrefix = getHomeDirPrefix();
|
|
68508
70114
|
const claudePath = `${homePrefix}/.claude/`;
|
|
68509
|
-
|
|
68510
|
-
|
|
68511
|
-
|
|
68512
|
-
|
|
68513
|
-
|
|
68514
|
-
|
|
68515
|
-
|
|
68516
|
-
|
|
68517
|
-
});
|
|
68518
|
-
transformed = transformed.replace(/\$HOME(?=\/|\\)/g, () => {
|
|
68519
|
-
changes++;
|
|
68520
|
-
return homePrefix;
|
|
68521
|
-
});
|
|
68522
|
-
transformed = transformed.replace(/\$\{HOME\}(?=\/|\\)/g, () => {
|
|
68523
|
-
changes++;
|
|
68524
|
-
return homePrefix;
|
|
68525
|
-
});
|
|
68526
|
-
}
|
|
70115
|
+
transformed = transformed.replace(/%USERPROFILE%\/\.claude\//g, () => {
|
|
70116
|
+
changes++;
|
|
70117
|
+
return claudePath;
|
|
70118
|
+
});
|
|
70119
|
+
transformed = transformed.replace(/%USERPROFILE%(?=\/|\\)/g, () => {
|
|
70120
|
+
changes++;
|
|
70121
|
+
return homePrefix;
|
|
70122
|
+
});
|
|
68527
70123
|
transformed = transformed.replace(/\$CLAUDE_PROJECT_DIR\/\.claude\//g, () => {
|
|
68528
70124
|
changes++;
|
|
68529
70125
|
return claudePath;
|
|
@@ -68536,12 +70132,10 @@ function transformContent(content) {
|
|
|
68536
70132
|
changes++;
|
|
68537
70133
|
return claudePath;
|
|
68538
70134
|
});
|
|
68539
|
-
|
|
68540
|
-
|
|
68541
|
-
|
|
68542
|
-
|
|
68543
|
-
});
|
|
68544
|
-
}
|
|
70135
|
+
transformed = transformed.replace(/%CLAUDE_PROJECT_DIR%\/\.claude\//g, () => {
|
|
70136
|
+
changes++;
|
|
70137
|
+
return claudePath;
|
|
70138
|
+
});
|
|
68545
70139
|
transformed = transformed.replace(/\.\/\.claude\//g, () => {
|
|
68546
70140
|
changes++;
|
|
68547
70141
|
return claudePath;
|
|
@@ -68582,8 +70176,8 @@ function transformContent(content) {
|
|
|
68582
70176
|
}
|
|
68583
70177
|
function shouldTransformFile3(filename) {
|
|
68584
70178
|
const ext2 = extname6(filename).toLowerCase();
|
|
68585
|
-
const
|
|
68586
|
-
return TRANSFORMABLE_EXTENSIONS3.has(ext2) || ALWAYS_TRANSFORM_FILES.has(
|
|
70179
|
+
const basename13 = filename.split("/").pop() || filename;
|
|
70180
|
+
return TRANSFORMABLE_EXTENSIONS3.has(ext2) || ALWAYS_TRANSFORM_FILES.has(basename13);
|
|
68587
70181
|
}
|
|
68588
70182
|
async function transformPathsForGlobalInstall(directory, options2 = {}) {
|
|
68589
70183
|
let filesTransformed = 0;
|
|
@@ -68593,7 +70187,7 @@ async function transformPathsForGlobalInstall(directory, options2 = {}) {
|
|
|
68593
70187
|
async function processDirectory2(dir) {
|
|
68594
70188
|
const entries = await readdir30(dir, { withFileTypes: true });
|
|
68595
70189
|
for (const entry of entries) {
|
|
68596
|
-
const fullPath =
|
|
70190
|
+
const fullPath = join107(dir, entry.name);
|
|
68597
70191
|
if (entry.isDirectory()) {
|
|
68598
70192
|
if (entry.name === "node_modules" || entry.name.startsWith(".") && entry.name !== ".claude") {
|
|
68599
70193
|
continue;
|
|
@@ -68601,7 +70195,7 @@ async function transformPathsForGlobalInstall(directory, options2 = {}) {
|
|
|
68601
70195
|
await processDirectory2(fullPath);
|
|
68602
70196
|
} else if (entry.isFile() && shouldTransformFile3(entry.name)) {
|
|
68603
70197
|
try {
|
|
68604
|
-
const content = await
|
|
70198
|
+
const content = await readFile42(fullPath, "utf-8");
|
|
68605
70199
|
const { transformed, changes } = transformContent(content);
|
|
68606
70200
|
if (changes > 0) {
|
|
68607
70201
|
await writeFile30(fullPath, transformed, "utf-8");
|
|
@@ -68860,20 +70454,20 @@ async function initCommand(options2) {
|
|
|
68860
70454
|
}
|
|
68861
70455
|
// src/commands/plan/plan-command.ts
|
|
68862
70456
|
init_output_manager();
|
|
68863
|
-
import { existsSync as
|
|
68864
|
-
import { dirname as
|
|
70457
|
+
import { existsSync as existsSync55, statSync as statSync7 } from "node:fs";
|
|
70458
|
+
import { dirname as dirname35, join as join111, parse as parse4, resolve as resolve29 } from "node:path";
|
|
68865
70459
|
|
|
68866
70460
|
// src/commands/plan/plan-read-handlers.ts
|
|
68867
|
-
import { existsSync as
|
|
68868
|
-
import { basename as
|
|
70461
|
+
import { existsSync as existsSync54, statSync as statSync6 } from "node:fs";
|
|
70462
|
+
import { basename as basename15, dirname as dirname34, join as join110, relative as relative19, resolve as resolve27 } from "node:path";
|
|
68869
70463
|
|
|
68870
70464
|
// src/domains/plan-parser/index.ts
|
|
68871
|
-
import { dirname as
|
|
70465
|
+
import { dirname as dirname33 } from "node:path";
|
|
68872
70466
|
|
|
68873
70467
|
// src/domains/plan-parser/plan-table-parser.ts
|
|
68874
70468
|
var import_gray_matter5 = __toESM(require_gray_matter(), 1);
|
|
68875
|
-
import { readFileSync as
|
|
68876
|
-
import { dirname as
|
|
70469
|
+
import { readFileSync as readFileSync17 } from "node:fs";
|
|
70470
|
+
import { dirname as dirname30, resolve as resolve26 } from "node:path";
|
|
68877
70471
|
function normalizeStatus(raw) {
|
|
68878
70472
|
const s3 = raw.toLowerCase().trim();
|
|
68879
70473
|
if (s3.includes("complete") || s3.includes("done") || s3.includes("✓") || s3.includes("✅")) {
|
|
@@ -68957,7 +70551,7 @@ function parseHeaderAwareTable(content, dir, options2) {
|
|
|
68957
70551
|
hasLinks = true;
|
|
68958
70552
|
linkText = linkMatch[1].trim();
|
|
68959
70553
|
name = filenameToTitle(linkText);
|
|
68960
|
-
file =
|
|
70554
|
+
file = resolve26(dir, linkMatch[2]);
|
|
68961
70555
|
} else {
|
|
68962
70556
|
name = nameRaw.replace(/\[.*?\]\(.*?\)/g, "").trim() || `Phase ${phaseId}`;
|
|
68963
70557
|
linkText = name;
|
|
@@ -68997,7 +70591,7 @@ function parseFormat1(content, dir, options2) {
|
|
|
68997
70591
|
phaseId,
|
|
68998
70592
|
name: name.trim(),
|
|
68999
70593
|
status: normalizeStatus(status2),
|
|
69000
|
-
file:
|
|
70594
|
+
file: resolve26(dir, linkPath),
|
|
69001
70595
|
linkText: linkText.trim(),
|
|
69002
70596
|
anchor
|
|
69003
70597
|
});
|
|
@@ -69017,7 +70611,7 @@ function parseFormat2(content, dir, options2) {
|
|
|
69017
70611
|
phaseId,
|
|
69018
70612
|
name: name.trim(),
|
|
69019
70613
|
status: normalizeStatus(status2),
|
|
69020
|
-
file:
|
|
70614
|
+
file: resolve26(dir, linkPath),
|
|
69021
70615
|
linkText,
|
|
69022
70616
|
anchor
|
|
69023
70617
|
});
|
|
@@ -69036,7 +70630,7 @@ function parseFormat2b(content, dir, options2) {
|
|
|
69036
70630
|
phaseId,
|
|
69037
70631
|
name: name.trim(),
|
|
69038
70632
|
status: normalizeStatus(status2),
|
|
69039
|
-
file:
|
|
70633
|
+
file: resolve26(dir, linkPath),
|
|
69040
70634
|
linkText: name.trim(),
|
|
69041
70635
|
anchor
|
|
69042
70636
|
});
|
|
@@ -69134,8 +70728,8 @@ function parseFormat4(content, planFilePath, options2) {
|
|
|
69134
70728
|
const hasCheck = /[✅✓]/.test(line);
|
|
69135
70729
|
current = { name, status: hasCheck ? "completed" : "pending" };
|
|
69136
70730
|
} else if (fileMatch && current) {
|
|
69137
|
-
const planDir =
|
|
69138
|
-
current.file =
|
|
70731
|
+
const planDir = dirname30(planFilePath);
|
|
70732
|
+
current.file = resolve26(planDir, fileMatch[1].trim());
|
|
69139
70733
|
} else if (statusMatch && current) {
|
|
69140
70734
|
current.status = normalizeStatus(statusMatch[2]);
|
|
69141
70735
|
}
|
|
@@ -69201,7 +70795,7 @@ function parseFormat6(content, dir, options2) {
|
|
|
69201
70795
|
phaseId,
|
|
69202
70796
|
name: phaseName,
|
|
69203
70797
|
status: checked.toLowerCase() === "x" ? "completed" : "pending",
|
|
69204
|
-
file:
|
|
70798
|
+
file: resolve26(dir, linkPath),
|
|
69205
70799
|
linkText: phaseName,
|
|
69206
70800
|
anchor
|
|
69207
70801
|
});
|
|
@@ -69238,31 +70832,31 @@ function parsePhasesFromBody(body, dir, options2) {
|
|
|
69238
70832
|
return parseFormat6(normalizedBody, dir, options2);
|
|
69239
70833
|
}
|
|
69240
70834
|
function parsePlanFile(planFilePath, options2) {
|
|
69241
|
-
const content =
|
|
69242
|
-
const dir =
|
|
70835
|
+
const content = readFileSync17(planFilePath, "utf8");
|
|
70836
|
+
const dir = dirname30(planFilePath);
|
|
69243
70837
|
const { data: frontmatter, content: body } = import_gray_matter5.default(content);
|
|
69244
70838
|
const phases = parsePhasesFromBody(body, dir, options2);
|
|
69245
70839
|
return { frontmatter, phases };
|
|
69246
70840
|
}
|
|
69247
70841
|
// src/domains/plan-parser/plan-scanner.ts
|
|
69248
|
-
import { existsSync as
|
|
69249
|
-
import { join as
|
|
70842
|
+
import { existsSync as existsSync51, readdirSync as readdirSync7 } from "node:fs";
|
|
70843
|
+
import { join as join108 } from "node:path";
|
|
69250
70844
|
function scanPlanDir(dir) {
|
|
69251
|
-
if (!
|
|
70845
|
+
if (!existsSync51(dir))
|
|
69252
70846
|
return [];
|
|
69253
70847
|
try {
|
|
69254
|
-
return
|
|
70848
|
+
return readdirSync7(dir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => join108(dir, entry.name, "plan.md")).filter(existsSync51);
|
|
69255
70849
|
} catch {
|
|
69256
70850
|
return [];
|
|
69257
70851
|
}
|
|
69258
70852
|
}
|
|
69259
70853
|
// src/domains/plan-parser/plan-validator.ts
|
|
69260
70854
|
var import_gray_matter6 = __toESM(require_gray_matter(), 1);
|
|
69261
|
-
import { existsSync as
|
|
69262
|
-
import { basename as
|
|
70855
|
+
import { existsSync as existsSync52, readFileSync as readFileSync18 } from "node:fs";
|
|
70856
|
+
import { basename as basename13, dirname as dirname31 } from "node:path";
|
|
69263
70857
|
function validatePlanFile(filePath, strict = false) {
|
|
69264
|
-
const content =
|
|
69265
|
-
const dir =
|
|
70858
|
+
const content = readFileSync18(filePath, "utf8");
|
|
70859
|
+
const dir = dirname31(filePath);
|
|
69266
70860
|
const issues = [];
|
|
69267
70861
|
const lines = content.split(`
|
|
69268
70862
|
`);
|
|
@@ -69298,14 +70892,14 @@ function validatePlanFile(filePath, strict = false) {
|
|
|
69298
70892
|
});
|
|
69299
70893
|
}
|
|
69300
70894
|
for (const phase of phases) {
|
|
69301
|
-
if (phase.file && !
|
|
69302
|
-
const fileBasename =
|
|
70895
|
+
if (phase.file && !existsSync52(phase.file)) {
|
|
70896
|
+
const fileBasename = basename13(phase.file);
|
|
69303
70897
|
const refLine = lines.findIndex((l2) => l2.includes(fileBasename));
|
|
69304
70898
|
issues.push({
|
|
69305
70899
|
line: refLine >= 0 ? refLine + 1 : 1,
|
|
69306
70900
|
severity: "warning",
|
|
69307
70901
|
code: "missing-phase-file",
|
|
69308
|
-
message: `Phase ${phase.phaseId} references '${
|
|
70902
|
+
message: `Phase ${phase.phaseId} references '${basename13(phase.file)}' which doesn't exist`
|
|
69309
70903
|
});
|
|
69310
70904
|
}
|
|
69311
70905
|
}
|
|
@@ -69318,9 +70912,9 @@ function validatePlanFile(filePath, strict = false) {
|
|
|
69318
70912
|
}
|
|
69319
70913
|
// src/domains/plan-parser/plan-writer.ts
|
|
69320
70914
|
var import_gray_matter7 = __toESM(require_gray_matter(), 1);
|
|
69321
|
-
import { mkdirSync as mkdirSync6, readFileSync as
|
|
69322
|
-
import { existsSync as
|
|
69323
|
-
import { basename as
|
|
70915
|
+
import { mkdirSync as mkdirSync6, readFileSync as readFileSync19, writeFileSync as writeFileSync9 } from "node:fs";
|
|
70916
|
+
import { existsSync as existsSync53 } from "node:fs";
|
|
70917
|
+
import { basename as basename14, dirname as dirname32, join as join109 } from "node:path";
|
|
69324
70918
|
function phaseNameToFilename(id, name) {
|
|
69325
70919
|
const numMatch = /^(\d+)([a-z]*)$/i.exec(id);
|
|
69326
70920
|
const num3 = numMatch ? numMatch[1] : id;
|
|
@@ -69428,12 +71022,12 @@ function scaffoldPlan(options2) {
|
|
|
69428
71022
|
mkdirSync6(dir, { recursive: true });
|
|
69429
71023
|
const resolvedPhases = resolvePhaseIds(options2.phases);
|
|
69430
71024
|
const optionsWithResolved = { ...options2, phases: resolvedPhases };
|
|
69431
|
-
const planFile =
|
|
71025
|
+
const planFile = join109(dir, "plan.md");
|
|
69432
71026
|
writeFileSync9(planFile, generatePlanMd(optionsWithResolved), "utf8");
|
|
69433
71027
|
const phaseFiles = [];
|
|
69434
71028
|
for (const phase of resolvedPhases) {
|
|
69435
71029
|
const filename = phaseNameToFilename(phase.id, phase.name);
|
|
69436
|
-
const phaseFile =
|
|
71030
|
+
const phaseFile = join109(dir, filename);
|
|
69437
71031
|
writeFileSync9(phaseFile, generatePhaseTemplate(phase), "utf8");
|
|
69438
71032
|
phaseFiles.push(phaseFile);
|
|
69439
71033
|
}
|
|
@@ -69458,7 +71052,7 @@ function isCanonicalFormat(content) {
|
|
|
69458
71052
|
return /^\|\s*phase\s*\|\s*name\s*\|\s*status\s*\|/im.test(content);
|
|
69459
71053
|
}
|
|
69460
71054
|
function updatePhaseStatus(planFile, phaseId, newStatus) {
|
|
69461
|
-
const raw =
|
|
71055
|
+
const raw = readFileSync19(planFile, "utf8").replace(/\r\n/g, `
|
|
69462
71056
|
`);
|
|
69463
71057
|
if (!isCanonicalFormat(raw)) {
|
|
69464
71058
|
console.error("[!] plan.md is not in canonical format — skipping status update");
|
|
@@ -69499,9 +71093,9 @@ function updatePhaseStatus(planFile, phaseId, newStatus) {
|
|
|
69499
71093
|
const updatedFrontmatter = { ...frontmatter, status: planStatus };
|
|
69500
71094
|
const updatedContent = import_gray_matter7.default.stringify(updatedBody, updatedFrontmatter);
|
|
69501
71095
|
writeFileSync9(planFile, updatedContent, "utf8");
|
|
69502
|
-
const planDir =
|
|
71096
|
+
const planDir = dirname32(planFile);
|
|
69503
71097
|
const phaseFilename = phaseNameFilenameFromTableRow(updatedBody, phaseId, planDir);
|
|
69504
|
-
if (phaseFilename &&
|
|
71098
|
+
if (phaseFilename && existsSync53(phaseFilename)) {
|
|
69505
71099
|
updatePhaseFileFrontmatter(phaseFilename, newStatus);
|
|
69506
71100
|
}
|
|
69507
71101
|
}
|
|
@@ -69513,25 +71107,25 @@ function phaseNameFilenameFromTableRow(body, phaseId, planDir) {
|
|
|
69513
71107
|
continue;
|
|
69514
71108
|
const linkMatch = /\[([^\]]+)\]\(\.\/([^)]+)\)/.exec(row);
|
|
69515
71109
|
if (linkMatch)
|
|
69516
|
-
return
|
|
71110
|
+
return join109(planDir, linkMatch[2]);
|
|
69517
71111
|
}
|
|
69518
71112
|
return null;
|
|
69519
71113
|
}
|
|
69520
71114
|
function updatePhaseFileFrontmatter(phaseFile, newStatus) {
|
|
69521
|
-
const raw =
|
|
71115
|
+
const raw = readFileSync19(phaseFile, "utf8");
|
|
69522
71116
|
const { data: frontmatter, content: body } = import_gray_matter7.default(raw);
|
|
69523
71117
|
const updated = { ...frontmatter, status: newStatus };
|
|
69524
71118
|
writeFileSync9(phaseFile, import_gray_matter7.default.stringify(body, updated), "utf8");
|
|
69525
71119
|
}
|
|
69526
71120
|
function addPhase(planFile, name, afterId) {
|
|
69527
|
-
const raw =
|
|
71121
|
+
const raw = readFileSync19(planFile, "utf8").replace(/\r\n/g, `
|
|
69528
71122
|
`);
|
|
69529
71123
|
if (!isCanonicalFormat(raw)) {
|
|
69530
71124
|
console.error("[!] plan.md is not in canonical format — cannot add phase");
|
|
69531
71125
|
throw new Error("Non-canonical plan.md — cannot add phase");
|
|
69532
71126
|
}
|
|
69533
71127
|
const { data: frontmatter, content: body } = import_gray_matter7.default(raw);
|
|
69534
|
-
const planDir =
|
|
71128
|
+
const planDir = dirname32(planFile);
|
|
69535
71129
|
const existingIds = [];
|
|
69536
71130
|
for (const match2 of body.matchAll(/^\|\s*(\d+[a-z]?)\s*\|/gim)) {
|
|
69537
71131
|
existingIds.push(match2[1].toLowerCase());
|
|
@@ -69560,7 +71154,7 @@ function addPhase(planFile, name, afterId) {
|
|
|
69560
71154
|
insertIdx = i;
|
|
69561
71155
|
}
|
|
69562
71156
|
if (insertIdx === -1) {
|
|
69563
|
-
throw new Error(`Phase ID "${afterId}" not found in ${
|
|
71157
|
+
throw new Error(`Phase ID "${afterId}" not found in ${basename14(planFile)}`);
|
|
69564
71158
|
}
|
|
69565
71159
|
lines.splice(insertIdx + 1, 0, newRow);
|
|
69566
71160
|
updatedBody = lines.join(`
|
|
@@ -69594,7 +71188,7 @@ function addPhase(planFile, name, afterId) {
|
|
|
69594
71188
|
`);
|
|
69595
71189
|
}
|
|
69596
71190
|
writeFileSync9(planFile, import_gray_matter7.default.stringify(updatedBody, frontmatter), "utf8");
|
|
69597
|
-
const phaseFilePath =
|
|
71191
|
+
const phaseFilePath = join109(planDir, filename);
|
|
69598
71192
|
writeFileSync9(phaseFilePath, generatePhaseTemplate({ id: phaseId, name }), "utf8");
|
|
69599
71193
|
return { phaseId, phaseFile: phaseFilePath };
|
|
69600
71194
|
}
|
|
@@ -69606,7 +71200,7 @@ function buildPlanSummary(planFile) {
|
|
|
69606
71200
|
const inProgress = phases.filter((p2) => p2.status === "in-progress").length;
|
|
69607
71201
|
const pending = phases.filter((p2) => p2.status === "pending").length;
|
|
69608
71202
|
return {
|
|
69609
|
-
planDir:
|
|
71203
|
+
planDir: dirname33(planFile),
|
|
69610
71204
|
planFile,
|
|
69611
71205
|
title: typeof frontmatter.title === "string" ? frontmatter.title : undefined,
|
|
69612
71206
|
description: typeof frontmatter.description === "string" ? frontmatter.description : undefined,
|
|
@@ -69643,7 +71237,7 @@ async function handleParse(target, options2) {
|
|
|
69643
71237
|
console.log(JSON.stringify({ file: relative19(process.cwd(), planFile), frontmatter, phases }, null, 2));
|
|
69644
71238
|
return;
|
|
69645
71239
|
}
|
|
69646
|
-
const title = typeof frontmatter.title === "string" ? frontmatter.title :
|
|
71240
|
+
const title = typeof frontmatter.title === "string" ? frontmatter.title : basename15(dirname34(planFile));
|
|
69647
71241
|
console.log();
|
|
69648
71242
|
console.log(import_picocolors25.default.bold(` Plan: ${title}`));
|
|
69649
71243
|
console.log(` File: ${planFile}`);
|
|
@@ -69697,8 +71291,8 @@ async function handleValidate(target, options2) {
|
|
|
69697
71291
|
process.exitCode = 1;
|
|
69698
71292
|
}
|
|
69699
71293
|
async function handleStatus(target, options2) {
|
|
69700
|
-
const t = target ?
|
|
69701
|
-
const plansDir = t &&
|
|
71294
|
+
const t = target ? resolve27(target) : null;
|
|
71295
|
+
const plansDir = t && existsSync54(t) && statSync6(t).isDirectory() && !existsSync54(join110(t, "plan.md")) ? t : null;
|
|
69702
71296
|
if (plansDir) {
|
|
69703
71297
|
const planFiles = scanPlanDir(plansDir);
|
|
69704
71298
|
if (planFiles.length === 0) {
|
|
@@ -69723,14 +71317,14 @@ async function handleStatus(target, options2) {
|
|
|
69723
71317
|
try {
|
|
69724
71318
|
const s3 = buildPlanSummary(pf);
|
|
69725
71319
|
const bar = progressBar(s3.completed, s3.totalPhases);
|
|
69726
|
-
const title2 = s3.title ??
|
|
71320
|
+
const title2 = s3.title ?? basename15(dirname34(pf));
|
|
69727
71321
|
console.log(` ${import_picocolors25.default.bold(title2)}`);
|
|
69728
71322
|
console.log(` ${bar}`);
|
|
69729
71323
|
if (s3.inProgress > 0)
|
|
69730
71324
|
console.log(` [~] ${s3.inProgress} in progress`);
|
|
69731
71325
|
console.log();
|
|
69732
71326
|
} catch {
|
|
69733
|
-
console.log(` [X] Failed to read: ${
|
|
71327
|
+
console.log(` [X] Failed to read: ${basename15(dirname34(pf))}`);
|
|
69734
71328
|
console.log();
|
|
69735
71329
|
}
|
|
69736
71330
|
}
|
|
@@ -69754,7 +71348,7 @@ async function handleStatus(target, options2) {
|
|
|
69754
71348
|
console.log(JSON.stringify(summary, null, 2));
|
|
69755
71349
|
return;
|
|
69756
71350
|
}
|
|
69757
|
-
const title = summary.title ??
|
|
71351
|
+
const title = summary.title ?? basename15(dirname34(planFile));
|
|
69758
71352
|
console.log();
|
|
69759
71353
|
console.log(import_picocolors25.default.bold(` ${title}`));
|
|
69760
71354
|
if (summary.status)
|
|
@@ -69780,7 +71374,7 @@ async function handleKanban(target, _options) {
|
|
|
69780
71374
|
}
|
|
69781
71375
|
|
|
69782
71376
|
// src/commands/plan/plan-write-handlers.ts
|
|
69783
|
-
import { basename as
|
|
71377
|
+
import { basename as basename16, relative as relative20, resolve as resolve28 } from "node:path";
|
|
69784
71378
|
init_output_manager();
|
|
69785
71379
|
var import_picocolors26 = __toESM(require_picocolors(), 1);
|
|
69786
71380
|
async function handleCreate(target, options2) {
|
|
@@ -69816,7 +71410,7 @@ async function handleCreate(target, options2) {
|
|
|
69816
71410
|
const result = scaffoldPlan({
|
|
69817
71411
|
title: options2.title,
|
|
69818
71412
|
phases: phaseNames.map((name) => ({ name })),
|
|
69819
|
-
dir:
|
|
71413
|
+
dir: resolve28(dir),
|
|
69820
71414
|
priority,
|
|
69821
71415
|
issue: options2.issue ? Number(options2.issue) : undefined
|
|
69822
71416
|
});
|
|
@@ -69830,10 +71424,10 @@ async function handleCreate(target, options2) {
|
|
|
69830
71424
|
}
|
|
69831
71425
|
console.log();
|
|
69832
71426
|
console.log(import_picocolors26.default.bold(` [OK] Plan created: ${options2.title}`));
|
|
69833
|
-
console.log(` Directory: ${
|
|
71427
|
+
console.log(` Directory: ${resolve28(dir)}`);
|
|
69834
71428
|
console.log(` Phases: ${result.phaseFiles.length}`);
|
|
69835
71429
|
for (const f4 of result.phaseFiles) {
|
|
69836
|
-
console.log(` [ ] ${
|
|
71430
|
+
console.log(` [ ] ${basename16(f4)}`);
|
|
69837
71431
|
}
|
|
69838
71432
|
console.log();
|
|
69839
71433
|
}
|
|
@@ -69928,23 +71522,23 @@ async function handleAddPhase(target, options2) {
|
|
|
69928
71522
|
|
|
69929
71523
|
// src/commands/plan/plan-command.ts
|
|
69930
71524
|
function resolvePlanFile(target) {
|
|
69931
|
-
const t = target ?
|
|
69932
|
-
if (
|
|
69933
|
-
const stat13 =
|
|
71525
|
+
const t = target ? resolve29(target) : process.cwd();
|
|
71526
|
+
if (existsSync55(t)) {
|
|
71527
|
+
const stat13 = statSync7(t);
|
|
69934
71528
|
if (stat13.isFile())
|
|
69935
71529
|
return t;
|
|
69936
|
-
const candidate =
|
|
69937
|
-
if (
|
|
71530
|
+
const candidate = join111(t, "plan.md");
|
|
71531
|
+
if (existsSync55(candidate))
|
|
69938
71532
|
return candidate;
|
|
69939
71533
|
}
|
|
69940
71534
|
if (!target) {
|
|
69941
71535
|
let dir = process.cwd();
|
|
69942
|
-
const root =
|
|
71536
|
+
const root = parse4(dir).root;
|
|
69943
71537
|
while (dir !== root) {
|
|
69944
|
-
const candidate =
|
|
69945
|
-
if (
|
|
71538
|
+
const candidate = join111(dir, "plan.md");
|
|
71539
|
+
if (existsSync55(candidate))
|
|
69946
71540
|
return candidate;
|
|
69947
|
-
dir =
|
|
71541
|
+
dir = dirname35(dir);
|
|
69948
71542
|
}
|
|
69949
71543
|
}
|
|
69950
71544
|
return null;
|
|
@@ -69992,7 +71586,7 @@ async function planCommand(action, target, options2) {
|
|
|
69992
71586
|
let resolvedTarget = target;
|
|
69993
71587
|
if (resolvedAction && !knownActions.has(resolvedAction)) {
|
|
69994
71588
|
const looksLikePath = resolvedAction.includes("/") || resolvedAction.includes("\\") || resolvedAction.endsWith(".md") || resolvedAction === "." || resolvedAction === "..";
|
|
69995
|
-
const existsOnDisk = !looksLikePath &&
|
|
71589
|
+
const existsOnDisk = !looksLikePath && existsSync55(resolve29(resolvedAction));
|
|
69996
71590
|
if (looksLikePath || existsOnDisk) {
|
|
69997
71591
|
resolvedTarget = resolvedAction;
|
|
69998
71592
|
resolvedAction = undefined;
|
|
@@ -70036,24 +71630,24 @@ init_logger();
|
|
|
70036
71630
|
init_logger();
|
|
70037
71631
|
|
|
70038
71632
|
// src/commands/telemetry/shared.ts
|
|
70039
|
-
import { existsSync as
|
|
70040
|
-
import { homedir as
|
|
70041
|
-
import { join as
|
|
71633
|
+
import { existsSync as existsSync56, readFileSync as readFileSync20, readdirSync as readdirSync8 } from "node:fs";
|
|
71634
|
+
import { homedir as homedir28 } from "node:os";
|
|
71635
|
+
import { join as join112 } from "node:path";
|
|
70042
71636
|
init_token_store();
|
|
70043
71637
|
init_manifest_path_resolver();
|
|
70044
71638
|
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 =
|
|
71639
|
+
var USER_CACHE_PATH = join112(homedir28(), ".claude", "sk-user.json");
|
|
71640
|
+
var EVENT_BUFFER_DIR = join112(homedir28(), ".claude", "sk-events");
|
|
71641
|
+
var RATE_STATE_PATH = join112(homedir28(), ".claude", "sk-rate-state.json");
|
|
71642
|
+
var TAKUMI_MANIFEST_PATH = join112(homedir28(), ".claude", MANIFEST_FILENAME);
|
|
71643
|
+
var LEGACY_METADATA_PATH = join112(homedir28(), ".claude", LEGACY_MANIFEST_FILENAME);
|
|
70050
71644
|
var TELEMETRY_HOOK_FIELD = "hooks.telemetry";
|
|
70051
71645
|
var TOKEN_PLACEHOLDER = "__INJECT_AT_RELEASE__";
|
|
70052
71646
|
function readUserCache() {
|
|
70053
71647
|
try {
|
|
70054
|
-
if (!
|
|
71648
|
+
if (!existsSync56(USER_CACHE_PATH))
|
|
70055
71649
|
return null;
|
|
70056
|
-
const parsed = JSON.parse(
|
|
71650
|
+
const parsed = JSON.parse(readFileSync20(USER_CACHE_PATH, "utf8"));
|
|
70057
71651
|
if (!parsed || typeof parsed !== "object")
|
|
70058
71652
|
return null;
|
|
70059
71653
|
return parsed;
|
|
@@ -70063,9 +71657,9 @@ function readUserCache() {
|
|
|
70063
71657
|
}
|
|
70064
71658
|
function countBufferFiles() {
|
|
70065
71659
|
try {
|
|
70066
|
-
if (!
|
|
71660
|
+
if (!existsSync56(EVENT_BUFFER_DIR))
|
|
70067
71661
|
return 0;
|
|
70068
|
-
return
|
|
71662
|
+
return readdirSync8(EVENT_BUFFER_DIR).filter((f4) => f4.endsWith(".jsonl")).length;
|
|
70069
71663
|
} catch {
|
|
70070
71664
|
return 0;
|
|
70071
71665
|
}
|
|
@@ -70075,9 +71669,9 @@ function readTelemetryConfig() {
|
|
|
70075
71669
|
const envToken = process.env.TAKUMI_TELEMETRY_TOKEN;
|
|
70076
71670
|
let metadata = null;
|
|
70077
71671
|
try {
|
|
70078
|
-
const resolved = findManifestPathSync(
|
|
71672
|
+
const resolved = findManifestPathSync(join112(homedir28(), ".claude"));
|
|
70079
71673
|
if (resolved) {
|
|
70080
|
-
metadata = JSON.parse(
|
|
71674
|
+
metadata = JSON.parse(readFileSync20(resolved.path, "utf8"));
|
|
70081
71675
|
}
|
|
70082
71676
|
} catch {
|
|
70083
71677
|
metadata = null;
|
|
@@ -70093,16 +71687,16 @@ function readTelemetryConfig() {
|
|
|
70093
71687
|
return { endpoint, token };
|
|
70094
71688
|
}
|
|
70095
71689
|
function collectRuntimeContext() {
|
|
70096
|
-
const
|
|
71690
|
+
const cache2 = readUserCache();
|
|
70097
71691
|
const { endpoint, token } = readTelemetryConfig();
|
|
70098
71692
|
return {
|
|
70099
|
-
githubLogin: typeof
|
|
70100
|
-
cacheResolvedAt: typeof
|
|
70101
|
-
cacheSource:
|
|
71693
|
+
githubLogin: typeof cache2?.githubLogin === "string" ? cache2.githubLogin : null,
|
|
71694
|
+
cacheResolvedAt: typeof cache2?.resolvedAt === "number" ? cache2.resolvedAt : null,
|
|
71695
|
+
cacheSource: cache2?.source === "gh" || cache2?.source === "manual" ? cache2.source : null,
|
|
70102
71696
|
bufferFileCount: countBufferFiles(),
|
|
70103
71697
|
bufferDir: EVENT_BUFFER_DIR,
|
|
70104
|
-
rateStateExists:
|
|
70105
|
-
userCacheExists:
|
|
71698
|
+
rateStateExists: existsSync56(RATE_STATE_PATH),
|
|
71699
|
+
userCacheExists: existsSync56(USER_CACHE_PATH),
|
|
70106
71700
|
endpoint,
|
|
70107
71701
|
tokenConfigured: Boolean(token)
|
|
70108
71702
|
};
|
|
@@ -70252,8 +71846,8 @@ init_logger();
|
|
|
70252
71846
|
init_safe_prompts();
|
|
70253
71847
|
init_safe_spinner();
|
|
70254
71848
|
var import_fs_extra36 = __toESM(require_lib(), 1);
|
|
70255
|
-
import { readdirSync as
|
|
70256
|
-
import { join as
|
|
71849
|
+
import { readdirSync as readdirSync10, rmSync as rmSync8 } from "node:fs";
|
|
71850
|
+
import { join as join114, resolve as resolve30, sep as sep10 } from "node:path";
|
|
70257
71851
|
|
|
70258
71852
|
// src/commands/uninstall/analysis-handler.ts
|
|
70259
71853
|
init_metadata_migration();
|
|
@@ -70263,13 +71857,13 @@ init_logger();
|
|
|
70263
71857
|
init_safe_prompts();
|
|
70264
71858
|
init_takumi_constants();
|
|
70265
71859
|
var import_picocolors27 = __toESM(require_picocolors(), 1);
|
|
70266
|
-
import { existsSync as
|
|
70267
|
-
import { dirname as
|
|
71860
|
+
import { existsSync as existsSync57, readdirSync as readdirSync9, rmSync as rmSync7 } from "node:fs";
|
|
71861
|
+
import { dirname as dirname36, join as join113 } from "node:path";
|
|
70268
71862
|
function listPresentManifestNames(installPath) {
|
|
70269
71863
|
const present = [];
|
|
70270
|
-
if (
|
|
71864
|
+
if (existsSync57(getManifestPath(installPath)))
|
|
70271
71865
|
present.push(MANIFEST_FILENAME);
|
|
70272
|
-
if (
|
|
71866
|
+
if (existsSync57(getLegacyManifestPath(installPath)))
|
|
70273
71867
|
present.push(LEGACY_MANIFEST_FILENAME);
|
|
70274
71868
|
return present;
|
|
70275
71869
|
}
|
|
@@ -70287,15 +71881,15 @@ function classifyFileByOwnership(ownership, forceOverwrite, deleteReason) {
|
|
|
70287
71881
|
}
|
|
70288
71882
|
async function cleanupEmptyDirectories3(filePath, installationRoot) {
|
|
70289
71883
|
let cleaned = 0;
|
|
70290
|
-
let currentDir =
|
|
71884
|
+
let currentDir = dirname36(filePath);
|
|
70291
71885
|
while (currentDir !== installationRoot && currentDir.startsWith(installationRoot)) {
|
|
70292
71886
|
try {
|
|
70293
|
-
const entries =
|
|
71887
|
+
const entries = readdirSync9(currentDir);
|
|
70294
71888
|
if (entries.length === 0) {
|
|
70295
71889
|
rmSync7(currentDir, { recursive: true });
|
|
70296
71890
|
cleaned++;
|
|
70297
71891
|
logger.debug(`Removed empty directory: ${currentDir}`);
|
|
70298
|
-
currentDir =
|
|
71892
|
+
currentDir = dirname36(currentDir);
|
|
70299
71893
|
} else {
|
|
70300
71894
|
break;
|
|
70301
71895
|
}
|
|
@@ -70317,7 +71911,7 @@ async function analyzeInstallation(installation, forceOverwrite, kit) {
|
|
|
70317
71911
|
if (uninstallManifest.isMultiKit && kit && metadata?.kits?.[kit]) {
|
|
70318
71912
|
const kitFiles = metadata.kits[kit].files || [];
|
|
70319
71913
|
for (const trackedFile of kitFiles) {
|
|
70320
|
-
const filePath =
|
|
71914
|
+
const filePath = join113(installation.path, trackedFile.path);
|
|
70321
71915
|
if (uninstallManifest.filesToPreserve.includes(trackedFile.path)) {
|
|
70322
71916
|
result.toPreserve.push({ path: trackedFile.path, reason: "shared with other kit" });
|
|
70323
71917
|
continue;
|
|
@@ -70349,7 +71943,7 @@ async function analyzeInstallation(installation, forceOverwrite, kit) {
|
|
|
70349
71943
|
return result;
|
|
70350
71944
|
}
|
|
70351
71945
|
for (const trackedFile of allTrackedFiles) {
|
|
70352
|
-
const filePath =
|
|
71946
|
+
const filePath = join113(installation.path, trackedFile.path);
|
|
70353
71947
|
const ownershipResult = await OwnershipChecker.checkOwnership(filePath, metadata, installation.path);
|
|
70354
71948
|
if (!ownershipResult.exists)
|
|
70355
71949
|
continue;
|
|
@@ -70405,17 +71999,17 @@ async function isDirectory(filePath) {
|
|
|
70405
71999
|
}
|
|
70406
72000
|
async function isPathSafeToRemove(filePath, baseDir) {
|
|
70407
72001
|
try {
|
|
70408
|
-
const resolvedPath =
|
|
70409
|
-
const resolvedBase =
|
|
70410
|
-
if (!resolvedPath.startsWith(resolvedBase +
|
|
72002
|
+
const resolvedPath = resolve30(filePath);
|
|
72003
|
+
const resolvedBase = resolve30(baseDir);
|
|
72004
|
+
if (!resolvedPath.startsWith(resolvedBase + sep10) && resolvedPath !== resolvedBase) {
|
|
70411
72005
|
logger.debug(`Path outside installation directory: ${filePath}`);
|
|
70412
72006
|
return false;
|
|
70413
72007
|
}
|
|
70414
72008
|
const stats = await import_fs_extra36.lstat(filePath);
|
|
70415
72009
|
if (stats.isSymbolicLink()) {
|
|
70416
72010
|
const realPath = await import_fs_extra36.realpath(filePath);
|
|
70417
|
-
const resolvedReal =
|
|
70418
|
-
if (!resolvedReal.startsWith(resolvedBase +
|
|
72011
|
+
const resolvedReal = resolve30(realPath);
|
|
72012
|
+
if (!resolvedReal.startsWith(resolvedBase + sep10) && resolvedReal !== resolvedBase) {
|
|
70419
72013
|
logger.debug(`Symlink points outside installation directory: ${filePath} -> ${realPath}`);
|
|
70420
72014
|
return false;
|
|
70421
72015
|
}
|
|
@@ -70448,7 +72042,7 @@ async function removeInstallations(installations, options2) {
|
|
|
70448
72042
|
let removedCount = 0;
|
|
70449
72043
|
let cleanedDirs = 0;
|
|
70450
72044
|
for (const item of analysis.toDelete) {
|
|
70451
|
-
const filePath =
|
|
72045
|
+
const filePath = join114(installation.path, item.path);
|
|
70452
72046
|
if (!await import_fs_extra36.pathExists(filePath))
|
|
70453
72047
|
continue;
|
|
70454
72048
|
if (!await isPathSafeToRemove(filePath, installation.path)) {
|
|
@@ -70467,7 +72061,7 @@ async function removeInstallations(installations, options2) {
|
|
|
70467
72061
|
await ManifestWriter.removeKitFromManifest(installation.path, options2.kit);
|
|
70468
72062
|
}
|
|
70469
72063
|
try {
|
|
70470
|
-
const remaining =
|
|
72064
|
+
const remaining = readdirSync10(installation.path);
|
|
70471
72065
|
if (remaining.length === 0) {
|
|
70472
72066
|
rmSync8(installation.path, { recursive: true });
|
|
70473
72067
|
logger.debug(`Removed empty installation directory: ${installation.path}`);
|
|
@@ -70878,12 +72472,12 @@ async function promptKitUpdate(beta, yes, deps) {
|
|
|
70878
72472
|
args.push("--beta");
|
|
70879
72473
|
const displayCmd = `tkm ${args.join(" ")}`;
|
|
70880
72474
|
logger.info(`Running: ${displayCmd}`);
|
|
70881
|
-
const spawnFn = deps?.spawnInitFn ?? ((spawnArgs) => new Promise((
|
|
72475
|
+
const spawnFn = deps?.spawnInitFn ?? ((spawnArgs) => new Promise((resolve31) => {
|
|
70882
72476
|
const child = spawn3("tkm", spawnArgs, { stdio: "inherit", shell: true });
|
|
70883
|
-
child.on("close", (code) =>
|
|
72477
|
+
child.on("close", (code) => resolve31(code ?? 1));
|
|
70884
72478
|
child.on("error", (err) => {
|
|
70885
72479
|
logger.verbose(`Failed to spawn tkm init: ${err.message}`);
|
|
70886
|
-
|
|
72480
|
+
resolve31(1);
|
|
70887
72481
|
});
|
|
70888
72482
|
}));
|
|
70889
72483
|
const exitCode = await spawnFn(args);
|
|
@@ -70921,6 +72515,8 @@ async function updateCliCommand(options2, deps = getDefaultUpdateCliCommandDeps(
|
|
|
70921
72515
|
logger.verbose(`Using npm configured registry: ${redactRegistryUrlForLog(registryUrl)}`);
|
|
70922
72516
|
}
|
|
70923
72517
|
}
|
|
72518
|
+
if (registryUrl)
|
|
72519
|
+
registryUrl = validateRegistryUrl(registryUrl);
|
|
70924
72520
|
s3.start("Checking for updates...");
|
|
70925
72521
|
let targetVersion = null;
|
|
70926
72522
|
const usePrereleaseChannel = opts.dev || opts.beta;
|
|
@@ -70969,6 +72565,9 @@ async function updateCliCommand(options2, deps = getDefaultUpdateCliCommandDeps(
|
|
|
70969
72565
|
const isDevChannelSwitch = (opts.dev || opts.beta) && isBetaVersion(targetVersion) && !isBetaVersion(currentVersion);
|
|
70970
72566
|
if (comparison > 0 && !opts.release && !isDevChannelSwitch) {
|
|
70971
72567
|
outro(`[+] Current version (${currentVersion}) is newer than latest (${targetVersion})`);
|
|
72568
|
+
if (isBetaVersion(currentVersion)) {
|
|
72569
|
+
note("You are on a prerelease build. `tkm update` tracks the stable channel.\nTo update within the dev/beta channel, run: tkm update --beta");
|
|
72570
|
+
}
|
|
70972
72571
|
await promptKitUpdateFn(targetIsPrerelease, opts.yes);
|
|
70973
72572
|
return;
|
|
70974
72573
|
}
|
|
@@ -71215,6 +72814,19 @@ function registerCommands(cli) {
|
|
|
71215
72814
|
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
72815
|
await versionCommand(options2);
|
|
71217
72816
|
});
|
|
72817
|
+
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) => {
|
|
72818
|
+
let port;
|
|
72819
|
+
if (options2.port !== undefined) {
|
|
72820
|
+
const n = Number(options2.port);
|
|
72821
|
+
if (!Number.isInteger(n) || n < 0 || n > 65535) {
|
|
72822
|
+
console.error(`Invalid --port value: ${options2.port}. Expected integer 0-65535.`);
|
|
72823
|
+
process.exitCode = 1;
|
|
72824
|
+
return;
|
|
72825
|
+
}
|
|
72826
|
+
port = n;
|
|
72827
|
+
}
|
|
72828
|
+
await consoleCommand({ port, noOpen: options2.open === false });
|
|
72829
|
+
});
|
|
71218
72830
|
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
72831
|
await doctorCommand(options2);
|
|
71220
72832
|
});
|
|
@@ -71243,8 +72855,8 @@ function registerCommands(cli) {
|
|
|
71243
72855
|
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
72856
|
await planCommand(action, target, options2);
|
|
71245
72857
|
});
|
|
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,
|
|
72858
|
+
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) => {
|
|
72859
|
+
await apiCommand(action, service, path11, options2);
|
|
71248
72860
|
});
|
|
71249
72861
|
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
72862
|
switch (action) {
|
|
@@ -71279,8 +72891,8 @@ init_version_checker();
|
|
|
71279
72891
|
init_manifest_path_resolver();
|
|
71280
72892
|
init_logger();
|
|
71281
72893
|
init_types2();
|
|
71282
|
-
import { readFileSync as
|
|
71283
|
-
import { join as
|
|
72894
|
+
import { readFileSync as readFileSync21 } from "node:fs";
|
|
72895
|
+
import { join as join115 } from "node:path";
|
|
71284
72896
|
var PROVIDER_LOCAL_SUBDIRS = {
|
|
71285
72897
|
"claude-code": ".claude",
|
|
71286
72898
|
codex: ".codex"
|
|
@@ -71335,7 +72947,7 @@ async function displayVersion() {
|
|
|
71335
72947
|
const localSubdir = PROVIDER_LOCAL_SUBDIRS[provider];
|
|
71336
72948
|
if (!localSubdir)
|
|
71337
72949
|
continue;
|
|
71338
|
-
const localRoot =
|
|
72950
|
+
const localRoot = join115(process.cwd(), localSubdir);
|
|
71339
72951
|
if (localRoot === inst.globalRoot())
|
|
71340
72952
|
continue;
|
|
71341
72953
|
const resolved = findManifestPathSync(localRoot);
|
|
@@ -71345,7 +72957,7 @@ async function displayVersion() {
|
|
|
71345
72957
|
}
|
|
71346
72958
|
for (const { provider, path: metaPath } of localChecks) {
|
|
71347
72959
|
try {
|
|
71348
|
-
const rawMetadata = JSON.parse(
|
|
72960
|
+
const rawMetadata = JSON.parse(readFileSync21(metaPath, "utf-8"));
|
|
71349
72961
|
const metadata = MetadataSchema.parse(rawMetadata);
|
|
71350
72962
|
const kitsDisplay = formatInstalledKits(metadata);
|
|
71351
72963
|
if (kitsDisplay) {
|
|
@@ -71365,7 +72977,7 @@ async function displayVersion() {
|
|
|
71365
72977
|
const resolved = findManifestPathSync(installPath);
|
|
71366
72978
|
if (resolved) {
|
|
71367
72979
|
try {
|
|
71368
|
-
const rawMetadata = JSON.parse(
|
|
72980
|
+
const rawMetadata = JSON.parse(readFileSync21(resolved.path, "utf-8"));
|
|
71369
72981
|
const metadata = MetadataSchema.parse(rawMetadata);
|
|
71370
72982
|
const kitsDisplay = formatInstalledKits(metadata);
|
|
71371
72983
|
if (kitsDisplay) {
|
|
@@ -71467,18 +73079,18 @@ class Logger2 {
|
|
|
71467
73079
|
isVerbose() {
|
|
71468
73080
|
return this.verboseEnabled;
|
|
71469
73081
|
}
|
|
71470
|
-
setLogFile(
|
|
73082
|
+
setLogFile(path11) {
|
|
71471
73083
|
if (this.logFileStream) {
|
|
71472
73084
|
this.logFileStream.end();
|
|
71473
73085
|
this.logFileStream = undefined;
|
|
71474
73086
|
}
|
|
71475
|
-
if (
|
|
71476
|
-
this.logFileStream = createWriteStream4(
|
|
73087
|
+
if (path11) {
|
|
73088
|
+
this.logFileStream = createWriteStream4(path11, {
|
|
71477
73089
|
flags: "a",
|
|
71478
73090
|
mode: 384
|
|
71479
73091
|
});
|
|
71480
73092
|
this.registerExitHandler();
|
|
71481
|
-
this.verbose(`Logging to file: ${
|
|
73093
|
+
this.verbose(`Logging to file: ${path11}`);
|
|
71482
73094
|
}
|
|
71483
73095
|
}
|
|
71484
73096
|
close() {
|