@sunasteriskrnd/takumi 1.0.0-dev.49 → 1.0.0-dev.50
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 +2099 -268
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -19815,7 +19815,7 @@ var package_default;
|
|
|
19815
19815
|
var init_package = __esm(() => {
|
|
19816
19816
|
package_default = {
|
|
19817
19817
|
name: "@sunasteriskrnd/takumi",
|
|
19818
|
-
version: "1.0.0-dev.
|
|
19818
|
+
version: "1.0.0-dev.50",
|
|
19819
19819
|
description: "CLI tool for bootstrapping and managing Takumi projects",
|
|
19820
19820
|
type: "module",
|
|
19821
19821
|
repository: {
|
|
@@ -20011,7 +20011,7 @@ function getLegacyManifestPath(providerRoot) {
|
|
|
20011
20011
|
return join4(providerRoot, LEGACY_MANIFEST_FILENAME);
|
|
20012
20012
|
}
|
|
20013
20013
|
function getCliVersion() {
|
|
20014
|
-
return
|
|
20014
|
+
return "1.0.0-dev.50"?.trim() || process.env.npm_package_version?.trim() || "unknown";
|
|
20015
20015
|
}
|
|
20016
20016
|
function getCliUserAgent() {
|
|
20017
20017
|
return `${TAKUMI_CLI_NPM_PACKAGE_NAME}/${getCliVersion()}`;
|
|
@@ -22249,6 +22249,7 @@ var init_kit = __esm(() => {
|
|
|
22249
22249
|
".mcp.json",
|
|
22250
22250
|
".tkmignore",
|
|
22251
22251
|
".skignore",
|
|
22252
|
+
"takumi.json",
|
|
22252
22253
|
".takumi.json"
|
|
22253
22254
|
];
|
|
22254
22255
|
PROTECTED_PATTERNS = [...NEVER_COPY_PATTERNS, ...USER_CONFIG_PATTERNS];
|
|
@@ -22515,7 +22516,7 @@ function normalizeTakumiConfigInput(value) {
|
|
|
22515
22516
|
}
|
|
22516
22517
|
return normalized;
|
|
22517
22518
|
}
|
|
22518
|
-
var PlanValidationModeSchema, PlanFocusAreaSchema, PlanResolutionOrderSchema, ProjectTypeSchema, PackageManagerSchema, FrameworkSchema, GEMINI_MODEL_VALUES, LEGACY_GEMINI_MODEL_ALIASES, GeminiModelSchema, StatuslineModeSchema, StatuslineSectionIdSchema, StatuslineSectionConfigSchema, StatuslineThemeSchema, StatuslineLayoutSchema, CodingLevelSchema, PlanResolutionSchema, PlanValidationSchema, SkPlanConfigSchema, SkDocsConfigSchema, SkPathsConfigSchema, SkLocaleConfigSchema, SkTrustConfigSchema, SkGraphifyConfigSchema, SkProjectConfigSchema, SkGeminiConfigSchema, SkSkillsConfigSchema, SkSkillExtensionsConfigSchema, UpdatePipelineSchema, ResolvedModelConfigSchema, ModelTierMapSchema, SkModelTaxonomySchema, SkAssertionSchema, SkHooksConfigSchema, TakumiConfigSchema, DEFAULT_TAKUMI_CONFIG, TAKUMI_HOOK_NAMES;
|
|
22519
|
+
var PlanValidationModeSchema, PlanFocusAreaSchema, PlanResolutionOrderSchema, ProjectTypeSchema, PackageManagerSchema, FrameworkSchema, GEMINI_MODEL_VALUES, LEGACY_GEMINI_MODEL_ALIASES, GeminiModelSchema, StatuslineModeSchema, StatuslineSectionIdSchema, StatuslineSectionConfigSchema, StatuslineThemeSchema, StatuslineLayoutSchema, StatuslineBarStyleSchema, StatuslineConfigSchema, CodingLevelSchema, PlanResolutionSchema, PlanValidationSchema, SkPlanConfigSchema, SkDocsConfigSchema, SkPathsConfigSchema, SkLocaleConfigSchema, SkTrustConfigSchema, SkGraphifyConfigSchema, SkProjectConfigSchema, SkGeminiConfigSchema, SkSkillsConfigSchema, SkSkillExtensionsConfigSchema, UpdatePipelineSchema, ResolvedModelConfigSchema, ModelTierMapSchema, SkModelTaxonomySchema, SkAssertionSchema, SkHooksConfigSchema, TakumiConfigSchema, DEFAULT_TAKUMI_CONFIG, TAKUMI_HOOK_NAMES;
|
|
22519
22520
|
var init_takumi_config = __esm(() => {
|
|
22520
22521
|
init_zod();
|
|
22521
22522
|
PlanValidationModeSchema = exports_external.enum(["prompt", "auto", "strict", "none"]);
|
|
@@ -22603,6 +22604,50 @@ var init_takumi_config = __esm(() => {
|
|
|
22603
22604
|
maxAgentRows: exports_external.number().int().min(1).max(10).default(4),
|
|
22604
22605
|
todoTruncation: exports_external.number().int().min(20).max(100).default(50)
|
|
22605
22606
|
});
|
|
22607
|
+
StatuslineBarStyleSchema = exports_external.enum(["geometric", "block"]);
|
|
22608
|
+
StatuslineConfigSchema = exports_external.object({
|
|
22609
|
+
prompt: exports_external.string().optional(),
|
|
22610
|
+
brand: exports_external.object({
|
|
22611
|
+
icon: exports_external.string().optional(),
|
|
22612
|
+
showCliVersion: exports_external.boolean().optional(),
|
|
22613
|
+
showCoreVersion: exports_external.boolean().optional(),
|
|
22614
|
+
color: exports_external.string().optional(),
|
|
22615
|
+
versionColor: exports_external.string().optional()
|
|
22616
|
+
}).passthrough().optional(),
|
|
22617
|
+
model: exports_external.object({ color: exports_external.string().optional() }).passthrough().optional(),
|
|
22618
|
+
context: exports_external.object({
|
|
22619
|
+
barWidth: exports_external.number().int().optional(),
|
|
22620
|
+
barStyle: StatuslineBarStyleSchema.optional(),
|
|
22621
|
+
showPercent: exports_external.boolean().optional(),
|
|
22622
|
+
colors: exports_external.object({ low: exports_external.string(), mid: exports_external.string(), high: exports_external.string() }).partial().passthrough().optional(),
|
|
22623
|
+
thresholds: exports_external.object({ mid: exports_external.number(), high: exports_external.number() }).partial().passthrough().optional()
|
|
22624
|
+
}).passthrough().optional(),
|
|
22625
|
+
quotas: exports_external.object({
|
|
22626
|
+
windows: exports_external.array(exports_external.string()).optional(),
|
|
22627
|
+
barWidth: exports_external.number().int().optional(),
|
|
22628
|
+
showCountdown: exports_external.boolean().optional(),
|
|
22629
|
+
icon: exports_external.string().optional()
|
|
22630
|
+
}).passthrough().optional(),
|
|
22631
|
+
directory: exports_external.object({
|
|
22632
|
+
icon: exports_external.string().optional(),
|
|
22633
|
+
collapseHome: exports_external.boolean().optional(),
|
|
22634
|
+
truncationLength: exports_external.number().int().optional(),
|
|
22635
|
+
color: exports_external.string().optional()
|
|
22636
|
+
}).passthrough().optional(),
|
|
22637
|
+
git: exports_external.object({
|
|
22638
|
+
icon: exports_external.string().optional(),
|
|
22639
|
+
showDirty: exports_external.boolean().optional(),
|
|
22640
|
+
dirtyInBrackets: exports_external.boolean().optional(),
|
|
22641
|
+
showAheadBehind: exports_external.boolean().optional(),
|
|
22642
|
+
countUntracked: exports_external.boolean().optional(),
|
|
22643
|
+
branchColor: exports_external.string().optional()
|
|
22644
|
+
}).passthrough().optional(),
|
|
22645
|
+
activity: exports_external.object({
|
|
22646
|
+
maxAgentRows: exports_external.number().int().optional(),
|
|
22647
|
+
todoTruncation: exports_external.number().int().optional()
|
|
22648
|
+
}).passthrough().optional(),
|
|
22649
|
+
cost: exports_external.object({ icon: exports_external.string().optional(), hideZero: exports_external.boolean().optional() }).passthrough().optional()
|
|
22650
|
+
}).passthrough();
|
|
22606
22651
|
CodingLevelSchema = exports_external.number().int().min(-1).max(5);
|
|
22607
22652
|
PlanResolutionSchema = exports_external.object({
|
|
22608
22653
|
order: exports_external.array(PlanResolutionOrderSchema).optional(),
|
|
@@ -22689,7 +22734,7 @@ var init_takumi_config = __esm(() => {
|
|
|
22689
22734
|
TakumiConfigSchema = exports_external.object({
|
|
22690
22735
|
$schema: exports_external.string().optional(),
|
|
22691
22736
|
codingLevel: CodingLevelSchema.optional(),
|
|
22692
|
-
statusline: StatuslineModeSchema.optional(),
|
|
22737
|
+
statusline: exports_external.union([StatuslineModeSchema, StatuslineConfigSchema]).optional(),
|
|
22693
22738
|
statuslineColors: exports_external.boolean().optional(),
|
|
22694
22739
|
statuslineQuota: exports_external.boolean().optional(),
|
|
22695
22740
|
statuslineLayout: StatuslineLayoutSchema.optional(),
|
|
@@ -24713,6 +24758,22 @@ var init_manifest_tracker = __esm(() => {
|
|
|
24713
24758
|
});
|
|
24714
24759
|
|
|
24715
24760
|
// src/services/file-operations/manifest/index.ts
|
|
24761
|
+
var exports_manifest = {};
|
|
24762
|
+
__export(exports_manifest, {
|
|
24763
|
+
writeManifest: () => writeManifest,
|
|
24764
|
+
writeKitPending: () => writeKitPending,
|
|
24765
|
+
trackFilesWithProgress: () => trackFilesWithProgress,
|
|
24766
|
+
removeKitFromManifest: () => removeKitFromManifest,
|
|
24767
|
+
readManifest: () => readManifest,
|
|
24768
|
+
readKitManifest: () => readKitManifest,
|
|
24769
|
+
getUninstallManifest: () => getUninstallManifest,
|
|
24770
|
+
findPendingKits: () => findPendingKits,
|
|
24771
|
+
findManifestPathSync: () => findManifestPathSync,
|
|
24772
|
+
findManifestPath: () => findManifestPath,
|
|
24773
|
+
findFileInInstalledKits: () => findFileInInstalledKits,
|
|
24774
|
+
buildFileTrackingList: () => buildFileTrackingList,
|
|
24775
|
+
ManifestTracker: () => ManifestTracker
|
|
24776
|
+
});
|
|
24716
24777
|
var init_manifest = __esm(() => {
|
|
24717
24778
|
init_manifest_reader();
|
|
24718
24779
|
init_manifest_tracker();
|
|
@@ -45575,14 +45636,26 @@ class TakumiConfigManager {
|
|
|
45575
45636
|
static getGlobalConfigDir() {
|
|
45576
45637
|
return join62(homedir18(), ".claude");
|
|
45577
45638
|
}
|
|
45639
|
+
static resolveConfigPath(dir) {
|
|
45640
|
+
const preferred = join62(dir, TAKUMI_CONFIG_FILE);
|
|
45641
|
+
if (existsSync26(preferred))
|
|
45642
|
+
return preferred;
|
|
45643
|
+
const legacy = join62(dir, LEGACY_TAKUMI_CONFIG_FILE);
|
|
45644
|
+
if (existsSync26(legacy))
|
|
45645
|
+
return legacy;
|
|
45646
|
+
return preferred;
|
|
45647
|
+
}
|
|
45648
|
+
static configFileExistsIn(dir) {
|
|
45649
|
+
return existsSync26(join62(dir, TAKUMI_CONFIG_FILE)) || existsSync26(join62(dir, LEGACY_TAKUMI_CONFIG_FILE));
|
|
45650
|
+
}
|
|
45578
45651
|
static getGlobalConfigPath() {
|
|
45579
|
-
return
|
|
45652
|
+
return TakumiConfigManager.resolveConfigPath(TakumiConfigManager.getGlobalConfigDir());
|
|
45580
45653
|
}
|
|
45581
45654
|
static getProjectConfigDir(projectDir) {
|
|
45582
45655
|
return join62(projectDir, ".claude");
|
|
45583
45656
|
}
|
|
45584
45657
|
static getProjectConfigPath(projectDir) {
|
|
45585
|
-
return
|
|
45658
|
+
return TakumiConfigManager.resolveConfigPath(TakumiConfigManager.getProjectConfigDir(projectDir));
|
|
45586
45659
|
}
|
|
45587
45660
|
static async loadConfigFile(configPath) {
|
|
45588
45661
|
try {
|
|
@@ -45676,8 +45749,8 @@ class TakumiConfigManager {
|
|
|
45676
45749
|
return TakumiConfigManager.loadConfigFile(TakumiConfigManager.getProjectConfigPath(projectDir));
|
|
45677
45750
|
}
|
|
45678
45751
|
static projectConfigExists(dir, isGlobal) {
|
|
45679
|
-
const
|
|
45680
|
-
return
|
|
45752
|
+
const searchDir = isGlobal ? dir : TakumiConfigManager.getProjectConfigDir(dir);
|
|
45753
|
+
return TakumiConfigManager.configFileExistsIn(searchDir);
|
|
45681
45754
|
}
|
|
45682
45755
|
static configExists(scope, projectDir) {
|
|
45683
45756
|
if (scope === "global") {
|
|
@@ -45699,7 +45772,7 @@ class TakumiConfigManager {
|
|
|
45699
45772
|
await TakumiConfigManager.saveFull(existing, scope, projectDir);
|
|
45700
45773
|
}
|
|
45701
45774
|
}
|
|
45702
|
-
var TAKUMI_CONFIG_FILE = ".takumi.json", DANGEROUS_KEYS;
|
|
45775
|
+
var TAKUMI_CONFIG_FILE = "takumi.json", LEGACY_TAKUMI_CONFIG_FILE = ".takumi.json", DANGEROUS_KEYS;
|
|
45703
45776
|
var init_takumi_config_manager = __esm(() => {
|
|
45704
45777
|
init_logger();
|
|
45705
45778
|
init_types2();
|
|
@@ -49666,19 +49739,305 @@ var require_parse4 = __commonJS((exports, module) => {
|
|
|
49666
49739
|
};
|
|
49667
49740
|
});
|
|
49668
49741
|
|
|
49742
|
+
// src/domains/statusline/cache-dir.ts
|
|
49743
|
+
import {
|
|
49744
|
+
closeSync as closeSync5,
|
|
49745
|
+
constants as fsConstants3,
|
|
49746
|
+
fstatSync,
|
|
49747
|
+
mkdirSync as mkdirSync5,
|
|
49748
|
+
openSync as openSync8,
|
|
49749
|
+
readSync as readSync5,
|
|
49750
|
+
renameSync as renameSync3,
|
|
49751
|
+
rmSync as rmSync3,
|
|
49752
|
+
writeFileSync as writeFileSync9
|
|
49753
|
+
} from "node:fs";
|
|
49754
|
+
import { join as join102 } from "node:path";
|
|
49755
|
+
function getStatuslineCacheDir() {
|
|
49756
|
+
return join102(getConfigDir(), "cache", "statusline");
|
|
49757
|
+
}
|
|
49758
|
+
function getStatuslineCachePath(fileName) {
|
|
49759
|
+
return join102(getStatuslineCacheDir(), fileName);
|
|
49760
|
+
}
|
|
49761
|
+
function ensureStatuslineCacheDir() {
|
|
49762
|
+
try {
|
|
49763
|
+
mkdirSync5(getStatuslineCacheDir(), { recursive: true, mode: 448 });
|
|
49764
|
+
return true;
|
|
49765
|
+
} catch {
|
|
49766
|
+
return false;
|
|
49767
|
+
}
|
|
49768
|
+
}
|
|
49769
|
+
function readCacheFileSafe(path10) {
|
|
49770
|
+
let fd;
|
|
49771
|
+
try {
|
|
49772
|
+
fd = openSync8(path10, fsConstants3.O_RDONLY | fsConstants3.O_NOFOLLOW);
|
|
49773
|
+
const stat9 = fstatSync(fd);
|
|
49774
|
+
if (!stat9.isFile())
|
|
49775
|
+
return null;
|
|
49776
|
+
const uid = typeof process.getuid === "function" ? process.getuid() : undefined;
|
|
49777
|
+
if (uid !== undefined && stat9.uid !== uid)
|
|
49778
|
+
return null;
|
|
49779
|
+
const size = stat9.size;
|
|
49780
|
+
if (size <= 0)
|
|
49781
|
+
return "";
|
|
49782
|
+
const buf = Buffer.allocUnsafe(size);
|
|
49783
|
+
let read = 0;
|
|
49784
|
+
while (read < size) {
|
|
49785
|
+
const n2 = readSync5(fd, buf, read, size - read, read);
|
|
49786
|
+
if (n2 <= 0)
|
|
49787
|
+
break;
|
|
49788
|
+
read += n2;
|
|
49789
|
+
}
|
|
49790
|
+
return buf.toString("utf8", 0, read);
|
|
49791
|
+
} catch {
|
|
49792
|
+
return null;
|
|
49793
|
+
} finally {
|
|
49794
|
+
if (fd !== undefined) {
|
|
49795
|
+
try {
|
|
49796
|
+
closeSync5(fd);
|
|
49797
|
+
} catch {}
|
|
49798
|
+
}
|
|
49799
|
+
}
|
|
49800
|
+
}
|
|
49801
|
+
function writeCacheFileSafe(path10, data) {
|
|
49802
|
+
if (!ensureStatuslineCacheDir())
|
|
49803
|
+
return false;
|
|
49804
|
+
const tmpPath = `${path10}.tmp.${process.pid}.${++writeCounter2}`;
|
|
49805
|
+
try {
|
|
49806
|
+
writeFileSync9(tmpPath, data, { mode: 384 });
|
|
49807
|
+
renameSync3(tmpPath, path10);
|
|
49808
|
+
return true;
|
|
49809
|
+
} catch {
|
|
49810
|
+
try {
|
|
49811
|
+
rmSync3(tmpPath, { force: true });
|
|
49812
|
+
} catch {}
|
|
49813
|
+
return false;
|
|
49814
|
+
}
|
|
49815
|
+
}
|
|
49816
|
+
var writeCounter2 = 0;
|
|
49817
|
+
var init_cache_dir = __esm(() => {
|
|
49818
|
+
init_paths2();
|
|
49819
|
+
});
|
|
49820
|
+
|
|
49821
|
+
// src/domains/hooks/handlers/usage-cache/usage-credential.ts
|
|
49822
|
+
import { execFileSync as execFileSync6 } from "node:child_process";
|
|
49823
|
+
import { closeSync as closeSync6, constants as fsConstants4, fstatSync as fstatSync2, openSync as openSync9, readFileSync as readFileSync18 } from "node:fs";
|
|
49824
|
+
import { homedir as homedir28, platform as platform10 } from "node:os";
|
|
49825
|
+
import { join as join111 } from "node:path";
|
|
49826
|
+
function hasAnthropicRuntimeOverride(env2 = process.env) {
|
|
49827
|
+
return OVERRIDE_ENV_KEYS.some((key) => {
|
|
49828
|
+
const value = env2[key];
|
|
49829
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
49830
|
+
});
|
|
49831
|
+
}
|
|
49832
|
+
function lowerTrimmed(value) {
|
|
49833
|
+
return typeof value === "string" ? value.trim().toLowerCase() : "";
|
|
49834
|
+
}
|
|
49835
|
+
function parseOAuth(raw) {
|
|
49836
|
+
if (!raw || typeof raw !== "object")
|
|
49837
|
+
return null;
|
|
49838
|
+
const bag = raw.claudeAiOauth;
|
|
49839
|
+
if (!bag || typeof bag !== "object")
|
|
49840
|
+
return null;
|
|
49841
|
+
const oauth = bag;
|
|
49842
|
+
const token = typeof oauth.accessToken === "string" ? oauth.accessToken.trim() : "";
|
|
49843
|
+
if (!token)
|
|
49844
|
+
return null;
|
|
49845
|
+
return {
|
|
49846
|
+
accessToken: token,
|
|
49847
|
+
subscriptionType: lowerTrimmed(oauth.subscriptionType),
|
|
49848
|
+
rateLimitTier: lowerTrimmed(oauth.rateLimitTier)
|
|
49849
|
+
};
|
|
49850
|
+
}
|
|
49851
|
+
function readTrustedFile(path10) {
|
|
49852
|
+
let fd;
|
|
49853
|
+
try {
|
|
49854
|
+
fd = openSync9(path10, fsConstants4.O_RDONLY | fsConstants4.O_NOFOLLOW);
|
|
49855
|
+
const stat9 = fstatSync2(fd);
|
|
49856
|
+
if (!stat9.isFile())
|
|
49857
|
+
return null;
|
|
49858
|
+
const uid = typeof process.getuid === "function" ? process.getuid() : undefined;
|
|
49859
|
+
if (uid !== undefined && stat9.uid !== uid)
|
|
49860
|
+
return null;
|
|
49861
|
+
if ((stat9.mode & 18) !== 0)
|
|
49862
|
+
return null;
|
|
49863
|
+
return readFileSync18(fd, "utf8");
|
|
49864
|
+
} catch {
|
|
49865
|
+
return null;
|
|
49866
|
+
} finally {
|
|
49867
|
+
if (fd !== undefined) {
|
|
49868
|
+
try {
|
|
49869
|
+
closeSync6(fd);
|
|
49870
|
+
} catch {}
|
|
49871
|
+
}
|
|
49872
|
+
}
|
|
49873
|
+
}
|
|
49874
|
+
function fromCredentialsFile() {
|
|
49875
|
+
const raw = readTrustedFile(join111(homedir28(), ".claude", ".credentials.json"));
|
|
49876
|
+
if (!raw)
|
|
49877
|
+
return null;
|
|
49878
|
+
try {
|
|
49879
|
+
return parseOAuth(JSON.parse(raw));
|
|
49880
|
+
} catch {
|
|
49881
|
+
return null;
|
|
49882
|
+
}
|
|
49883
|
+
}
|
|
49884
|
+
function fromKeychain() {
|
|
49885
|
+
if (platform10() !== "darwin")
|
|
49886
|
+
return null;
|
|
49887
|
+
try {
|
|
49888
|
+
const out = execFileSync6("security", ["find-generic-password", "-s", KEYCHAIN_SERVICE, "-w"], {
|
|
49889
|
+
timeout: 5000,
|
|
49890
|
+
encoding: "utf8",
|
|
49891
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
49892
|
+
});
|
|
49893
|
+
return parseOAuth(JSON.parse(out.trim()));
|
|
49894
|
+
} catch {
|
|
49895
|
+
return null;
|
|
49896
|
+
}
|
|
49897
|
+
}
|
|
49898
|
+
function isPaidSubscription(oauth) {
|
|
49899
|
+
const sub = oauth.subscriptionType;
|
|
49900
|
+
const hasPaidPlan = sub.length > 0 && sub !== "free" && sub !== "none";
|
|
49901
|
+
return hasPaidPlan || PAID_TIER_PATTERN.test(oauth.rateLimitTier);
|
|
49902
|
+
}
|
|
49903
|
+
function resolveUsageAccess() {
|
|
49904
|
+
if (hasAnthropicRuntimeOverride()) {
|
|
49905
|
+
return { eligible: false, note: "runtime-override", accessToken: null };
|
|
49906
|
+
}
|
|
49907
|
+
const oauth = fromKeychain() ?? fromCredentialsFile();
|
|
49908
|
+
if (!oauth) {
|
|
49909
|
+
return { eligible: false, note: "missing-credentials", accessToken: null };
|
|
49910
|
+
}
|
|
49911
|
+
if (!isPaidSubscription(oauth)) {
|
|
49912
|
+
return { eligible: false, note: "non-subscription-auth", accessToken: null };
|
|
49913
|
+
}
|
|
49914
|
+
return { eligible: true, note: "eligible", accessToken: oauth.accessToken };
|
|
49915
|
+
}
|
|
49916
|
+
var OVERRIDE_ENV_KEYS, PAID_TIER_PATTERN, KEYCHAIN_SERVICE = "Claude Code-credentials";
|
|
49917
|
+
var init_usage_credential = __esm(() => {
|
|
49918
|
+
OVERRIDE_ENV_KEYS = [
|
|
49919
|
+
"ANTHROPIC_BASE_URL",
|
|
49920
|
+
"ANTHROPIC_AUTH_TOKEN",
|
|
49921
|
+
"ANTHROPIC_API_KEY"
|
|
49922
|
+
];
|
|
49923
|
+
PAID_TIER_PATTERN = /claude|max|pro|team|enterprise/;
|
|
49924
|
+
});
|
|
49925
|
+
|
|
49926
|
+
// src/domains/hooks/handlers/usage-cache/usage-limits-cache.ts
|
|
49927
|
+
var exports_usage_limits_cache = {};
|
|
49928
|
+
__export(exports_usage_limits_cache, {
|
|
49929
|
+
refreshUsageCache: () => refreshUsageCache,
|
|
49930
|
+
readUsageCache: () => readUsageCache,
|
|
49931
|
+
normalizeUtilization: () => normalizeUtilization,
|
|
49932
|
+
isUsageCacheFresh: () => isUsageCacheFresh,
|
|
49933
|
+
getCacheAgeMs: () => getCacheAgeMs
|
|
49934
|
+
});
|
|
49935
|
+
function cachePath() {
|
|
49936
|
+
return getStatuslineCachePath(USAGE_CACHE_FILE);
|
|
49937
|
+
}
|
|
49938
|
+
function readUsageCache() {
|
|
49939
|
+
const raw = readCacheFileSafe(cachePath());
|
|
49940
|
+
if (!raw)
|
|
49941
|
+
return null;
|
|
49942
|
+
try {
|
|
49943
|
+
return JSON.parse(raw);
|
|
49944
|
+
} catch {
|
|
49945
|
+
return null;
|
|
49946
|
+
}
|
|
49947
|
+
}
|
|
49948
|
+
function getCacheAgeMs(cache3, now = Date.now()) {
|
|
49949
|
+
if (!cache3 || typeof cache3.timestamp !== "number")
|
|
49950
|
+
return Number.POSITIVE_INFINITY;
|
|
49951
|
+
return Math.max(0, now - cache3.timestamp);
|
|
49952
|
+
}
|
|
49953
|
+
function isUsageCacheFresh(cache3, maxAgeMs, now = Date.now()) {
|
|
49954
|
+
return getCacheAgeMs(cache3, now) <= maxAgeMs;
|
|
49955
|
+
}
|
|
49956
|
+
function normalizeUtilization(utilization) {
|
|
49957
|
+
if (typeof utilization !== "number" || !Number.isFinite(utilization))
|
|
49958
|
+
return null;
|
|
49959
|
+
if (utilization > 0 && utilization < 1)
|
|
49960
|
+
return Math.round(utilization * 100);
|
|
49961
|
+
return Math.max(0, Math.round(utilization));
|
|
49962
|
+
}
|
|
49963
|
+
function buildSnapshot(data, now) {
|
|
49964
|
+
if (!data)
|
|
49965
|
+
return null;
|
|
49966
|
+
return {
|
|
49967
|
+
sourceVersion: SNAPSHOT_VERSION,
|
|
49968
|
+
fetchedAt: new Date(now).toISOString(),
|
|
49969
|
+
fiveHourPercent: normalizeUtilization(data.five_hour?.utilization),
|
|
49970
|
+
weekPercent: normalizeUtilization(data.seven_day?.utilization)
|
|
49971
|
+
};
|
|
49972
|
+
}
|
|
49973
|
+
function persist(status2, data) {
|
|
49974
|
+
const now = Date.now();
|
|
49975
|
+
const cache3 = {
|
|
49976
|
+
timestamp: now,
|
|
49977
|
+
status: status2,
|
|
49978
|
+
data,
|
|
49979
|
+
snapshot: status2 === "available" ? buildSnapshot(data, now) : null
|
|
49980
|
+
};
|
|
49981
|
+
writeCacheFileSafe(cachePath(), JSON.stringify(cache3));
|
|
49982
|
+
}
|
|
49983
|
+
async function fetchUsage() {
|
|
49984
|
+
const access3 = resolveUsageAccess();
|
|
49985
|
+
if (!access3.eligible || !access3.accessToken) {
|
|
49986
|
+
return { status: "unavailable", note: access3.note, data: null };
|
|
49987
|
+
}
|
|
49988
|
+
const controller = new AbortController;
|
|
49989
|
+
const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
|
|
49990
|
+
try {
|
|
49991
|
+
const response = await fetch(USAGE_ENDPOINT, {
|
|
49992
|
+
method: "GET",
|
|
49993
|
+
headers: {
|
|
49994
|
+
Accept: "application/json",
|
|
49995
|
+
"Content-Type": "application/json",
|
|
49996
|
+
Authorization: `Bearer ${access3.accessToken}`,
|
|
49997
|
+
"anthropic-beta": OAUTH_BETA_HEADER,
|
|
49998
|
+
"User-Agent": USER_AGENT
|
|
49999
|
+
},
|
|
50000
|
+
signal: controller.signal
|
|
50001
|
+
});
|
|
50002
|
+
if (!response.ok) {
|
|
50003
|
+
return { status: "unavailable", note: `http-${response.status}`, data: null };
|
|
50004
|
+
}
|
|
50005
|
+
const body = await response.json();
|
|
50006
|
+
if (!body || typeof body !== "object") {
|
|
50007
|
+
return { status: "unavailable", note: "invalid-body", data: null };
|
|
50008
|
+
}
|
|
50009
|
+
return { status: "available", note: "fetched", data: body };
|
|
50010
|
+
} catch (err) {
|
|
50011
|
+
const aborted = err instanceof Error && err.name === "AbortError";
|
|
50012
|
+
return { status: "unavailable", note: aborted ? "timeout" : "fetch-failed", data: null };
|
|
50013
|
+
} finally {
|
|
50014
|
+
clearTimeout(timer);
|
|
50015
|
+
}
|
|
50016
|
+
}
|
|
50017
|
+
async function refreshUsageCache() {
|
|
50018
|
+
const outcome = await fetchUsage();
|
|
50019
|
+
persist(outcome.status, outcome.data);
|
|
50020
|
+
return outcome.note;
|
|
50021
|
+
}
|
|
50022
|
+
var USAGE_ENDPOINT = "https://api.anthropic.com/api/oauth/usage", USER_AGENT = "takumi-agent-kit-engineer/usage-cache", FETCH_TIMEOUT_MS = 5000, USAGE_CACHE_FILE = "usage-limits.json", OAUTH_BETA_HEADER = "oauth-2025-04-20", SNAPSHOT_VERSION = 1;
|
|
50023
|
+
var init_usage_limits_cache = __esm(() => {
|
|
50024
|
+
init_cache_dir();
|
|
50025
|
+
init_usage_credential();
|
|
50026
|
+
});
|
|
50027
|
+
|
|
49669
50028
|
// src/shared/monorepo-resolver.ts
|
|
49670
50029
|
var exports_monorepo_resolver = {};
|
|
49671
50030
|
__export(exports_monorepo_resolver, {
|
|
49672
50031
|
resolveMonorepoRoot: () => resolveMonorepoRoot
|
|
49673
50032
|
});
|
|
49674
|
-
import { existsSync as
|
|
49675
|
-
import { dirname as dirname33, join as
|
|
50033
|
+
import { existsSync as existsSync58, readFileSync as readFileSync23 } from "node:fs";
|
|
50034
|
+
import { dirname as dirname33, join as join121, resolve as resolve26 } from "node:path";
|
|
49676
50035
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
49677
50036
|
function parseMetadataAt(metadataPath) {
|
|
49678
|
-
if (!
|
|
50037
|
+
if (!existsSync58(metadataPath))
|
|
49679
50038
|
return null;
|
|
49680
50039
|
try {
|
|
49681
|
-
const raw =
|
|
50040
|
+
const raw = readFileSync23(metadataPath, "utf-8");
|
|
49682
50041
|
const parsed = JSON.parse(raw);
|
|
49683
50042
|
if (typeof parsed.name !== "string" || typeof parsed.version !== "string" || !ACCEPTED_METADATA_NAMES.has(parsed.name)) {
|
|
49684
50043
|
return null;
|
|
@@ -49689,11 +50048,11 @@ function parseMetadataAt(metadataPath) {
|
|
|
49689
50048
|
}
|
|
49690
50049
|
}
|
|
49691
50050
|
function readSourceDirFromPackageJson(candidateRoot) {
|
|
49692
|
-
const packageJsonPath =
|
|
49693
|
-
if (!
|
|
50051
|
+
const packageJsonPath = join121(candidateRoot, "package.json");
|
|
50052
|
+
if (!existsSync58(packageJsonPath))
|
|
49694
50053
|
return null;
|
|
49695
50054
|
try {
|
|
49696
|
-
const parsed = JSON.parse(
|
|
50055
|
+
const parsed = JSON.parse(readFileSync23(packageJsonPath, "utf-8"));
|
|
49697
50056
|
const kitCfg = parsed.takumi;
|
|
49698
50057
|
if (kitCfg && typeof kitCfg.sourceDir === "string" && kitCfg.sourceDir.length > 0) {
|
|
49699
50058
|
return kitCfg.sourceDir;
|
|
@@ -49712,7 +50071,7 @@ function tryReadAtCandidate(candidateRoot) {
|
|
|
49712
50071
|
};
|
|
49713
50072
|
}
|
|
49714
50073
|
const sourceDir = readSourceDirFromPackageJson(candidateRoot) ?? "claude";
|
|
49715
|
-
const sourceRoot =
|
|
50074
|
+
const sourceRoot = join121(candidateRoot, sourceDir);
|
|
49716
50075
|
const nestedMetadata = parseMetadataAt(getManifestPath(sourceRoot)) ?? parseMetadataAt(getLegacyManifestPath(sourceRoot));
|
|
49717
50076
|
if (nestedMetadata) {
|
|
49718
50077
|
return {
|
|
@@ -50442,7 +50801,7 @@ var init_help_commands = __esm(() => {
|
|
|
50442
50801
|
});
|
|
50443
50802
|
|
|
50444
50803
|
// src/domains/help/help-interactive.ts
|
|
50445
|
-
import { spawn as
|
|
50804
|
+
import { spawn as spawn6 } from "node:child_process";
|
|
50446
50805
|
import * as readline from "node:readline";
|
|
50447
50806
|
function getTerminalHeight() {
|
|
50448
50807
|
return process.stdout.rows || 24;
|
|
@@ -50477,7 +50836,7 @@ async function trySystemPager(content) {
|
|
|
50477
50836
|
const pagerCmd = process.env.PAGER || "less";
|
|
50478
50837
|
const pagerArgs = getPagerArgs(pagerCmd);
|
|
50479
50838
|
try {
|
|
50480
|
-
const pager =
|
|
50839
|
+
const pager = spawn6(pagerCmd, pagerArgs, {
|
|
50481
50840
|
stdio: ["pipe", process.stdout, process.stderr],
|
|
50482
50841
|
shell: false
|
|
50483
50842
|
});
|
|
@@ -73292,13 +73651,538 @@ var metricsRecord = {
|
|
|
73292
73651
|
}
|
|
73293
73652
|
};
|
|
73294
73653
|
|
|
73654
|
+
// src/domains/statusline/activity-cache.ts
|
|
73655
|
+
import { readdirSync as readdirSync7, rmSync as rmSync4, statSync as statSync8 } from "node:fs";
|
|
73656
|
+
import { join as join103 } from "node:path";
|
|
73657
|
+
|
|
73658
|
+
// src/domains/statusline/activity-snapshot.ts
|
|
73659
|
+
import { existsSync as existsSync49 } from "node:fs";
|
|
73660
|
+
|
|
73661
|
+
// src/domains/statusline/transcript-parser.ts
|
|
73662
|
+
import { createReadStream as createReadStream4, existsSync as existsSync48 } from "node:fs";
|
|
73663
|
+
import { createInterface as createInterface2 } from "node:readline";
|
|
73664
|
+
var MAX_TOOLS = 20;
|
|
73665
|
+
var MAX_AGENTS = 10;
|
|
73666
|
+
var NATIVE_TASK = "native_task";
|
|
73667
|
+
var LEGACY_TODOWRITE = "legacy_todowrite";
|
|
73668
|
+
var BASH_TARGET_LIMIT = 30;
|
|
73669
|
+
var TASK_ID_PATTERN = /["']?task[_-]?id["']?\s*[:=]\s*["']([^"']+)["']/i;
|
|
73670
|
+
function asRecord2(value) {
|
|
73671
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
73672
|
+
}
|
|
73673
|
+
function stringOr(value, fallback2) {
|
|
73674
|
+
return typeof value === "string" ? value : fallback2;
|
|
73675
|
+
}
|
|
73676
|
+
function stringOrNull(value) {
|
|
73677
|
+
return typeof value === "string" ? value : null;
|
|
73678
|
+
}
|
|
73679
|
+
function extractTarget(toolName, input) {
|
|
73680
|
+
switch (toolName) {
|
|
73681
|
+
case "Read":
|
|
73682
|
+
case "Write":
|
|
73683
|
+
case "Edit":
|
|
73684
|
+
return stringOrNull(input.file_path) ?? stringOrNull(input.path);
|
|
73685
|
+
case "Glob":
|
|
73686
|
+
case "Grep":
|
|
73687
|
+
return stringOrNull(input.pattern);
|
|
73688
|
+
case "Bash": {
|
|
73689
|
+
const command = input.command;
|
|
73690
|
+
if (typeof command !== "string")
|
|
73691
|
+
return null;
|
|
73692
|
+
return command.length > BASH_TARGET_LIMIT ? `${command.slice(0, BASH_TARGET_LIMIT)}...` : command;
|
|
73693
|
+
}
|
|
73694
|
+
default:
|
|
73695
|
+
return null;
|
|
73696
|
+
}
|
|
73697
|
+
}
|
|
73698
|
+
function findEmbeddedTaskId(node) {
|
|
73699
|
+
if (node == null)
|
|
73700
|
+
return null;
|
|
73701
|
+
if (typeof node === "string") {
|
|
73702
|
+
try {
|
|
73703
|
+
const parsed = JSON.parse(node);
|
|
73704
|
+
if (parsed && typeof parsed === "object")
|
|
73705
|
+
return findEmbeddedTaskId(parsed);
|
|
73706
|
+
} catch {}
|
|
73707
|
+
const match = node.match(TASK_ID_PATTERN);
|
|
73708
|
+
return match ? match[1] : null;
|
|
73709
|
+
}
|
|
73710
|
+
if (Array.isArray(node)) {
|
|
73711
|
+
for (const item of node) {
|
|
73712
|
+
const found = findEmbeddedTaskId(item);
|
|
73713
|
+
if (found)
|
|
73714
|
+
return found;
|
|
73715
|
+
}
|
|
73716
|
+
return null;
|
|
73717
|
+
}
|
|
73718
|
+
if (typeof node === "object") {
|
|
73719
|
+
const obj = node;
|
|
73720
|
+
for (const key of ["taskId", "task_id"]) {
|
|
73721
|
+
const direct = obj[key];
|
|
73722
|
+
if (typeof direct === "string" || typeof direct === "number")
|
|
73723
|
+
return String(direct);
|
|
73724
|
+
}
|
|
73725
|
+
for (const value of Object.values(obj)) {
|
|
73726
|
+
const found = findEmbeddedTaskId(value);
|
|
73727
|
+
if (found)
|
|
73728
|
+
return found;
|
|
73729
|
+
}
|
|
73730
|
+
}
|
|
73731
|
+
return null;
|
|
73732
|
+
}
|
|
73733
|
+
function normalizeTodo(todo) {
|
|
73734
|
+
if (!todo || typeof todo !== "object")
|
|
73735
|
+
return null;
|
|
73736
|
+
const t = todo;
|
|
73737
|
+
const out = {
|
|
73738
|
+
content: typeof t.content === "string" ? t.content : "",
|
|
73739
|
+
status: typeof t.status === "string" ? t.status : "pending",
|
|
73740
|
+
activeForm: typeof t.activeForm === "string" ? t.activeForm : null
|
|
73741
|
+
};
|
|
73742
|
+
if (t.id != null)
|
|
73743
|
+
out.id = t.id;
|
|
73744
|
+
return out;
|
|
73745
|
+
}
|
|
73746
|
+
function emptyTranscript() {
|
|
73747
|
+
return {
|
|
73748
|
+
tools: [],
|
|
73749
|
+
agents: [],
|
|
73750
|
+
todos: [],
|
|
73751
|
+
sessionStart: null,
|
|
73752
|
+
statuslineActivityCount: 0,
|
|
73753
|
+
invalidLineCount: 0,
|
|
73754
|
+
lastValidEntryAt: null,
|
|
73755
|
+
lastActivityAt: null
|
|
73756
|
+
};
|
|
73757
|
+
}
|
|
73758
|
+
async function parseTranscript(transcriptPath) {
|
|
73759
|
+
if (!transcriptPath || !existsSync48(transcriptPath))
|
|
73760
|
+
return emptyTranscript();
|
|
73761
|
+
const tools = new Map;
|
|
73762
|
+
const agents = new Map;
|
|
73763
|
+
let todos = [];
|
|
73764
|
+
let sessionStart = null;
|
|
73765
|
+
let activityCount = 0;
|
|
73766
|
+
let invalidLines = 0;
|
|
73767
|
+
let lastValidEntryAt = null;
|
|
73768
|
+
let lastActivityAt = null;
|
|
73769
|
+
const applyTaskUpdate = (input) => {
|
|
73770
|
+
const { taskId, status: status2 } = input;
|
|
73771
|
+
if (!taskId || !status2)
|
|
73772
|
+
return;
|
|
73773
|
+
const taskIdStr = String(taskId);
|
|
73774
|
+
const natives = todos.filter((t) => t._source === NATIVE_TASK);
|
|
73775
|
+
let target = natives.find((t) => String(t.id) === taskIdStr);
|
|
73776
|
+
if (!target && /^\d+$/.test(taskIdStr)) {
|
|
73777
|
+
target = natives[Number.parseInt(taskIdStr, 10) - 1];
|
|
73778
|
+
}
|
|
73779
|
+
if (!target)
|
|
73780
|
+
return;
|
|
73781
|
+
target.status = String(status2);
|
|
73782
|
+
if ("activeForm" in input) {
|
|
73783
|
+
target.activeForm = typeof input.activeForm === "string" ? input.activeForm : null;
|
|
73784
|
+
}
|
|
73785
|
+
};
|
|
73786
|
+
const handleToolUse = (block, at) => {
|
|
73787
|
+
const id = block.id;
|
|
73788
|
+
const name2 = block.name;
|
|
73789
|
+
if (typeof id !== "string" || typeof name2 !== "string")
|
|
73790
|
+
return false;
|
|
73791
|
+
const input = asRecord2(block.input);
|
|
73792
|
+
switch (name2) {
|
|
73793
|
+
case "Task":
|
|
73794
|
+
agents.set(id, {
|
|
73795
|
+
id,
|
|
73796
|
+
type: stringOr(input.subagent_type, "unknown"),
|
|
73797
|
+
model: stringOrNull(input.model),
|
|
73798
|
+
description: stringOrNull(input.description),
|
|
73799
|
+
status: "running",
|
|
73800
|
+
startTime: at,
|
|
73801
|
+
endTime: null
|
|
73802
|
+
});
|
|
73803
|
+
return true;
|
|
73804
|
+
case "TodoWrite":
|
|
73805
|
+
if (Array.isArray(input.todos)) {
|
|
73806
|
+
todos = input.todos.map((raw) => ({ ...asRecord2(raw), _source: LEGACY_TODOWRITE }));
|
|
73807
|
+
}
|
|
73808
|
+
return true;
|
|
73809
|
+
case "TaskCreate":
|
|
73810
|
+
if (input.subject) {
|
|
73811
|
+
todos.push({
|
|
73812
|
+
id,
|
|
73813
|
+
content: String(input.subject),
|
|
73814
|
+
status: "pending",
|
|
73815
|
+
activeForm: input.activeForm ? String(input.activeForm) : null,
|
|
73816
|
+
_source: NATIVE_TASK,
|
|
73817
|
+
_toolUseId: id
|
|
73818
|
+
});
|
|
73819
|
+
}
|
|
73820
|
+
return true;
|
|
73821
|
+
case "TaskUpdate":
|
|
73822
|
+
applyTaskUpdate(input);
|
|
73823
|
+
return true;
|
|
73824
|
+
default:
|
|
73825
|
+
tools.set(id, {
|
|
73826
|
+
id,
|
|
73827
|
+
name: name2,
|
|
73828
|
+
target: extractTarget(name2, input),
|
|
73829
|
+
status: "running",
|
|
73830
|
+
startTime: at,
|
|
73831
|
+
endTime: null
|
|
73832
|
+
});
|
|
73833
|
+
return false;
|
|
73834
|
+
}
|
|
73835
|
+
};
|
|
73836
|
+
const handleToolResult = (block, at) => {
|
|
73837
|
+
const id = block.tool_use_id;
|
|
73838
|
+
if (typeof id !== "string")
|
|
73839
|
+
return false;
|
|
73840
|
+
const tool = tools.get(id);
|
|
73841
|
+
if (tool) {
|
|
73842
|
+
tool.status = block.is_error ? "error" : "completed";
|
|
73843
|
+
tool.endTime = at;
|
|
73844
|
+
}
|
|
73845
|
+
let agentActivity = false;
|
|
73846
|
+
const agent = agents.get(id);
|
|
73847
|
+
if (agent) {
|
|
73848
|
+
agent.status = "completed";
|
|
73849
|
+
agent.endTime = at;
|
|
73850
|
+
agentActivity = true;
|
|
73851
|
+
}
|
|
73852
|
+
const nativeTodo = todos.find((t) => t._source === NATIVE_TASK && t._toolUseId === id);
|
|
73853
|
+
if (nativeTodo) {
|
|
73854
|
+
const resolvedId = findEmbeddedTaskId(block.content);
|
|
73855
|
+
if (resolvedId)
|
|
73856
|
+
nativeTodo.id = resolvedId;
|
|
73857
|
+
}
|
|
73858
|
+
return agentActivity;
|
|
73859
|
+
};
|
|
73860
|
+
const processEntry = (entry) => {
|
|
73861
|
+
const rawTs = entry.timestamp;
|
|
73862
|
+
const parsed = rawTs == null ? new Date(Number.NaN) : new Date(rawTs);
|
|
73863
|
+
const hasValidTime = !Number.isNaN(parsed.getTime());
|
|
73864
|
+
const at = hasValidTime ? parsed : new Date;
|
|
73865
|
+
lastValidEntryAt = at.toISOString();
|
|
73866
|
+
if (sessionStart === null && hasValidTime)
|
|
73867
|
+
sessionStart = at;
|
|
73868
|
+
const content = asRecord2(entry.message).content;
|
|
73869
|
+
if (!Array.isArray(content))
|
|
73870
|
+
return;
|
|
73871
|
+
let activity = false;
|
|
73872
|
+
for (const rawBlock of content) {
|
|
73873
|
+
const block = asRecord2(rawBlock);
|
|
73874
|
+
if (block.type === "tool_use") {
|
|
73875
|
+
if (handleToolUse(block, at)) {
|
|
73876
|
+
activityCount++;
|
|
73877
|
+
activity = true;
|
|
73878
|
+
}
|
|
73879
|
+
} else if (block.type === "tool_result") {
|
|
73880
|
+
if (handleToolResult(block, at)) {
|
|
73881
|
+
activityCount++;
|
|
73882
|
+
activity = true;
|
|
73883
|
+
}
|
|
73884
|
+
}
|
|
73885
|
+
}
|
|
73886
|
+
if (activity)
|
|
73887
|
+
lastActivityAt = at.toISOString();
|
|
73888
|
+
};
|
|
73889
|
+
await new Promise((resolve21) => {
|
|
73890
|
+
let stream;
|
|
73891
|
+
try {
|
|
73892
|
+
stream = createReadStream4(transcriptPath, { encoding: "utf8" });
|
|
73893
|
+
} catch {
|
|
73894
|
+
resolve21();
|
|
73895
|
+
return;
|
|
73896
|
+
}
|
|
73897
|
+
stream.on("error", () => resolve21());
|
|
73898
|
+
const rl = createInterface2({ input: stream, crlfDelay: Number.POSITIVE_INFINITY });
|
|
73899
|
+
rl.on("line", (line) => {
|
|
73900
|
+
if (!line.trim())
|
|
73901
|
+
return;
|
|
73902
|
+
let entry;
|
|
73903
|
+
try {
|
|
73904
|
+
entry = JSON.parse(line);
|
|
73905
|
+
} catch {
|
|
73906
|
+
invalidLines++;
|
|
73907
|
+
return;
|
|
73908
|
+
}
|
|
73909
|
+
if (entry && typeof entry === "object")
|
|
73910
|
+
processEntry(entry);
|
|
73911
|
+
});
|
|
73912
|
+
rl.on("error", () => resolve21());
|
|
73913
|
+
rl.on("close", () => resolve21());
|
|
73914
|
+
});
|
|
73915
|
+
return {
|
|
73916
|
+
tools: Array.from(tools.values()).slice(-MAX_TOOLS),
|
|
73917
|
+
agents: Array.from(agents.values()).slice(-MAX_AGENTS),
|
|
73918
|
+
todos: todos.map(normalizeTodo).filter((t) => t !== null),
|
|
73919
|
+
sessionStart,
|
|
73920
|
+
statuslineActivityCount: activityCount,
|
|
73921
|
+
invalidLineCount: invalidLines,
|
|
73922
|
+
lastValidEntryAt,
|
|
73923
|
+
lastActivityAt
|
|
73924
|
+
};
|
|
73925
|
+
}
|
|
73926
|
+
|
|
73927
|
+
// src/domains/statusline/activity-snapshot.ts
|
|
73928
|
+
var MAX_AGENTS2 = 10;
|
|
73929
|
+
var WARM_SOURCES = new Set(["startup", "resume", "compact"]);
|
|
73930
|
+
function nowIso() {
|
|
73931
|
+
return new Date().toISOString();
|
|
73932
|
+
}
|
|
73933
|
+
function asRecord3(value) {
|
|
73934
|
+
return value && typeof value === "object" ? value : {};
|
|
73935
|
+
}
|
|
73936
|
+
function stringOr2(value, fallback2) {
|
|
73937
|
+
return typeof value === "string" && value ? value : fallback2;
|
|
73938
|
+
}
|
|
73939
|
+
function toIsoOrNull(value) {
|
|
73940
|
+
if (!value)
|
|
73941
|
+
return null;
|
|
73942
|
+
const date = value instanceof Date ? value : new Date(value);
|
|
73943
|
+
return Number.isNaN(date.getTime()) ? null : date.toISOString();
|
|
73944
|
+
}
|
|
73945
|
+
function isoOr(value, fallback2) {
|
|
73946
|
+
return toIsoOrNull(value) ?? fallback2;
|
|
73947
|
+
}
|
|
73948
|
+
function normalizeAgent(raw) {
|
|
73949
|
+
if (!raw || typeof raw !== "object")
|
|
73950
|
+
return null;
|
|
73951
|
+
const a3 = raw;
|
|
73952
|
+
return {
|
|
73953
|
+
id: a3.id != null ? String(a3.id) : null,
|
|
73954
|
+
type: stringOr2(a3.type, "unknown"),
|
|
73955
|
+
model: stringOr2(a3.model, null),
|
|
73956
|
+
description: stringOr2(a3.description, null),
|
|
73957
|
+
status: a3.status === "completed" ? "completed" : "running",
|
|
73958
|
+
startTime: toIsoOrNull(a3.startTime),
|
|
73959
|
+
endTime: toIsoOrNull(a3.endTime)
|
|
73960
|
+
};
|
|
73961
|
+
}
|
|
73962
|
+
function normalizeTodo2(raw) {
|
|
73963
|
+
if (!raw || typeof raw !== "object")
|
|
73964
|
+
return null;
|
|
73965
|
+
const t = raw;
|
|
73966
|
+
const todo = {
|
|
73967
|
+
content: stringOr2(t.content, ""),
|
|
73968
|
+
status: stringOr2(t.status, "pending"),
|
|
73969
|
+
activeForm: stringOr2(t.activeForm, null)
|
|
73970
|
+
};
|
|
73971
|
+
if (t.id != null)
|
|
73972
|
+
todo.id = String(t.id);
|
|
73973
|
+
return todo;
|
|
73974
|
+
}
|
|
73975
|
+
function createEmptyActivitySnapshot(now = nowIso()) {
|
|
73976
|
+
return { sessionStart: now, updatedAt: now, warmed: false, agents: [], todos: [] };
|
|
73977
|
+
}
|
|
73978
|
+
function sanitizeActivitySnapshot(snapshot) {
|
|
73979
|
+
const now = nowIso();
|
|
73980
|
+
if (!snapshot || typeof snapshot !== "object")
|
|
73981
|
+
return createEmptyActivitySnapshot(now);
|
|
73982
|
+
const s = snapshot;
|
|
73983
|
+
const rawAgents = Array.isArray(s.agents) ? s.agents : [];
|
|
73984
|
+
const rawTodos = Array.isArray(s.todos) ? s.todos : [];
|
|
73985
|
+
return {
|
|
73986
|
+
sessionStart: isoOr(s.sessionStart, now),
|
|
73987
|
+
updatedAt: isoOr(s.updatedAt, now),
|
|
73988
|
+
warmed: Boolean(s.warmed),
|
|
73989
|
+
agents: rawAgents.map(normalizeAgent).filter((a3) => a3 !== null).slice(-MAX_AGENTS2),
|
|
73990
|
+
todos: rawTodos.map(normalizeTodo2).filter((t) => t !== null)
|
|
73991
|
+
};
|
|
73992
|
+
}
|
|
73993
|
+
function applyStatuslineEvent(snapshot, input, now) {
|
|
73994
|
+
const base = sanitizeActivitySnapshot({ ...asRecord3(snapshot), updatedAt: now });
|
|
73995
|
+
if (input.hook_event_name !== "SubagentStop")
|
|
73996
|
+
return base;
|
|
73997
|
+
const agentId = input.agent_id != null ? String(input.agent_id) : null;
|
|
73998
|
+
const agentType = typeof input.agent_type === "string" ? input.agent_type : null;
|
|
73999
|
+
if (!agentId && !agentType)
|
|
74000
|
+
return base;
|
|
74001
|
+
for (let i = base.agents.length - 1;i >= 0; i--) {
|
|
74002
|
+
const agent = base.agents[i];
|
|
74003
|
+
const matchesId = agentId != null && agent.id === agentId;
|
|
74004
|
+
const matchesType = agentId == null && agentType != null && agent.status === "running" && agent.type === agentType;
|
|
74005
|
+
if (matchesId || matchesType) {
|
|
74006
|
+
agent.status = "completed";
|
|
74007
|
+
agent.endTime = agent.endTime || now;
|
|
74008
|
+
break;
|
|
74009
|
+
}
|
|
74010
|
+
}
|
|
74011
|
+
return base;
|
|
74012
|
+
}
|
|
74013
|
+
function shouldPreserveExistingSnapshot(existing, parsed, transcript) {
|
|
74014
|
+
if (!existing)
|
|
74015
|
+
return false;
|
|
74016
|
+
const existingHasActivity = existing.agents.length > 0 || existing.todos.length > 0;
|
|
74017
|
+
if (!existingHasActivity || existing.warmed !== true)
|
|
74018
|
+
return false;
|
|
74019
|
+
const existingAt = Date.parse(existing.updatedAt);
|
|
74020
|
+
const transcriptAt = Date.parse(transcript.lastActivityAt || transcript.lastValidEntryAt || "");
|
|
74021
|
+
const bothDated = Number.isFinite(existingAt) && Number.isFinite(transcriptAt);
|
|
74022
|
+
if (bothDated && existingAt >= transcriptAt)
|
|
74023
|
+
return true;
|
|
74024
|
+
if (transcript.invalidLineCount > 0) {
|
|
74025
|
+
if (!bothDated)
|
|
74026
|
+
return true;
|
|
74027
|
+
return existingAt >= transcriptAt;
|
|
74028
|
+
}
|
|
74029
|
+
const parsedHasActivity = parsed.agents.length > 0 || parsed.todos.length > 0;
|
|
74030
|
+
if (parsedHasActivity)
|
|
74031
|
+
return false;
|
|
74032
|
+
return transcript.statuslineActivityCount === 0;
|
|
74033
|
+
}
|
|
74034
|
+
function resolveTranscriptPath(input, cachedPath) {
|
|
74035
|
+
const fromInput = input.transcript_path;
|
|
74036
|
+
if (typeof fromInput === "string" && fromInput && existsSync49(fromInput))
|
|
74037
|
+
return fromInput;
|
|
74038
|
+
if (cachedPath && existsSync49(cachedPath))
|
|
74039
|
+
return cachedPath;
|
|
74040
|
+
return "";
|
|
74041
|
+
}
|
|
74042
|
+
function shouldWarmStatuslineCache(source, snapshot) {
|
|
74043
|
+
if (!source || !WARM_SOURCES.has(source))
|
|
74044
|
+
return false;
|
|
74045
|
+
return snapshot?.warmed !== true;
|
|
74046
|
+
}
|
|
74047
|
+
async function refreshActivitySnapshot(input, sessionId) {
|
|
74048
|
+
try {
|
|
74049
|
+
if (!sessionId)
|
|
74050
|
+
return;
|
|
74051
|
+
const now = nowIso();
|
|
74052
|
+
const existing = readActivity(sessionId);
|
|
74053
|
+
const current = existing?.snapshot ?? createEmptyActivitySnapshot(now);
|
|
74054
|
+
const existingPath = existing?.lastTranscriptPath ?? "";
|
|
74055
|
+
const transcriptPath = resolveTranscriptPath(input, existingPath);
|
|
74056
|
+
if (!transcriptPath) {
|
|
74057
|
+
const next2 = sanitizeActivitySnapshot(applyStatuslineEvent(current, input, now));
|
|
74058
|
+
writeActivity(sessionId, next2, existingPath);
|
|
74059
|
+
return;
|
|
74060
|
+
}
|
|
74061
|
+
const transcript = await parseTranscript(transcriptPath);
|
|
74062
|
+
const parsedSnapshot = applyStatuslineEvent({
|
|
74063
|
+
sessionStart: transcript.sessionStart?.toISOString() || current.sessionStart || now,
|
|
74064
|
+
updatedAt: now,
|
|
74065
|
+
warmed: true,
|
|
74066
|
+
agents: transcript.agents,
|
|
74067
|
+
todos: transcript.todos
|
|
74068
|
+
}, input, now);
|
|
74069
|
+
const preserve = shouldPreserveExistingSnapshot(current, parsedSnapshot, transcript);
|
|
74070
|
+
const next = sanitizeActivitySnapshot(preserve ? applyStatuslineEvent(current, input, now) : parsedSnapshot);
|
|
74071
|
+
writeActivity(sessionId, next, preserve && existingPath ? existingPath : transcriptPath);
|
|
74072
|
+
} catch {}
|
|
74073
|
+
}
|
|
74074
|
+
|
|
74075
|
+
// src/domains/statusline/activity-cache.ts
|
|
74076
|
+
init_cache_dir();
|
|
74077
|
+
var ACTIVITY_TTL_MS = 7 * 24 * 60 * 60 * 1000;
|
|
74078
|
+
var FILE_PREFIX = "statusline-activity-";
|
|
74079
|
+
var FILE_SUFFIX = ".json";
|
|
74080
|
+
var MAX_ID_LENGTH = 128;
|
|
74081
|
+
function fileNameFor(sessionId) {
|
|
74082
|
+
const safe = sessionId.replace(/[^A-Za-z0-9_-]/g, "_").slice(0, MAX_ID_LENGTH);
|
|
74083
|
+
return `${FILE_PREFIX}${safe}${FILE_SUFFIX}`;
|
|
74084
|
+
}
|
|
74085
|
+
function readActivity(sessionId) {
|
|
74086
|
+
if (!sessionId)
|
|
74087
|
+
return null;
|
|
74088
|
+
const raw = readCacheFileSafe(getStatuslineCachePath(fileNameFor(sessionId)));
|
|
74089
|
+
if (!raw)
|
|
74090
|
+
return null;
|
|
74091
|
+
try {
|
|
74092
|
+
const parsed = JSON.parse(raw);
|
|
74093
|
+
return {
|
|
74094
|
+
snapshot: sanitizeActivitySnapshot(parsed.snapshot),
|
|
74095
|
+
lastTranscriptPath: typeof parsed.lastTranscriptPath === "string" ? parsed.lastTranscriptPath : ""
|
|
74096
|
+
};
|
|
74097
|
+
} catch {
|
|
74098
|
+
return null;
|
|
74099
|
+
}
|
|
74100
|
+
}
|
|
74101
|
+
function writeActivity(sessionId, snapshot, lastTranscriptPath) {
|
|
74102
|
+
if (!sessionId)
|
|
74103
|
+
return false;
|
|
74104
|
+
return writeCacheFileSafe(getStatuslineCachePath(fileNameFor(sessionId)), JSON.stringify({ snapshot, lastTranscriptPath }));
|
|
74105
|
+
}
|
|
74106
|
+
function cleanupStaleActivity(now = Date.now()) {
|
|
74107
|
+
let entries;
|
|
74108
|
+
try {
|
|
74109
|
+
entries = readdirSync7(getStatuslineCacheDir());
|
|
74110
|
+
} catch {
|
|
74111
|
+
return;
|
|
74112
|
+
}
|
|
74113
|
+
for (const entry of entries) {
|
|
74114
|
+
if (!entry.startsWith(FILE_PREFIX) || !entry.endsWith(FILE_SUFFIX))
|
|
74115
|
+
continue;
|
|
74116
|
+
const full = join103(getStatuslineCacheDir(), entry);
|
|
74117
|
+
try {
|
|
74118
|
+
if (now - statSync8(full).mtimeMs > ACTIVITY_TTL_MS)
|
|
74119
|
+
rmSync4(full, { force: true });
|
|
74120
|
+
} catch {}
|
|
74121
|
+
}
|
|
74122
|
+
}
|
|
74123
|
+
|
|
74124
|
+
// src/domains/hooks/handlers/session-activity/handler.ts
|
|
74125
|
+
var ENABLE_GATE_KEY = "session-state";
|
|
74126
|
+
var TRACKED_TOOLS = new Set([
|
|
74127
|
+
"Task",
|
|
74128
|
+
"TaskCreate",
|
|
74129
|
+
"TaskUpdate",
|
|
74130
|
+
"TodoWrite"
|
|
74131
|
+
]);
|
|
74132
|
+
var RECORD_RESULT = { status: "record", timingMs: 0 };
|
|
74133
|
+
var NOOP_RESULT = { status: "no-op", timingMs: 0 };
|
|
74134
|
+
var sessionActivity = {
|
|
74135
|
+
name: "session-activity",
|
|
74136
|
+
category: "session",
|
|
74137
|
+
policy: "record",
|
|
74138
|
+
events: ["SessionStart", "PostToolUse", "Stop", "SubagentStop"],
|
|
74139
|
+
matchers: {
|
|
74140
|
+
SessionStart: "startup|resume|compact",
|
|
74141
|
+
PostToolUse: "Task|TaskCreate|TaskUpdate|TodoWrite"
|
|
74142
|
+
},
|
|
74143
|
+
async run(input, ctx) {
|
|
74144
|
+
try {
|
|
74145
|
+
if (!isHandlerEnabled(ctx, ENABLE_GATE_KEY))
|
|
74146
|
+
return NOOP_RESULT;
|
|
74147
|
+
const sessionId = ctx.sessionId;
|
|
74148
|
+
if (!sessionId)
|
|
74149
|
+
return RECORD_RESULT;
|
|
74150
|
+
switch (ctx.event) {
|
|
74151
|
+
case "SessionStart": {
|
|
74152
|
+
cleanupStaleActivity();
|
|
74153
|
+
const source = typeof input.source === "string" ? input.source : "";
|
|
74154
|
+
const existing = readActivity(sessionId)?.snapshot ?? null;
|
|
74155
|
+
if (shouldWarmStatuslineCache(source, existing)) {
|
|
74156
|
+
await refreshActivitySnapshot(input, sessionId);
|
|
74157
|
+
}
|
|
74158
|
+
return RECORD_RESULT;
|
|
74159
|
+
}
|
|
74160
|
+
case "PostToolUse": {
|
|
74161
|
+
const tool = typeof input.tool_name === "string" ? input.tool_name : "";
|
|
74162
|
+
if (TRACKED_TOOLS.has(tool))
|
|
74163
|
+
await refreshActivitySnapshot(input, sessionId);
|
|
74164
|
+
return RECORD_RESULT;
|
|
74165
|
+
}
|
|
74166
|
+
case "Stop":
|
|
74167
|
+
case "SubagentStop":
|
|
74168
|
+
await refreshActivitySnapshot(input, sessionId);
|
|
74169
|
+
return RECORD_RESULT;
|
|
74170
|
+
default:
|
|
74171
|
+
return NOOP_RESULT;
|
|
74172
|
+
}
|
|
74173
|
+
} catch {
|
|
74174
|
+
return NOOP_RESULT;
|
|
74175
|
+
}
|
|
74176
|
+
}
|
|
74177
|
+
};
|
|
74178
|
+
|
|
73295
74179
|
// src/domains/hooks/handlers/session-init/handler.ts
|
|
73296
|
-
import { mkdirSync as
|
|
73297
|
-
import { dirname as dirname28, join as
|
|
74180
|
+
import { mkdirSync as mkdirSync6 } from "node:fs";
|
|
74181
|
+
import { dirname as dirname28, join as join107 } from "node:path";
|
|
73298
74182
|
|
|
73299
74183
|
// src/domains/hooks/handlers/_shared/project-detector.ts
|
|
73300
|
-
import { existsSync as
|
|
73301
|
-
import { join as
|
|
74184
|
+
import { existsSync as existsSync50, readFileSync as readFileSync15 } from "node:fs";
|
|
74185
|
+
import { join as join104 } from "node:path";
|
|
73302
74186
|
var LOCKFILE_PRIORITY = [
|
|
73303
74187
|
{ manager: "bun", files: ["bun.lockb", "bun.lock"] },
|
|
73304
74188
|
{ manager: "pnpm", files: ["pnpm-lock.yaml"] },
|
|
@@ -73333,14 +74217,14 @@ var APP_FRAMEWORKS = new Set([
|
|
|
73333
74217
|
var WORKSPACE_MARKER_FILES = ["pnpm-workspace.yaml", "turbo.json", "lerna.json"];
|
|
73334
74218
|
function fileExists(cwd2, name2) {
|
|
73335
74219
|
try {
|
|
73336
|
-
return
|
|
74220
|
+
return existsSync50(join104(cwd2, name2));
|
|
73337
74221
|
} catch {
|
|
73338
74222
|
return false;
|
|
73339
74223
|
}
|
|
73340
74224
|
}
|
|
73341
74225
|
function readPackageJson(cwd2) {
|
|
73342
74226
|
try {
|
|
73343
|
-
const raw = readFileSync15(
|
|
74227
|
+
const raw = readFileSync15(join104(cwd2, "package.json"), "utf8");
|
|
73344
74228
|
const parsed = JSON.parse(raw);
|
|
73345
74229
|
if (parsed && typeof parsed === "object")
|
|
73346
74230
|
return parsed;
|
|
@@ -73424,26 +74308,26 @@ function detectProject(cwd2) {
|
|
|
73424
74308
|
// src/domains/hooks/handlers/session-init/env-entries.ts
|
|
73425
74309
|
import { createHash as createHash14 } from "node:crypto";
|
|
73426
74310
|
import { platform as platform8, userInfo } from "node:os";
|
|
73427
|
-
import { join as
|
|
74311
|
+
import { join as join106 } from "node:path";
|
|
73428
74312
|
|
|
73429
74313
|
// src/domains/hooks/handlers/session-init/plan-resolver.ts
|
|
73430
|
-
import { existsSync as
|
|
73431
|
-
import { join as
|
|
74314
|
+
import { existsSync as existsSync51, readFileSync as readFileSync16, readdirSync as readdirSync8 } from "node:fs";
|
|
74315
|
+
import { join as join105 } from "node:path";
|
|
73432
74316
|
var MAX_PLAN_DIRS = 100;
|
|
73433
74317
|
var MAX_PLAN_FILE_BYTES = 64 * 1024;
|
|
73434
74318
|
function listPlanDirs(plansPath) {
|
|
73435
74319
|
try {
|
|
73436
|
-
if (!
|
|
74320
|
+
if (!existsSync51(plansPath))
|
|
73437
74321
|
return [];
|
|
73438
|
-
return
|
|
74322
|
+
return readdirSync8(plansPath, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort().slice(0, MAX_PLAN_DIRS);
|
|
73439
74323
|
} catch {
|
|
73440
74324
|
return [];
|
|
73441
74325
|
}
|
|
73442
74326
|
}
|
|
73443
74327
|
function planFileMentionsSession(planDir, sessionId) {
|
|
73444
74328
|
try {
|
|
73445
|
-
const planFile =
|
|
73446
|
-
if (!
|
|
74329
|
+
const planFile = join105(planDir, "plan.md");
|
|
74330
|
+
if (!existsSync51(planFile))
|
|
73447
74331
|
return false;
|
|
73448
74332
|
const body = readFileSync16(planFile, { encoding: "utf8" });
|
|
73449
74333
|
if (body.length > MAX_PLAN_FILE_BYTES)
|
|
@@ -73457,7 +74341,7 @@ function resolveActivePlan(plansPath, sessionId) {
|
|
|
73457
74341
|
if (!sessionId)
|
|
73458
74342
|
return "";
|
|
73459
74343
|
for (const name2 of listPlanDirs(plansPath)) {
|
|
73460
|
-
const dir =
|
|
74344
|
+
const dir = join105(plansPath, name2);
|
|
73461
74345
|
if (name2.includes(sessionId) || planFileMentionsSession(dir, sessionId)) {
|
|
73462
74346
|
return dir;
|
|
73463
74347
|
}
|
|
@@ -73478,7 +74362,7 @@ function resolveSuggestedPlan(plansPath, branch, branchPattern) {
|
|
|
73478
74362
|
return "";
|
|
73479
74363
|
for (const name2 of listPlanDirs(plansPath)) {
|
|
73480
74364
|
if (name2.includes(slug))
|
|
73481
|
-
return
|
|
74365
|
+
return join105(plansPath, name2);
|
|
73482
74366
|
}
|
|
73483
74367
|
return "";
|
|
73484
74368
|
}
|
|
@@ -73532,11 +74416,11 @@ function buildEnvEntries(params) {
|
|
|
73532
74416
|
const plan = config.plan ?? {};
|
|
73533
74417
|
const locale = config.locale ?? {};
|
|
73534
74418
|
const validation = plan.validation ?? {};
|
|
73535
|
-
const settingsDir =
|
|
73536
|
-
const docsPath =
|
|
73537
|
-
const plansPath =
|
|
74419
|
+
const settingsDir = join106(projectRoot, ".claude");
|
|
74420
|
+
const docsPath = join106(projectRoot, paths.docs ?? "docs");
|
|
74421
|
+
const plansPath = join106(projectRoot, paths.plans ?? "plans");
|
|
73538
74422
|
const reportsDir = plan.reportsDir ?? "reports";
|
|
73539
|
-
const reportsPath =
|
|
74423
|
+
const reportsPath = join106(plansPath, reportsDir);
|
|
73540
74424
|
const namingFormat = plan.namingFormat ?? "";
|
|
73541
74425
|
const activePlan = resolveActivePlan(plansPath, ctx.sessionId);
|
|
73542
74426
|
const suggestedPlan = resolveSuggestedPlan(plansPath, branch, plan.resolution?.branchPattern ?? "");
|
|
@@ -73585,11 +74469,12 @@ function numberString(value) {
|
|
|
73585
74469
|
// src/domains/hooks/handlers/session-init/git-facts.ts
|
|
73586
74470
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
73587
74471
|
var GIT_TIMEOUT_MS = 800;
|
|
73588
|
-
|
|
74472
|
+
var GIT_STATUS_TIMEOUT_MS = 500;
|
|
74473
|
+
function runGit(cwd2, args, timeoutMs = GIT_TIMEOUT_MS) {
|
|
73589
74474
|
try {
|
|
73590
74475
|
const out = execFileSync2("git", ["-C", cwd2, ...args], {
|
|
73591
74476
|
encoding: "utf8",
|
|
73592
|
-
timeout:
|
|
74477
|
+
timeout: timeoutMs,
|
|
73593
74478
|
stdio: ["ignore", "pipe", "ignore"]
|
|
73594
74479
|
});
|
|
73595
74480
|
return out.trim();
|
|
@@ -73597,13 +74482,20 @@ function runGit(cwd2, args) {
|
|
|
73597
74482
|
return "";
|
|
73598
74483
|
}
|
|
73599
74484
|
}
|
|
73600
|
-
function resolveGitRoot(cwd2) {
|
|
73601
|
-
return runGit(cwd2, ["rev-parse", "--show-toplevel"]);
|
|
74485
|
+
function resolveGitRoot(cwd2, timeoutMs) {
|
|
74486
|
+
return runGit(cwd2, ["rev-parse", "--show-toplevel"], timeoutMs);
|
|
73602
74487
|
}
|
|
73603
|
-
function resolveGitBranch(cwd2) {
|
|
73604
|
-
const branch = runGit(cwd2, ["rev-parse", "--abbrev-ref", "HEAD"]);
|
|
74488
|
+
function resolveGitBranch(cwd2, timeoutMs) {
|
|
74489
|
+
const branch = runGit(cwd2, ["rev-parse", "--abbrev-ref", "HEAD"], timeoutMs);
|
|
73605
74490
|
return branch === "HEAD" ? "" : branch;
|
|
73606
74491
|
}
|
|
74492
|
+
var GIT_RENDER_TIMEOUT_MS = GIT_STATUS_TIMEOUT_MS;
|
|
74493
|
+
function resolveGitBranchOrCommit(cwd2, timeoutMs) {
|
|
74494
|
+
const current = runGit(cwd2, ["branch", "--show-current"], timeoutMs);
|
|
74495
|
+
if (current)
|
|
74496
|
+
return current;
|
|
74497
|
+
return runGit(cwd2, ["rev-parse", "--short", "HEAD"], timeoutMs);
|
|
74498
|
+
}
|
|
73607
74499
|
|
|
73608
74500
|
// src/domains/hooks/handlers/session-init/handler.ts
|
|
73609
74501
|
var KNOWN_SOURCES = new Set(["startup", "resume", "clear", "compact"]);
|
|
@@ -73617,11 +74509,11 @@ function resolveEnvFilePath(settingsDir) {
|
|
|
73617
74509
|
const override = process.env.CLAUDE_ENV_FILE;
|
|
73618
74510
|
if (override && override.trim().length > 0)
|
|
73619
74511
|
return override;
|
|
73620
|
-
return
|
|
74512
|
+
return join107(settingsDir, DEFAULT_ENV_FILE);
|
|
73621
74513
|
}
|
|
73622
74514
|
function persistEntries(envFilePath, entries) {
|
|
73623
74515
|
try {
|
|
73624
|
-
|
|
74516
|
+
mkdirSync6(dirname28(envFilePath), { recursive: true });
|
|
73625
74517
|
writeEnvFile(envFilePath, entries);
|
|
73626
74518
|
return true;
|
|
73627
74519
|
} catch {
|
|
@@ -73672,9 +74564,9 @@ var sessionInit = {
|
|
|
73672
74564
|
// src/domains/hooks/handlers/_shared/context-assembler.ts
|
|
73673
74565
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
73674
74566
|
import { createHash as createHash15 } from "node:crypto";
|
|
73675
|
-
import { existsSync as
|
|
74567
|
+
import { existsSync as existsSync52, mkdirSync as mkdirSync7, readFileSync as readFileSync17, rmSync as rmSync5, statSync as statSync9, writeFileSync as writeFileSync10 } from "node:fs";
|
|
73676
74568
|
import { homedir as homedir27, platform as platform9, tmpdir as tmpdir4 } from "node:os";
|
|
73677
|
-
import { basename as basename18, join as
|
|
74569
|
+
import { basename as basename18, join as join108, resolve as resolve21 } from "node:path";
|
|
73678
74570
|
var INJECTED_TTL_MS = 12 * 60 * 60 * 1000;
|
|
73679
74571
|
var RESERVATION_TTL_MS = 60 * 1000;
|
|
73680
74572
|
function gitBranch(dir) {
|
|
@@ -73751,16 +74643,16 @@ function scopeKey(baseDir) {
|
|
|
73751
74643
|
return `${slug}-${hash}`;
|
|
73752
74644
|
}
|
|
73753
74645
|
function stateDir() {
|
|
73754
|
-
return
|
|
74646
|
+
return join108(tmpdir4(), "takumi-context-throttle");
|
|
73755
74647
|
}
|
|
73756
74648
|
function stateFile(sessionId, scope, transcriptPath) {
|
|
73757
74649
|
const key = `${sessionId}\x00${scope}\x00${transcriptPath ?? ""}`;
|
|
73758
74650
|
const hash = createHash15("sha256").update(key).digest("hex").slice(0, 32);
|
|
73759
|
-
return
|
|
74651
|
+
return join108(stateDir(), `${hash}.json`);
|
|
73760
74652
|
}
|
|
73761
74653
|
function readState(file) {
|
|
73762
74654
|
try {
|
|
73763
|
-
if (!
|
|
74655
|
+
if (!existsSync52(file))
|
|
73764
74656
|
return null;
|
|
73765
74657
|
return JSON.parse(readFileSync17(file, "utf8"));
|
|
73766
74658
|
} catch {
|
|
@@ -73768,14 +74660,14 @@ function readState(file) {
|
|
|
73768
74660
|
}
|
|
73769
74661
|
}
|
|
73770
74662
|
function writeState(file, state) {
|
|
73771
|
-
|
|
73772
|
-
|
|
74663
|
+
mkdirSync7(stateDir(), { recursive: true });
|
|
74664
|
+
writeFileSync10(file, JSON.stringify(state), "utf8");
|
|
73773
74665
|
}
|
|
73774
74666
|
function transcriptSize(transcriptPath) {
|
|
73775
74667
|
if (!transcriptPath)
|
|
73776
74668
|
return 0;
|
|
73777
74669
|
try {
|
|
73778
|
-
return
|
|
74670
|
+
return statSync9(transcriptPath).size;
|
|
73779
74671
|
} catch {
|
|
73780
74672
|
return 0;
|
|
73781
74673
|
}
|
|
@@ -73820,14 +74712,14 @@ function clearPending(sessionId, scope, transcriptPath) {
|
|
|
73820
74712
|
if (state.injectedAt) {
|
|
73821
74713
|
writeState(file, { ...state, pending: false, reservedAt: undefined });
|
|
73822
74714
|
} else {
|
|
73823
|
-
|
|
74715
|
+
rmSync5(file, { force: true });
|
|
73824
74716
|
}
|
|
73825
74717
|
} catch {}
|
|
73826
74718
|
}
|
|
73827
74719
|
function resolveSkillsVenv(_cwd) {
|
|
73828
|
-
const base =
|
|
73829
|
-
const interpreter = platform9() === "win32" ?
|
|
73830
|
-
return
|
|
74720
|
+
const base = join108(homedir27(), ".claude", "skills", ".venv");
|
|
74721
|
+
const interpreter = platform9() === "win32" ? join108(base, "Scripts", "python.exe") : join108(base, "bin", "python3");
|
|
74722
|
+
return existsSync52(interpreter) ? interpreter : null;
|
|
73831
74723
|
}
|
|
73832
74724
|
|
|
73833
74725
|
// src/domains/hooks/handlers/session-prompt-context/handler.ts
|
|
@@ -73865,12 +74757,12 @@ var sessionPromptContext = {
|
|
|
73865
74757
|
};
|
|
73866
74758
|
|
|
73867
74759
|
// src/domains/hooks/handlers/session-subagent-init/context-block.ts
|
|
73868
|
-
import { join as
|
|
74760
|
+
import { join as join110 } from "node:path";
|
|
73869
74761
|
|
|
73870
74762
|
// src/domains/hooks/handlers/session-subagent-init/context-sources.ts
|
|
73871
74763
|
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
73872
|
-
import { readdirSync as
|
|
73873
|
-
import { isAbsolute as isAbsolute4, join as
|
|
74764
|
+
import { readdirSync as readdirSync9, statSync as statSync10 } from "node:fs";
|
|
74765
|
+
import { isAbsolute as isAbsolute4, join as join109, resolve as resolve22 } from "node:path";
|
|
73874
74766
|
var MAX_DOCS_FILES = 15;
|
|
73875
74767
|
var MAX_DOCS_SUBDIRS = 5;
|
|
73876
74768
|
function gitFacts(dir) {
|
|
@@ -73902,16 +74794,16 @@ function planDirTemplate(format, dateStr) {
|
|
|
73902
74794
|
}
|
|
73903
74795
|
function detectPlan(plansAbs) {
|
|
73904
74796
|
try {
|
|
73905
|
-
const entries =
|
|
74797
|
+
const entries = readdirSync9(plansAbs, { withFileTypes: true });
|
|
73906
74798
|
let best = null;
|
|
73907
74799
|
for (const e2 of entries) {
|
|
73908
74800
|
if (!e2.isDirectory())
|
|
73909
74801
|
continue;
|
|
73910
|
-
const dir =
|
|
74802
|
+
const dir = join109(plansAbs, e2.name);
|
|
73911
74803
|
try {
|
|
73912
|
-
if (!
|
|
74804
|
+
if (!readdirSync9(dir).includes("plan.md"))
|
|
73913
74805
|
continue;
|
|
73914
|
-
const mtime =
|
|
74806
|
+
const mtime = statSync10(join109(dir, "plan.md")).mtimeMs;
|
|
73915
74807
|
if (!best || mtime > best.mtime)
|
|
73916
74808
|
best = { name: e2.name, mtime };
|
|
73917
74809
|
} catch {}
|
|
@@ -73923,7 +74815,7 @@ function detectPlan(plansAbs) {
|
|
|
73923
74815
|
}
|
|
73924
74816
|
function docsCatalogue(docsAbs) {
|
|
73925
74817
|
try {
|
|
73926
|
-
const entries =
|
|
74818
|
+
const entries = readdirSync9(docsAbs, { withFileTypes: true });
|
|
73927
74819
|
const files = entries.filter((e2) => e2.isFile() && e2.name.toLowerCase().endsWith(".md")).map((e2) => e2.name).sort();
|
|
73928
74820
|
const subdirs = entries.filter((e2) => e2.isDirectory()).map((e2) => e2.name).sort();
|
|
73929
74821
|
const lines = [];
|
|
@@ -73934,7 +74826,7 @@ function docsCatalogue(docsAbs) {
|
|
|
73934
74826
|
for (const d3 of subdirs.slice(0, MAX_DOCS_SUBDIRS)) {
|
|
73935
74827
|
let count = 0;
|
|
73936
74828
|
try {
|
|
73937
|
-
count =
|
|
74829
|
+
count = readdirSync9(join109(docsAbs, d3)).length;
|
|
73938
74830
|
} catch {}
|
|
73939
74831
|
lines.push(`- ${d3}/ (${count} entries)`);
|
|
73940
74832
|
}
|
|
@@ -73978,11 +74870,11 @@ function buildSubagentContext(input, ctx) {
|
|
|
73978
74870
|
const agentId = strField(input, "agent_id") || "unknown";
|
|
73979
74871
|
const plansAbs = abs(base, cfg.paths?.plans?.trim() || "plans");
|
|
73980
74872
|
const docsAbs = abs(base, cfg.paths?.docs?.trim() || "docs");
|
|
73981
|
-
const reportsAbs =
|
|
74873
|
+
const reportsAbs = join110(plansAbs, cfg.plan?.reportsDir?.trim() || "reports");
|
|
73982
74874
|
const dateStr = stamp(cfg.plan?.dateFormat?.trim() || "YYMMDD-HHmm", new Date);
|
|
73983
74875
|
const namingFormat = cfg.plan?.namingFormat?.trim() || "{date}-{slug}";
|
|
73984
|
-
const planDir =
|
|
73985
|
-
const reportFile =
|
|
74876
|
+
const planDir = join110(plansAbs, planDirTemplate(namingFormat, dateStr));
|
|
74877
|
+
const reportFile = join110(reportsAbs, `${agentKey}-${dateStr}-{slug}-report.md`);
|
|
73986
74878
|
const activePlan = detectPlan(plansAbs);
|
|
73987
74879
|
const venv = resolveSkillsVenv(effectiveCwd);
|
|
73988
74880
|
const respLang = cfg.locale?.responseLanguage?.trim() || null;
|
|
@@ -74060,12 +74952,12 @@ var sessionSubagentInit = {
|
|
|
74060
74952
|
// src/domains/hooks/handlers/session-wip-checkpoint/handler.ts
|
|
74061
74953
|
import { execFileSync as execFileSync5 } from "node:child_process";
|
|
74062
74954
|
var CONFIG_KEY5 = "precompact-guard";
|
|
74063
|
-
var
|
|
74955
|
+
var GIT_STATUS_TIMEOUT_MS2 = 800;
|
|
74064
74956
|
function countUncommittedEntries(cwd2) {
|
|
74065
74957
|
try {
|
|
74066
74958
|
const stdout = execFileSync5("git", ["status", "--porcelain"], {
|
|
74067
74959
|
cwd: cwd2,
|
|
74068
|
-
timeout:
|
|
74960
|
+
timeout: GIT_STATUS_TIMEOUT_MS2,
|
|
74069
74961
|
encoding: "utf8",
|
|
74070
74962
|
stdio: ["ignore", "pipe", "ignore"],
|
|
74071
74963
|
windowsHide: true
|
|
@@ -74102,6 +74994,69 @@ var sessionWipCheckpoint = {
|
|
|
74102
74994
|
}
|
|
74103
74995
|
};
|
|
74104
74996
|
|
|
74997
|
+
// src/domains/hooks/handlers/usage-cache/handler.ts
|
|
74998
|
+
import { spawn as spawn4 } from "node:child_process";
|
|
74999
|
+
init_usage_credential();
|
|
75000
|
+
init_usage_limits_cache();
|
|
75001
|
+
var ENABLE_GATE_KEY2 = "usage-context-awareness";
|
|
75002
|
+
var REFRESH_INTERVAL_PROMPT_MS = 60000;
|
|
75003
|
+
var REFRESH_INTERVAL_TOOL_MS = 300000;
|
|
75004
|
+
var RECORD_RESULT2 = { status: "record", timingMs: 0 };
|
|
75005
|
+
var NOOP_RESULT2 = { status: "no-op", timingMs: 0 };
|
|
75006
|
+
function isPromptEvent(event) {
|
|
75007
|
+
return event === "SessionStart" || event === "UserPromptSubmit";
|
|
75008
|
+
}
|
|
75009
|
+
function decideUsageRefresh(ctx, event) {
|
|
75010
|
+
if (!isHandlerEnabled(ctx, ENABLE_GATE_KEY2))
|
|
75011
|
+
return "disabled";
|
|
75012
|
+
if (hasAnthropicRuntimeOverride())
|
|
75013
|
+
return "override";
|
|
75014
|
+
const interval = isPromptEvent(event) ? REFRESH_INTERVAL_PROMPT_MS : REFRESH_INTERVAL_TOOL_MS;
|
|
75015
|
+
return getCacheAgeMs(readUsageCache()) >= interval ? "refresh" : "throttled";
|
|
75016
|
+
}
|
|
75017
|
+
function spawnRefresh(ctx) {
|
|
75018
|
+
try {
|
|
75019
|
+
const { command, prefixArgs } = resolveInvocationPrefix();
|
|
75020
|
+
const args = [...prefixArgs, "statusline", "--refresh-usage-cache"];
|
|
75021
|
+
if (ctx.runtimeFlags?.debug)
|
|
75022
|
+
args.push("--debug");
|
|
75023
|
+
const child = spawn4(command, args, {
|
|
75024
|
+
detached: true,
|
|
75025
|
+
stdio: "ignore",
|
|
75026
|
+
env: buildChildEnv()
|
|
75027
|
+
});
|
|
75028
|
+
child.on("error", (err) => {
|
|
75029
|
+
hookLog("usage_cache_refresh", { spawn_error: err.message });
|
|
75030
|
+
});
|
|
75031
|
+
child.unref();
|
|
75032
|
+
} catch (err) {
|
|
75033
|
+
hookLog("usage_cache_refresh", {
|
|
75034
|
+
spawn_error: err instanceof Error ? err.message : String(err)
|
|
75035
|
+
});
|
|
75036
|
+
}
|
|
75037
|
+
}
|
|
75038
|
+
var usageCache = {
|
|
75039
|
+
name: "perf-usage-cache",
|
|
75040
|
+
category: "perf",
|
|
75041
|
+
policy: "record",
|
|
75042
|
+
events: ["SessionStart", "UserPromptSubmit", "PostToolUse"],
|
|
75043
|
+
installAgents: ["claude"],
|
|
75044
|
+
run(_input, ctx) {
|
|
75045
|
+
try {
|
|
75046
|
+
if (ctx.agent !== "claude")
|
|
75047
|
+
return NOOP_RESULT2;
|
|
75048
|
+
const decision = decideUsageRefresh(ctx, ctx.event);
|
|
75049
|
+
if (decision === "disabled")
|
|
75050
|
+
return NOOP_RESULT2;
|
|
75051
|
+
if (decision === "refresh")
|
|
75052
|
+
spawnRefresh(ctx);
|
|
75053
|
+
return RECORD_RESULT2;
|
|
75054
|
+
} catch {
|
|
75055
|
+
return NOOP_RESULT2;
|
|
75056
|
+
}
|
|
75057
|
+
}
|
|
75058
|
+
};
|
|
75059
|
+
|
|
74105
75060
|
// src/domains/hooks/handlers/registry.ts
|
|
74106
75061
|
var HOOK_HANDLERS = [
|
|
74107
75062
|
guardJailbreak,
|
|
@@ -74115,7 +75070,9 @@ var HOOK_HANDLERS = [
|
|
|
74115
75070
|
conventionQualityGate,
|
|
74116
75071
|
extensionSkill,
|
|
74117
75072
|
metricsRecord,
|
|
74118
|
-
metricsFlush
|
|
75073
|
+
metricsFlush,
|
|
75074
|
+
usageCache,
|
|
75075
|
+
sessionActivity
|
|
74119
75076
|
];
|
|
74120
75077
|
function shortHandlerName(handler) {
|
|
74121
75078
|
const prefix = `${handler.category}-`;
|
|
@@ -74588,7 +75545,7 @@ init_hooks_settings_merger();
|
|
|
74588
75545
|
|
|
74589
75546
|
// src/commands/portable/settings-write-with-confirm.ts
|
|
74590
75547
|
init_safe_prompts();
|
|
74591
|
-
import { existsSync as
|
|
75548
|
+
import { existsSync as existsSync53, mkdirSync as mkdirSync8, readFileSync as readFileSync19, renameSync as renameSync4, rmSync as rmSync6, writeFileSync as writeFileSync11 } from "node:fs";
|
|
74592
75549
|
import { dirname as dirname29 } from "node:path";
|
|
74593
75550
|
|
|
74594
75551
|
// node_modules/diff/libesm/diff/base.js
|
|
@@ -75761,11 +76718,11 @@ var EMPTY_RESULT = (status2) => ({
|
|
|
75761
76718
|
backupPath: null
|
|
75762
76719
|
});
|
|
75763
76720
|
function readCurrent(path10) {
|
|
75764
|
-
if (!
|
|
76721
|
+
if (!existsSync53(path10))
|
|
75765
76722
|
return { kind: "missing" };
|
|
75766
76723
|
let raw = "";
|
|
75767
76724
|
try {
|
|
75768
|
-
raw =
|
|
76725
|
+
raw = readFileSync19(path10, "utf8");
|
|
75769
76726
|
const parsed = JSON.parse(raw);
|
|
75770
76727
|
return { kind: "ok", raw, parsed };
|
|
75771
76728
|
} catch {
|
|
@@ -75792,13 +76749,13 @@ function diffStats(diff) {
|
|
|
75792
76749
|
return { additions, deletions };
|
|
75793
76750
|
}
|
|
75794
76751
|
function atomicWrite2(path10, contents, backupPath) {
|
|
75795
|
-
|
|
76752
|
+
mkdirSync8(dirname29(path10), { recursive: true });
|
|
75796
76753
|
const tmp = `${path10}.tmp`;
|
|
75797
76754
|
try {
|
|
75798
|
-
|
|
75799
|
-
|
|
76755
|
+
writeFileSync11(tmp, contents);
|
|
76756
|
+
renameSync4(tmp, path10);
|
|
75800
76757
|
} catch (err) {
|
|
75801
|
-
|
|
76758
|
+
rmSync6(tmp, { force: true });
|
|
75802
76759
|
const trailer = backupPath ? `. Backup preserved at: ${backupPath}` : "";
|
|
75803
76760
|
throw new Error(`Failed to write ${path10}: ${err instanceof Error ? err.message : String(err)}${trailer}`);
|
|
75804
76761
|
}
|
|
@@ -75807,7 +76764,7 @@ function writeBackup(path10, raw) {
|
|
|
75807
76764
|
const timestamp = new Date().toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
75808
76765
|
const backupPath = `${path10}.${timestamp}.bak`;
|
|
75809
76766
|
try {
|
|
75810
|
-
|
|
76767
|
+
writeFileSync11(backupPath, raw);
|
|
75811
76768
|
return backupPath;
|
|
75812
76769
|
} catch {
|
|
75813
76770
|
return null;
|
|
@@ -75878,18 +76835,18 @@ init_dist2();
|
|
|
75878
76835
|
// src/commands/hooks/lib/agent-target-picker.ts
|
|
75879
76836
|
init_safe_prompts();
|
|
75880
76837
|
init_dist2();
|
|
75881
|
-
import { existsSync as
|
|
76838
|
+
import { existsSync as existsSync54 } from "node:fs";
|
|
75882
76839
|
|
|
75883
76840
|
// src/commands/hooks/lib/settings-path-resolver.ts
|
|
75884
76841
|
import { lstatSync as lstatSync3, realpathSync as realpathSync3 } from "node:fs";
|
|
75885
|
-
import { homedir as
|
|
75886
|
-
import { join as
|
|
76842
|
+
import { homedir as homedir29 } from "node:os";
|
|
76843
|
+
import { join as join112 } from "node:path";
|
|
75887
76844
|
function rawPath(agent, global3) {
|
|
75888
|
-
const root = global3 ?
|
|
76845
|
+
const root = global3 ? homedir29() : process.cwd();
|
|
75889
76846
|
if (agent === "claude") {
|
|
75890
|
-
return
|
|
76847
|
+
return join112(root, ".claude", "settings.json");
|
|
75891
76848
|
}
|
|
75892
|
-
return
|
|
76849
|
+
return join112(root, ".codex", "hooks.json");
|
|
75893
76850
|
}
|
|
75894
76851
|
function resolveSettingsPath(agent, options2 = {}) {
|
|
75895
76852
|
const originalPath = rawPath(agent, Boolean(options2.global));
|
|
@@ -75917,7 +76874,7 @@ function probe(global3) {
|
|
|
75917
76874
|
return {
|
|
75918
76875
|
agent,
|
|
75919
76876
|
path: location2.realPath,
|
|
75920
|
-
exists:
|
|
76877
|
+
exists: existsSync54(location2.realPath)
|
|
75921
76878
|
};
|
|
75922
76879
|
});
|
|
75923
76880
|
}
|
|
@@ -76020,6 +76977,8 @@ function planEntry(handler, event, agent, bin, flags) {
|
|
|
76020
76977
|
function buildHookSection(agent, bin, flags = {}, handlers3 = HOOK_HANDLERS) {
|
|
76021
76978
|
const section = {};
|
|
76022
76979
|
for (const handler of handlers3) {
|
|
76980
|
+
if (handler.installAgents && !handler.installAgents.includes(agent))
|
|
76981
|
+
continue;
|
|
76023
76982
|
for (const event of handler.events) {
|
|
76024
76983
|
const planned = planEntry(handler, event, agent, bin, flags);
|
|
76025
76984
|
if (!planned)
|
|
@@ -76038,9 +76997,82 @@ function buildHookSection(agent, bin, flags = {}, handlers3 = HOOK_HANDLERS) {
|
|
|
76038
76997
|
return section;
|
|
76039
76998
|
}
|
|
76040
76999
|
|
|
77000
|
+
// src/commands/hooks/lib/install-statusline.ts
|
|
77001
|
+
var USAGE_HANDLER = "perf-usage-cache";
|
|
77002
|
+
var ACTIVITY_HANDLER = "session-activity";
|
|
77003
|
+
var USAGE_PRODUCERS = ["usage-quota-cache-refresh.cjs", "usage-context-awareness.cjs"];
|
|
77004
|
+
var ACTIVITY_PRODUCER = "session-state.cjs";
|
|
77005
|
+
var ACTIVITY_PRODUCER_EVENT = "PostToolUse";
|
|
77006
|
+
function buildStatuslineCommand(bin, flags) {
|
|
77007
|
+
const parts = [bin || DEFAULT_HOOK_BIN, "statusline"];
|
|
77008
|
+
if (flags.debug)
|
|
77009
|
+
parts.push("--debug");
|
|
77010
|
+
return parts.join(" ");
|
|
77011
|
+
}
|
|
77012
|
+
function strippedBasenamesForEvent(event, installsUsage, installsActivity) {
|
|
77013
|
+
const out = [];
|
|
77014
|
+
if (installsUsage)
|
|
77015
|
+
out.push(...USAGE_PRODUCERS);
|
|
77016
|
+
if (installsActivity && event === ACTIVITY_PRODUCER_EVENT)
|
|
77017
|
+
out.push(ACTIVITY_PRODUCER);
|
|
77018
|
+
return out;
|
|
77019
|
+
}
|
|
77020
|
+
function commandReferences(command, basename19) {
|
|
77021
|
+
return typeof command === "string" && command.includes(basename19);
|
|
77022
|
+
}
|
|
77023
|
+
function isCliStatuslineCommand(command) {
|
|
77024
|
+
return /^\S+\s+statusline(\s|$)/.test(command);
|
|
77025
|
+
}
|
|
77026
|
+
function shouldSetStatusline(command) {
|
|
77027
|
+
if (typeof command !== "string" || command.trim() === "")
|
|
77028
|
+
return true;
|
|
77029
|
+
return command.includes("statusline.cjs") || isCliStatuslineCommand(command);
|
|
77030
|
+
}
|
|
77031
|
+
function installStatusline(settings, opts) {
|
|
77032
|
+
if (opts.agent !== "claude")
|
|
77033
|
+
return settings;
|
|
77034
|
+
const installsUsage = opts.handlerNames.has(USAGE_HANDLER);
|
|
77035
|
+
const installsActivity = opts.handlerNames.has(ACTIVITY_HANDLER);
|
|
77036
|
+
if (!installsUsage && !installsActivity)
|
|
77037
|
+
return settings;
|
|
77038
|
+
const next = { ...settings };
|
|
77039
|
+
if (installsUsage && installsActivity) {
|
|
77040
|
+
const existing = next.statusLine;
|
|
77041
|
+
if (shouldSetStatusline(existing?.command)) {
|
|
77042
|
+
const command = buildStatuslineCommand(opts.bin, opts.flags ?? {});
|
|
77043
|
+
next.statusLine = { type: "command", ...existing ?? {}, command };
|
|
77044
|
+
}
|
|
77045
|
+
}
|
|
77046
|
+
const hooks = next.hooks;
|
|
77047
|
+
if (hooks && typeof hooks === "object") {
|
|
77048
|
+
const rebuilt = {};
|
|
77049
|
+
for (const [event, groups] of Object.entries(hooks)) {
|
|
77050
|
+
if (!Array.isArray(groups)) {
|
|
77051
|
+
rebuilt[event] = groups;
|
|
77052
|
+
continue;
|
|
77053
|
+
}
|
|
77054
|
+
const strip = strippedBasenamesForEvent(event, installsUsage, installsActivity);
|
|
77055
|
+
const keptGroups = [];
|
|
77056
|
+
for (const group of groups) {
|
|
77057
|
+
if (!Array.isArray(group.hooks)) {
|
|
77058
|
+
keptGroups.push(group);
|
|
77059
|
+
continue;
|
|
77060
|
+
}
|
|
77061
|
+
const keptHooks = group.hooks.filter((entry) => !strip.some((basename19) => commandReferences(entry.command, basename19)));
|
|
77062
|
+
if (keptHooks.length > 0)
|
|
77063
|
+
keptGroups.push({ ...group, hooks: keptHooks });
|
|
77064
|
+
}
|
|
77065
|
+
if (keptGroups.length > 0)
|
|
77066
|
+
rebuilt[event] = keptGroups;
|
|
77067
|
+
}
|
|
77068
|
+
next.hooks = rebuilt;
|
|
77069
|
+
}
|
|
77070
|
+
return next;
|
|
77071
|
+
}
|
|
77072
|
+
|
|
76041
77073
|
// src/commands/hooks/uninstall-handler.ts
|
|
76042
77074
|
init_logger();
|
|
76043
|
-
import { existsSync as
|
|
77075
|
+
import { existsSync as existsSync55, mkdirSync as mkdirSync9, readFileSync as readFileSync20, renameSync as renameSync5, rmSync as rmSync7, writeFileSync as writeFileSync12 } from "node:fs";
|
|
76044
77076
|
import { dirname as dirname30 } from "node:path";
|
|
76045
77077
|
var AGENT_DISPLAY2 = {
|
|
76046
77078
|
claude: "Claude Code",
|
|
@@ -76082,13 +77114,13 @@ function pruneHooksSection(hooks, agent) {
|
|
|
76082
77114
|
return { pruned, removed };
|
|
76083
77115
|
}
|
|
76084
77116
|
function writeAtomic(path10, contents) {
|
|
76085
|
-
|
|
77117
|
+
mkdirSync9(dirname30(path10), { recursive: true });
|
|
76086
77118
|
const tmp = `${path10}.tmp`;
|
|
76087
77119
|
try {
|
|
76088
|
-
|
|
76089
|
-
|
|
77120
|
+
writeFileSync12(tmp, contents);
|
|
77121
|
+
renameSync5(tmp, path10);
|
|
76090
77122
|
} catch (err) {
|
|
76091
|
-
|
|
77123
|
+
rmSync7(tmp, { force: true });
|
|
76092
77124
|
throw err;
|
|
76093
77125
|
}
|
|
76094
77126
|
}
|
|
@@ -76100,12 +77132,12 @@ async function uninstallForAgent(agent, options2) {
|
|
|
76100
77132
|
removed: 0,
|
|
76101
77133
|
dryRun: Boolean(options2.dryRun)
|
|
76102
77134
|
};
|
|
76103
|
-
if (!
|
|
77135
|
+
if (!existsSync55(location2.realPath)) {
|
|
76104
77136
|
return result;
|
|
76105
77137
|
}
|
|
76106
77138
|
let parsed;
|
|
76107
77139
|
try {
|
|
76108
|
-
parsed = JSON.parse(
|
|
77140
|
+
parsed = JSON.parse(readFileSync20(location2.realPath, "utf8"));
|
|
76109
77141
|
} catch {
|
|
76110
77142
|
logger.warning(`[hooks] could not parse ${location2.realPath}; uninstall skipped to avoid clobbering`);
|
|
76111
77143
|
return result;
|
|
@@ -76169,11 +77201,13 @@ function eventsSummary(section) {
|
|
|
76169
77201
|
}
|
|
76170
77202
|
async function installForAgent(agent, options2, interactive, useStepUI) {
|
|
76171
77203
|
const location2 = resolveSettingsPath(agent, { global: options2.global });
|
|
77204
|
+
const handlers3 = selectHandlersForInstall(options2.categories);
|
|
76172
77205
|
const section = buildHookSection(agent, options2.bin, {
|
|
76173
77206
|
noDetach: options2.noDetach,
|
|
76174
77207
|
debug: options2.debug
|
|
76175
|
-
},
|
|
77208
|
+
}, handlers3);
|
|
76176
77209
|
const entriesPlanned = countEntries(section);
|
|
77210
|
+
const handlerNames = new Set(handlers3.map((h2) => h2.name));
|
|
76177
77211
|
const result = await writeSettingsWithConfirm({
|
|
76178
77212
|
path: location2.realPath,
|
|
76179
77213
|
label: `${AGENT_DISPLAY3[agent]} settings`,
|
|
@@ -76182,7 +77216,13 @@ async function installForAgent(agent, options2, interactive, useStepUI) {
|
|
|
76182
77216
|
const existingHooks = safeCurrent.hooks ?? {};
|
|
76183
77217
|
const { pruned } = pruneHooksSection(existingHooks, agent);
|
|
76184
77218
|
const purged = { ...safeCurrent, hooks: pruned };
|
|
76185
|
-
|
|
77219
|
+
const merged = mergeHooksObject(purged, section);
|
|
77220
|
+
return installStatusline(merged, {
|
|
77221
|
+
agent,
|
|
77222
|
+
handlerNames,
|
|
77223
|
+
bin: options2.bin,
|
|
77224
|
+
flags: { noDetach: options2.noDetach, debug: options2.debug }
|
|
77225
|
+
});
|
|
76186
77226
|
},
|
|
76187
77227
|
missingFile: resolveMissingFileMode(options2, interactive),
|
|
76188
77228
|
yes: options2.yes,
|
|
@@ -76319,7 +77359,7 @@ async function installHook(options2) {
|
|
|
76319
77359
|
// src/commands/hooks/status.ts
|
|
76320
77360
|
init_takumi_config_manager();
|
|
76321
77361
|
init_logger();
|
|
76322
|
-
import { existsSync as
|
|
77362
|
+
import { existsSync as existsSync56, readFileSync as readFileSync21 } from "node:fs";
|
|
76323
77363
|
var AGENT_DISPLAY4 = { claude: "Claude Code", codex: "Codex" };
|
|
76324
77364
|
var NEW_SHAPE = /\bhook-exec\b.*--hook\s+(guard|session|convention|extension|metrics|perf)\.(\S+).*-a\s+(claude|codex)(?![\w-])/;
|
|
76325
77365
|
var LEGACY_SHAPE = /\bhooks\s+(?:session-start|user-prompt-submit|pre-tool-use|post-tool-use|stop|session-end)\s+-a\s+(claude|codex)(?![\w-])/;
|
|
@@ -76349,7 +77389,7 @@ async function statusForAgent(agent, options2, cwd2 = process.cwd()) {
|
|
|
76349
77389
|
const result = {
|
|
76350
77390
|
agent,
|
|
76351
77391
|
settingsPath: location2.realPath,
|
|
76352
|
-
exists:
|
|
77392
|
+
exists: existsSync56(location2.realPath),
|
|
76353
77393
|
shape: "none",
|
|
76354
77394
|
byCategory: {},
|
|
76355
77395
|
newEntryCount: 0,
|
|
@@ -76360,7 +77400,7 @@ async function statusForAgent(agent, options2, cwd2 = process.cwd()) {
|
|
|
76360
77400
|
return result;
|
|
76361
77401
|
let hooks;
|
|
76362
77402
|
try {
|
|
76363
|
-
const parsed = JSON.parse(
|
|
77403
|
+
const parsed = JSON.parse(readFileSync21(location2.realPath, "utf8"));
|
|
76364
77404
|
hooks = parsed.hooks ?? {};
|
|
76365
77405
|
} catch {
|
|
76366
77406
|
return result;
|
|
@@ -77350,7 +78390,7 @@ async function promptFreshConfirmation(targetPath, analysis) {
|
|
|
77350
78390
|
// src/domains/ui/prompts/confirmation-prompts.ts
|
|
77351
78391
|
init_output_manager();
|
|
77352
78392
|
init_safe_prompts();
|
|
77353
|
-
import { platform as
|
|
78393
|
+
import { platform as platform11 } from "node:os";
|
|
77354
78394
|
|
|
77355
78395
|
// src/types/skills-dependencies.ts
|
|
77356
78396
|
var SKILLS_DEPENDENCIES = {
|
|
@@ -77412,7 +78452,7 @@ async function promptSkillsInstallation() {
|
|
|
77412
78452
|
if (output.isJson()) {
|
|
77413
78453
|
return false;
|
|
77414
78454
|
}
|
|
77415
|
-
const isWindows2 =
|
|
78455
|
+
const isWindows2 = platform11() === "win32";
|
|
77416
78456
|
const pythonDeps = formatDependencyList(SKILLS_DEPENDENCIES.python);
|
|
77417
78457
|
const systemDeps = formatDependencyList(SKILLS_DEPENDENCIES.system);
|
|
77418
78458
|
const nodeDeps = formatDependencyList(SKILLS_DEPENDENCIES.node);
|
|
@@ -77590,7 +78630,7 @@ init_logger();
|
|
|
77590
78630
|
init_takumi_constants();
|
|
77591
78631
|
var import_fs_extra33 = __toESM(require_lib(), 1);
|
|
77592
78632
|
var import_semver5 = __toESM(require_semver2(), 1);
|
|
77593
|
-
import { join as
|
|
78633
|
+
import { join as join113 } from "node:path";
|
|
77594
78634
|
function evaluateCliVersionGate(input) {
|
|
77595
78635
|
const min = typeof input.minCliVersion === "string" ? input.minCliVersion.trim() : undefined;
|
|
77596
78636
|
if (!min)
|
|
@@ -77611,7 +78651,7 @@ function evaluateCliVersionGate(input) {
|
|
|
77611
78651
|
}
|
|
77612
78652
|
async function readKitMinCliVersion(extractDir) {
|
|
77613
78653
|
try {
|
|
77614
|
-
const resolved = await findManifestPath(
|
|
78654
|
+
const resolved = await findManifestPath(join113(extractDir, ".claude"));
|
|
77615
78655
|
if (!resolved)
|
|
77616
78656
|
return;
|
|
77617
78657
|
const raw = await import_fs_extra33.readFile(resolved.path, "utf-8");
|
|
@@ -77803,7 +78843,7 @@ init_logger();
|
|
|
77803
78843
|
init_safe_spinner();
|
|
77804
78844
|
import { mkdir as mkdir25, stat as stat11 } from "node:fs/promises";
|
|
77805
78845
|
import { tmpdir as tmpdir5 } from "node:os";
|
|
77806
|
-
import { join as
|
|
78846
|
+
import { join as join119 } from "node:path";
|
|
77807
78847
|
|
|
77808
78848
|
// src/shared/temp-cleanup.ts
|
|
77809
78849
|
init_logger();
|
|
@@ -77820,9 +78860,9 @@ var import_ignore6 = __toESM(require_ignore(), 1);
|
|
|
77820
78860
|
// src/domains/installation/download/file-downloader.ts
|
|
77821
78861
|
init_logger();
|
|
77822
78862
|
init_output_manager();
|
|
77823
|
-
import { createWriteStream as createWriteStream2, rmSync as
|
|
78863
|
+
import { createWriteStream as createWriteStream2, rmSync as rmSync8 } from "node:fs";
|
|
77824
78864
|
import { mkdir as mkdir21 } from "node:fs/promises";
|
|
77825
|
-
import { join as
|
|
78865
|
+
import { join as join114 } from "node:path";
|
|
77826
78866
|
|
|
77827
78867
|
// src/shared/progress-bar.ts
|
|
77828
78868
|
init_output_manager();
|
|
@@ -78032,7 +79072,7 @@ var MAX_DOWNLOAD_SIZE = 500 * 1024 * 1024;
|
|
|
78032
79072
|
class FileDownloader {
|
|
78033
79073
|
async downloadAsset(asset, destDir) {
|
|
78034
79074
|
try {
|
|
78035
|
-
const destPath =
|
|
79075
|
+
const destPath = join114(destDir, asset.name);
|
|
78036
79076
|
await mkdir21(destDir, { recursive: true });
|
|
78037
79077
|
output.info(`Downloading ${asset.name} (${formatBytes(asset.size)})...`);
|
|
78038
79078
|
logger.verbose("Download details", {
|
|
@@ -78090,7 +79130,7 @@ class FileDownloader {
|
|
|
78090
79130
|
fileStream.end();
|
|
78091
79131
|
await new Promise((resolve24) => fileStream.once("close", resolve24));
|
|
78092
79132
|
try {
|
|
78093
|
-
|
|
79133
|
+
rmSync8(destPath, { force: true });
|
|
78094
79134
|
} catch (cleanupError) {
|
|
78095
79135
|
const errorMsg = cleanupError instanceof Error ? cleanupError.message : String(cleanupError);
|
|
78096
79136
|
logger.debug(`Failed to clean up partial download ${destPath}: ${errorMsg}`);
|
|
@@ -78104,7 +79144,7 @@ class FileDownloader {
|
|
|
78104
79144
|
fileStream.end();
|
|
78105
79145
|
await new Promise((resolve24) => fileStream.once("close", resolve24));
|
|
78106
79146
|
try {
|
|
78107
|
-
|
|
79147
|
+
rmSync8(destPath, { force: true });
|
|
78108
79148
|
} catch (cleanupError) {
|
|
78109
79149
|
const errorMsg = cleanupError instanceof Error ? cleanupError.message : String(cleanupError);
|
|
78110
79150
|
logger.debug(`Failed to clean up partial download ${destPath}: ${errorMsg}`);
|
|
@@ -78117,7 +79157,7 @@ class FileDownloader {
|
|
|
78117
79157
|
}
|
|
78118
79158
|
async downloadFile(params) {
|
|
78119
79159
|
const { url, name: name2, size, destDir, token } = params;
|
|
78120
|
-
const destPath =
|
|
79160
|
+
const destPath = join114(destDir, name2);
|
|
78121
79161
|
await mkdir21(destDir, { recursive: true });
|
|
78122
79162
|
output.info(`Downloading ${name2}${size ? ` (${formatBytes(size)})` : ""}...`);
|
|
78123
79163
|
const headers = {};
|
|
@@ -78187,7 +79227,7 @@ class FileDownloader {
|
|
|
78187
79227
|
fileStream.end();
|
|
78188
79228
|
await new Promise((resolve24) => fileStream.once("close", resolve24));
|
|
78189
79229
|
try {
|
|
78190
|
-
|
|
79230
|
+
rmSync8(destPath, { force: true });
|
|
78191
79231
|
} catch (cleanupError) {
|
|
78192
79232
|
const errorMsg = cleanupError instanceof Error ? cleanupError.message : String(cleanupError);
|
|
78193
79233
|
logger.debug(`Failed to clean up partial download ${destPath}: ${errorMsg}`);
|
|
@@ -78205,7 +79245,7 @@ class FileDownloader {
|
|
|
78205
79245
|
fileStream.end();
|
|
78206
79246
|
await new Promise((resolve24) => fileStream.once("close", resolve24));
|
|
78207
79247
|
try {
|
|
78208
|
-
|
|
79248
|
+
rmSync8(destPath, { force: true });
|
|
78209
79249
|
} catch (cleanupError) {
|
|
78210
79250
|
const errorMsg = cleanupError instanceof Error ? cleanupError.message : String(cleanupError);
|
|
78211
79251
|
logger.debug(`Failed to clean up partial download ${destPath}: ${errorMsg}`);
|
|
@@ -78220,7 +79260,7 @@ init_logger();
|
|
|
78220
79260
|
init_types2();
|
|
78221
79261
|
import { constants as constants3 } from "node:fs";
|
|
78222
79262
|
import { access as access3, readdir as readdir26 } from "node:fs/promises";
|
|
78223
|
-
import { join as
|
|
79263
|
+
import { join as join115 } from "node:path";
|
|
78224
79264
|
async function validateExtraction(extractDir) {
|
|
78225
79265
|
try {
|
|
78226
79266
|
const entries = await readdir26(extractDir, { encoding: "utf8" });
|
|
@@ -78232,7 +79272,7 @@ async function validateExtraction(extractDir) {
|
|
|
78232
79272
|
const missingPaths = [];
|
|
78233
79273
|
for (const path10 of criticalPaths) {
|
|
78234
79274
|
try {
|
|
78235
|
-
await access3(
|
|
79275
|
+
await access3(join115(extractDir, path10), constants3.F_OK);
|
|
78236
79276
|
logger.debug(`Found: ${path10}`);
|
|
78237
79277
|
} catch {
|
|
78238
79278
|
logger.warning(`Expected path not found: ${path10}`);
|
|
@@ -78254,7 +79294,7 @@ async function validateExtraction(extractDir) {
|
|
|
78254
79294
|
// src/domains/installation/extraction/tar-extractor.ts
|
|
78255
79295
|
init_logger();
|
|
78256
79296
|
import { copyFile as copyFile5, mkdir as mkdir23, readdir as readdir28, rm as rm8, stat as stat9 } from "node:fs/promises";
|
|
78257
|
-
import { join as
|
|
79297
|
+
import { join as join117 } from "node:path";
|
|
78258
79298
|
|
|
78259
79299
|
// node_modules/tar/dist/esm/index.min.js
|
|
78260
79300
|
import Kr from "events";
|
|
@@ -81467,7 +82507,7 @@ function decodeFilePath(path10) {
|
|
|
81467
82507
|
init_logger();
|
|
81468
82508
|
init_types2();
|
|
81469
82509
|
import { copyFile as copyFile4, lstat as lstat8, mkdir as mkdir22, readdir as readdir27 } from "node:fs/promises";
|
|
81470
|
-
import { join as
|
|
82510
|
+
import { join as join116, relative as relative17 } from "node:path";
|
|
81471
82511
|
async function withRetry2(fn2, retries = 3) {
|
|
81472
82512
|
for (let i = 0;i < retries; i++) {
|
|
81473
82513
|
try {
|
|
@@ -81489,8 +82529,8 @@ async function moveDirectoryContents(sourceDir, destDir, shouldExclude, sizeTrac
|
|
|
81489
82529
|
await mkdir22(destDir, { recursive: true });
|
|
81490
82530
|
const entries = await readdir27(sourceDir, { encoding: "utf8" });
|
|
81491
82531
|
for (const entry of entries) {
|
|
81492
|
-
const sourcePath =
|
|
81493
|
-
const destPath =
|
|
82532
|
+
const sourcePath = join116(sourceDir, entry);
|
|
82533
|
+
const destPath = join116(destDir, entry);
|
|
81494
82534
|
const relativePath = relative17(sourceDir, sourcePath);
|
|
81495
82535
|
if (!isPathSafe(destDir, destPath)) {
|
|
81496
82536
|
logger.warning(`Skipping unsafe path: ${relativePath}`);
|
|
@@ -81517,8 +82557,8 @@ async function copyDirectory(sourceDir, destDir, shouldExclude, sizeTracker) {
|
|
|
81517
82557
|
await mkdir22(destDir, { recursive: true });
|
|
81518
82558
|
const entries = await readdir27(sourceDir, { encoding: "utf8" });
|
|
81519
82559
|
for (const entry of entries) {
|
|
81520
|
-
const sourcePath =
|
|
81521
|
-
const destPath =
|
|
82560
|
+
const sourcePath = join116(sourceDir, entry);
|
|
82561
|
+
const destPath = join116(destDir, entry);
|
|
81522
82562
|
const relativePath = relative17(sourceDir, sourcePath);
|
|
81523
82563
|
if (!isPathSafe(destDir, destPath)) {
|
|
81524
82564
|
logger.warning(`Skipping unsafe path: ${relativePath}`);
|
|
@@ -81573,7 +82613,7 @@ class TarExtractor {
|
|
|
81573
82613
|
logger.debug(`Root entries: ${entries.join(", ")}`);
|
|
81574
82614
|
if (entries.length === 1) {
|
|
81575
82615
|
const rootEntry = entries[0];
|
|
81576
|
-
const rootPath =
|
|
82616
|
+
const rootPath = join117(tempExtractDir, rootEntry);
|
|
81577
82617
|
const rootStat = await stat9(rootPath);
|
|
81578
82618
|
if (rootStat.isDirectory()) {
|
|
81579
82619
|
const rootContents = await readdir28(rootPath, { encoding: "utf8" });
|
|
@@ -81589,7 +82629,7 @@ class TarExtractor {
|
|
|
81589
82629
|
}
|
|
81590
82630
|
} else {
|
|
81591
82631
|
await mkdir23(destDir, { recursive: true });
|
|
81592
|
-
await copyFile5(rootPath,
|
|
82632
|
+
await copyFile5(rootPath, join117(destDir, rootEntry));
|
|
81593
82633
|
}
|
|
81594
82634
|
} else {
|
|
81595
82635
|
logger.debug("Multiple root entries - moving all");
|
|
@@ -81610,7 +82650,7 @@ class TarExtractor {
|
|
|
81610
82650
|
init_logger();
|
|
81611
82651
|
import { createWriteStream as createWriteStream3 } from "node:fs";
|
|
81612
82652
|
import { chmod as chmod4, copyFile as copyFile6, mkdir as mkdir24, readdir as readdir29, rm as rm9, stat as stat10 } from "node:fs/promises";
|
|
81613
|
-
import { dirname as dirname31, join as
|
|
82653
|
+
import { dirname as dirname31, join as join118, resolve as resolve24 } from "node:path";
|
|
81614
82654
|
import { pipeline } from "node:stream/promises";
|
|
81615
82655
|
import yauzl from "yauzl-promise";
|
|
81616
82656
|
class ZipExtractor {
|
|
@@ -81624,7 +82664,7 @@ class ZipExtractor {
|
|
|
81624
82664
|
logger.debug(`Root entries: ${entries.join(", ")}`);
|
|
81625
82665
|
if (entries.length === 1) {
|
|
81626
82666
|
const rootEntry = entries[0];
|
|
81627
|
-
const rootPath =
|
|
82667
|
+
const rootPath = join118(tempExtractDir, rootEntry);
|
|
81628
82668
|
const rootStat = await stat10(rootPath);
|
|
81629
82669
|
if (rootStat.isDirectory()) {
|
|
81630
82670
|
const rootContents = await readdir29(rootPath, { encoding: "utf8" });
|
|
@@ -81640,7 +82680,7 @@ class ZipExtractor {
|
|
|
81640
82680
|
}
|
|
81641
82681
|
} else {
|
|
81642
82682
|
await mkdir24(destDir, { recursive: true });
|
|
81643
|
-
await copyFile6(rootPath,
|
|
82683
|
+
await copyFile6(rootPath, join118(destDir, rootEntry));
|
|
81644
82684
|
}
|
|
81645
82685
|
} else {
|
|
81646
82686
|
logger.debug("Multiple root entries - moving all");
|
|
@@ -81769,7 +82809,7 @@ class DownloadManager {
|
|
|
81769
82809
|
async createTempDir() {
|
|
81770
82810
|
const timestamp = Date.now();
|
|
81771
82811
|
const counter = DownloadManager.tempDirCounter++;
|
|
81772
|
-
const primaryTempDir =
|
|
82812
|
+
const primaryTempDir = join119(tmpdir5(), `takumi-${timestamp}-${counter}`);
|
|
81773
82813
|
try {
|
|
81774
82814
|
await mkdir25(primaryTempDir, { recursive: true });
|
|
81775
82815
|
logger.debug(`Created temp directory: ${primaryTempDir}`);
|
|
@@ -81786,7 +82826,7 @@ Solutions:
|
|
|
81786
82826
|
2. Set HOME environment variable
|
|
81787
82827
|
3. Try running from a different directory`);
|
|
81788
82828
|
}
|
|
81789
|
-
const fallbackTempDir =
|
|
82829
|
+
const fallbackTempDir = join119(homeDir, ".sunagentkit", "tmp", `takumi-${timestamp}-${counter}`);
|
|
81790
82830
|
try {
|
|
81791
82831
|
await mkdir25(fallbackTempDir, { recursive: true });
|
|
81792
82832
|
logger.debug(`Created temp directory (fallback): ${fallbackTempDir}`);
|
|
@@ -82493,7 +83533,7 @@ Re-run with explicit base kit, e.g. --kit ${BASE_KIT} --kit ${parsed2.join(" --k
|
|
|
82493
83533
|
}
|
|
82494
83534
|
// src/commands/init/phases/selection-handler.ts
|
|
82495
83535
|
import { mkdir as mkdir26 } from "node:fs/promises";
|
|
82496
|
-
import { join as
|
|
83536
|
+
import { join as join123, resolve as resolve28 } from "node:path";
|
|
82497
83537
|
|
|
82498
83538
|
// src/commands/shared/agent-selector.ts
|
|
82499
83539
|
init_registry();
|
|
@@ -82646,8 +83686,8 @@ init_logger();
|
|
|
82646
83686
|
init_safe_spinner();
|
|
82647
83687
|
init_takumi_constants();
|
|
82648
83688
|
var import_fs_extra34 = __toESM(require_lib(), 1);
|
|
82649
|
-
import { existsSync as
|
|
82650
|
-
import { dirname as dirname34, join as
|
|
83689
|
+
import { existsSync as existsSync59, readdirSync as readdirSync10, rmSync as rmSync9, rmdirSync as rmdirSync2, unlinkSync as unlinkSync6 } from "node:fs";
|
|
83690
|
+
import { dirname as dirname34, join as join122, resolve as resolve27 } from "node:path";
|
|
82651
83691
|
var TAKUMI_SUBDIRECTORIES = ["commands", "agents", "skills", "rules", "hooks"];
|
|
82652
83692
|
async function analyzeFreshInstallation(claudeDir) {
|
|
82653
83693
|
const metadata = await readManifest(claudeDir);
|
|
@@ -82696,7 +83736,7 @@ function cleanupEmptyDirectories2(filePath, claudeDir) {
|
|
|
82696
83736
|
let currentDir = resolve27(dirname34(filePath));
|
|
82697
83737
|
while (currentDir !== normalizedClaudeDir && currentDir.startsWith(normalizedClaudeDir)) {
|
|
82698
83738
|
try {
|
|
82699
|
-
const entries =
|
|
83739
|
+
const entries = readdirSync10(currentDir);
|
|
82700
83740
|
if (entries.length === 0) {
|
|
82701
83741
|
rmdirSync2(currentDir);
|
|
82702
83742
|
logger.debug(`Removed empty directory: ${currentDir}`);
|
|
@@ -82717,9 +83757,9 @@ async function removeFilesByOwnership(claudeDir, analysis, includeModified) {
|
|
|
82717
83757
|
const filesToRemove = includeModified ? [...analysis.ckFiles, ...analysis.ckModifiedFiles] : analysis.ckFiles;
|
|
82718
83758
|
const filesToPreserve = includeModified ? analysis.userFiles : [...analysis.ckModifiedFiles, ...analysis.userFiles];
|
|
82719
83759
|
for (const file of filesToRemove) {
|
|
82720
|
-
const fullPath =
|
|
83760
|
+
const fullPath = join122(claudeDir, file.path);
|
|
82721
83761
|
try {
|
|
82722
|
-
if (
|
|
83762
|
+
if (existsSync59(fullPath)) {
|
|
82723
83763
|
unlinkSync6(fullPath);
|
|
82724
83764
|
removedFiles.push(file.path);
|
|
82725
83765
|
logger.debug(`Removed: ${file.path}`);
|
|
@@ -82791,9 +83831,9 @@ async function removeSubdirectoriesFallback(claudeDir) {
|
|
|
82791
83831
|
const removedFiles = [];
|
|
82792
83832
|
let removedDirCount = 0;
|
|
82793
83833
|
for (const subdir of TAKUMI_SUBDIRECTORIES) {
|
|
82794
|
-
const subdirPath =
|
|
83834
|
+
const subdirPath = join122(claudeDir, subdir);
|
|
82795
83835
|
if (await import_fs_extra34.pathExists(subdirPath)) {
|
|
82796
|
-
|
|
83836
|
+
rmSync9(subdirPath, { recursive: true, force: true });
|
|
82797
83837
|
removedDirCount++;
|
|
82798
83838
|
removedFiles.push(`${subdir}/ (entire directory)`);
|
|
82799
83839
|
logger.debug(`Removed subdirectory: ${subdir}/`);
|
|
@@ -83016,7 +84056,7 @@ async function handleSelection(ctx) {
|
|
|
83016
84056
|
}
|
|
83017
84057
|
if (!ctx.options.fresh) {
|
|
83018
84058
|
const prefix = PathResolver.getPathPrefix(ctx.options.global);
|
|
83019
|
-
const claudeDir = prefix ?
|
|
84059
|
+
const claudeDir = prefix ? join123(resolvedDir, prefix) : resolvedDir;
|
|
83020
84060
|
try {
|
|
83021
84061
|
const existingMetadata = await readManifest(claudeDir);
|
|
83022
84062
|
if (existingMetadata?.kits) {
|
|
@@ -83049,7 +84089,7 @@ async function handleSelection(ctx) {
|
|
|
83049
84089
|
}
|
|
83050
84090
|
if (ctx.options.fresh) {
|
|
83051
84091
|
const prefix = PathResolver.getPathPrefix(ctx.options.global);
|
|
83052
|
-
const claudeDir = prefix ?
|
|
84092
|
+
const claudeDir = prefix ? join123(resolvedDir, prefix) : resolvedDir;
|
|
83053
84093
|
const canProceed = await handleFreshInstallation(claudeDir, ctx.prompts);
|
|
83054
84094
|
if (!canProceed) {
|
|
83055
84095
|
return { ...ctx, cancelled: true };
|
|
@@ -83069,7 +84109,7 @@ async function handleSelection(ctx) {
|
|
|
83069
84109
|
let currentVersion = null;
|
|
83070
84110
|
try {
|
|
83071
84111
|
const prefix = PathResolver.getPathPrefix(ctx.options.global);
|
|
83072
|
-
const claudeDir = prefix ?
|
|
84112
|
+
const claudeDir = prefix ? join123(resolvedDir, prefix) : resolvedDir;
|
|
83073
84113
|
const existingMetadata = await readManifest(claudeDir);
|
|
83074
84114
|
currentVersion = existingMetadata?.kits?.[kitType]?.version || null;
|
|
83075
84115
|
if (currentVersion) {
|
|
@@ -83157,7 +84197,7 @@ async function handleSelection(ctx) {
|
|
|
83157
84197
|
if (ctx.options.yes && !ctx.options.fresh && !ctx.options.force && releaseTag && !isOfflineMode) {
|
|
83158
84198
|
try {
|
|
83159
84199
|
const prefix = PathResolver.getPathPrefix(ctx.options.global);
|
|
83160
|
-
const claudeDir = prefix ?
|
|
84200
|
+
const claudeDir = prefix ? join123(resolvedDir, prefix) : resolvedDir;
|
|
83161
84201
|
const existingMetadata = await readManifest(claudeDir);
|
|
83162
84202
|
const installedKitVersion = existingMetadata?.kits?.[kitType]?.version;
|
|
83163
84203
|
if (installedKitVersion && versionsMatch(installedKitVersion, releaseTag)) {
|
|
@@ -83180,7 +84220,7 @@ async function handleSelection(ctx) {
|
|
|
83180
84220
|
let currentSecondaryVersion = null;
|
|
83181
84221
|
try {
|
|
83182
84222
|
const prefix = PathResolver.getPathPrefix(ctx.options.global);
|
|
83183
|
-
const claudeDir = prefix ?
|
|
84223
|
+
const claudeDir = prefix ? join123(resolvedDir, prefix) : resolvedDir;
|
|
83184
84224
|
const existingMetadata = await readManifest(claudeDir);
|
|
83185
84225
|
currentSecondaryVersion = existingMetadata?.kits?.[secondaryKit]?.version || null;
|
|
83186
84226
|
} catch {}
|
|
@@ -83264,12 +84304,12 @@ function resolveGlobalTargetDir(targetAgents2) {
|
|
|
83264
84304
|
// src/commands/init/phases/sync-handler.ts
|
|
83265
84305
|
init_paths();
|
|
83266
84306
|
import { copyFile as copyFile7, mkdir as mkdir28, open as open3, readFile as readFile43, rename as rename8, stat as stat13, unlink as unlink11, writeFile as writeFile29 } from "node:fs/promises";
|
|
83267
|
-
import { dirname as dirname35, join as
|
|
84307
|
+
import { dirname as dirname35, join as join126, resolve as resolve29 } from "node:path";
|
|
83268
84308
|
|
|
83269
84309
|
// src/domains/sync/config-version-checker.ts
|
|
83270
84310
|
init_auth_client();
|
|
83271
84311
|
import { mkdir as mkdir27, readFile as readFile41, unlink as unlink10, writeFile as writeFile28 } from "node:fs/promises";
|
|
83272
|
-
import { join as
|
|
84312
|
+
import { join as join124 } from "node:path";
|
|
83273
84313
|
init_version_utils();
|
|
83274
84314
|
init_logger();
|
|
83275
84315
|
init_path_resolver();
|
|
@@ -83305,12 +84345,12 @@ var CACHE_FILENAME = "config-update-cache.json";
|
|
|
83305
84345
|
class ConfigVersionChecker {
|
|
83306
84346
|
static getCacheFilePath(kitType, global3) {
|
|
83307
84347
|
const cacheDir = PathResolver.getCacheDir(global3);
|
|
83308
|
-
return
|
|
84348
|
+
return join124(cacheDir, `${kitType}-${CACHE_FILENAME}`);
|
|
83309
84349
|
}
|
|
83310
84350
|
static async loadCache(kitType, global3) {
|
|
83311
84351
|
try {
|
|
83312
|
-
const
|
|
83313
|
-
const data = await readFile41(
|
|
84352
|
+
const cachePath2 = ConfigVersionChecker.getCacheFilePath(kitType, global3);
|
|
84353
|
+
const data = await readFile41(cachePath2, "utf8");
|
|
83314
84354
|
const parsed = JSON.parse(data);
|
|
83315
84355
|
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) {
|
|
83316
84356
|
logger.debug("Invalid cache structure, ignoring");
|
|
@@ -83323,10 +84363,10 @@ class ConfigVersionChecker {
|
|
|
83323
84363
|
}
|
|
83324
84364
|
static async saveCache(kitType, global3, cache3) {
|
|
83325
84365
|
try {
|
|
83326
|
-
const
|
|
84366
|
+
const cachePath2 = ConfigVersionChecker.getCacheFilePath(kitType, global3);
|
|
83327
84367
|
const cacheDir = PathResolver.getCacheDir(global3);
|
|
83328
84368
|
await mkdir27(cacheDir, { recursive: true });
|
|
83329
|
-
await writeFile28(
|
|
84369
|
+
await writeFile28(cachePath2, JSON.stringify(cache3, null, 2));
|
|
83330
84370
|
} catch (error) {
|
|
83331
84371
|
logger.debug(`Cache write failed: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
83332
84372
|
}
|
|
@@ -83410,9 +84450,9 @@ class ConfigVersionChecker {
|
|
|
83410
84450
|
};
|
|
83411
84451
|
}
|
|
83412
84452
|
static async clearCache(kitType, global3 = false) {
|
|
83413
|
-
const
|
|
84453
|
+
const cachePath2 = ConfigVersionChecker.getCacheFilePath(kitType, global3);
|
|
83414
84454
|
try {
|
|
83415
|
-
await unlink10(
|
|
84455
|
+
await unlink10(cachePath2);
|
|
83416
84456
|
logger.debug(`Cleared sync cache for ${kitType}`);
|
|
83417
84457
|
} catch (error) {
|
|
83418
84458
|
if (error.code !== "ENOENT") {
|
|
@@ -83425,7 +84465,7 @@ class ConfigVersionChecker {
|
|
|
83425
84465
|
init_ownership_checker();
|
|
83426
84466
|
init_logger();
|
|
83427
84467
|
import { lstat as lstat9, readFile as readFile42, readlink, realpath as realpath3, stat as stat12 } from "node:fs/promises";
|
|
83428
|
-
import { isAbsolute as isAbsolute5, join as
|
|
84468
|
+
import { isAbsolute as isAbsolute5, join as join125, normalize as normalize9, relative as relative18 } from "node:path";
|
|
83429
84469
|
var MAX_SYNC_FILE_SIZE = 10 * 1024 * 1024;
|
|
83430
84470
|
var MAX_SYMLINK_DEPTH = 20;
|
|
83431
84471
|
async function validateSymlinkChain(path11, basePath, maxDepth = MAX_SYMLINK_DEPTH) {
|
|
@@ -83437,7 +84477,7 @@ async function validateSymlinkChain(path11, basePath, maxDepth = MAX_SYMLINK_DEP
|
|
|
83437
84477
|
if (!stats.isSymbolicLink())
|
|
83438
84478
|
break;
|
|
83439
84479
|
const target = await readlink(current);
|
|
83440
|
-
const resolvedTarget = isAbsolute5(target) ? target :
|
|
84480
|
+
const resolvedTarget = isAbsolute5(target) ? target : join125(current, "..", target);
|
|
83441
84481
|
const normalizedTarget = normalize9(resolvedTarget);
|
|
83442
84482
|
const rel = relative18(basePath, normalizedTarget);
|
|
83443
84483
|
if (rel.startsWith("..") || isAbsolute5(rel)) {
|
|
@@ -83473,7 +84513,7 @@ async function validateSyncPath(basePath, filePath) {
|
|
|
83473
84513
|
if (normalized.startsWith("..") || normalized.includes("/../")) {
|
|
83474
84514
|
throw new Error(`Path traversal not allowed: ${filePath}`);
|
|
83475
84515
|
}
|
|
83476
|
-
const fullPath =
|
|
84516
|
+
const fullPath = join125(basePath, normalized);
|
|
83477
84517
|
const rel = relative18(basePath, fullPath);
|
|
83478
84518
|
if (rel.startsWith("..") || isAbsolute5(rel)) {
|
|
83479
84519
|
throw new Error(`Path escapes base directory: ${filePath}`);
|
|
@@ -83488,7 +84528,7 @@ async function validateSyncPath(basePath, filePath) {
|
|
|
83488
84528
|
}
|
|
83489
84529
|
} catch (error) {
|
|
83490
84530
|
if (error.code === "ENOENT") {
|
|
83491
|
-
const parentPath =
|
|
84531
|
+
const parentPath = join125(fullPath, "..");
|
|
83492
84532
|
try {
|
|
83493
84533
|
const resolvedBase = await realpath3(basePath);
|
|
83494
84534
|
const resolvedParent = await realpath3(parentPath);
|
|
@@ -83979,7 +85019,7 @@ function getLockTimeout() {
|
|
|
83979
85019
|
var STALE_LOCK_THRESHOLD_MS = 5 * 60 * 1000;
|
|
83980
85020
|
async function acquireSyncLock(global3) {
|
|
83981
85021
|
const cacheDir = PathResolver.getCacheDir(global3);
|
|
83982
|
-
const lockPath2 =
|
|
85022
|
+
const lockPath2 = join126(cacheDir, ".sync-lock");
|
|
83983
85023
|
const startTime = Date.now();
|
|
83984
85024
|
const lockTimeout = getLockTimeout();
|
|
83985
85025
|
await mkdir28(dirname35(lockPath2), { recursive: true });
|
|
@@ -84060,7 +85100,7 @@ async function executeSyncMerge(ctx) {
|
|
|
84060
85100
|
try {
|
|
84061
85101
|
const sourcePath = await validateSyncPath(upstreamDir, file.path);
|
|
84062
85102
|
const targetPath = await validateSyncPath(ctx.claudeDir, file.path);
|
|
84063
|
-
const targetDir =
|
|
85103
|
+
const targetDir = join126(targetPath, "..");
|
|
84064
85104
|
try {
|
|
84065
85105
|
await mkdir28(targetDir, { recursive: true });
|
|
84066
85106
|
} catch (mkdirError) {
|
|
@@ -84231,7 +85271,7 @@ async function createBackup(claudeDir, files, backupDir) {
|
|
|
84231
85271
|
const sourcePath = await validateSyncPath(claudeDir, file.path);
|
|
84232
85272
|
if (await import_fs_extra36.pathExists(sourcePath)) {
|
|
84233
85273
|
const targetPath = await validateSyncPath(backupDir, file.path);
|
|
84234
|
-
const targetDir =
|
|
85274
|
+
const targetDir = join126(targetPath, "..");
|
|
84235
85275
|
await mkdir28(targetDir, { recursive: true });
|
|
84236
85276
|
await copyFile7(sourcePath, targetPath);
|
|
84237
85277
|
}
|
|
@@ -84257,38 +85297,38 @@ init_logger();
|
|
|
84257
85297
|
init_types2();
|
|
84258
85298
|
var import_fs_extra37 = __toESM(require_lib(), 1);
|
|
84259
85299
|
import { rename as rename9, rm as rm10 } from "node:fs/promises";
|
|
84260
|
-
import { join as
|
|
85300
|
+
import { join as join127, relative as relative19 } from "node:path";
|
|
84261
85301
|
async function collectDirsToRename(extractDir, folders) {
|
|
84262
85302
|
const dirsToRename = [];
|
|
84263
85303
|
if (folders.docs !== DEFAULT_FOLDERS.docs) {
|
|
84264
|
-
const docsPath =
|
|
85304
|
+
const docsPath = join127(extractDir, DEFAULT_FOLDERS.docs);
|
|
84265
85305
|
if (await import_fs_extra37.pathExists(docsPath)) {
|
|
84266
85306
|
dirsToRename.push({
|
|
84267
85307
|
from: docsPath,
|
|
84268
|
-
to:
|
|
85308
|
+
to: join127(extractDir, folders.docs)
|
|
84269
85309
|
});
|
|
84270
85310
|
}
|
|
84271
|
-
const claudeDocsPath =
|
|
85311
|
+
const claudeDocsPath = join127(extractDir, ".claude", DEFAULT_FOLDERS.docs);
|
|
84272
85312
|
if (await import_fs_extra37.pathExists(claudeDocsPath)) {
|
|
84273
85313
|
dirsToRename.push({
|
|
84274
85314
|
from: claudeDocsPath,
|
|
84275
|
-
to:
|
|
85315
|
+
to: join127(extractDir, ".claude", folders.docs)
|
|
84276
85316
|
});
|
|
84277
85317
|
}
|
|
84278
85318
|
}
|
|
84279
85319
|
if (folders.plans !== DEFAULT_FOLDERS.plans) {
|
|
84280
|
-
const plansPath =
|
|
85320
|
+
const plansPath = join127(extractDir, DEFAULT_FOLDERS.plans);
|
|
84281
85321
|
if (await import_fs_extra37.pathExists(plansPath)) {
|
|
84282
85322
|
dirsToRename.push({
|
|
84283
85323
|
from: plansPath,
|
|
84284
|
-
to:
|
|
85324
|
+
to: join127(extractDir, folders.plans)
|
|
84285
85325
|
});
|
|
84286
85326
|
}
|
|
84287
|
-
const claudePlansPath =
|
|
85327
|
+
const claudePlansPath = join127(extractDir, ".claude", DEFAULT_FOLDERS.plans);
|
|
84288
85328
|
if (await import_fs_extra37.pathExists(claudePlansPath)) {
|
|
84289
85329
|
dirsToRename.push({
|
|
84290
85330
|
from: claudePlansPath,
|
|
84291
|
-
to:
|
|
85331
|
+
to: join127(extractDir, ".claude", folders.plans)
|
|
84292
85332
|
});
|
|
84293
85333
|
}
|
|
84294
85334
|
}
|
|
@@ -84329,7 +85369,7 @@ async function renameFolders(dirsToRename, extractDir, options2) {
|
|
|
84329
85369
|
init_logger();
|
|
84330
85370
|
init_types2();
|
|
84331
85371
|
import { readFile as readFile44, readdir as readdir30, writeFile as writeFile30 } from "node:fs/promises";
|
|
84332
|
-
import { join as
|
|
85372
|
+
import { join as join128, relative as relative20 } from "node:path";
|
|
84333
85373
|
var TRANSFORMABLE_FILE_PATTERNS = [
|
|
84334
85374
|
".md",
|
|
84335
85375
|
".txt",
|
|
@@ -84382,7 +85422,7 @@ async function transformFileContents(dir, compiledReplacements, options2) {
|
|
|
84382
85422
|
let replacementsCount = 0;
|
|
84383
85423
|
const entries = await readdir30(dir, { withFileTypes: true });
|
|
84384
85424
|
for (const entry of entries) {
|
|
84385
|
-
const fullPath =
|
|
85425
|
+
const fullPath = join128(dir, entry.name);
|
|
84386
85426
|
if (entry.isDirectory()) {
|
|
84387
85427
|
if (entry.name === "node_modules" || entry.name === ".git") {
|
|
84388
85428
|
continue;
|
|
@@ -84518,9 +85558,9 @@ async function transformFolderPaths(extractDir, folders, options2 = {}) {
|
|
|
84518
85558
|
// src/services/transformers/global-path-transformer.ts
|
|
84519
85559
|
init_logger();
|
|
84520
85560
|
import { readFile as readFile45, readdir as readdir31, writeFile as writeFile31 } from "node:fs/promises";
|
|
84521
|
-
import { platform as
|
|
84522
|
-
import { extname as extname8, join as
|
|
84523
|
-
var IS_WINDOWS3 =
|
|
85561
|
+
import { platform as platform12 } from "node:os";
|
|
85562
|
+
import { extname as extname8, join as join129 } from "node:path";
|
|
85563
|
+
var IS_WINDOWS3 = platform12() === "win32";
|
|
84524
85564
|
var HOME_PREFIX = "$HOME";
|
|
84525
85565
|
function getHomeDirPrefix() {
|
|
84526
85566
|
return HOME_PREFIX;
|
|
@@ -84619,7 +85659,7 @@ async function transformPathsForGlobalInstall(directory, options2 = {}) {
|
|
|
84619
85659
|
async function processDirectory2(dir) {
|
|
84620
85660
|
const entries = await readdir31(dir, { withFileTypes: true });
|
|
84621
85661
|
for (const entry of entries) {
|
|
84622
|
-
const fullPath =
|
|
85662
|
+
const fullPath = join129(dir, entry.name);
|
|
84623
85663
|
if (entry.isDirectory()) {
|
|
84624
85664
|
if (entry.name === "node_modules" || entry.name.startsWith(".") && entry.name !== ".claude") {
|
|
84625
85665
|
continue;
|
|
@@ -84912,8 +85952,8 @@ init_dist2();
|
|
|
84912
85952
|
|
|
84913
85953
|
// src/domains/mcp/agent-detector.ts
|
|
84914
85954
|
init_environment();
|
|
84915
|
-
import { existsSync as
|
|
84916
|
-
import { join as
|
|
85955
|
+
import { existsSync as existsSync60 } from "node:fs";
|
|
85956
|
+
import { join as join130 } from "node:path";
|
|
84917
85957
|
|
|
84918
85958
|
// src/domains/mcp/shell-out.ts
|
|
84919
85959
|
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
@@ -85003,9 +86043,9 @@ function getAgentConfigPath(agent) {
|
|
|
85003
86043
|
return null;
|
|
85004
86044
|
switch (agent) {
|
|
85005
86045
|
case "claude-code":
|
|
85006
|
-
return
|
|
86046
|
+
return join130(home6, ".claude.json");
|
|
85007
86047
|
case "codex":
|
|
85008
|
-
return
|
|
86048
|
+
return join130(home6, ".codex", "config.toml");
|
|
85009
86049
|
default: {
|
|
85010
86050
|
const _exhaustive = agent;
|
|
85011
86051
|
return _exhaustive;
|
|
@@ -85014,7 +86054,7 @@ function getAgentConfigPath(agent) {
|
|
|
85014
86054
|
}
|
|
85015
86055
|
var defaultCheckers = {
|
|
85016
86056
|
binaryOnPath: isBinaryOnPath,
|
|
85017
|
-
configExists:
|
|
86057
|
+
configExists: existsSync60
|
|
85018
86058
|
};
|
|
85019
86059
|
function isAgentPresent(agent, checkers = defaultCheckers) {
|
|
85020
86060
|
if (checkers.binaryOnPath(AGENT_BINARY[agent])) {
|
|
@@ -85030,8 +86070,8 @@ var PROJECT_MARKERS = {
|
|
|
85030
86070
|
"claude-code": [".claude", "CLAUDE.md"],
|
|
85031
86071
|
codex: [".codex", "AGENTS.md"]
|
|
85032
86072
|
};
|
|
85033
|
-
function detectProjectAgents(cwd2 = process.cwd(), exists2 =
|
|
85034
|
-
return ALL_MCP_AGENTS.filter((agent) => PROJECT_MARKERS[agent].some((marker) => exists2(
|
|
86073
|
+
function detectProjectAgents(cwd2 = process.cwd(), exists2 = existsSync60) {
|
|
86074
|
+
return ALL_MCP_AGENTS.filter((agent) => PROJECT_MARKERS[agent].some((marker) => exists2(join130(cwd2, marker))));
|
|
85035
86075
|
}
|
|
85036
86076
|
|
|
85037
86077
|
// src/domains/mcp/registry-client.ts
|
|
@@ -85043,12 +86083,12 @@ init_auth_client();
|
|
|
85043
86083
|
init_logger();
|
|
85044
86084
|
init_paths2();
|
|
85045
86085
|
import { promises as fs33 } from "node:fs";
|
|
85046
|
-
import { join as
|
|
86086
|
+
import { join as join131 } from "node:path";
|
|
85047
86087
|
function getCacheDir() {
|
|
85048
|
-
return
|
|
86088
|
+
return join131(getConfigDir(), "mcp");
|
|
85049
86089
|
}
|
|
85050
86090
|
function getCachePath2() {
|
|
85051
|
-
return
|
|
86091
|
+
return join131(getCacheDir(), "registry-cache.json");
|
|
85052
86092
|
}
|
|
85053
86093
|
async function readCachedRegistry() {
|
|
85054
86094
|
try {
|
|
@@ -85177,16 +86217,16 @@ function resolveService(registry, name2) {
|
|
|
85177
86217
|
}
|
|
85178
86218
|
|
|
85179
86219
|
// src/domains/mcp/writers/claude-config-file.ts
|
|
85180
|
-
import { existsSync as
|
|
86220
|
+
import { existsSync as existsSync61 } from "node:fs";
|
|
85181
86221
|
import { mkdir as mkdir29, writeFile as writeFile32 } from "node:fs/promises";
|
|
85182
|
-
import { dirname as dirname36, join as
|
|
86222
|
+
import { dirname as dirname36, join as join132 } from "node:path";
|
|
85183
86223
|
var AGENT = "claude-code";
|
|
85184
86224
|
var LOCAL_SCOPE_FALLBACK_WARNING = "claude CLI not found; local scope isn't representable via direct file write, wrote to user-level ~/.claude.json instead";
|
|
85185
86225
|
function userConfigPath() {
|
|
85186
86226
|
return getAgentConfigPath(AGENT);
|
|
85187
86227
|
}
|
|
85188
86228
|
function projectConfigPath() {
|
|
85189
|
-
return
|
|
86229
|
+
return join132(process.cwd(), ".mcp.json");
|
|
85190
86230
|
}
|
|
85191
86231
|
function configPathFor(scope) {
|
|
85192
86232
|
return scope === "project" ? projectConfigPath() : userConfigPath();
|
|
@@ -85225,7 +86265,7 @@ async function fileAdd(entry, scope) {
|
|
|
85225
86265
|
}
|
|
85226
86266
|
async function fileRemove(name2, scope) {
|
|
85227
86267
|
const path11 = configPathFor(scope);
|
|
85228
|
-
if (!path11 || !
|
|
86268
|
+
if (!path11 || !existsSync61(path11)) {
|
|
85229
86269
|
return { agent: AGENT, status: "skipped", detail: "No config file present" };
|
|
85230
86270
|
}
|
|
85231
86271
|
const existing = await readJsonConfigFile(path11);
|
|
@@ -85340,7 +86380,7 @@ var claudeWriter = {
|
|
|
85340
86380
|
|
|
85341
86381
|
// src/domains/mcp/writers/codex-writer.ts
|
|
85342
86382
|
init_path_safety();
|
|
85343
|
-
import { existsSync as
|
|
86383
|
+
import { existsSync as existsSync62 } from "node:fs";
|
|
85344
86384
|
import { readFile as readFile47, writeFile as writeFile33 } from "node:fs/promises";
|
|
85345
86385
|
|
|
85346
86386
|
// src/domains/mcp/writers/codex-config-file.ts
|
|
@@ -85431,7 +86471,7 @@ async function fileAdd2(entry, scope) {
|
|
|
85431
86471
|
}
|
|
85432
86472
|
async function fileRemove2(name2) {
|
|
85433
86473
|
const path11 = configPath();
|
|
85434
|
-
if (!path11 || !
|
|
86474
|
+
if (!path11 || !existsSync62(path11)) {
|
|
85435
86475
|
return { agent: AGENT3, status: "skipped", detail: "No config file present" };
|
|
85436
86476
|
}
|
|
85437
86477
|
try {
|
|
@@ -85510,7 +86550,7 @@ async function remove13(name2, opts) {
|
|
|
85510
86550
|
}
|
|
85511
86551
|
async function listConfigured() {
|
|
85512
86552
|
const path11 = configPath();
|
|
85513
|
-
if (!path11 || !
|
|
86553
|
+
if (!path11 || !existsSync62(path11))
|
|
85514
86554
|
return { has: () => false };
|
|
85515
86555
|
try {
|
|
85516
86556
|
const content = await readFile47(path11, "utf-8");
|
|
@@ -85866,19 +86906,19 @@ async function mcpCommand(action, service, options2 = {}) {
|
|
|
85866
86906
|
}
|
|
85867
86907
|
// src/commands/plan/plan-command.ts
|
|
85868
86908
|
init_output_manager();
|
|
85869
|
-
import { existsSync as
|
|
85870
|
-
import { dirname as dirname42, join as
|
|
86909
|
+
import { existsSync as existsSync67, statSync as statSync12 } from "node:fs";
|
|
86910
|
+
import { dirname as dirname42, join as join136, parse as parse4, resolve as resolve33 } from "node:path";
|
|
85871
86911
|
|
|
85872
86912
|
// src/commands/plan/plan-read-handlers.ts
|
|
85873
|
-
import { existsSync as
|
|
85874
|
-
import { basename as basename21, dirname as dirname41, join as
|
|
86913
|
+
import { existsSync as existsSync66, statSync as statSync11 } from "node:fs";
|
|
86914
|
+
import { basename as basename21, dirname as dirname41, join as join135, relative as relative21, resolve as resolve31 } from "node:path";
|
|
85875
86915
|
|
|
85876
86916
|
// src/domains/plan-parser/index.ts
|
|
85877
86917
|
import { dirname as dirname40 } from "node:path";
|
|
85878
86918
|
|
|
85879
86919
|
// src/domains/plan-parser/plan-table-parser.ts
|
|
85880
86920
|
var import_gray_matter6 = __toESM(require_gray_matter(), 1);
|
|
85881
|
-
import { readFileSync as
|
|
86921
|
+
import { readFileSync as readFileSync24 } from "node:fs";
|
|
85882
86922
|
import { dirname as dirname37, resolve as resolve30 } from "node:path";
|
|
85883
86923
|
function normalizeStatus(raw) {
|
|
85884
86924
|
const s3 = raw.toLowerCase().trim();
|
|
@@ -86244,30 +87284,30 @@ function parsePhasesFromBody(body, dir, options2) {
|
|
|
86244
87284
|
return parseFormat6(normalizedBody, dir, options2);
|
|
86245
87285
|
}
|
|
86246
87286
|
function parsePlanFile(planFilePath, options2) {
|
|
86247
|
-
const content =
|
|
87287
|
+
const content = readFileSync24(planFilePath, "utf8");
|
|
86248
87288
|
const dir = dirname37(planFilePath);
|
|
86249
87289
|
const { data: frontmatter, content: body } = import_gray_matter6.default(content);
|
|
86250
87290
|
const phases = parsePhasesFromBody(body, dir, options2);
|
|
86251
87291
|
return { frontmatter, phases };
|
|
86252
87292
|
}
|
|
86253
87293
|
// src/domains/plan-parser/plan-scanner.ts
|
|
86254
|
-
import { existsSync as
|
|
86255
|
-
import { join as
|
|
87294
|
+
import { existsSync as existsSync63, readdirSync as readdirSync11 } from "node:fs";
|
|
87295
|
+
import { join as join133 } from "node:path";
|
|
86256
87296
|
function scanPlanDir(dir) {
|
|
86257
|
-
if (!
|
|
87297
|
+
if (!existsSync63(dir))
|
|
86258
87298
|
return [];
|
|
86259
87299
|
try {
|
|
86260
|
-
return
|
|
87300
|
+
return readdirSync11(dir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => join133(dir, entry.name, "plan.md")).filter(existsSync63);
|
|
86261
87301
|
} catch {
|
|
86262
87302
|
return [];
|
|
86263
87303
|
}
|
|
86264
87304
|
}
|
|
86265
87305
|
// src/domains/plan-parser/plan-validator.ts
|
|
86266
87306
|
var import_gray_matter7 = __toESM(require_gray_matter(), 1);
|
|
86267
|
-
import { existsSync as
|
|
87307
|
+
import { existsSync as existsSync64, readFileSync as readFileSync25 } from "node:fs";
|
|
86268
87308
|
import { basename as basename19, dirname as dirname38 } from "node:path";
|
|
86269
87309
|
function validatePlanFile(filePath, strict = false) {
|
|
86270
|
-
const content =
|
|
87310
|
+
const content = readFileSync25(filePath, "utf8");
|
|
86271
87311
|
const dir = dirname38(filePath);
|
|
86272
87312
|
const issues = [];
|
|
86273
87313
|
const lines = content.split(`
|
|
@@ -86304,7 +87344,7 @@ function validatePlanFile(filePath, strict = false) {
|
|
|
86304
87344
|
});
|
|
86305
87345
|
}
|
|
86306
87346
|
for (const phase of phases) {
|
|
86307
|
-
if (phase.file && !
|
|
87347
|
+
if (phase.file && !existsSync64(phase.file)) {
|
|
86308
87348
|
const fileBasename = basename19(phase.file);
|
|
86309
87349
|
const refLine = lines.findIndex((l2) => l2.includes(fileBasename));
|
|
86310
87350
|
issues.push({
|
|
@@ -86324,9 +87364,9 @@ function validatePlanFile(filePath, strict = false) {
|
|
|
86324
87364
|
}
|
|
86325
87365
|
// src/domains/plan-parser/plan-writer.ts
|
|
86326
87366
|
var import_gray_matter8 = __toESM(require_gray_matter(), 1);
|
|
86327
|
-
import { mkdirSync as
|
|
86328
|
-
import { existsSync as
|
|
86329
|
-
import { basename as basename20, dirname as dirname39, join as
|
|
87367
|
+
import { mkdirSync as mkdirSync10, readFileSync as readFileSync26, writeFileSync as writeFileSync13 } from "node:fs";
|
|
87368
|
+
import { existsSync as existsSync65 } from "node:fs";
|
|
87369
|
+
import { basename as basename20, dirname as dirname39, join as join134 } from "node:path";
|
|
86330
87370
|
function phaseNameToFilename(id, name2) {
|
|
86331
87371
|
const numMatch = /^(\d+)([a-z]*)$/i.exec(id);
|
|
86332
87372
|
const num4 = numMatch ? numMatch[1] : id;
|
|
@@ -86431,16 +87471,16 @@ function resolvePhaseIds(phases) {
|
|
|
86431
87471
|
}
|
|
86432
87472
|
function scaffoldPlan(options2) {
|
|
86433
87473
|
const { dir } = options2;
|
|
86434
|
-
|
|
87474
|
+
mkdirSync10(dir, { recursive: true });
|
|
86435
87475
|
const resolvedPhases = resolvePhaseIds(options2.phases);
|
|
86436
87476
|
const optionsWithResolved = { ...options2, phases: resolvedPhases };
|
|
86437
|
-
const planFile =
|
|
86438
|
-
|
|
87477
|
+
const planFile = join134(dir, "plan.md");
|
|
87478
|
+
writeFileSync13(planFile, generatePlanMd(optionsWithResolved), "utf8");
|
|
86439
87479
|
const phaseFiles = [];
|
|
86440
87480
|
for (const phase of resolvedPhases) {
|
|
86441
87481
|
const filename = phaseNameToFilename(phase.id, phase.name);
|
|
86442
|
-
const phaseFile =
|
|
86443
|
-
|
|
87482
|
+
const phaseFile = join134(dir, filename);
|
|
87483
|
+
writeFileSync13(phaseFile, generatePhaseTemplate(phase), "utf8");
|
|
86444
87484
|
phaseFiles.push(phaseFile);
|
|
86445
87485
|
}
|
|
86446
87486
|
return { planFile, phaseFiles };
|
|
@@ -86464,7 +87504,7 @@ function isCanonicalFormat(content) {
|
|
|
86464
87504
|
return /^\|\s*phase\s*\|\s*name\s*\|\s*status\s*\|/im.test(content);
|
|
86465
87505
|
}
|
|
86466
87506
|
function updatePhaseStatus(planFile, phaseId, newStatus) {
|
|
86467
|
-
const raw =
|
|
87507
|
+
const raw = readFileSync26(planFile, "utf8").replace(/\r\n/g, `
|
|
86468
87508
|
`);
|
|
86469
87509
|
if (!isCanonicalFormat(raw)) {
|
|
86470
87510
|
console.error("[!] plan.md is not in canonical format — skipping status update");
|
|
@@ -86504,10 +87544,10 @@ function updatePhaseStatus(planFile, phaseId, newStatus) {
|
|
|
86504
87544
|
}
|
|
86505
87545
|
const updatedFrontmatter = { ...frontmatter, status: planStatus };
|
|
86506
87546
|
const updatedContent = import_gray_matter8.default.stringify(updatedBody, updatedFrontmatter);
|
|
86507
|
-
|
|
87547
|
+
writeFileSync13(planFile, updatedContent, "utf8");
|
|
86508
87548
|
const planDir = dirname39(planFile);
|
|
86509
87549
|
const phaseFilename = phaseNameFilenameFromTableRow(updatedBody, phaseId, planDir);
|
|
86510
|
-
if (phaseFilename &&
|
|
87550
|
+
if (phaseFilename && existsSync65(phaseFilename)) {
|
|
86511
87551
|
updatePhaseFileFrontmatter(phaseFilename, newStatus);
|
|
86512
87552
|
}
|
|
86513
87553
|
}
|
|
@@ -86519,18 +87559,18 @@ function phaseNameFilenameFromTableRow(body, phaseId, planDir) {
|
|
|
86519
87559
|
continue;
|
|
86520
87560
|
const linkMatch = /\[([^\]]+)\]\(\.\/([^)]+)\)/.exec(row);
|
|
86521
87561
|
if (linkMatch)
|
|
86522
|
-
return
|
|
87562
|
+
return join134(planDir, linkMatch[2]);
|
|
86523
87563
|
}
|
|
86524
87564
|
return null;
|
|
86525
87565
|
}
|
|
86526
87566
|
function updatePhaseFileFrontmatter(phaseFile, newStatus) {
|
|
86527
|
-
const raw =
|
|
87567
|
+
const raw = readFileSync26(phaseFile, "utf8");
|
|
86528
87568
|
const { data: frontmatter, content: body } = import_gray_matter8.default(raw);
|
|
86529
87569
|
const updated = { ...frontmatter, status: newStatus };
|
|
86530
|
-
|
|
87570
|
+
writeFileSync13(phaseFile, import_gray_matter8.default.stringify(body, updated), "utf8");
|
|
86531
87571
|
}
|
|
86532
87572
|
function addPhase(planFile, name2, afterId) {
|
|
86533
|
-
const raw =
|
|
87573
|
+
const raw = readFileSync26(planFile, "utf8").replace(/\r\n/g, `
|
|
86534
87574
|
`);
|
|
86535
87575
|
if (!isCanonicalFormat(raw)) {
|
|
86536
87576
|
console.error("[!] plan.md is not in canonical format — cannot add phase");
|
|
@@ -86599,9 +87639,9 @@ function addPhase(planFile, name2, afterId) {
|
|
|
86599
87639
|
updatedBody = lines.join(`
|
|
86600
87640
|
`);
|
|
86601
87641
|
}
|
|
86602
|
-
|
|
86603
|
-
const phaseFilePath =
|
|
86604
|
-
|
|
87642
|
+
writeFileSync13(planFile, import_gray_matter8.default.stringify(updatedBody, frontmatter), "utf8");
|
|
87643
|
+
const phaseFilePath = join134(planDir, filename);
|
|
87644
|
+
writeFileSync13(phaseFilePath, generatePhaseTemplate({ id: phaseId, name: name2 }), "utf8");
|
|
86605
87645
|
return { phaseId, phaseFile: phaseFilePath };
|
|
86606
87646
|
}
|
|
86607
87647
|
|
|
@@ -86704,7 +87744,7 @@ async function handleValidate(target, options2) {
|
|
|
86704
87744
|
}
|
|
86705
87745
|
async function handleStatus(target, options2) {
|
|
86706
87746
|
const t = target ? resolve31(target) : null;
|
|
86707
|
-
const plansDir = t &&
|
|
87747
|
+
const plansDir = t && existsSync66(t) && statSync11(t).isDirectory() && !existsSync66(join135(t, "plan.md")) ? t : null;
|
|
86708
87748
|
if (plansDir) {
|
|
86709
87749
|
const planFiles = scanPlanDir(plansDir);
|
|
86710
87750
|
if (planFiles.length === 0) {
|
|
@@ -86935,20 +87975,20 @@ async function handleAddPhase(target, options2) {
|
|
|
86935
87975
|
// src/commands/plan/plan-command.ts
|
|
86936
87976
|
function resolvePlanFile(target) {
|
|
86937
87977
|
const t = target ? resolve33(target) : process.cwd();
|
|
86938
|
-
if (
|
|
86939
|
-
const stat14 =
|
|
87978
|
+
if (existsSync67(t)) {
|
|
87979
|
+
const stat14 = statSync12(t);
|
|
86940
87980
|
if (stat14.isFile())
|
|
86941
87981
|
return t;
|
|
86942
|
-
const candidate =
|
|
86943
|
-
if (
|
|
87982
|
+
const candidate = join136(t, "plan.md");
|
|
87983
|
+
if (existsSync67(candidate))
|
|
86944
87984
|
return candidate;
|
|
86945
87985
|
}
|
|
86946
87986
|
if (!target) {
|
|
86947
87987
|
let dir = process.cwd();
|
|
86948
87988
|
const root = parse4(dir).root;
|
|
86949
87989
|
while (dir !== root) {
|
|
86950
|
-
const candidate =
|
|
86951
|
-
if (
|
|
87990
|
+
const candidate = join136(dir, "plan.md");
|
|
87991
|
+
if (existsSync67(candidate))
|
|
86952
87992
|
return candidate;
|
|
86953
87993
|
dir = dirname42(dir);
|
|
86954
87994
|
}
|
|
@@ -86998,7 +88038,7 @@ async function planCommand(action, target, options2) {
|
|
|
86998
88038
|
let resolvedTarget = target;
|
|
86999
88039
|
if (resolvedAction && !knownActions.has(resolvedAction)) {
|
|
87000
88040
|
const looksLikePath = resolvedAction.includes("/") || resolvedAction.includes("\\") || resolvedAction.endsWith(".md") || resolvedAction === "." || resolvedAction === "..";
|
|
87001
|
-
const existsOnDisk = !looksLikePath &&
|
|
88041
|
+
const existsOnDisk = !looksLikePath && existsSync67(resolve33(resolvedAction));
|
|
87002
88042
|
if (looksLikePath || existsOnDisk) {
|
|
87003
88043
|
resolvedTarget = resolvedAction;
|
|
87004
88044
|
resolvedAction = undefined;
|
|
@@ -87035,6 +88075,791 @@ async function planCommand(action, target, options2) {
|
|
|
87035
88075
|
process.exitCode = 1;
|
|
87036
88076
|
}
|
|
87037
88077
|
}
|
|
88078
|
+
// src/commands/statusline/statusline-command.ts
|
|
88079
|
+
import { appendFileSync as appendFileSync3 } from "node:fs";
|
|
88080
|
+
import { homedir as homedir31 } from "node:os";
|
|
88081
|
+
init_cache_dir();
|
|
88082
|
+
|
|
88083
|
+
// src/domains/statusline/config-loader.ts
|
|
88084
|
+
init_takumi_config_manager();
|
|
88085
|
+
|
|
88086
|
+
// src/domains/statusline/config.ts
|
|
88087
|
+
var PRESET_PROMPTS = {
|
|
88088
|
+
full: "$brand $model $context $quotas $directory $git $activity",
|
|
88089
|
+
compact: "$model $context $quotas $directory $git",
|
|
88090
|
+
minimal: "$model $context $directory",
|
|
88091
|
+
none: ""
|
|
88092
|
+
};
|
|
88093
|
+
var DEFAULT_STATUSLINE_SETTINGS = {
|
|
88094
|
+
prompt: PRESET_PROMPTS.full,
|
|
88095
|
+
brand: {
|
|
88096
|
+
icon: "◆",
|
|
88097
|
+
showCliVersion: true,
|
|
88098
|
+
showCoreVersion: false,
|
|
88099
|
+
color: "magenta",
|
|
88100
|
+
versionColor: "dim"
|
|
88101
|
+
},
|
|
88102
|
+
model: { color: "brightCyan" },
|
|
88103
|
+
context: {
|
|
88104
|
+
barWidth: 10,
|
|
88105
|
+
barStyle: "geometric",
|
|
88106
|
+
showPercent: true,
|
|
88107
|
+
colors: { low: "brightGreen", mid: "brightYellow", high: "brightRed" },
|
|
88108
|
+
thresholds: { mid: 50, high: 80 }
|
|
88109
|
+
},
|
|
88110
|
+
quotas: { windows: ["5h", "week"], barWidth: 0, showCountdown: true, icon: "⏳" },
|
|
88111
|
+
directory: { icon: "\uD83D\uDCC2", collapseHome: true, truncationLength: 3, color: "yellow" },
|
|
88112
|
+
git: {
|
|
88113
|
+
icon: "✦",
|
|
88114
|
+
showDirty: true,
|
|
88115
|
+
dirtyInBrackets: true,
|
|
88116
|
+
showAheadBehind: true,
|
|
88117
|
+
countUntracked: true,
|
|
88118
|
+
branchColor: "magenta"
|
|
88119
|
+
},
|
|
88120
|
+
activity: { maxAgentRows: 4, todoTruncation: 50 },
|
|
88121
|
+
cost: { icon: "\uD83D\uDCB0", hideZero: true }
|
|
88122
|
+
};
|
|
88123
|
+
function isPreset(value) {
|
|
88124
|
+
return value === "full" || value === "compact" || value === "minimal" || value === "none";
|
|
88125
|
+
}
|
|
88126
|
+
function mergeSettings2(base, override) {
|
|
88127
|
+
const o2 = override;
|
|
88128
|
+
return {
|
|
88129
|
+
prompt: o2.prompt ?? base.prompt,
|
|
88130
|
+
brand: { ...base.brand, ...o2.brand },
|
|
88131
|
+
model: { ...base.model, ...o2.model },
|
|
88132
|
+
context: {
|
|
88133
|
+
...base.context,
|
|
88134
|
+
...o2.context,
|
|
88135
|
+
colors: { ...base.context.colors, ...o2.context?.colors },
|
|
88136
|
+
thresholds: { ...base.context.thresholds, ...o2.context?.thresholds }
|
|
88137
|
+
},
|
|
88138
|
+
quotas: { ...base.quotas, ...o2.quotas },
|
|
88139
|
+
directory: { ...base.directory, ...o2.directory },
|
|
88140
|
+
git: { ...base.git, ...o2.git },
|
|
88141
|
+
activity: { ...base.activity, ...o2.activity },
|
|
88142
|
+
cost: { ...base.cost, ...o2.cost }
|
|
88143
|
+
};
|
|
88144
|
+
}
|
|
88145
|
+
function cloneDefaults() {
|
|
88146
|
+
return mergeSettings2(DEFAULT_STATUSLINE_SETTINGS, {});
|
|
88147
|
+
}
|
|
88148
|
+
function resolveStatuslineSettings(raw) {
|
|
88149
|
+
if (raw == null)
|
|
88150
|
+
return cloneDefaults();
|
|
88151
|
+
if (typeof raw === "string") {
|
|
88152
|
+
const prompt = isPreset(raw) ? PRESET_PROMPTS[raw] : PRESET_PROMPTS.full;
|
|
88153
|
+
return { ...cloneDefaults(), prompt };
|
|
88154
|
+
}
|
|
88155
|
+
return mergeSettings2(DEFAULT_STATUSLINE_SETTINGS, raw);
|
|
88156
|
+
}
|
|
88157
|
+
|
|
88158
|
+
// src/domains/statusline/config-loader.ts
|
|
88159
|
+
async function loadStatuslineSettings(cwd2) {
|
|
88160
|
+
try {
|
|
88161
|
+
const { config } = await TakumiConfigManager.loadFull(cwd2);
|
|
88162
|
+
return resolveStatuslineSettings(config.statusline);
|
|
88163
|
+
} catch {
|
|
88164
|
+
return resolveStatuslineSettings(undefined);
|
|
88165
|
+
}
|
|
88166
|
+
}
|
|
88167
|
+
|
|
88168
|
+
// src/domains/statusline/context-usage.ts
|
|
88169
|
+
var AUTOCOMPACT_BUFFER = 40000;
|
|
88170
|
+
function usedTokens(usage2) {
|
|
88171
|
+
if (!usage2)
|
|
88172
|
+
return 0;
|
|
88173
|
+
const { input_tokens, cache_creation_input_tokens, cache_read_input_tokens } = usage2;
|
|
88174
|
+
return (input_tokens ?? 0) + (cache_creation_input_tokens ?? 0) + (cache_read_input_tokens ?? 0);
|
|
88175
|
+
}
|
|
88176
|
+
function computeContextPercent(cw) {
|
|
88177
|
+
const size = cw.context_window_size ?? 0;
|
|
88178
|
+
if (size <= 0)
|
|
88179
|
+
return 0;
|
|
88180
|
+
const reported = cw.used_percentage;
|
|
88181
|
+
if (typeof reported === "number" && reported >= 0)
|
|
88182
|
+
return Math.round(reported);
|
|
88183
|
+
if (size <= AUTOCOMPACT_BUFFER)
|
|
88184
|
+
return 0;
|
|
88185
|
+
const occupied = usedTokens(cw.current_usage) + AUTOCOMPACT_BUFFER;
|
|
88186
|
+
return Math.min(100, Math.round(occupied / size * 100));
|
|
88187
|
+
}
|
|
88188
|
+
|
|
88189
|
+
// src/domains/statusline/git-cache.ts
|
|
88190
|
+
import { createHash as createHash16 } from "node:crypto";
|
|
88191
|
+
import { readFileSync as readFileSync27 } from "node:fs";
|
|
88192
|
+
init_cache_dir();
|
|
88193
|
+
var GIT_CACHE_TTL_MS = 30000;
|
|
88194
|
+
var MAX_UNTRACKED_FILES = 200;
|
|
88195
|
+
var MAX_UNTRACKED_BYTES = 4 * 1024 * 1024;
|
|
88196
|
+
var NEWLINE = 10;
|
|
88197
|
+
function emptySnapshot(branch = "") {
|
|
88198
|
+
return {
|
|
88199
|
+
branch,
|
|
88200
|
+
trackedInsertions: 0,
|
|
88201
|
+
untrackedInsertions: 0,
|
|
88202
|
+
deletions: 0,
|
|
88203
|
+
ahead: 0,
|
|
88204
|
+
behind: 0
|
|
88205
|
+
};
|
|
88206
|
+
}
|
|
88207
|
+
function cachePathFor(cwd2) {
|
|
88208
|
+
const key = createHash16("md5").update(cwd2).digest("hex").slice(0, 8);
|
|
88209
|
+
return getStatuslineCachePath(`git-${key}.json`);
|
|
88210
|
+
}
|
|
88211
|
+
function readFreshCache(cwd2, now) {
|
|
88212
|
+
const raw = readCacheFileSafe(cachePathFor(cwd2));
|
|
88213
|
+
if (!raw)
|
|
88214
|
+
return null;
|
|
88215
|
+
try {
|
|
88216
|
+
const parsed = JSON.parse(raw);
|
|
88217
|
+
if (typeof parsed.timestamp !== "number" || !parsed.data)
|
|
88218
|
+
return null;
|
|
88219
|
+
if (now - parsed.timestamp >= GIT_CACHE_TTL_MS)
|
|
88220
|
+
return null;
|
|
88221
|
+
return parsed.data;
|
|
88222
|
+
} catch {
|
|
88223
|
+
return null;
|
|
88224
|
+
}
|
|
88225
|
+
}
|
|
88226
|
+
function toCount(field) {
|
|
88227
|
+
const n2 = Number.parseInt(field ?? "", 10);
|
|
88228
|
+
return Number.isNaN(n2) ? 0 : n2;
|
|
88229
|
+
}
|
|
88230
|
+
function sumNumstat(numstat) {
|
|
88231
|
+
return numstat.split(`
|
|
88232
|
+
`).filter(Boolean).reduce((acc, row) => {
|
|
88233
|
+
const [added, removed] = row.split("\t");
|
|
88234
|
+
if (added === "-")
|
|
88235
|
+
return acc;
|
|
88236
|
+
acc.insertions += toCount(added);
|
|
88237
|
+
acc.deletions += toCount(removed);
|
|
88238
|
+
return acc;
|
|
88239
|
+
}, { insertions: 0, deletions: 0 });
|
|
88240
|
+
}
|
|
88241
|
+
function trackedDiff(cwd2) {
|
|
88242
|
+
const vsHead = runGit(cwd2, ["diff", "HEAD", "--numstat"], GIT_RENDER_TIMEOUT_MS);
|
|
88243
|
+
if (vsHead)
|
|
88244
|
+
return sumNumstat(vsHead);
|
|
88245
|
+
const staged = runGit(cwd2, ["diff", "--cached", "--numstat"], GIT_RENDER_TIMEOUT_MS);
|
|
88246
|
+
const unstaged = runGit(cwd2, ["diff", "--numstat"], GIT_RENDER_TIMEOUT_MS);
|
|
88247
|
+
return sumNumstat([staged, unstaged].join(`
|
|
88248
|
+
`));
|
|
88249
|
+
}
|
|
88250
|
+
function countBufferLines(buf) {
|
|
88251
|
+
if (buf.length === 0)
|
|
88252
|
+
return 0;
|
|
88253
|
+
let count = 0;
|
|
88254
|
+
for (let idx = buf.indexOf(NEWLINE);idx !== -1; idx = buf.indexOf(NEWLINE, idx + 1)) {
|
|
88255
|
+
count++;
|
|
88256
|
+
}
|
|
88257
|
+
return buf[buf.length - 1] === NEWLINE ? count : count + 1;
|
|
88258
|
+
}
|
|
88259
|
+
function untrackedInsertions(cwd2) {
|
|
88260
|
+
const listing = runGit(cwd2, ["ls-files", "--others", "--exclude-standard"], GIT_RENDER_TIMEOUT_MS);
|
|
88261
|
+
if (!listing)
|
|
88262
|
+
return 0;
|
|
88263
|
+
const files = listing.split(`
|
|
88264
|
+
`).filter(Boolean).slice(0, MAX_UNTRACKED_FILES);
|
|
88265
|
+
let total = 0;
|
|
88266
|
+
let byteBudget = MAX_UNTRACKED_BYTES;
|
|
88267
|
+
for (const relative23 of files) {
|
|
88268
|
+
if (byteBudget <= 0)
|
|
88269
|
+
break;
|
|
88270
|
+
let buf;
|
|
88271
|
+
try {
|
|
88272
|
+
buf = readFileSync27(`${cwd2}/${relative23}`);
|
|
88273
|
+
} catch {
|
|
88274
|
+
continue;
|
|
88275
|
+
}
|
|
88276
|
+
const slice = buf.length > byteBudget ? buf.subarray(0, byteBudget) : buf;
|
|
88277
|
+
total += countBufferLines(slice);
|
|
88278
|
+
byteBudget -= slice.length;
|
|
88279
|
+
}
|
|
88280
|
+
return total;
|
|
88281
|
+
}
|
|
88282
|
+
function aheadBehind(cwd2) {
|
|
88283
|
+
const out = runGit(cwd2, ["rev-list", "--left-right", "--count", "@{u}...HEAD"], GIT_RENDER_TIMEOUT_MS);
|
|
88284
|
+
if (!out)
|
|
88285
|
+
return { ahead: 0, behind: 0 };
|
|
88286
|
+
const [behind, ahead] = out.split(/\s+/);
|
|
88287
|
+
return { ahead: Number.parseInt(ahead, 10) || 0, behind: Number.parseInt(behind, 10) || 0 };
|
|
88288
|
+
}
|
|
88289
|
+
function probe2(cwd2, branch) {
|
|
88290
|
+
const tracked = trackedDiff(cwd2);
|
|
88291
|
+
const { ahead, behind } = aheadBehind(cwd2);
|
|
88292
|
+
return {
|
|
88293
|
+
branch,
|
|
88294
|
+
trackedInsertions: tracked.insertions,
|
|
88295
|
+
untrackedInsertions: untrackedInsertions(cwd2),
|
|
88296
|
+
deletions: tracked.deletions,
|
|
88297
|
+
ahead,
|
|
88298
|
+
behind
|
|
88299
|
+
};
|
|
88300
|
+
}
|
|
88301
|
+
function getGitSnapshot(cwd2) {
|
|
88302
|
+
try {
|
|
88303
|
+
const now = Date.now();
|
|
88304
|
+
const cached = readFreshCache(cwd2, now);
|
|
88305
|
+
if (cached)
|
|
88306
|
+
return cached;
|
|
88307
|
+
const branch = resolveGitBranchOrCommit(cwd2, GIT_RENDER_TIMEOUT_MS);
|
|
88308
|
+
const snapshot = branch ? probe2(cwd2, branch) : emptySnapshot("");
|
|
88309
|
+
const envelope = { timestamp: now, data: snapshot };
|
|
88310
|
+
writeCacheFileSafe(cachePathFor(cwd2), JSON.stringify(envelope));
|
|
88311
|
+
return snapshot;
|
|
88312
|
+
} catch {
|
|
88313
|
+
return emptySnapshot("");
|
|
88314
|
+
}
|
|
88315
|
+
}
|
|
88316
|
+
|
|
88317
|
+
// src/domains/statusline/payload.ts
|
|
88318
|
+
function finiteOrUndefined(value) {
|
|
88319
|
+
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
88320
|
+
}
|
|
88321
|
+
function finiteOr0(value) {
|
|
88322
|
+
return finiteOrUndefined(value) ?? 0;
|
|
88323
|
+
}
|
|
88324
|
+
function record(value) {
|
|
88325
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
88326
|
+
}
|
|
88327
|
+
function text(value) {
|
|
88328
|
+
return typeof value === "string" ? value : "";
|
|
88329
|
+
}
|
|
88330
|
+
var NUMERIC_STRING = /^\d+(\.\d+)?$/;
|
|
88331
|
+
function parseCost(value) {
|
|
88332
|
+
if (typeof value === "number")
|
|
88333
|
+
return Number.isFinite(value) ? value : null;
|
|
88334
|
+
if (typeof value === "string" && NUMERIC_STRING.test(value))
|
|
88335
|
+
return Number.parseFloat(value);
|
|
88336
|
+
return null;
|
|
88337
|
+
}
|
|
88338
|
+
function parseContextWindow(value) {
|
|
88339
|
+
const raw = record(value);
|
|
88340
|
+
const usage2 = record(raw.current_usage);
|
|
88341
|
+
return {
|
|
88342
|
+
used_percentage: finiteOrUndefined(raw.used_percentage),
|
|
88343
|
+
context_window_size: finiteOr0(raw.context_window_size),
|
|
88344
|
+
remaining_percentage: finiteOrUndefined(raw.remaining_percentage),
|
|
88345
|
+
current_usage: {
|
|
88346
|
+
input_tokens: finiteOr0(usage2.input_tokens),
|
|
88347
|
+
cache_creation_input_tokens: finiteOr0(usage2.cache_creation_input_tokens),
|
|
88348
|
+
cache_read_input_tokens: finiteOr0(usage2.cache_read_input_tokens)
|
|
88349
|
+
}
|
|
88350
|
+
};
|
|
88351
|
+
}
|
|
88352
|
+
function parseStatusPayload(raw) {
|
|
88353
|
+
const model = record(raw.model);
|
|
88354
|
+
const workspace = record(raw.workspace);
|
|
88355
|
+
const cost = record(raw.cost);
|
|
88356
|
+
const workspaceDir = workspace.current_dir;
|
|
88357
|
+
const cwd2 = typeof workspaceDir === "string" && workspaceDir.length > 0 ? workspaceDir : text(raw.cwd);
|
|
88358
|
+
const displayName = model.display_name;
|
|
88359
|
+
return {
|
|
88360
|
+
sessionId: text(raw.session_id),
|
|
88361
|
+
modelName: typeof displayName === "string" ? displayName : "Claude",
|
|
88362
|
+
cwd: cwd2,
|
|
88363
|
+
contextWindow: parseContextWindow(raw.context_window),
|
|
88364
|
+
costUsd: parseCost(cost.total_cost_usd),
|
|
88365
|
+
linesAdded: finiteOr0(cost.total_lines_added),
|
|
88366
|
+
linesRemoved: finiteOr0(cost.total_lines_removed)
|
|
88367
|
+
};
|
|
88368
|
+
}
|
|
88369
|
+
|
|
88370
|
+
// src/domains/statusline/quota-windows.ts
|
|
88371
|
+
init_usage_limits_cache();
|
|
88372
|
+
|
|
88373
|
+
// src/domains/statusline/time-format.ts
|
|
88374
|
+
function safeGetTime(value) {
|
|
88375
|
+
if (!value)
|
|
88376
|
+
return 0;
|
|
88377
|
+
const ms2 = value instanceof Date ? value.getTime() : new Date(value).getTime();
|
|
88378
|
+
return Number.isNaN(ms2) ? 0 : ms2;
|
|
88379
|
+
}
|
|
88380
|
+
function formatElapsed(start2, end) {
|
|
88381
|
+
const from = safeGetTime(start2);
|
|
88382
|
+
if (!from)
|
|
88383
|
+
return "0s";
|
|
88384
|
+
const to2 = end == null ? Date.now() : safeGetTime(end) || Date.now();
|
|
88385
|
+
const span = to2 - from;
|
|
88386
|
+
if (span < 1000)
|
|
88387
|
+
return "<1s";
|
|
88388
|
+
if (span < 60000)
|
|
88389
|
+
return `${Math.round(span / 1000)}s`;
|
|
88390
|
+
const minutes = Math.floor(span / 60000);
|
|
88391
|
+
const seconds = Math.round(span % 60000 / 1000);
|
|
88392
|
+
return `${minutes}m ${seconds}s`;
|
|
88393
|
+
}
|
|
88394
|
+
function formatCountdown(msLeft) {
|
|
88395
|
+
if (!Number.isFinite(msLeft) || msLeft <= 0)
|
|
88396
|
+
return "";
|
|
88397
|
+
const totalMinutes = Math.floor(msLeft / 60000);
|
|
88398
|
+
if (totalMinutes < 60)
|
|
88399
|
+
return `${totalMinutes}m`;
|
|
88400
|
+
if (totalMinutes < 1440) {
|
|
88401
|
+
const hours = Math.floor(totalMinutes / 60);
|
|
88402
|
+
const minutes = totalMinutes % 60;
|
|
88403
|
+
return minutes === 0 ? `${hours}h` : `${hours}h${minutes}m`;
|
|
88404
|
+
}
|
|
88405
|
+
return `${Math.floor(totalMinutes / 1440)}d`;
|
|
88406
|
+
}
|
|
88407
|
+
|
|
88408
|
+
// src/domains/statusline/quota-windows.ts
|
|
88409
|
+
var RENDER_TTL_MS = 300000;
|
|
88410
|
+
var FIVE_HOUR_LABEL = "5h";
|
|
88411
|
+
var WEEK_LABEL = "wk";
|
|
88412
|
+
function pushSnapshotWindow(into, label, percent, resetsAt, now) {
|
|
88413
|
+
if (percent == null)
|
|
88414
|
+
return;
|
|
88415
|
+
let text2 = `${label} ${percent}%`;
|
|
88416
|
+
if (resetsAt) {
|
|
88417
|
+
const countdown = formatCountdown(new Date(resetsAt).getTime() - now);
|
|
88418
|
+
if (countdown)
|
|
88419
|
+
text2 += ` (${countdown})`;
|
|
88420
|
+
}
|
|
88421
|
+
into.push(text2);
|
|
88422
|
+
}
|
|
88423
|
+
function fromSnapshot(snapshot, data, now) {
|
|
88424
|
+
if (!snapshot)
|
|
88425
|
+
return [];
|
|
88426
|
+
const windows = [];
|
|
88427
|
+
pushSnapshotWindow(windows, FIVE_HOUR_LABEL, snapshot.fiveHourPercent, data?.five_hour?.resets_at, now);
|
|
88428
|
+
pushSnapshotWindow(windows, WEEK_LABEL, snapshot.weekPercent, data?.seven_day?.resets_at, now);
|
|
88429
|
+
return windows;
|
|
88430
|
+
}
|
|
88431
|
+
function fromRawUtilization(data) {
|
|
88432
|
+
if (!data)
|
|
88433
|
+
return [];
|
|
88434
|
+
const windows = [];
|
|
88435
|
+
const fiveHour = normalizeUtilization(data.five_hour?.utilization);
|
|
88436
|
+
if (fiveHour != null)
|
|
88437
|
+
windows.push(`${FIVE_HOUR_LABEL} ${fiveHour}%`);
|
|
88438
|
+
const week = normalizeUtilization(data.seven_day?.utilization);
|
|
88439
|
+
if (week != null)
|
|
88440
|
+
windows.push(`${WEEK_LABEL} ${week}%`);
|
|
88441
|
+
return windows;
|
|
88442
|
+
}
|
|
88443
|
+
function quotaWindows(now = Date.now()) {
|
|
88444
|
+
const cache3 = readUsageCache();
|
|
88445
|
+
if (!cache3 || cache3.status !== "available")
|
|
88446
|
+
return [];
|
|
88447
|
+
if (!isUsageCacheFresh(cache3, RENDER_TTL_MS, now))
|
|
88448
|
+
return [];
|
|
88449
|
+
const snapshotWindows = fromSnapshot(cache3.snapshot, cache3.data, now);
|
|
88450
|
+
return snapshotWindows.length > 0 ? snapshotWindows : fromRawUtilization(cache3.data);
|
|
88451
|
+
}
|
|
88452
|
+
|
|
88453
|
+
// src/domains/statusline/components.ts
|
|
88454
|
+
import { homedir as homedir30 } from "node:os";
|
|
88455
|
+
|
|
88456
|
+
// src/domains/statusline/colors.ts
|
|
88457
|
+
init_help_colors();
|
|
88458
|
+
var COLOR_ENABLED = process.env.NO_COLOR === undefined;
|
|
88459
|
+
var RESET = "\x1B[0m";
|
|
88460
|
+
var CLEAR_INTENSITY = "\x1B[22m";
|
|
88461
|
+
var CLEAR_FOREGROUND = "\x1B[39m";
|
|
88462
|
+
var STABLE_PREFIX = `${CLEAR_INTENSITY}${CLEAR_FOREGROUND}`;
|
|
88463
|
+
var STABLE_SUFFIX = `${RESET}${CLEAR_INTENSITY}${CLEAR_FOREGROUND}`;
|
|
88464
|
+
var CODES = {
|
|
88465
|
+
dim: "\x1B[2m",
|
|
88466
|
+
red: "\x1B[31m",
|
|
88467
|
+
green: "\x1B[32m",
|
|
88468
|
+
yellow: "\x1B[33m",
|
|
88469
|
+
magenta: "\x1B[35m",
|
|
88470
|
+
cyan: "\x1B[36m",
|
|
88471
|
+
brightRed: "\x1B[91m",
|
|
88472
|
+
brightGreen: "\x1B[92m",
|
|
88473
|
+
brightYellow: "\x1B[93m",
|
|
88474
|
+
brightMagenta: "\x1B[95m",
|
|
88475
|
+
brightCyan: "\x1B[96m"
|
|
88476
|
+
};
|
|
88477
|
+
function paint(name2, text2) {
|
|
88478
|
+
if (!COLOR_ENABLED)
|
|
88479
|
+
return text2;
|
|
88480
|
+
const code = CODES[name2];
|
|
88481
|
+
return code ? `${STABLE_PREFIX}${code}${text2}${STABLE_SUFFIX}` : text2;
|
|
88482
|
+
}
|
|
88483
|
+
function percentColorName(percent) {
|
|
88484
|
+
if (percent >= 80)
|
|
88485
|
+
return "brightRed";
|
|
88486
|
+
if (percent >= 50)
|
|
88487
|
+
return "brightYellow";
|
|
88488
|
+
return "brightGreen";
|
|
88489
|
+
}
|
|
88490
|
+
var BAR_GLYPHS = {
|
|
88491
|
+
geometric: { filled: "▰", empty: "▱" },
|
|
88492
|
+
block: { filled: "█", empty: "░" }
|
|
88493
|
+
};
|
|
88494
|
+
function progressBar2(percent, width = 10, style = "geometric", color) {
|
|
88495
|
+
if (width <= 0)
|
|
88496
|
+
return "";
|
|
88497
|
+
const { filled: fg, empty: bg } = BAR_GLYPHS[style];
|
|
88498
|
+
const clamped = Math.max(0, Math.min(100, percent));
|
|
88499
|
+
const filled = Math.round(clamped / 100 * width);
|
|
88500
|
+
const empty = width - filled;
|
|
88501
|
+
if (!COLOR_ENABLED)
|
|
88502
|
+
return fg.repeat(filled) + bg.repeat(empty);
|
|
88503
|
+
const filledColor = color && CODES[color] || CODES[percentColorName(percent)];
|
|
88504
|
+
return `${STABLE_PREFIX}${filledColor}${fg.repeat(filled)}${STABLE_PREFIX}${CODES.dim}${bg.repeat(empty)}${STABLE_SUFFIX}`;
|
|
88505
|
+
}
|
|
88506
|
+
|
|
88507
|
+
// src/domains/statusline/sanitize.ts
|
|
88508
|
+
var ANSI_SEQUENCE = /\x1b\[[0-9;?]*[ -/]*[@-~]|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|\x1b[@-Z\\-_]/g;
|
|
88509
|
+
var CONTROL_CHARS = /[\x00-\x1f\x7f-\x9f]/g;
|
|
88510
|
+
function sanitizeField(value) {
|
|
88511
|
+
if (typeof value !== "string")
|
|
88512
|
+
return "";
|
|
88513
|
+
return value.replace(ANSI_SEQUENCE, "").replace(CONTROL_CHARS, "");
|
|
88514
|
+
}
|
|
88515
|
+
|
|
88516
|
+
// src/domains/statusline/activity-renderers.ts
|
|
88517
|
+
var MAX_AGENT_ROWS = 4;
|
|
88518
|
+
var TODO_TRUNCATION = 50;
|
|
88519
|
+
var DETAIL_LIMIT = 50;
|
|
88520
|
+
var NEXT_LIMIT = 40;
|
|
88521
|
+
function orderAgents(agents) {
|
|
88522
|
+
const rank = (a3) => a3.status === "running" ? 0 : 1;
|
|
88523
|
+
return [...agents].sort((a3, b4) => rank(a3) - rank(b4) || safeGetTime(a3.startTime) - safeGetTime(b4.startTime));
|
|
88524
|
+
}
|
|
88525
|
+
function collapseAgents(ordered) {
|
|
88526
|
+
const groups = [];
|
|
88527
|
+
for (const agent of ordered) {
|
|
88528
|
+
const type = sanitizeField(agent.type) || "agent";
|
|
88529
|
+
const previous = groups[groups.length - 1];
|
|
88530
|
+
if (previous && previous.type === type && previous.status === agent.status) {
|
|
88531
|
+
previous.count++;
|
|
88532
|
+
} else {
|
|
88533
|
+
groups.push({ type, status: agent.status, count: 1 });
|
|
88534
|
+
}
|
|
88535
|
+
}
|
|
88536
|
+
return groups;
|
|
88537
|
+
}
|
|
88538
|
+
function renderDetailLine(ordered) {
|
|
88539
|
+
const running = ordered.find((a3) => a3.status === "running");
|
|
88540
|
+
const completed = ordered.filter((a3) => a3.status === "completed");
|
|
88541
|
+
const agent = running ?? completed[completed.length - 1];
|
|
88542
|
+
if (!agent || !agent.description)
|
|
88543
|
+
return null;
|
|
88544
|
+
let desc = sanitizeField(agent.description);
|
|
88545
|
+
if (!desc)
|
|
88546
|
+
return null;
|
|
88547
|
+
if (desc.length > DETAIL_LIMIT)
|
|
88548
|
+
desc = `${desc.slice(0, DETAIL_LIMIT - 3)}...`;
|
|
88549
|
+
const tone = agent.status === "running" ? "yellow" : "dim";
|
|
88550
|
+
const elapsed = formatElapsed(agent.startTime, agent.endTime);
|
|
88551
|
+
return ` ${paint(tone, `▸ ${desc}`)} ${paint("dim", `(${elapsed})`)}`;
|
|
88552
|
+
}
|
|
88553
|
+
function renderAgentLines(agents, maxRows) {
|
|
88554
|
+
if (agents.length === 0)
|
|
88555
|
+
return [];
|
|
88556
|
+
const ordered = orderAgents(agents);
|
|
88557
|
+
const groups = collapseAgents(ordered).slice(-Math.max(1, maxRows));
|
|
88558
|
+
const rendered = groups.map((g3) => {
|
|
88559
|
+
const tone = g3.status === "running" ? "yellow" : "dim";
|
|
88560
|
+
const icon = g3.status === "running" ? "●" : "○";
|
|
88561
|
+
const suffix = g3.count > 1 ? `×${g3.count}` : "";
|
|
88562
|
+
return paint(tone, `${icon} ${g3.type}${suffix}`);
|
|
88563
|
+
});
|
|
88564
|
+
let summary = rendered.join(" → ");
|
|
88565
|
+
const completedCount = ordered.filter((a3) => a3.status === "completed").length;
|
|
88566
|
+
if (completedCount > 2)
|
|
88567
|
+
summary += paint("dim", ` (${completedCount} done)`);
|
|
88568
|
+
const lines = [summary];
|
|
88569
|
+
const detail = renderDetailLine(ordered);
|
|
88570
|
+
if (detail)
|
|
88571
|
+
lines.push(detail);
|
|
88572
|
+
return lines;
|
|
88573
|
+
}
|
|
88574
|
+
function renderTodoLine(todos, truncation) {
|
|
88575
|
+
if (todos.length === 0)
|
|
88576
|
+
return null;
|
|
88577
|
+
const limit = Math.max(10, truncation);
|
|
88578
|
+
const done = todos.filter((t) => t.status === "completed").length;
|
|
88579
|
+
const pending = todos.filter((t) => t.status === "pending").length;
|
|
88580
|
+
const active = todos.find((t) => t.status === "in_progress");
|
|
88581
|
+
if (active) {
|
|
88582
|
+
let text2 = sanitizeField(active.activeForm || active.content);
|
|
88583
|
+
if (!text2)
|
|
88584
|
+
return null;
|
|
88585
|
+
if (text2.length > limit)
|
|
88586
|
+
text2 = `${text2.slice(0, limit - 3)}...`;
|
|
88587
|
+
return paint("yellow", `▸ ${text2} (${done} done, ${pending} pending)`);
|
|
88588
|
+
}
|
|
88589
|
+
if (done === todos.length) {
|
|
88590
|
+
return paint("green", `✓ All ${todos.length} todos complete`);
|
|
88591
|
+
}
|
|
88592
|
+
if (pending > 0) {
|
|
88593
|
+
const next = todos.find((t) => t.status === "pending");
|
|
88594
|
+
let text2 = sanitizeField(next?.content || "Next task");
|
|
88595
|
+
if (text2.length > NEXT_LIMIT)
|
|
88596
|
+
text2 = `${text2.slice(0, NEXT_LIMIT - 3)}...`;
|
|
88597
|
+
return paint("dim", `○ Next: ${text2} (${done} done, ${pending} pending)`);
|
|
88598
|
+
}
|
|
88599
|
+
return null;
|
|
88600
|
+
}
|
|
88601
|
+
function renderActivityLines(snapshot, opts) {
|
|
88602
|
+
if (!snapshot)
|
|
88603
|
+
return [];
|
|
88604
|
+
const lines = renderAgentLines(snapshot.agents, opts?.maxAgentRows ?? MAX_AGENT_ROWS);
|
|
88605
|
+
const todoLine = renderTodoLine(snapshot.todos, opts?.todoTruncation ?? TODO_TRUNCATION);
|
|
88606
|
+
if (todoLine)
|
|
88607
|
+
lines.push(todoLine);
|
|
88608
|
+
return lines;
|
|
88609
|
+
}
|
|
88610
|
+
|
|
88611
|
+
// src/domains/statusline/components.ts
|
|
88612
|
+
function normalizeVersion2(raw) {
|
|
88613
|
+
const v3 = sanitizeField(raw ?? "").trim();
|
|
88614
|
+
if (!v3 || v3.toLowerCase() === "unknown")
|
|
88615
|
+
return null;
|
|
88616
|
+
return `v${v3.replace(/^v/i, "")}`;
|
|
88617
|
+
}
|
|
88618
|
+
function renderBrand(data, s3) {
|
|
88619
|
+
const cli = s3.showCliVersion ? normalizeVersion2(data.versions.cli) : null;
|
|
88620
|
+
let takumi = paint(s3.color, "Takumi");
|
|
88621
|
+
if (cli)
|
|
88622
|
+
takumi += ` ${paint(s3.versionColor, cli)}`;
|
|
88623
|
+
const pieces = [takumi];
|
|
88624
|
+
const core = s3.showCoreVersion ? normalizeVersion2(data.versions.core) : null;
|
|
88625
|
+
if (core)
|
|
88626
|
+
pieces.push(`${paint(s3.color, "core")} ${paint(s3.versionColor, core)}`);
|
|
88627
|
+
const icon = s3.icon ? `${paint(s3.color, s3.icon)} ` : "";
|
|
88628
|
+
return `${icon}${pieces.join(paint(s3.color, " · "))}`;
|
|
88629
|
+
}
|
|
88630
|
+
function renderModel(data, s3) {
|
|
88631
|
+
return paint(s3.color, sanitizeField(data.modelName) || "Claude");
|
|
88632
|
+
}
|
|
88633
|
+
function renderContext(data, s3) {
|
|
88634
|
+
const pct = data.contextPercent;
|
|
88635
|
+
if (!(pct > 0))
|
|
88636
|
+
return null;
|
|
88637
|
+
const color = pct >= s3.thresholds.high ? s3.colors.high : pct >= s3.thresholds.mid ? s3.colors.mid : s3.colors.low;
|
|
88638
|
+
const bar = progressBar2(pct, s3.barWidth, s3.barStyle, color);
|
|
88639
|
+
const pctText = s3.showPercent ? paint(color, `${pct}%`) : "";
|
|
88640
|
+
const parts = [bar, pctText].filter(Boolean);
|
|
88641
|
+
return parts.length ? parts.join(" ") : null;
|
|
88642
|
+
}
|
|
88643
|
+
var WINDOW_ALIASES = {
|
|
88644
|
+
"5h": "5h",
|
|
88645
|
+
"5hour": "5h",
|
|
88646
|
+
week: "wk",
|
|
88647
|
+
weekly: "wk",
|
|
88648
|
+
wk: "wk"
|
|
88649
|
+
};
|
|
88650
|
+
function renderQuotas(data, s3) {
|
|
88651
|
+
if (data.usageWindows.length === 0)
|
|
88652
|
+
return null;
|
|
88653
|
+
const allow = new Set(s3.windows.map((w4) => WINDOW_ALIASES[w4.toLowerCase()] ?? w4.toLowerCase()));
|
|
88654
|
+
const parts = [];
|
|
88655
|
+
for (const windowText of data.usageWindows) {
|
|
88656
|
+
const clean = sanitizeField(windowText);
|
|
88657
|
+
const match = clean.match(/^(\w+)\s+(\d+)%(.*)$/);
|
|
88658
|
+
if (!match) {
|
|
88659
|
+
parts.push(paint("dim", clean));
|
|
88660
|
+
continue;
|
|
88661
|
+
}
|
|
88662
|
+
const [, label, pctStr, rest] = match;
|
|
88663
|
+
if (allow.size > 0 && !allow.has(label.toLowerCase()))
|
|
88664
|
+
continue;
|
|
88665
|
+
const pct = Number.parseInt(pctStr, 10);
|
|
88666
|
+
const color = pct >= 85 ? "brightRed" : "brightGreen";
|
|
88667
|
+
const value = paint(color, `${pct}%${s3.showCountdown ? rest : ""}`);
|
|
88668
|
+
parts.push(s3.barWidth > 0 ? `${label} ${progressBar2(pct, s3.barWidth, "geometric", color)} ${value}` : `${paint("dim", label)} ${value}`);
|
|
88669
|
+
}
|
|
88670
|
+
return parts.length ? `${s3.icon} ${parts.join(" ")}` : null;
|
|
88671
|
+
}
|
|
88672
|
+
function shortenLeadingDirs(path11, keepFull) {
|
|
88673
|
+
if (keepFull <= 0)
|
|
88674
|
+
return path11;
|
|
88675
|
+
const marker = path11.startsWith("~") ? "~" : "";
|
|
88676
|
+
const body = marker ? path11.slice(marker.length) : path11;
|
|
88677
|
+
const leadingSlash = body.startsWith("/");
|
|
88678
|
+
const segments = body.split("/").filter(Boolean);
|
|
88679
|
+
if (segments.length <= keepFull)
|
|
88680
|
+
return path11;
|
|
88681
|
+
const leadCount = segments.length - keepFull;
|
|
88682
|
+
const shortened = segments.map((seg, i) => i < leadCount ? Array.from(seg)[0] ?? seg : seg);
|
|
88683
|
+
const sep9 = marker || leadingSlash ? "/" : "";
|
|
88684
|
+
return `${marker}${sep9}${shortened.join("/")}`;
|
|
88685
|
+
}
|
|
88686
|
+
function renderDirectory(data, s3) {
|
|
88687
|
+
let path11 = data.cwd || process.cwd();
|
|
88688
|
+
if (s3.collapseHome) {
|
|
88689
|
+
const home6 = homedir30();
|
|
88690
|
+
if (home6 && path11.startsWith(home6))
|
|
88691
|
+
path11 = `~${path11.slice(home6.length)}`;
|
|
88692
|
+
}
|
|
88693
|
+
path11 = shortenLeadingDirs(path11, s3.truncationLength);
|
|
88694
|
+
return `${s3.icon} ${paint(s3.color, sanitizeField(path11))}`;
|
|
88695
|
+
}
|
|
88696
|
+
function renderGit(data, s3) {
|
|
88697
|
+
const git = data.git;
|
|
88698
|
+
if (!git || !git.branch)
|
|
88699
|
+
return null;
|
|
88700
|
+
let part = `${s3.icon} ${paint(s3.branchColor, sanitizeField(git.branch))}`;
|
|
88701
|
+
if (s3.showDirty) {
|
|
88702
|
+
const insertions = git.trackedInsertions + (s3.countUntracked ? git.untrackedInsertions : 0);
|
|
88703
|
+
const tokens = [];
|
|
88704
|
+
if (insertions > 0)
|
|
88705
|
+
tokens.push(paint("green", `+${insertions}`));
|
|
88706
|
+
if (git.deletions > 0)
|
|
88707
|
+
tokens.push(paint("red", `-${git.deletions}`));
|
|
88708
|
+
if (tokens.length > 0) {
|
|
88709
|
+
part += s3.dirtyInBrackets ? ` (${tokens.join(" ")})` : ` ${tokens.join(" ")}`;
|
|
88710
|
+
}
|
|
88711
|
+
}
|
|
88712
|
+
if (s3.showAheadBehind) {
|
|
88713
|
+
if (git.ahead > 0)
|
|
88714
|
+
part += ` ${paint("dim", `⇡${git.ahead}`)}`;
|
|
88715
|
+
if (git.behind > 0)
|
|
88716
|
+
part += ` ${paint("dim", `⇣${git.behind}`)}`;
|
|
88717
|
+
}
|
|
88718
|
+
return part;
|
|
88719
|
+
}
|
|
88720
|
+
function renderCost(data, s3) {
|
|
88721
|
+
const cost = data.costUsd;
|
|
88722
|
+
if (cost == null)
|
|
88723
|
+
return null;
|
|
88724
|
+
if (s3.hideZero && !(cost > 0))
|
|
88725
|
+
return null;
|
|
88726
|
+
return `${s3.icon} ${paint("dim", `$${cost.toFixed(4)}`)}`;
|
|
88727
|
+
}
|
|
88728
|
+
function renderActivity(data, s3) {
|
|
88729
|
+
return renderActivityLines(data.activity, {
|
|
88730
|
+
maxAgentRows: s3.maxAgentRows,
|
|
88731
|
+
todoTruncation: s3.todoTruncation
|
|
88732
|
+
});
|
|
88733
|
+
}
|
|
88734
|
+
|
|
88735
|
+
// src/domains/statusline/renderer.ts
|
|
88736
|
+
function renderInline(name2, data, settings) {
|
|
88737
|
+
switch (name2) {
|
|
88738
|
+
case "brand":
|
|
88739
|
+
return renderBrand(data, settings.brand);
|
|
88740
|
+
case "model":
|
|
88741
|
+
return renderModel(data, settings.model);
|
|
88742
|
+
case "context":
|
|
88743
|
+
return renderContext(data, settings.context);
|
|
88744
|
+
case "quotas":
|
|
88745
|
+
return renderQuotas(data, settings.quotas);
|
|
88746
|
+
case "directory":
|
|
88747
|
+
return renderDirectory(data, settings.directory);
|
|
88748
|
+
case "git":
|
|
88749
|
+
return renderGit(data, settings.git);
|
|
88750
|
+
case "cost":
|
|
88751
|
+
return renderCost(data, settings.cost);
|
|
88752
|
+
default:
|
|
88753
|
+
return null;
|
|
88754
|
+
}
|
|
88755
|
+
}
|
|
88756
|
+
function renderStatusline(data, settings) {
|
|
88757
|
+
const prompt = settings.prompt ?? "";
|
|
88758
|
+
const activityLines = prompt.includes("$activity") ? renderActivity(data, settings.activity) : [];
|
|
88759
|
+
const inlinePrompt = prompt.replace(/\$activity/g, "");
|
|
88760
|
+
const substituted = inlinePrompt.replace(/\$([a-z]+)/g, (_match, name2) => {
|
|
88761
|
+
return renderInline(name2, data, settings) ?? "";
|
|
88762
|
+
});
|
|
88763
|
+
const mainLine = substituted.replace(/[ \t]{2,}/g, " ").trim();
|
|
88764
|
+
const lines = [];
|
|
88765
|
+
if (mainLine)
|
|
88766
|
+
lines.push(mainLine);
|
|
88767
|
+
for (const line of activityLines) {
|
|
88768
|
+
if (line)
|
|
88769
|
+
lines.push(line);
|
|
88770
|
+
}
|
|
88771
|
+
return lines.join(`
|
|
88772
|
+
`);
|
|
88773
|
+
}
|
|
88774
|
+
|
|
88775
|
+
// src/domains/statusline/versions.ts
|
|
88776
|
+
import { join as join137 } from "node:path";
|
|
88777
|
+
async function resolveCoreVersion(cwd2) {
|
|
88778
|
+
try {
|
|
88779
|
+
const { readManifest: readManifest3 } = await Promise.resolve().then(() => (init_manifest(), exports_manifest));
|
|
88780
|
+
const meta = await readManifest3(join137(cwd2, ".claude"));
|
|
88781
|
+
if (!meta)
|
|
88782
|
+
return null;
|
|
88783
|
+
const kits = meta.kits;
|
|
88784
|
+
const version3 = kits?.core?.version ?? meta.version;
|
|
88785
|
+
return typeof version3 === "string" && version3.length > 0 ? version3 : null;
|
|
88786
|
+
} catch {
|
|
88787
|
+
return null;
|
|
88788
|
+
}
|
|
88789
|
+
}
|
|
88790
|
+
|
|
88791
|
+
// src/commands/statusline/statusline-command.ts
|
|
88792
|
+
init_takumi_constants();
|
|
88793
|
+
function writeDebug(enabled, context, err) {
|
|
88794
|
+
if (!enabled)
|
|
88795
|
+
return;
|
|
88796
|
+
try {
|
|
88797
|
+
ensureStatuslineCacheDir();
|
|
88798
|
+
const detail = err instanceof Error ? err.stack ?? err.message : String(err);
|
|
88799
|
+
appendFileSync3(getStatuslineCachePath("debug.log"), `[${new Date().toISOString()}] ${context}: ${detail}
|
|
88800
|
+
`, {
|
|
88801
|
+
mode: 384
|
|
88802
|
+
});
|
|
88803
|
+
} catch {}
|
|
88804
|
+
}
|
|
88805
|
+
function collapseHome(p2) {
|
|
88806
|
+
const home6 = homedir31();
|
|
88807
|
+
return home6 && p2.startsWith(home6) ? `~${p2.slice(home6.length)}` : p2;
|
|
88808
|
+
}
|
|
88809
|
+
function fallbackLine(cwd2) {
|
|
88810
|
+
const safe = sanitizeField(collapseHome(cwd2 || process.cwd() || "unknown")) || "unknown";
|
|
88811
|
+
return `\uD83D\uDCC1 ${safe}`;
|
|
88812
|
+
}
|
|
88813
|
+
async function runUsageCacheRefresh(debug) {
|
|
88814
|
+
try {
|
|
88815
|
+
const { refreshUsageCache: refreshUsageCache2 } = await Promise.resolve().then(() => (init_usage_limits_cache(), exports_usage_limits_cache));
|
|
88816
|
+
await refreshUsageCache2();
|
|
88817
|
+
} catch (err) {
|
|
88818
|
+
writeDebug(debug, "refresh-usage-cache", err);
|
|
88819
|
+
}
|
|
88820
|
+
process.exitCode = 0;
|
|
88821
|
+
}
|
|
88822
|
+
async function statuslineCommand(options2 = {}) {
|
|
88823
|
+
if (options2.refreshUsageCache) {
|
|
88824
|
+
await runUsageCacheRefresh(options2.debug);
|
|
88825
|
+
return;
|
|
88826
|
+
}
|
|
88827
|
+
let fallbackCwd = "";
|
|
88828
|
+
try {
|
|
88829
|
+
const raw = await readStdinJson();
|
|
88830
|
+
if (Object.keys(raw).length === 0) {
|
|
88831
|
+
process.stdout.write(`${fallbackLine(process.cwd())}
|
|
88832
|
+
`);
|
|
88833
|
+
process.exitCode = 0;
|
|
88834
|
+
return;
|
|
88835
|
+
}
|
|
88836
|
+
const payload = parseStatusPayload(raw);
|
|
88837
|
+
fallbackCwd = payload.cwd;
|
|
88838
|
+
const cwd2 = payload.cwd || process.cwd();
|
|
88839
|
+
const settings = await loadStatuslineSettings(cwd2);
|
|
88840
|
+
const billingMode = process.env.CLAUDE_BILLING_MODE || "api";
|
|
88841
|
+
const costUsd = billingMode === "api" ? payload.costUsd : null;
|
|
88842
|
+
const core = settings.brand.showCoreVersion ? await resolveCoreVersion(cwd2) : null;
|
|
88843
|
+
const data = {
|
|
88844
|
+
modelName: payload.modelName,
|
|
88845
|
+
cwd: cwd2,
|
|
88846
|
+
git: getGitSnapshot(cwd2),
|
|
88847
|
+
contextPercent: computeContextPercent(payload.contextWindow),
|
|
88848
|
+
costUsd,
|
|
88849
|
+
usageWindows: quotaWindows(),
|
|
88850
|
+
activity: readActivity(payload.sessionId)?.snapshot ?? null,
|
|
88851
|
+
versions: { cli: getCliVersion(), core }
|
|
88852
|
+
};
|
|
88853
|
+
process.stdout.write(`${renderStatusline(data, settings)}
|
|
88854
|
+
`);
|
|
88855
|
+
process.exitCode = 0;
|
|
88856
|
+
} catch (err) {
|
|
88857
|
+
writeDebug(options2.debug, "render", err);
|
|
88858
|
+
process.stdout.write(`${fallbackLine(fallbackCwd)}
|
|
88859
|
+
`);
|
|
88860
|
+
process.exitCode = 0;
|
|
88861
|
+
}
|
|
88862
|
+
}
|
|
87038
88863
|
// src/commands/telemetry/telemetry-command.ts
|
|
87039
88864
|
init_logger();
|
|
87040
88865
|
|
|
@@ -87042,24 +88867,24 @@ init_logger();
|
|
|
87042
88867
|
init_logger();
|
|
87043
88868
|
|
|
87044
88869
|
// src/commands/telemetry/shared.ts
|
|
87045
|
-
import { existsSync as
|
|
87046
|
-
import { homedir as
|
|
87047
|
-
import { join as
|
|
88870
|
+
import { existsSync as existsSync68, readFileSync as readFileSync28, readdirSync as readdirSync12 } from "node:fs";
|
|
88871
|
+
import { homedir as homedir32 } from "node:os";
|
|
88872
|
+
import { join as join138 } from "node:path";
|
|
87048
88873
|
init_token_store();
|
|
87049
88874
|
init_manifest_path_resolver();
|
|
87050
88875
|
init_takumi_constants();
|
|
87051
|
-
var USER_CACHE_PATH =
|
|
87052
|
-
var EVENT_BUFFER_DIR =
|
|
87053
|
-
var RATE_STATE_PATH =
|
|
87054
|
-
var TAKUMI_MANIFEST_PATH =
|
|
87055
|
-
var LEGACY_METADATA_PATH =
|
|
88876
|
+
var USER_CACHE_PATH = join138(homedir32(), ".claude", "sk-user.json");
|
|
88877
|
+
var EVENT_BUFFER_DIR = join138(homedir32(), ".claude", "sk-events");
|
|
88878
|
+
var RATE_STATE_PATH = join138(homedir32(), ".claude", "sk-rate-state.json");
|
|
88879
|
+
var TAKUMI_MANIFEST_PATH = join138(homedir32(), ".claude", MANIFEST_FILENAME);
|
|
88880
|
+
var LEGACY_METADATA_PATH = join138(homedir32(), ".claude", LEGACY_MANIFEST_FILENAME);
|
|
87056
88881
|
var TELEMETRY_HOOK_FIELD = "hooks.telemetry";
|
|
87057
88882
|
var TOKEN_PLACEHOLDER = "__INJECT_AT_RELEASE__";
|
|
87058
88883
|
function readUserCache() {
|
|
87059
88884
|
try {
|
|
87060
|
-
if (!
|
|
88885
|
+
if (!existsSync68(USER_CACHE_PATH))
|
|
87061
88886
|
return null;
|
|
87062
|
-
const parsed = JSON.parse(
|
|
88887
|
+
const parsed = JSON.parse(readFileSync28(USER_CACHE_PATH, "utf8"));
|
|
87063
88888
|
if (!parsed || typeof parsed !== "object")
|
|
87064
88889
|
return null;
|
|
87065
88890
|
return parsed;
|
|
@@ -87069,9 +88894,9 @@ function readUserCache() {
|
|
|
87069
88894
|
}
|
|
87070
88895
|
function countBufferFiles() {
|
|
87071
88896
|
try {
|
|
87072
|
-
if (!
|
|
88897
|
+
if (!existsSync68(EVENT_BUFFER_DIR))
|
|
87073
88898
|
return 0;
|
|
87074
|
-
return
|
|
88899
|
+
return readdirSync12(EVENT_BUFFER_DIR).filter((f4) => f4.endsWith(".jsonl")).length;
|
|
87075
88900
|
} catch {
|
|
87076
88901
|
return 0;
|
|
87077
88902
|
}
|
|
@@ -87081,9 +88906,9 @@ function readTelemetryConfig() {
|
|
|
87081
88906
|
const envToken = process.env.TAKUMI_TELEMETRY_TOKEN;
|
|
87082
88907
|
let metadata = null;
|
|
87083
88908
|
try {
|
|
87084
|
-
const resolved = findManifestPathSync(
|
|
88909
|
+
const resolved = findManifestPathSync(join138(homedir32(), ".claude"));
|
|
87085
88910
|
if (resolved) {
|
|
87086
|
-
metadata = JSON.parse(
|
|
88911
|
+
metadata = JSON.parse(readFileSync28(resolved.path, "utf8"));
|
|
87087
88912
|
}
|
|
87088
88913
|
} catch {
|
|
87089
88914
|
metadata = null;
|
|
@@ -87107,8 +88932,8 @@ function collectRuntimeContext() {
|
|
|
87107
88932
|
cacheSource: cache3?.source === "gh" || cache3?.source === "manual" ? cache3.source : null,
|
|
87108
88933
|
bufferFileCount: countBufferFiles(),
|
|
87109
88934
|
bufferDir: EVENT_BUFFER_DIR,
|
|
87110
|
-
rateStateExists:
|
|
87111
|
-
userCacheExists:
|
|
88935
|
+
rateStateExists: existsSync68(RATE_STATE_PATH),
|
|
88936
|
+
userCacheExists: existsSync68(USER_CACHE_PATH),
|
|
87112
88937
|
endpoint,
|
|
87113
88938
|
tokenConfigured: Boolean(token)
|
|
87114
88939
|
};
|
|
@@ -87258,8 +89083,8 @@ init_logger();
|
|
|
87258
89083
|
init_safe_prompts();
|
|
87259
89084
|
init_safe_spinner();
|
|
87260
89085
|
var import_fs_extra39 = __toESM(require_lib(), 1);
|
|
87261
|
-
import { readdirSync as
|
|
87262
|
-
import { join as
|
|
89086
|
+
import { readdirSync as readdirSync14, rmSync as rmSync11 } from "node:fs";
|
|
89087
|
+
import { join as join140, resolve as resolve34, sep as sep9 } from "node:path";
|
|
87263
89088
|
|
|
87264
89089
|
// src/commands/uninstall/analysis-handler.ts
|
|
87265
89090
|
init_metadata_migration();
|
|
@@ -87269,13 +89094,13 @@ init_logger();
|
|
|
87269
89094
|
init_safe_prompts();
|
|
87270
89095
|
init_takumi_constants();
|
|
87271
89096
|
var import_picocolors28 = __toESM(require_picocolors(), 1);
|
|
87272
|
-
import { existsSync as
|
|
87273
|
-
import { dirname as dirname43, join as
|
|
89097
|
+
import { existsSync as existsSync69, readdirSync as readdirSync13, rmSync as rmSync10 } from "node:fs";
|
|
89098
|
+
import { dirname as dirname43, join as join139 } from "node:path";
|
|
87274
89099
|
function listPresentManifestNames(installPath) {
|
|
87275
89100
|
const present = [];
|
|
87276
|
-
if (
|
|
89101
|
+
if (existsSync69(getManifestPath(installPath)))
|
|
87277
89102
|
present.push(MANIFEST_FILENAME);
|
|
87278
|
-
if (
|
|
89103
|
+
if (existsSync69(getLegacyManifestPath(installPath)))
|
|
87279
89104
|
present.push(LEGACY_MANIFEST_FILENAME);
|
|
87280
89105
|
return present;
|
|
87281
89106
|
}
|
|
@@ -87296,9 +89121,9 @@ async function cleanupEmptyDirectories3(filePath, installationRoot) {
|
|
|
87296
89121
|
let currentDir = dirname43(filePath);
|
|
87297
89122
|
while (currentDir !== installationRoot && currentDir.startsWith(installationRoot)) {
|
|
87298
89123
|
try {
|
|
87299
|
-
const entries =
|
|
89124
|
+
const entries = readdirSync13(currentDir);
|
|
87300
89125
|
if (entries.length === 0) {
|
|
87301
|
-
|
|
89126
|
+
rmSync10(currentDir, { recursive: true });
|
|
87302
89127
|
cleaned++;
|
|
87303
89128
|
logger.debug(`Removed empty directory: ${currentDir}`);
|
|
87304
89129
|
currentDir = dirname43(currentDir);
|
|
@@ -87323,7 +89148,7 @@ async function analyzeInstallation(installation, forceOverwrite, kit) {
|
|
|
87323
89148
|
if (uninstallManifest.isMultiKit && kit && metadata?.kits?.[kit]) {
|
|
87324
89149
|
const kitFiles = metadata.kits[kit].files || [];
|
|
87325
89150
|
for (const trackedFile of kitFiles) {
|
|
87326
|
-
const filePath =
|
|
89151
|
+
const filePath = join139(installation.path, trackedFile.path);
|
|
87327
89152
|
if (uninstallManifest.filesToPreserve.includes(trackedFile.path)) {
|
|
87328
89153
|
result.toPreserve.push({ path: trackedFile.path, reason: "shared with other kit" });
|
|
87329
89154
|
continue;
|
|
@@ -87355,7 +89180,7 @@ async function analyzeInstallation(installation, forceOverwrite, kit) {
|
|
|
87355
89180
|
return result;
|
|
87356
89181
|
}
|
|
87357
89182
|
for (const trackedFile of allTrackedFiles) {
|
|
87358
|
-
const filePath =
|
|
89183
|
+
const filePath = join139(installation.path, trackedFile.path);
|
|
87359
89184
|
const ownershipResult = await OwnershipChecker.checkOwnership(filePath, metadata, installation.path);
|
|
87360
89185
|
if (!ownershipResult.exists)
|
|
87361
89186
|
continue;
|
|
@@ -87454,7 +89279,7 @@ async function removeInstallations(installations, options2) {
|
|
|
87454
89279
|
let removedCount = 0;
|
|
87455
89280
|
let cleanedDirs = 0;
|
|
87456
89281
|
for (const item of analysis.toDelete) {
|
|
87457
|
-
const filePath =
|
|
89282
|
+
const filePath = join140(installation.path, item.path);
|
|
87458
89283
|
if (!await import_fs_extra39.pathExists(filePath))
|
|
87459
89284
|
continue;
|
|
87460
89285
|
if (!await isPathSafeToRemove(filePath, installation.path)) {
|
|
@@ -87473,9 +89298,9 @@ async function removeInstallations(installations, options2) {
|
|
|
87473
89298
|
await ManifestWriter.removeKitFromManifest(installation.path, options2.kit);
|
|
87474
89299
|
}
|
|
87475
89300
|
try {
|
|
87476
|
-
const remaining =
|
|
89301
|
+
const remaining = readdirSync14(installation.path);
|
|
87477
89302
|
if (remaining.length === 0) {
|
|
87478
|
-
|
|
89303
|
+
rmSync11(installation.path, { recursive: true });
|
|
87479
89304
|
logger.debug(`Removed empty installation directory: ${installation.path}`);
|
|
87480
89305
|
}
|
|
87481
89306
|
} catch {}
|
|
@@ -87656,7 +89481,7 @@ ${import_picocolors29.default.yellow("User modifications will be permanently del
|
|
|
87656
89481
|
// src/commands/update-cli.ts
|
|
87657
89482
|
init_takumi_config_manager();
|
|
87658
89483
|
init_npm_registry();
|
|
87659
|
-
import { exec as exec8, spawn as
|
|
89484
|
+
import { exec as exec8, spawn as spawn5 } from "node:child_process";
|
|
87660
89485
|
import { promisify as promisify14 } from "node:util";
|
|
87661
89486
|
init_metadata_migration();
|
|
87662
89487
|
init_version_utils();
|
|
@@ -87885,7 +89710,7 @@ async function promptKitUpdate(beta, yes, deps) {
|
|
|
87885
89710
|
const displayCmd = `tkm ${args.join(" ")}`;
|
|
87886
89711
|
logger.info(`Running: ${displayCmd}`);
|
|
87887
89712
|
const spawnFn = deps?.spawnInitFn ?? ((spawnArgs) => new Promise((resolve35) => {
|
|
87888
|
-
const child =
|
|
89713
|
+
const child = spawn5("tkm", spawnArgs, { stdio: "inherit", shell: true });
|
|
87889
89714
|
child.on("close", (code) => resolve35(code ?? 1));
|
|
87890
89715
|
child.on("error", (err) => {
|
|
87891
89716
|
logger.verbose(`Failed to spawn tkm init: ${err.message}`);
|
|
@@ -88274,6 +90099,12 @@ function registerCommands(cli) {
|
|
|
88274
90099
|
debug: options2.debug
|
|
88275
90100
|
});
|
|
88276
90101
|
});
|
|
90102
|
+
cli.command("statusline", "Render the Takumi statusline from a piped status JSON (agent-invoked)").option("--refresh-usage-cache", "Internal: run the detached usage-cache refresh").option("--debug", "Log swallowed errors to <cache>/statusline/debug.log").action(async (options2 = {}) => {
|
|
90103
|
+
await statuslineCommand({
|
|
90104
|
+
refreshUsageCache: options2.refreshUsageCache,
|
|
90105
|
+
debug: options2.debug
|
|
90106
|
+
});
|
|
90107
|
+
});
|
|
88277
90108
|
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) => {
|
|
88278
90109
|
await planCommand(action, target, options2);
|
|
88279
90110
|
});
|
|
@@ -88325,8 +90156,8 @@ init_version_checker();
|
|
|
88325
90156
|
init_manifest_path_resolver();
|
|
88326
90157
|
init_logger();
|
|
88327
90158
|
init_types2();
|
|
88328
|
-
import { readFileSync as
|
|
88329
|
-
import { join as
|
|
90159
|
+
import { readFileSync as readFileSync29 } from "node:fs";
|
|
90160
|
+
import { join as join141 } from "node:path";
|
|
88330
90161
|
var PROVIDER_LOCAL_SUBDIRS = {
|
|
88331
90162
|
"claude-code": ".claude",
|
|
88332
90163
|
codex: ".codex"
|
|
@@ -88381,7 +90212,7 @@ async function displayVersion() {
|
|
|
88381
90212
|
const localSubdir = PROVIDER_LOCAL_SUBDIRS[provider];
|
|
88382
90213
|
if (!localSubdir)
|
|
88383
90214
|
continue;
|
|
88384
|
-
const localRoot =
|
|
90215
|
+
const localRoot = join141(process.cwd(), localSubdir);
|
|
88385
90216
|
if (localRoot === inst.globalRoot())
|
|
88386
90217
|
continue;
|
|
88387
90218
|
const resolved = findManifestPathSync(localRoot);
|
|
@@ -88391,7 +90222,7 @@ async function displayVersion() {
|
|
|
88391
90222
|
}
|
|
88392
90223
|
for (const { provider, path: metaPath } of localChecks) {
|
|
88393
90224
|
try {
|
|
88394
|
-
const rawMetadata = JSON.parse(
|
|
90225
|
+
const rawMetadata = JSON.parse(readFileSync29(metaPath, "utf-8"));
|
|
88395
90226
|
const metadata = MetadataSchema.parse(rawMetadata);
|
|
88396
90227
|
const kitsDisplay = formatInstalledKits(metadata);
|
|
88397
90228
|
if (kitsDisplay) {
|
|
@@ -88411,7 +90242,7 @@ async function displayVersion() {
|
|
|
88411
90242
|
const resolved = findManifestPathSync(installPath);
|
|
88412
90243
|
if (resolved) {
|
|
88413
90244
|
try {
|
|
88414
|
-
const rawMetadata = JSON.parse(
|
|
90245
|
+
const rawMetadata = JSON.parse(readFileSync29(resolved.path, "utf-8"));
|
|
88415
90246
|
const metadata = MetadataSchema.parse(rawMetadata);
|
|
88416
90247
|
const kitsDisplay = formatInstalledKits(metadata);
|
|
88417
90248
|
if (kitsDisplay) {
|
|
@@ -88566,8 +90397,8 @@ class Logger2 {
|
|
|
88566
90397
|
process.exit(1);
|
|
88567
90398
|
});
|
|
88568
90399
|
}
|
|
88569
|
-
sanitize(
|
|
88570
|
-
return
|
|
90400
|
+
sanitize(text2) {
|
|
90401
|
+
return text2.replace(/ghp_[a-zA-Z0-9]{36}/g, "ghp_***").replace(/github_pat_[a-zA-Z0-9_]{82}/g, "github_pat_***").replace(/gho_[a-zA-Z0-9]{36}/g, "gho_***").replace(/ghu_[a-zA-Z0-9]{36}/g, "ghu_***").replace(/ghs_[a-zA-Z0-9]{36}/g, "ghs_***").replace(/ghr_[a-zA-Z0-9]{36}/g, "ghr_***").replace(/Bearer [a-zA-Z0-9_-]+/g, "Bearer ***").replace(/token=[a-zA-Z0-9_-]+/g, "token=***");
|
|
88571
90402
|
}
|
|
88572
90403
|
getTimestamp() {
|
|
88573
90404
|
return new Date().toISOString();
|
|
@@ -88793,7 +90624,7 @@ var output2 = new OutputManager2;
|
|
|
88793
90624
|
// src/shared/temp-cleanup.ts
|
|
88794
90625
|
init_logger();
|
|
88795
90626
|
var import_fs_extra41 = __toESM(require_lib(), 1);
|
|
88796
|
-
import { rmSync as
|
|
90627
|
+
import { rmSync as rmSync12 } from "node:fs";
|
|
88797
90628
|
var tempDirs2 = new Set;
|
|
88798
90629
|
async function cleanup() {
|
|
88799
90630
|
if (tempDirs2.size === 0)
|
|
@@ -88814,7 +90645,7 @@ function cleanupSync() {
|
|
|
88814
90645
|
return;
|
|
88815
90646
|
for (const dir of tempDirs2) {
|
|
88816
90647
|
try {
|
|
88817
|
-
|
|
90648
|
+
rmSync12(dir, { recursive: true, force: true });
|
|
88818
90649
|
} catch {}
|
|
88819
90650
|
}
|
|
88820
90651
|
tempDirs2.clear();
|