claude-code-session-manager 0.120.0 → 0.122.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/{AgentLibrary-LBg3mVL8.js → AgentLibrary-BmJ8hIPw.js} +1 -1
- package/dist/assets/{Button-C4BN5ISR.js → Button-BS4kmz4p.js} +1 -1
- package/dist/assets/{DataModel-CHhjk61s.js → DataModel-DZHBZrfL.js} +1 -1
- package/dist/assets/History-pg00b2Gd.js +2 -0
- package/dist/assets/{Hooks-ByWVgXIf.js → Hooks-BTEs0UZY.js} +1 -1
- package/dist/assets/{Library-QvYVAEmY.js → Library-DuaJ-VSn.js} +1 -1
- package/dist/assets/{ListDetail-FvNe6fo5.js → ListDetail-Cud72s-O.js} +1 -1
- package/dist/assets/{McpServers-C7EmPm8B.js → McpServers-Dy-wnG_X.js} +1 -1
- package/dist/assets/{Memory-nyLR4Yw4.js → Memory-Bs1T1Jo7.js} +1 -1
- package/dist/assets/{Panel-thElCbLX.js → Panel-8UhLXEOW.js} +1 -1
- package/dist/assets/{Permissions-FQ9GM6Ca.js → Permissions-BfwzvmBS.js} +1 -1
- package/dist/assets/Plugins-McjyvvKh.js +2 -0
- package/dist/assets/{ProvenanceBadge-lAViG8yV.js → ProvenanceBadge-D0Ov_6WJ.js} +1 -1
- package/dist/assets/{RemoteMachines-AWpARk7N.js → RemoteMachines-gOlFTvWq.js} +1 -1
- package/dist/assets/{SaveBar-c15EEGB_.js → SaveBar-Cd6hJR6K.js} +1 -1
- package/dist/assets/Scheduler-BZXKqYJP.js +16 -0
- package/dist/assets/{ScopeSwitcher-BLep1rtB.js → ScopeSwitcher-C24ysV1K.js} +1 -1
- package/dist/assets/{Settings-D1kTUIDB.js → Settings-DWnN2qxn.js} +1 -1
- package/dist/assets/{SkillReferenceGraph-_40_f0t3.js → SkillReferenceGraph-BsWuiTbw.js} +1 -1
- package/dist/assets/{Skills-DaTkSOuU.js → Skills-6pHn6glu.js} +1 -1
- package/dist/assets/{SystemPrompt-DxNf-soM.js → SystemPrompt-DT0LBH-K.js} +1 -1
- package/dist/assets/{TagLibrary-L6KpBV-x.js → TagLibrary-DbJ0zbYL.js} +1 -1
- package/dist/assets/{TiptapBody-C_XjtJ82.js → TiptapBody-C4kIvIMH.js} +1 -1
- package/dist/assets/{Toggle-H0rERKNI.js → Toggle-pP19zlyk.js} +1 -1
- package/dist/assets/{ViewTabs-ZUWphDat.js → ViewTabs-CpzN8e5I.js} +1 -1
- package/dist/assets/{historyTotals-BxFKOztb.js → historyTotals-Caq78bb5.js} +1 -1
- package/dist/assets/{index-B5wj0DEX.js → index-Bjtguv6I.js} +434 -434
- package/dist/assets/{settingsSchema-BRcYkXJN.js → settingsSchema-CC2ySu3d.js} +1 -1
- package/dist/assets/{skillFrontmatter-DFGp4DST.js → skillFrontmatter-hDhNo8jE.js} +1 -1
- package/dist/assets/{useAgentsDirWatch-VvrgalfC.js → useAgentsDirWatch-BuOtY25U.js} +1 -1
- package/dist/assets/{useRemotePeers-mvXKNEE3.js → useRemotePeers-CNQmRBpt.js} +1 -1
- package/dist/index.html +1 -1
- package/package.json +1 -1
- package/plugins/session-manager-dev/skills/develop/SKILL.md +7 -7
- package/plugins/session-manager-dev/skills/develop/standards.md +4 -10
- package/scripts/scheduler-mcp-server.cjs +2 -2
- package/src/main/build-info.json +4 -4
- package/src/main/chatRunner.cjs +56 -43
- package/src/main/docEdit.cjs +1 -0
- package/src/main/index.cjs +12 -13
- package/src/main/ipcSchemas.cjs +17 -3
- package/src/main/lib/classifyPromptTicket.cjs +1 -0
- package/src/main/lib/claude/effectiveModelInfo.cjs +9 -21
- package/src/main/lib/claude/personaToolScope.cjs +7 -1
- package/src/main/lib/claude/runClaudeP.cjs +1 -0
- package/src/main/lib/epic/delegationReadiness.cjs +75 -8
- package/src/main/lib/mcpToolCatalog.cjs +0 -1
- package/src/main/lib/persona-macro/macroLibrary.cjs +75 -0
- package/src/main/lib/persona-macro/shippedPersonaSeeds.cjs +11 -0
- package/src/main/lib/prd/prdCreate.cjs +28 -1
- package/src/main/lib/prd/prdSizing.cjs +1 -8
- package/src/main/lib/remoteTranscriptTail.cjs +69 -2
- package/src/main/lib/runSeeders.cjs +21 -0
- package/src/main/lib/scheduler/loopEfficiency.cjs +109 -0
- package/src/main/lib/scheduler/queueHistory.cjs +44 -1
- package/src/main/lib/scheduler/queueStore.cjs +4 -72
- package/src/main/lib/scheduler/rcaReport.cjs +1 -1
- package/src/main/lib/scheduler/refireCap.cjs +40 -0
- package/src/main/lib/scheduler/reviewNotice.cjs +1 -1
- package/src/main/lib/scheduler/schedulerConfig.cjs +1 -2
- package/src/main/lib/scheduler/schedulerPaths.cjs +0 -2
- package/src/main/lib/scheduler/sessionSlots.cjs +1 -1
- package/src/main/lib/telemetry/auditLog.cjs +65 -14
- package/src/main/loopEfficiencyHandlers.cjs +160 -0
- package/src/main/queueOps.cjs +4 -9
- package/src/main/runVerify.cjs +22 -454
- package/src/main/scheduler/reviewLadder.cjs +12 -2
- package/src/main/scheduler.cjs +103 -177
- package/src/main/seedDevPlugin.cjs +49 -22
- package/src/main/seedStatus.cjs +3 -2
- package/src/main/supervisor.cjs +1 -0
- package/src/main/templates/PRD_AUTHORING.md +16 -31
- package/src/main/webRemote.cjs +82 -91
- package/src/preload/api.d.ts +39 -6
- package/src/preload/index.cjs +3 -0
- package/src/seed/agents/dev-lead.md +2 -9
- package/dist/assets/History-CL-T6Lv3.js +0 -2
- package/dist/assets/Plugins-D9KE7XTI.js +0 -2
- package/dist/assets/Scheduler-FvduP1FG.js +0 -16
package/src/preload/api.d.ts
CHANGED
|
@@ -489,10 +489,10 @@ export interface DelegationReadiness {
|
|
|
489
489
|
}
|
|
490
490
|
|
|
491
491
|
/** First-boot seeder outcome, one per seeder id, derived from its marker file.
|
|
492
|
-
* `fix` is the manual remedy shown by the Plugins banner when `status` is 'exhausted'. */
|
|
492
|
+
* `fix` is the manual remedy shown by the Plugins banner when `status` is 'failed' or 'exhausted'. */
|
|
493
493
|
export type SeedStatus = Record<
|
|
494
494
|
'dev-plugin' | 'scheduler-mcp' | 'agent-personas',
|
|
495
|
-
{ status: 'done' | 'pending' | 'exhausted'; fix: string }
|
|
495
|
+
{ status: 'done' | 'pending' | 'failed' | 'exhausted'; fix: string }
|
|
496
496
|
>;
|
|
497
497
|
|
|
498
498
|
export interface OtelConfig {
|
|
@@ -622,14 +622,14 @@ export interface TelemetryFlushResult {
|
|
|
622
622
|
reason: string;
|
|
623
623
|
}
|
|
624
624
|
|
|
625
|
-
export type ScheduleFirePolicy = 'manual' | '
|
|
625
|
+
export type ScheduleFirePolicy = 'manual' | 'when-available';
|
|
626
626
|
|
|
627
627
|
export interface ScheduleConfig {
|
|
628
628
|
/** Legacy on/off — kept for backwards compat with v0.4 queue.json. New
|
|
629
629
|
* installs derive enablement from firePolicy ('manual' === disabled). */
|
|
630
630
|
enabled: boolean;
|
|
631
631
|
/** Minutes to wait after the 5h reset before firing pending jobs.
|
|
632
|
-
*
|
|
632
|
+
* Currently unused by the fire policies ('when-available', 'manual'). */
|
|
633
633
|
offsetMinutes: number;
|
|
634
634
|
defaultCwd: string;
|
|
635
635
|
/** Auto-fire policy. Default 'when-available'. */
|
|
@@ -977,7 +977,6 @@ export interface ScheduleStateSnapshot {
|
|
|
977
977
|
/** Why the last tick fired (or didn't). Null before the first tick. */
|
|
978
978
|
lastTick?: ScheduleLastTick | null;
|
|
979
979
|
jobs: ScheduleJob[];
|
|
980
|
-
scheduledFor: string | null;
|
|
981
980
|
lastRunAt: string | null;
|
|
982
981
|
/** Stamped every time tickQueue reaches the picker at all, whether or not
|
|
983
982
|
* that pass ends in a launch — distinct from lastRunAt (only stamped on an
|
|
@@ -1646,6 +1645,17 @@ export interface ChatExternalSendEvent {
|
|
|
1646
1645
|
/** Epic's claudeSessionId + project cwd, resolved by main so the renderer can deliver before the Epic's project is loaded. */
|
|
1647
1646
|
sessionId?: string;
|
|
1648
1647
|
cwd?: string;
|
|
1648
|
+
/** Set by main's enqueueExternalPrompt on every push; the renderer must echo it back via `reportExternalSendResult`. */
|
|
1649
|
+
requestId?: string;
|
|
1650
|
+
}
|
|
1651
|
+
|
|
1652
|
+
export type ChatExternalSendDisposition = 'sent' | 'queued' | 'refused';
|
|
1653
|
+
export type ChatExternalSendRefusalReason = 'terminal-attached' | 'completed' | 'unknown-target' | 'empty-prompt';
|
|
1654
|
+
/** What the renderer did with a `ChatExternalSendEvent`, reported back to main. */
|
|
1655
|
+
export interface ChatExternalSendResult {
|
|
1656
|
+
requestId: string;
|
|
1657
|
+
disposition: ChatExternalSendDisposition;
|
|
1658
|
+
reason?: ChatExternalSendRefusalReason;
|
|
1649
1659
|
}
|
|
1650
1660
|
|
|
1651
1661
|
export type CreateProjectFolderResult =
|
|
@@ -1770,7 +1780,7 @@ export interface SessionManagerAPI {
|
|
|
1770
1780
|
* on macOS symlinked-/Users mismatch and blocks all session spawns. */
|
|
1771
1781
|
homeSelfCheck: () => Promise<{ ok: boolean; error?: string; realCwd?: string }>;
|
|
1772
1782
|
/** First-boot seeder outcomes, read live from each seeder's own marker
|
|
1773
|
-
* file: 'done' (succeeded), 'pending' (not yet run
|
|
1783
|
+
* file: 'done' (succeeded), 'pending' (not yet run), 'failed' (an attempt failed; retries next launch),
|
|
1774
1784
|
* 'exhausted' (gave up after MAX_ATTEMPTS — manual fix needed). */
|
|
1775
1785
|
seedStatus: () => Promise<SeedStatus>;
|
|
1776
1786
|
/** "Can this project actually delegate?" — the 4 preconditions for
|
|
@@ -2046,6 +2056,8 @@ export interface SessionManagerAPI {
|
|
|
2046
2056
|
aggregate: (req?: HistoryAggregateRequest) => Promise<HistoryAggregateResult>;
|
|
2047
2057
|
scanProjects: () => Promise<SessionScanResult>;
|
|
2048
2058
|
dashboard: (req: HistoryDashboardRequest) => Promise<HistoryDashboardResult>;
|
|
2059
|
+
/** This usage week's validated-PRDs-per-usage efficiency, per project (loopEfficiency.cjs). */
|
|
2060
|
+
loopEfficiency: () => Promise<LoopEfficiencyResult>;
|
|
2049
2061
|
/** Fires (throttled to 1/5 s) when main appends days to the rollup. Returns unsubscribe. */
|
|
2050
2062
|
onUpdated: (handler: () => void) => () => void;
|
|
2051
2063
|
};
|
|
@@ -2297,6 +2309,8 @@ export interface SessionManagerAPI {
|
|
|
2297
2309
|
* tool) pushes a prompt into an open tab's queue from outside the
|
|
2298
2310
|
* renderer (PRD 753). */
|
|
2299
2311
|
onExternalSend: (handler: (e: ChatExternalSendEvent) => void) => () => void;
|
|
2312
|
+
/** Reports what the renderer did with an external send (echoing its requestId) back to main. */
|
|
2313
|
+
reportExternalSendResult: (result: ChatExternalSendResult) => Promise<void>;
|
|
2300
2314
|
/** Fires when a paired phone asks main to start a new Session (payload pre-validated in main). */
|
|
2301
2315
|
onExternalNewSession: (
|
|
2302
2316
|
handler: (e: { cwd: string; agentName: string; tag: AgentPersonaTag; title: string; prompt: string }) => void,
|
|
@@ -2501,3 +2515,22 @@ declare global {
|
|
|
2501
2515
|
}
|
|
2502
2516
|
|
|
2503
2517
|
export {};
|
|
2518
|
+
|
|
2519
|
+
interface LoopEfficiencyRow {
|
|
2520
|
+
cwd: string;
|
|
2521
|
+
project: string;
|
|
2522
|
+
runs: number;
|
|
2523
|
+
wastedRuns: number;
|
|
2524
|
+
verified: number;
|
|
2525
|
+
refuted: number;
|
|
2526
|
+
executorUsd: number;
|
|
2527
|
+
usdPerVerified: number | null;
|
|
2528
|
+
}
|
|
2529
|
+
interface LoopEfficiencyResult {
|
|
2530
|
+
fromMs: number;
|
|
2531
|
+
toMs: number;
|
|
2532
|
+
rows: LoopEfficiencyRow[];
|
|
2533
|
+
totals: { runs: number; wastedRuns: number; verified: number; refuted: number; executorUsd: number; wastedRunRate: number };
|
|
2534
|
+
weeklyUtilizationPct: number | null;
|
|
2535
|
+
verifiedPerUsagePct: number | null;
|
|
2536
|
+
}
|
package/src/preload/index.cjs
CHANGED
|
@@ -244,6 +244,7 @@ contextBridge.exposeInMainWorld('api', {
|
|
|
244
244
|
aggregate: (req) => ipcRenderer.invoke('history:aggregate', req),
|
|
245
245
|
scanProjects: () => ipcRenderer.invoke('history:scan-projects'),
|
|
246
246
|
dashboard: (req) => ipcRenderer.invoke('history:dashboard', req),
|
|
247
|
+
loopEfficiency: () => ipcRenderer.invoke('history:loop-efficiency'),
|
|
247
248
|
// Fired (throttled) after main appends new days to the rollup.
|
|
248
249
|
onUpdated: (handler) => {
|
|
249
250
|
const listener = () => handler();
|
|
@@ -536,6 +537,8 @@ contextBridge.exposeInMainWorld('api', {
|
|
|
536
537
|
ipcRenderer.on('chat:external-send', listener);
|
|
537
538
|
return () => ipcRenderer.removeListener('chat:external-send', listener);
|
|
538
539
|
},
|
|
540
|
+
/** Reports the renderer's disposition for an external send back to main. */
|
|
541
|
+
reportExternalSendResult: (result) => ipcRenderer.invoke('chat:external-send-result', result),
|
|
539
542
|
/** Fires when a paired phone asks main to start a new Session. */
|
|
540
543
|
onExternalNewSession: (handler) => {
|
|
541
544
|
const listener = (_e, payload) => handler(payload);
|
|
@@ -5,7 +5,7 @@ tools: Read, Grep, Glob, Bash, Edit, Write
|
|
|
5
5
|
model: sonnet
|
|
6
6
|
effort: medium
|
|
7
7
|
title: Engineering — Software Engineer
|
|
8
|
-
seedVersion:
|
|
8
|
+
seedVersion: 4
|
|
9
9
|
---
|
|
10
10
|
|
|
11
11
|
You are dev-lead. You execute one PRD — nothing above it, nothing beyond it. You don't decide
|
|
@@ -32,14 +32,7 @@ points you at), and the project's own files.
|
|
|
32
32
|
2. BUILD. Change only the files listed in `# Files`. If you need another file, change it and say why in your report. Why: an edit outside the list collides with another PRD's own edit to that file.
|
|
33
33
|
3. FINISH. Follow the SCHEDULER FINISH PROTOCOL at the end of your prompt — do not run the gate, commit, or print a verdict yourself outside it. That protocol runs the `# Gate` commands in order, commits with exact paths, and prints the scheduler's own last line, `SCHEDULER_VERDICT: PASS`, only when the gate came back green and the commit landed.
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
- A bare absence check reads as an error. Write it `if grep …; then echo HALT; exit 1; fi; echo clean` so a clean result exits 0.
|
|
37
|
-
- Run an expected failure (a red test, a probe) early and capture its output. Nothing may error after the gate runs.
|
|
38
|
-
- When a probe errors, re-run it corrected at once, or print `# expected/handled: <why>` on the next line. Never leave an unexplained error in the transcript.
|
|
39
|
-
- A `timeout` that exits 124 as expected still needs a branch: print OK on 124, never leave a bare 124 in the output.
|
|
40
|
-
- Never call ScheduleWakeup or Monitor, never start background work, never invoke /develop or queue work. The finish protocol's review steps are the only exception: run them in the foreground.
|
|
41
|
-
- `gh pr checks` exits 8 while a run is still pending. Wrap it, annotate the exit code, and poll with the identical command each time.
|
|
42
|
-
- Retry a transient failure with the exact same command text, so the verifier can pair the recovery with the failure it recovered from.
|
|
35
|
+
Never call ScheduleWakeup or Monitor, never start background work, never invoke /develop or queue work. The finish protocol's review steps run in the foreground.
|
|
43
36
|
|
|
44
37
|
Out of contract: anything past the Acceptance Criteria list. If the PRD looks wrong, do the AC as written anyway and say why in your report — don't expand or redesign it yourself.
|
|
45
38
|
`standards.md` (the PRD names its path) carries the reasoning behind every line above. Open the one section you need; don't re-read the whole file every run.
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{az as xe,aI as ze,bm as Ke,ap as e,aF as f,aX as q,aA as A,aB as O,b6 as Ge,be as ye,au as Ye,b5 as Ve,n as Xe}from"./index-B5wj0DEX.js";import{P as qe}from"./Panel-thElCbLX.js";import{p as De,i as L,m as $e,t as I,u as $,f as Qe}from"./historyTotals-BxFKOztb.js";import"./monaco-editor-BsIlgG7c.js";function re(){return{promptCount:0,inputTokens:0,outputTokens:0,cacheReadTokens:0,cacheCreationTokens:0,toolCallCount:0,sessionCount:0,errorCount:0,activeMinutes:0,estimatedCostUsd:0}}function Ce(t,s){t.promptCount+=s.promptCount,t.inputTokens+=s.inputTokens,t.outputTokens+=s.outputTokens,t.cacheReadTokens+=s.cacheReadTokens,t.cacheCreationTokens+=s.cacheCreationTokens,t.toolCallCount+=s.toolCallCount,t.sessionCount+=s.sessionCount,t.errorCount+=s.errorCount,t.activeMinutes+=s.activeMinutes,t.estimatedCostUsd+=s.estimatedCostUsd}function Ze(t){return t.promptCount>0||t.sessionCount>0||t.toolCallCount>0||t.inputTokens>0||t.outputTokens>0}function Je(t,s){const n=s===null,c=[],o=re(),r={};let a=0;for(const l of t.days){const u=re();let d=!1;for(const[i,x]of Object.entries(l.byProject))if(!(!n&&!s.has(i))){Ce(u,x),Ce(o,x),Ze(x)&&(d=!0);for(const[m,k]of Object.entries(x.byModel)){const v=r[m]??(r[m]={inputTokens:0,outputTokens:0,cacheReadTokens:0,cacheCreationTokens:0,costUsd:0});v.inputTokens+=k.inputTokens,v.outputTokens+=k.outputTokens,v.cacheReadTokens+=k.cacheReadTokens,v.cacheCreationTokens+=k.cacheCreationTokens,v.costUsd+=k.costUsd,k.estimated&&(v.estimated=!0)}}d&&(a+=1),c.push({date:l.date,totals:u})}return{days:c,totals:o,prevTotals:n?t.prevTotals:re(),prevAvailable:n,byModelTotals:r,activeDays:a}}function Ee(t,s){if(!s)return{pct:null,direction:"flat"};const n=(t-s)/s*100,c=n>0?"up":n<0?"down":"flat";return{pct:n,direction:c}}function et(t,s,n){return s<=0?0:t/s*n}const tt=["promptCount","inputTokens","outputTokens","cacheReadTokens","cacheCreationTokens","toolCallCount","sessionCount","errorCount","activeMinutes","estimatedCostUsd"],st=["inputTokens","outputTokens","cacheReadTokens","cacheCreationTokens","costUsd"];function Te(t){const s={promptCount:0,inputTokens:0,outputTokens:0,cacheReadTokens:0,cacheCreationTokens:0,toolCallCount:0,sessionCount:0,errorCount:0,activeMinutes:0,estimatedCostUsd:0,byModel:{}},n=c=>typeof c=="number"&&Number.isFinite(c)?c:0;for(const c of t){for(const o of tt)s[o]+=n(c[o]);for(const[o,r]of Object.entries(c.byModel??{})){const a=s.byModel[o]??(s.byModel[o]={inputTokens:0,outputTokens:0,cacheReadTokens:0,cacheCreationTokens:0,costUsd:0});for(const l of st)a[l]+=n(r==null?void 0:r[l])}}return s}const Ue={in:"In tokens",out:"Out tokens",total:"Total tokens",prompts:"Prompts",sessions:"Sessions",time:"Time",spend:"Spend"};function S(t,s){const n=t.inputTokens+t.cacheReadTokens+t.cacheCreationTokens;switch(s){case"in":return n;case"out":return t.outputTokens;case"total":return n+t.outputTokens;case"prompts":return t.promptCount;case"sessions":return t.sessionCount;case"time":return t.activeMinutes;case"spend":return t.estimatedCostUsd}}function nt(t,s){const n=S(t.totals,s),c=t.prevAvailable?Ee(n,S(t.prevTotals,s)):null,o=t.days.map(r=>S(r.totals,s));return{value:n,delta:c,series:o}}function Ne(t,s){const n=new Map,c=Math.ceil(t.length/2);t.forEach((a,l)=>{for(const[u,d]of Object.entries(a.byProject)){let i=n.get(u);i||(i={totals:{promptCount:0,inputTokens:0,outputTokens:0,cacheReadTokens:0,cacheCreationTokens:0,toolCallCount:0,sessionCount:0,errorCount:0,activeMinutes:0,estimatedCostUsd:0},toolBreakdown:{},firstHalf:0,secondHalf:0},n.set(u,i)),i.totals.promptCount+=d.promptCount,i.totals.inputTokens+=d.inputTokens,i.totals.outputTokens+=d.outputTokens,i.totals.cacheReadTokens+=d.cacheReadTokens,i.totals.cacheCreationTokens+=d.cacheCreationTokens,i.totals.toolCallCount+=d.toolCallCount,i.totals.sessionCount+=d.sessionCount,i.totals.errorCount+=d.errorCount,i.totals.activeMinutes+=d.activeMinutes,i.totals.estimatedCostUsd+=d.estimatedCostUsd;for(const[m,k]of Object.entries(d.toolBreakdown))i.toolBreakdown[m]=(i.toolBreakdown[m]??0)+k;const x=S(d,s);l<c?i.firstHalf+=x:i.secondHalf+=x}});const o=Array.from(n.entries()).map(([a,l])=>{let u="",d=-1;for(const[i,x]of Object.entries(l.toolBreakdown))x>d&&(d=x,u=i);return{projectDir:a,value:S(l.totals,s),sharePct:0,trend:Ee(l.secondHalf,l.firstHalf),sessions:l.totals.sessionCount,topTool:u}}),r=o.reduce((a,l)=>a+l.value,0);for(const a of o)a.sharePct=r>0?a.value/r*100:0;return o.sort((a,l)=>l.value-a.value)}const ot=["date","cost_usd","input_tokens","output_tokens","cache_write_tokens","cache_read_tokens","total_tokens","cache_hit_pct","num_models","top_model"];function at(t){return/[",\n]/.test(t)?`"${t.replace(/"/g,'""')}"`:t}function we(t){return t.inputTokens+t.outputTokens+t.cacheReadTokens+t.cacheCreationTokens}function ct(t){const s=t.map(n=>{const c=n.inputTokens+n.outputTokens+n.cacheCreationTokens+n.cacheReadTokens,o=n.inputTokens+n.cacheReadTokens+n.cacheCreationTokens,r=o>0?n.cacheReadTokens/o*100:0,a=Object.entries(n.byModel).filter(([,i])=>we(i)>0);let l="",u=-1;for(const[i,x]of a){const m=we(x);m>u&&(u=m,l=i)}return[n.date,n.costUsd.toFixed(4),String(n.inputTokens),String(n.outputTokens),String(n.cacheCreationTokens),String(n.cacheReadTokens),String(c),r.toFixed(1),String(a.length),l?xe(l):""].map(at).join(",")});return[ot.join(","),...s].join(`
|
|
2
|
-
`)}const rt={folderCount:0,sessionCount:0,promptCount:0,estimatedCostUsd:0,totalTokens:0};function it(t,s){t.promptCount+=s.promptCount,t.inputTokens+=s.inputTokens,t.outputTokens+=s.outputTokens,t.cacheReadTokens+=s.cacheReadTokens,t.cacheCreationTokens+=s.cacheCreationTokens,t.toolCallCount+=s.toolCallCount,t.sessionCount+=s.sessionCount,t.errorCount+=s.errorCount,t.activeMinutes+=s.activeMinutes,t.estimatedCostUsd+=s.estimatedCostUsd;for(const[n,c]of Object.entries(s.toolBreakdown??{}))t.toolBreakdown[n]=(t.toolBreakdown[n]??0)+c;for(const[n,c]of Object.entries(s.byModel??{})){const o=t.byModel[n]??(t.byModel[n]={inputTokens:0,outputTokens:0,cacheReadTokens:0,cacheCreationTokens:0,costUsd:0});o.inputTokens+=c.inputTokens,o.outputTokens+=c.outputTokens,o.cacheReadTokens+=c.cacheReadTokens,o.cacheCreationTokens+=c.cacheCreationTokens,o.costUsd+=c.costUsd,c.estimated&&(o.estimated=!0)}}function lt(t,s){const n={};for(const[c,o]of Object.entries(t.byModel??{}))n[c]={...o};return{...t,projectDir:s,toolBreakdown:{...t.toolBreakdown??{}},byModel:n}}function dt(t,s){const n={...rt},c=new Set,o=t.map(r=>{const a={};for(const[l,u]of Object.entries(r.byProject)){const d=s[l];if(!d){c.add(l),n.sessionCount+=u.sessionCount,n.promptCount+=u.promptCount,n.estimatedCostUsd+=u.estimatedCostUsd,n.totalTokens+=u.inputTokens+u.outputTokens;continue}const i=a[d];i?it(i,u):a[d]=lt(u,d)}return{...r,byProject:a}});return n.folderCount=c.size,{days:o,excluded:n}}function ut(t){return t.folderCount>0}function pt(t){const s=[`${t.folderCount} transcript folder${t.folderCount===1?"":"s"} with no resolvable working directory`];return t.sessionCount&&s.push(`${t.sessionCount.toLocaleString()} sessions`),t.promptCount&&s.push(`${t.promptCount.toLocaleString()} prompts`),t.estimatedCostUsd>=.005&&s.push(`$${t.estimatedCostUsd.toFixed(2)}`),`Excluded: ${s.join(" · ")}`}async function fe(){return(await ze()).history??{}}let Me=Promise.resolve();function ue(t){const s=Me.then(async()=>{const n=await fe();await Ke({history:{...n,...t}})});return Me=s.catch(()=>{}),s}const xt=["in","out","total","prompts","sessions","time","spend"],ft=[{value:30,label:"30d"},{value:60,label:"60d"},{value:90,label:"90d"},{value:0,label:"All time"}];function Re({value:t,options:s,onChange:n}){return e.jsx("div",{className:"flex gap-0.5 p-0.5 rounded bg-bg-elev shadow-[inset_0_0_0_1px_rgba(0,0,0,0.06)] text-[11px]",children:s.map(c=>e.jsx("button",{onClick:()=>n(c.value),className:`px-2 py-1 rounded whitespace-nowrap font-mono ${t===c.value?"bg-bg-hi text-fg shadow-sm":"text-fg-faint hover:text-fg"}`,children:c.label},String(c.value)))})}function ht({measure:t,onMeasure:s,range:n,onRange:c,projectsShown:o,projectsTotal:r,fromDate:a,toDate:l,onRefresh:u,onExport:d,exportDisabled:i}){return e.jsxs("div",{className:"sticky top-0 z-10 border-b border-line px-4 py-2.5 flex flex-wrap items-center gap-3 backdrop-blur-sm",style:{backgroundColor:"rgba(246,239,225,0.93)"},children:[e.jsx(Re,{value:t,options:xt.map(x=>({value:x,label:Ue[x]})),onChange:s}),e.jsx(Re,{value:n,options:ft,onChange:c}),e.jsxs("span",{className:"text-[11px] text-fg-faint font-mono",children:[o," / ",r," projects"]}),e.jsxs("span",{className:"text-[11px] text-fg-faint font-mono",children:[a," → ",l]}),e.jsx("div",{className:"flex-1"}),e.jsx("button",{onClick:u,className:"px-2 py-1 text-[11px] border border-line rounded hover:text-fg hover:bg-bg-hi text-fg-faint",title:"Re-fetch the rollup (no scan)",children:"↻ Refresh"}),e.jsx("button",{onClick:d,disabled:i,className:"px-2 py-1 text-[11px] border border-line rounded hover:text-fg hover:bg-bg-hi text-fg-faint disabled:opacity-40 disabled:pointer-events-none",children:"Export CSV"})]})}const w="rounded-card bg-bg-hi border border-line",mt="#ded2bd",jt="#6f7d52";function D({kicker:t,title:s,right:n}){return e.jsxs("div",{className:"flex items-baseline justify-between gap-3 mb-3",children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-[10.5px] uppercase tracking-wider text-accent font-mono",children:t}),e.jsx("h2",{className:"font-serif text-[25px] leading-tight tracking-tight text-fg",children:s})]}),n]})}function Q(t,s){switch(t){case"spend":return $(s);case"in":case"out":case"total":return I(s);case"time":return $e(s);default:return L(s)}}function gt({measure:t,headline:s,activeDays:n,projectsTouched:c,totalSessions:o}){const r=n>0?s.value/n:0,a=o>0?s.value/o:0,{delta:l}=s,u=l&&(t==="spend"?l.direction==="down":l.direction==="up"),d=l&&l.direction!=="flat"&&(t==="spend"?l.direction==="up":l.direction==="down"),i=u?"text-delta-good":d?"text-delta-bad":"text-fg-faint";return e.jsxs("div",{className:`${w} p-4`,children:[e.jsx(D,{kicker:"01 · overview",title:Ue[t]}),e.jsxs("div",{className:"flex items-start justify-between gap-4",children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-[52px] leading-none font-mono tracking-tight text-fg",children:Q(t,s.value)}),l?e.jsxs("div",{className:`text-xs font-mono mt-2 ${i}`,children:[l.direction==="up"?"▲":l.direction==="down"?"▼":"·"," ",De(Math.abs(l.pct??0))," vs prior period"]}):e.jsx("div",{className:"text-xs text-fg-faint mt-2",children:"no prior window to compare"})]}),e.jsx("div",{className:"flex-1 min-w-0 self-stretch",children:e.jsx(bt,{series:s.series})})]}),e.jsxs("div",{className:"grid grid-cols-4 gap-3 mt-4 pt-3 border-t border-line",children:[e.jsx(X,{label:"per active day",value:Q(t,r)}),e.jsx(X,{label:"per session",value:Q(t,a)}),e.jsx(X,{label:"active days",value:L(n)}),e.jsx(X,{label:"projects touched",value:L(c)})]})]})}function X({label:t,value:s}){return e.jsxs("div",{children:[e.jsx("div",{className:"text-[10px] text-fg-faint uppercase tracking-wider",children:t}),e.jsx("div",{className:"text-[17px] font-mono tracking-tight text-fg-dim",children:s})]})}function bt({series:t}){if(t.length<2)return null;const c=Math.max(...t,0),o=Math.min(...t,0),r=c-o||1,a=160/(t.length-1),l=t.map((d,i)=>`${i*a},${48-(d-o)/r*48}`).join(" "),u=`0,48 ${l} 160,48`;return e.jsxs("svg",{viewBox:"0 0 160 48",preserveAspectRatio:"none",className:"w-full h-full min-h-[48px]",children:[e.jsx("polygon",{points:u,fill:"#b85c34",opacity:.15}),e.jsx("polyline",{points:l,fill:"none",stroke:"#b85c34",strokeWidth:1.5,vectorEffect:"non-scaling-stroke"})]})}const kt=50;function vt({days:t}){const[s,n]=f.useState(kt),c=f.useRef(!1);f.useEffect(()=>{let d=!1;return fe().then(i=>{d||c.current||typeof i.budgetCapUsd=="number"&&Number.isFinite(i.budgetCapUsd)&&i.budgetCapUsd>0&&n(i.budgetCapUsd)}),()=>{d=!0}},[]);const o=d=>{c.current=!0;const i=s;n(d),ue({budgetCapUsd:d}).catch(()=>{n(i),q.error("Couldn't save the budget cap — reverted.")})},{mtdSpend:r,projectedSpend:a}=f.useMemo(()=>{const d=new Date,i=d.toLocaleDateString("en-CA").slice(0,7),x=new Date(d.getFullYear(),d.getMonth()+1,0).getDate(),m=d.getDate();let k=0;for(const v of t)if(v.date.startsWith(i))for(const M of Object.values(v.byProject))k+=M.estimatedCostUsd;return{mtdSpend:k,projectedSpend:et(k,m,x)}},[t]),l=a>s,u=s>0?Math.min(100,r/s*100):0;return e.jsxs("div",{className:`${w} p-3`,children:[e.jsxs("div",{className:"flex items-center justify-between mb-2",children:[e.jsx("h3",{className:"text-[10.5px] uppercase tracking-wider text-fg-faint font-mono",children:"Monthly budget"}),e.jsxs("label",{className:"flex items-center gap-1.5 text-[10px] text-fg-faint",children:["cap",e.jsx("span",{children:"$"}),e.jsx("input",{type:"number",min:1,step:1,value:s,onChange:d=>{const i=Number(d.target.value);Number.isFinite(i)&&i>0&&o(i)},className:"w-16 bg-bg border border-line rounded px-1.5 py-0.5 text-xs text-fg font-mono"})]})]}),e.jsxs("div",{className:"flex items-center gap-4 text-xs font-mono mb-1.5",children:[e.jsxs("span",{className:"text-fg",children:[$(r)," ",e.jsx("span",{className:"text-fg-faint",children:"month-to-date"})]}),e.jsxs("span",{className:l?"text-delta-bad":"text-fg-dim",children:[$(a)," ",e.jsx("span",{className:"text-fg-faint",children:"projected"})]})]}),e.jsx("div",{className:"h-1.5 rounded bg-bg-hi overflow-hidden",children:e.jsx("div",{className:`h-full ${l?"bg-delta-bad":"bg-sage"}`,style:{width:`${Math.max(u,u>0?2:0)}%`}})}),e.jsx("div",{className:`text-[10px] mt-1 font-mono ${l?"text-delta-bad":"text-fg-faint"}`,children:l?`projected to exceed $${s.toFixed(0)} cap`:`${u.toFixed(0)}% of $${s.toFixed(0)} cap`})]})}function yt({chips:t,keep:s,onToggle:n,onIsolate:c,onShowAll:o}){const r=s===null;return e.jsxs("div",{className:"flex flex-wrap items-center gap-1.5",children:[e.jsxs("button",{onClick:o,className:`px-2 py-1 rounded text-[11px] font-mono border ${r?"bg-accent text-white border-accent":"border-line text-fg-faint hover:text-fg hover:bg-bg-hi"}`,children:["show all (",t.length,")"]}),t.map(a=>{const l=r||s.has(a.projectDir);return e.jsxs("button",{onClick:u=>u.shiftKey?c(a.projectDir):n(a.projectDir),title:a.projectDir,className:`inline-flex items-center gap-1.5 px-2 py-1 rounded text-[11px] font-mono border ${l?"border-line text-fg-dim bg-bg-hi":"border-line text-fg-faint opacity-40 hover:opacity-70"}`,children:[e.jsx("span",{className:"w-1.5 h-1.5 rounded-full shrink-0",style:{backgroundColor:A(a.projectDir)}}),O(a.projectDir)]},a.projectDir)})]})}function Ct(t,s){const n=new Map;for(const o of t)for(const[r,a]of Object.entries(o.values))n.set(r,(n.get(r)??0)+a);const c=Array.from(n.entries()).sort((o,r)=>r[1]-o[1]).map(([o])=>o);return t.map(o=>{const r=c.reduce((u,d)=>u+(o.values[d]??0),0);let a=0;const l=c.map(u=>{const d=o.values[u]??0;if(r<=0)return{projectDir:u,value:d,y0:0,y1:0};const i=s==="share"?d/r:d,x=a,m=a+i;return a=m,{projectDir:u,value:d,y0:x,y1:m}});return{date:o.date,bands:l,total:r}})}const ie=720,le=220,de=44,Tt=20;function Nt(t,s){return t==="spend"?$(s):I(s)}function wt({days:t,measure:s,selected:n,onSelect:c}){const[o,r]=f.useState("absolute"),a=f.useMemo(()=>Ct(t,o),[t,o]),l=f.useMemo(()=>{if(o==="share")return 1;let h=0;for(const g of a)h=Math.max(h,g.total);return h||1},[a,o]),u=ie-de,d=le-Tt,i=a.length>1?u/(a.length-1):u,x=h=>de+h*i,m=h=>d-h/l*d,k=Math.max(1,Math.ceil(a.length/8)),v=4,M=Array.from({length:v+1},(h,g)=>l/v*g);return e.jsxs("div",{className:`${w} p-4`,children:[e.jsx(D,{kicker:"02 · over time",title:"Trend by project",right:e.jsx("div",{className:"flex border border-line rounded overflow-hidden text-[10px] font-mono",children:["absolute","share"].map(h=>e.jsx("button",{onClick:()=>r(h),className:`px-2 py-0.5 ${o===h?"bg-accent text-white":"text-fg-faint hover:text-fg"}`,children:h},h))})}),e.jsxs("svg",{width:"100%",viewBox:`0 0 ${ie} ${le}`,className:"overflow-visible",children:[M.map((h,g)=>e.jsxs("g",{children:[e.jsx("line",{x1:de,x2:ie,y1:m(h),y2:m(h),stroke:"currentColor",className:"text-line",strokeWidth:1}),e.jsx("text",{x:0,y:m(h)+3,fontSize:9,className:"fill-fg-faint",children:o==="share"?`${Math.round(h*100)}%`:Nt(s,h)})]},g)),a.map((h,g)=>{if(g===0)return null;const E=a[g-1];return h.bands.map((j,J)=>{const z=E.bands[J],W=n!==null&&n!==j.projectDir,ee=W?mt:A(j.projectDir),te=[`${x(g-1)},${m(z.y0)}`,`${x(g)},${m(j.y0)}`,`${x(g)},${m(j.y1)}`,`${x(g-1)},${m(z.y1)}`].join(" ");return e.jsx("polygon",{points:te,fill:ee,opacity:W?.6:.75,className:"cursor-pointer",onClick:()=>c(n===j.projectDir?null:j.projectDir),children:e.jsx("title",{children:O(j.projectDir)})},`${j.projectDir}-${g}`)})}),a.map((h,g)=>g%k!==0&&g!==a.length-1?null:e.jsx("text",{x:x(g),y:le-4,fontSize:9,textAnchor:"middle",className:"fill-fg-faint",children:h.date.slice(5)},h.date))]})]})}function Mt({rows:t,measure:s,selected:n,onSelect:c}){return t.length?e.jsxs("div",{className:`${w} overflow-hidden`,children:[e.jsx("div",{className:"p-4 pb-0",children:e.jsx(D,{kicker:"03 · by project",title:"Ranking"})}),e.jsxs("table",{className:"w-full text-xs",children:[e.jsx("thead",{className:"bg-bg-elev",children:e.jsx("tr",{children:["project","share","value","share %","trend","sessions","top tool"].map(o=>e.jsx("th",{className:"text-left px-3 py-2 text-fg-faint uppercase tracking-wider whitespace-nowrap",children:o},o))})}),e.jsx("tbody",{children:t.map(o=>{const r=A(o.projectDir),a=n===o.projectDir;return e.jsxs("tr",{onClick:()=>c(o.projectDir),className:`border-t border-line hover:bg-bg-elev cursor-pointer ${a?"bg-bg-elev":""}`,children:[e.jsx("td",{className:"px-3 py-2 font-mono text-fg-dim",children:e.jsxs("span",{className:"inline-flex items-center gap-1.5",children:[e.jsx("span",{className:"w-1.5 h-1.5 rounded-full shrink-0",style:{backgroundColor:r}}),O(o.projectDir)]})}),e.jsx("td",{className:"px-3 py-2 w-32",children:e.jsx("div",{className:"h-1.5 rounded bg-bg-hi overflow-hidden",children:e.jsx("div",{className:"h-full",style:{width:`${Math.max(o.sharePct,o.sharePct>0?2:0)}%`,backgroundColor:r}})})}),e.jsx("td",{className:"px-3 py-2 text-fg-faint font-mono",children:Q(s,o.value)}),e.jsxs("td",{className:"px-3 py-2 text-fg-faint font-mono",children:[o.sharePct.toFixed(1),"%"]}),e.jsx("td",{className:"px-3 py-2 font-mono",children:o.trend.pct===null?e.jsx("span",{className:"text-fg-faint",children:"—"}):e.jsxs("span",{className:o.trend.direction==="up"?"text-delta-good":o.trend.direction==="down"?"text-delta-bad":"text-fg-faint",children:[o.trend.direction==="up"?"▲":o.trend.direction==="down"?"▼":"·"," ",De(Math.abs(o.trend.pct))]})}),e.jsx("td",{className:"px-3 py-2 text-fg-faint font-mono",children:L(o.sessions)}),e.jsx("td",{className:"px-3 py-2 text-fg-faint font-mono",children:o.topTool||"—"})]},o.projectDir)})})]})]}):e.jsxs("div",{className:`${w} p-4`,children:[e.jsx(D,{kicker:"03 · by project",title:"Ranking"}),e.jsx("div",{className:"text-xs text-fg-faint",children:"no projects in range"})]})}function Rt({projectDir:t,totals:s,byModel:n,toolBreakdown:c,onClear:o}){var i;const r=S(s,"in"),a=S(s,"out"),l=Object.entries(n).sort((x,m)=>m[1].costUsd-x[1].costUsd),u=Object.entries(c).sort((x,m)=>m[1]-x[1]),d=((i=u[0])==null?void 0:i[1])??0;return e.jsxs("div",{className:`${w} p-4`,children:[e.jsx(D,{kicker:"04 · drill in",title:O(t),right:e.jsx("button",{onClick:o,className:"text-[11px] text-fg-faint hover:text-fg font-mono",children:"clear ✕"})}),e.jsx("div",{className:"flex items-center gap-1.5 -mt-2 mb-3",children:e.jsx("span",{className:"w-1.5 h-1.5 rounded-full shrink-0",style:{backgroundColor:A(t)}})}),e.jsxs("div",{className:"grid grid-cols-6 gap-3 mb-4",children:[e.jsx(H,{label:"prompts",value:L(s.promptCount)}),e.jsx(H,{label:"sessions",value:L(s.sessionCount)}),e.jsx(H,{label:"in tokens",value:I(r)}),e.jsx(H,{label:"out tokens",value:I(a)}),e.jsx(H,{label:"spend",value:$(s.estimatedCostUsd)}),e.jsx(H,{label:"time",value:$e(s.activeMinutes)})]}),e.jsxs("div",{className:"grid grid-cols-2 gap-4",children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-[10px] text-fg-faint uppercase tracking-wider mb-1.5",children:"model mix"}),l.length===0?e.jsx("div",{className:"text-xs text-fg-faint",children:"no model data"}):e.jsx("div",{className:"space-y-1",children:l.map(([x,m])=>e.jsxs("div",{className:"flex items-center justify-between text-[11px] font-mono text-fg-dim",children:[e.jsx("span",{children:xe(x)}),e.jsx("span",{className:"text-fg-faint",children:$(m.costUsd)})]},x))})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-[10px] text-fg-faint uppercase tracking-wider mb-1.5",children:"tool mix"}),u.length===0?e.jsx("div",{className:"text-xs text-fg-faint",children:"no tool data"}):e.jsx("div",{className:"space-y-1",children:u.slice(0,6).map(([x,m])=>e.jsxs("div",{className:"flex items-center gap-2 text-[11px]",children:[e.jsx("span",{className:"w-20 shrink-0 truncate text-fg-dim font-mono",children:x}),e.jsx("div",{className:"flex-1 h-1.5 rounded bg-bg-hi overflow-hidden",children:e.jsx("div",{className:"h-full bg-hive-teal",style:{width:`${d>0?m/d*100:0}%`}})}),e.jsx("span",{className:"text-fg-faint font-mono w-8 text-right",children:m})]},x))})]})]})]})}function H({label:t,value:s}){return e.jsxs("div",{children:[e.jsx("div",{className:"text-[10px] text-fg-faint uppercase tracking-wider",children:t}),e.jsx("div",{className:"text-[17px] font-mono tracking-tight text-fg",children:s})]})}function St({byModelTotals:t}){const s=Object.entries(t).sort((c,o)=>o[1].costUsd-c[1].costUsd),n=s.reduce((c,[,o])=>c+o.costUsd,0);return e.jsxs("div",{className:`${w} p-4`,children:[e.jsx(D,{kicker:"05 · composition",title:"Model mix",right:e.jsxs("span",{className:"text-xs font-mono text-fg-faint",children:[$(n)," total"]})}),s.length===0?e.jsx("div",{className:"text-xs text-fg-faint",children:"no model data in range"}):e.jsx("div",{className:"space-y-2",children:s.map(([c,o])=>{const r=n>0?o.costUsd/n*100:0,a=A(c);return e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center justify-between text-xs mb-0.5",children:[e.jsxs("span",{className:"flex items-center gap-1.5 font-mono text-fg-dim truncate",children:[e.jsx("span",{className:"w-2 h-2 rounded-sm shrink-0",style:{backgroundColor:a}}),xe(c),o.estimated&&e.jsx("span",{className:"text-fg-faint",children:"(est.)"})]}),e.jsxs("span",{className:"text-fg-faint whitespace-nowrap ml-2",children:[$(o.costUsd)," · ",r.toFixed(0),"%"]})]}),e.jsx("div",{className:"h-1.5 rounded bg-bg-hi overflow-hidden",children:e.jsx("div",{className:"h-full",style:{width:`${Math.max(r,r>0?2:0)}%`,backgroundColor:a}})})]},c)})})]})}function Dt({rows:t}){const s=t.slice(0,3),n=s.reduce((r,a)=>r+a.sharePct,0),c=t.slice(3),o=c.reduce((r,a)=>r+a.sharePct,0);return e.jsxs("div",{className:`${w} p-4`,children:[e.jsx(D,{kicker:"05 · composition",title:"Concentration",right:e.jsxs("span",{className:"text-xs font-mono text-fg-faint",children:["top 3 = ",n.toFixed(0),"%"]})}),t.length===0?e.jsx("div",{className:"text-xs text-fg-faint",children:"no projects in range"}):e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"flex h-3 rounded overflow-hidden mb-2",children:t.map(r=>e.jsx("div",{style:{width:`${Math.max(r.sharePct,.5)}%`,backgroundColor:A(r.projectDir)},title:`${O(r.projectDir)} · ${r.sharePct.toFixed(1)}%`},r.projectDir))}),e.jsx("div",{className:"space-y-1 mb-2",children:s.map(r=>e.jsxs("div",{className:"flex items-center justify-between text-[11px] font-mono",children:[e.jsxs("span",{className:"flex items-center gap-1.5 text-fg-dim truncate",children:[e.jsx("span",{className:"w-1.5 h-1.5 rounded-full shrink-0",style:{backgroundColor:A(r.projectDir)}}),O(r.projectDir)]}),e.jsxs("span",{className:"text-fg-faint",children:[r.sharePct.toFixed(1),"%"]})]},r.projectDir))}),c.length>0&&e.jsxs("p",{className:"text-[10px] text-fg-faint",children:[c.length," more project",c.length===1?"":"s"," account for ",o.toFixed(1),"% (long tail)."]})]})]})}const Z=30,pe=9,P=(Z+pe)*2;function $t({totals:t}){const s=t.inputTokens+t.cacheReadTokens+t.cacheCreationTokens,n=s>0?t.cacheReadTokens/s*100:0,c=2*Math.PI*Z,o=P/2;return e.jsxs("div",{className:`${w} p-4`,children:[e.jsx(D,{kicker:"05 · composition",title:"Cache"}),e.jsxs("div",{className:"flex items-center gap-4",children:[e.jsxs("div",{className:"relative shrink-0",style:{width:P,height:P},children:[e.jsxs("svg",{width:P,height:P,viewBox:`0 0 ${P} ${P}`,className:"-rotate-90",children:[e.jsx("circle",{cx:o,cy:o,r:Z,fill:"none",stroke:"currentColor",className:"text-bg-hi",strokeWidth:pe}),e.jsx("circle",{cx:o,cy:o,r:Z,fill:"none",stroke:jt,strokeWidth:pe,strokeDasharray:c,strokeDashoffset:c*(1-n/100),strokeLinecap:"round"})]}),e.jsxs("div",{className:"absolute inset-0 flex items-center justify-center text-[13px] font-mono text-fg",children:[n.toFixed(0),"%"]})]}),e.jsxs("div",{className:"text-[11px] space-y-1 font-mono",children:[e.jsxs("div",{className:"flex items-center justify-between gap-3",children:[e.jsx("span",{className:"text-fg-faint",children:"reused (cache read)"}),e.jsx("span",{className:"text-fg-dim",children:I(t.cacheReadTokens)})]}),e.jsxs("div",{className:"flex items-center justify-between gap-3",children:[e.jsx("span",{className:"text-fg-faint",children:"written to cache"}),e.jsx("span",{className:"text-fg-dim",children:I(t.cacheCreationTokens)})]})]})]})]})}const Et=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"];function Ut({days:t,measure:s}){const{buckets:n,weekendShare:c,peakIdx:o}=f.useMemo(()=>{const a=new Array(7).fill(0);for(const i of t){const[x,m,k]=i.date.split("-").map(Number),v=new Date(x,m-1,k).getDay();a[v]+=S(i.totals,s)}const l=a.reduce((i,x)=>i+x,0),u=a[0]+a[6];let d=0;for(let i=1;i<7;i++)a[i]>a[d]&&(d=i);return{buckets:a,weekendShare:l>0?u/l*100:0,peakIdx:d}},[t,s]),r=Math.max(...n,1);return e.jsxs("div",{className:`${w} p-4`,children:[e.jsx(D,{kicker:"05 · composition",title:"Rhythm",right:e.jsxs("span",{className:"text-xs font-mono text-fg-faint",children:["weekend ",c.toFixed(0),"%"]})}),e.jsx("div",{className:"flex items-end gap-2 h-24",children:n.map((a,l)=>e.jsxs("div",{className:"flex-1 flex flex-col items-center justify-end gap-1 h-full",children:[e.jsx("div",{className:`w-full rounded-t ${l===o?"bg-accent":"bg-rhythm"}`,style:{height:`${r>0?a/r*100:0}%`,minHeight:a>0?2:0}}),e.jsx("span",{className:"text-[9px] text-fg-faint font-mono",children:Et[l]})]},l))})]})}const Pt=["in","out","total","prompts","sessions","time","spend"],At=[30,60,90,0],Ft="spend",_t=30,Bt=3e4,Ht=[];function Ot(){var ve;const[t,s]=f.useState(Ft),[n,c]=f.useState(_t),o=f.useRef(!1),r=f.useRef(!1),a=p=>{o.current=!0;const b=t;s(p),ue({measure:p}).catch(()=>{s(b),q.error("Couldn't save the measure preference — reverted.")})},l=p=>{r.current=!0;const b=n;c(p),ue({range:p}).catch(()=>{c(b),q.error("Couldn't save the range preference — reverted.")})};f.useEffect(()=>{let p=!1;return fe().then(b=>{p||(!o.current&&b.measure&&Pt.includes(b.measure)&&s(b.measure),!r.current&&b.range!==void 0&&At.includes(b.range)&&c(b.range))}),()=>{p=!0}},[]);const u=Ge(p=>p.navFace),d=ye(p=>p.tabs),i=ye(p=>p.activeTabId),x=((ve=d.find(p=>p.id===i))==null?void 0:ve.cwd)??null,m=f.useRef(u),k=x?Ye(x):null,[v,M]=f.useState(null),h=f.useMemo(()=>u==="project"&&k?new Set([k]):v,[u,k,v]),[g,E]=f.useState(null),[j,J]=f.useState(null),[z,W]=f.useState(!0),[ee,te]=f.useState(0),se=f.useRef(n);se.current=n;const K=f.useRef(!0),ne=f.useRef(0),he=f.useRef(0),F=f.useRef(null),G=f.useCallback(p=>{const b=se.current;ne.current+=1,he.current=Date.now(),Qe(b).then(y=>{if(ne.current-=1,!(!K.current||b!==se.current)){if(W(!1),y.ok){J(y.data);return}p||q.error(`History analytics failed to load: ${y.error}`)}})},[]);f.useEffect(()=>{K.current=!0,W(!0),G(!1)},[n,ee,G]),f.useEffect(()=>{const p=()=>{if(!K.current)return;const T=he.current+Bt-Date.now();if(ne.current===0&&T<=0){G(!0);return}F.current||(F.current=setTimeout(()=>{F.current=null,p()},Math.max(T,1e3)))},b=()=>{document.visibilityState==="visible"&&p()},y=window.api.history.onUpdated(p);return window.addEventListener("focus",p),document.addEventListener("visibilitychange",b),()=>{K.current=!1,y(),window.removeEventListener("focus",p),document.removeEventListener("visibilitychange",b),F.current&&(clearTimeout(F.current),F.current=null)}},[G]);const me=f.useRef(!1);f.useEffect(()=>{if(!me.current){me.current=!0;return}M(null),E(null)},[n]),f.useEffect(()=>{m.current!==u&&(m.current=u,u==="home"&&M(null))},[u]);const{projects:je,resolving:ge}=Ve(),be=f.useMemo(()=>{const p={};for(const b of je)for(const y of b.encodedIds)p[y]=b.cwd;return p},[je]),_=f.useMemo(()=>j&&!ge?dt(j.days,be):null,[j,be,ge]),N=(_==null?void 0:_.days)??(j==null?void 0:j.days)??Ht,oe=(_==null?void 0:_.excluded)??null,R=f.useMemo(()=>j?Je({days:N,totals:j.totals,prevTotals:j.prevTotals},h):null,[j,N,h]),B=f.useMemo(()=>h===null?N:N.map(p=>({date:p.date,byProject:Object.fromEntries(Object.entries(p.byProject).filter(([b])=>h.has(b)))})),[N,h]),Y=f.useMemo(()=>Ne(N,t),[N,t]),ae=f.useMemo(()=>Ne(B,t),[B,t]),Pe=f.useMemo(()=>B.map(p=>({date:p.date,values:Object.fromEntries(Object.entries(p.byProject).map(([b,y])=>[b,S(y,t)]))})),[B,t]),ke=f.useMemo(()=>R?nt(R,t):null,[R,t]),V=f.useMemo(()=>{if(!j||!g)return null;const p=N.flatMap(C=>C.byProject[g]?[C.byProject[g]]:[]),{byModel:b,...y}=Te(p),T={};for(const C of p)for(const[U,ce]of Object.entries(C.toolBreakdown))T[U]=(T[U]??0)+ce;return{totals:y,byModel:b,toolBreakdown:T}},[j,N,g]);f.useEffect(()=>{g&&h!==null&&!h.has(g)&&E(null)},[g,h]);function Ae(p){M(b=>{const y=new Set(Y.map(U=>U.projectDir)),T=b??new Set(y),C=new Set(T);return C.has(p)?C.delete(p):C.add(p),C.size>=y.size?null:C})}function Fe(p){M(new Set([p]))}function _e(){M(null)}function Be(){if(!j)return;const p=B.map(U=>{const{byModel:ce,estimatedCostUsd:He,inputTokens:Oe,outputTokens:Le,cacheCreationTokens:Ie,cacheReadTokens:We}=Te(Object.values(U.byProject));return{date:U.date,costUsd:He,inputTokens:Oe,outputTokens:Le,cacheCreationTokens:Ie,cacheReadTokens:We,byModel:ce}}),b=ct(p),y=new Blob([b],{type:"text/csv"}),T=URL.createObjectURL(y),C=document.createElement("a");C.href=T,C.download=`usage-history-${j.from}-${j.to}.csv`,C.click(),URL.revokeObjectURL(T)}return z&&!j?e.jsx(Se,{}):j&&j.days.length===0?e.jsx(Xe,{title:"no sessions in range",hint:"Widen the range or check back after your next session."}):!j||!R||!ke?e.jsx(Se,{}):e.jsxs("div",{"data-testid":"history-dashboard",className:"flex flex-col h-full",children:[e.jsxs("h1",{className:"font-serif text-[42px] leading-tight tracking-tight text-fg px-4 pt-4",children:["Where your ",e.jsx("em",{className:"italic text-accent",children:"Claude time"})," goes"]}),e.jsx(ht,{measure:t,onMeasure:a,range:n,onRange:l,projectsShown:h===null?Y.length:h.size,projectsTotal:Y.length,fromDate:j.from,toDate:j.to,onRefresh:()=>te(p=>p+1),onExport:Be,exportDisabled:B.length===0}),e.jsxs("div",{className:"flex-1 min-h-0 overflow-auto p-4 space-y-4",children:[e.jsx(gt,{measure:t,headline:ke,activeDays:R.activeDays,projectsTouched:ae.length,totalSessions:R.totals.sessionCount}),e.jsx(vt,{days:N}),oe&&ut(oe)&&e.jsx("div",{"data-testid":"history-excluded-note",className:"rounded-[10px] border border-line bg-bg-hi px-3 py-2 text-[11.5px] font-mono text-fg-faint",title:"A project is a working directory. ~/.claude/projects holds one folder per path the CLI was ever launched from — throwaway /tmp dirs and test fixtures included — and a folder whose cwd can't be recovered from its transcripts is not a project. Their totals are stated here rather than silently folded into the charts.",children:pt(oe)}),u==="home"&&e.jsx(yt,{chips:Y.map(p=>({projectDir:p.projectDir,value:p.value})),keep:h,onToggle:Ae,onIsolate:Fe,onShowAll:_e}),e.jsx(wt,{days:Pe,measure:t,selected:g,onSelect:E}),e.jsx(Mt,{rows:ae,measure:t,selected:g,onSelect:E}),g&&V&&e.jsx(Rt,{projectDir:g,totals:V.totals,byModel:V.byModel,toolBreakdown:V.toolBreakdown,onClear:()=>E(null)}),e.jsxs("div",{className:"grid grid-cols-2 lg:grid-cols-4 gap-4",children:[e.jsx(St,{byModelTotals:R.byModelTotals}),e.jsx(Dt,{rows:ae}),e.jsx($t,{totals:R.totals}),e.jsx(Ut,{days:R.days,measure:t})]})]})]})}function Se(){return e.jsxs("div",{className:"p-4 space-y-4 animate-pulse",children:[e.jsx("div",{className:"h-24 bg-bg-elev rounded"}),e.jsx("div",{className:"h-16 bg-bg-elev rounded"}),e.jsx("div",{className:"h-8 bg-bg-elev rounded"}),e.jsx("div",{className:"h-56 bg-bg-elev rounded"}),e.jsx("div",{className:"h-40 bg-bg-elev rounded"})]})}function Lt(){return e.jsx(qe,{children:e.jsx(Ot,{})})}const Gt=f.memo(Lt);export{Gt as History};
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./SkillReferenceGraph-_40_f0t3.js","./index-B5wj0DEX.js","./monaco-editor-BsIlgG7c.js","./monaco-editor-Cu5D__1H.css","./index-Dd7UQabV.css"])))=>i.map(i=>d[i]);
|
|
2
|
-
import{ap as t,aF as c,n as S,b4 as pe,aX as q,a$ as ae,a as xe}from"./index-B5wj0DEX.js";import{P as ee}from"./Panel-thElCbLX.js";import{P as re}from"./ProvenanceBadge-lAViG8yV.js";import{e as ge}from"./Library-QvYVAEmY.js";import{p as le,M as je}from"./skillFrontmatter-DFGp4DST.js";import{l as be}from"./listSkills-C1aWKf0T.js";import{_ as ye}from"./monaco-editor-BsIlgG7c.js";import{L as ve}from"./ListDetail-FvNe6fo5.js";import"./Button-C4BN5ISR.js";function ke({columns:e,rows:n,getKey:i,onRowClick:s,activeKey:a,empty:d}){return n.length===0?t.jsx("div",{className:"p-6 text-fg-faint text-xs text-center",children:d??"no entries"}):t.jsxs("table",{className:"w-full text-xs",children:[t.jsx("thead",{className:"sticky top-0 bg-bg-elev text-fg-faint uppercase tracking-wider",children:t.jsx("tr",{className:"border-b border-line",children:e.map(l=>t.jsx("th",{className:`text-left font-normal px-3 py-1.5 ${l.className??""}`,style:l.width?{width:l.width}:void 0,children:l.header},l.key))})}),t.jsx("tbody",{children:n.map(l=>{const h=i(l),o=a===h;return t.jsx("tr",{"data-row-key":h,onClick:()=>s==null?void 0:s(l),className:`border-b border-line/50 transition-colors ${s?"cursor-pointer":""} ${o?"bg-bg-hi text-fg":"text-fg-dim hover:bg-bg-hi/50"}`,children:e.map(u=>t.jsx("td",{className:`px-3 py-1 ${u.className??""}`,children:u.render(l)},u.key))},h)})})]})}async function oe(e){const n=`${e}/skills`;return await window.api.config.exists(n)?n:null}async function ce(e){const{entries:n}=await be(e,{nested:!1});return n.map(i=>{const s=le(i.text);return{id:i.name,name:s.name,description:s.description,dir:i.dir,path:i.path,body:s.body}})}function Ne(e){const n=[],i=new Set;for(const s of e)for(const a of e){if(s.id===a.id)continue;const d=a.id.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),l=[`/${d}\\b`,`\`${d}\``];if(a.id.length>=4&&l.push(`\\b${d}\\b`),!l.some(u=>new RegExp(u,"i").test(s.body)))continue;const o=`${s.id}->${a.id}`;i.has(o)||(i.add(o),n.push({from:s.id,to:a.id}))}return n}const we=c.lazy(()=>ye(()=>import("./SkillReferenceGraph-_40_f0t3.js"),__vite__mapDeps([0,1,2,3,4]),import.meta.url).then(e=>({default:e.SkillReferenceGraph})));function Se({pluginName:e,skills:n,onBack:i,initialSelectedId:s}){var N;const[a,d]=c.useState(s??((N=n[0])==null?void 0:N.id)??null),l=a?n.find(m=>m.id===a)??null:null,h=c.useMemo(()=>Ne(n),[n]),[o,u]=c.useState("list");return t.jsxs("div",{className:"flex flex-col h-full min-h-0 overflow-hidden",children:[t.jsxs("div",{className:"shrink-0 h-11 flex items-baseline gap-3.5 px-3 border-b border-line bg-bg",children:[t.jsxs("button",{type:"button",onClick:i,className:"font-mono text-accent hover:underline shrink-0 text-xs",children:["← ",e]}),t.jsx("span",{className:"font-serif text-[22px] text-fg shrink-0 truncate max-w-[16rem]",children:(l==null?void 0:l.name)??(l==null?void 0:l.id)??"skill"}),t.jsx("span",{className:"flex-1"}),t.jsx("div",{className:"flex items-center gap-1.5 shrink-0",children:t.jsxs("div",{className:"flex rounded border border-line overflow-hidden",children:[t.jsx("button",{onClick:()=>u("list"),className:`px-2 py-0.5 text-xs ${o==="list"?"bg-bg-hi text-fg":"text-fg-dim hover:text-fg hover:bg-bg-hi"}`,children:"list"}),t.jsx("button",{onClick:()=>u("graph"),className:`px-2 py-0.5 text-xs ${o==="graph"?"bg-bg-hi text-fg":"text-fg-dim hover:text-fg hover:bg-bg-hi"}`,children:"graph"})]})})]}),t.jsxs("div",{className:"shrink-0 h-[26px] flex items-center gap-[18px] px-3 bg-bg-elev border-b border-line text-[9px] font-mono uppercase tracking-wide overflow-hidden",children:[l!=null&&l.description?t.jsx("span",{className:"text-fg-dim truncate normal-case",children:l.description}):null,t.jsxs("span",{className:"ml-auto text-fg-faint truncate normal-case",children:[n.length," ",n.length===1?"skill":"skills"," · ",h.length," ",h.length===1?"reference":"references"]})]}),t.jsx("div",{className:"flex-1 min-h-0 overflow-hidden",children:n.length===0?t.jsx(S,{title:"no skills in this plugin"}):o==="graph"?t.jsx(c.Suspense,{fallback:t.jsx("div",{className:"p-6 text-xs text-fg-faint",children:"Loading graph…"}),children:t.jsx(we,{skills:n,edges:h,selectedId:a,onSelect:d})}):t.jsx(ve,{sidebar:t.jsx("div",{className:"py-1",children:n.map(m=>t.jsxs("button",{onClick:()=>d(m.id),className:`w-full px-3 py-1 text-xs text-left ${a===m.id?"bg-bg-hi text-fg":"text-fg-dim hover:text-fg hover:bg-bg-hi"}`,children:[t.jsx("div",{className:"truncate",children:m.name??m.id}),m.description?t.jsx("div",{className:"truncate text-fg-faint",children:m.description}):null]},m.id))}),detail:l?t.jsx("div",{className:"h-full min-h-0",children:t.jsx(je,{path:l.path,value:l.body,onChange:()=>{},readOnly:!0})}):t.jsx(S,{title:"select a skill"})})})]})}const de=e=>{var n,i;return{type:"plugin",name:e.name,repository:(n=e.manifest)==null?void 0:n.repository,homepage:(i=e.manifest)==null?void 0:i.homepage}};function $e(){const e=pe(),[n,i]=c.useState([]),[s,a]=c.useState(!0),[d,l]=c.useState(null),[h,o]=c.useState(null),[u,N]=c.useState("installed"),[m,I]=c.useState(null),[D,F]=c.useState(new Set);c.useEffect(()=>{var g,k;let r=!1;return(k=(g=window.api.app).seedStatus)==null||k.call(g).then($=>{r||I($)}).catch(()=>{}),()=>{r=!0}},[]);const E=c.useRef(0),C=c.useRef(!1),b=c.useCallback(async()=>{const r=++E.current;if(!e)return;C.current||a(!0);const g=`${e}/.claude/plugins/installed_plugins.json`;let k=[],$=null;try{const x=await window.api.config.readJson(g);if(x.exists&&x.parseError)$=`could not parse installed_plugins.json${x.error?`: ${x.error}`:""}`;else if(x.exists&&x.data&&typeof x.data=="object"){const T=x.data,J=[];for(const[W,R]of Object.entries(T.plugins??{})){if(!Array.isArray(R))continue;const[_,O]=W.split("@");for(const j of R)j!=null&&j.installPath&&J.push({name:_,marketplace:O,entry:j})}k=await De(J,Le,async({name:W,marketplace:R,entry:_})=>{var H;const O={name:W,path:_.installPath,isDirectory:!0,isFile:!1,mtimeMs:0,size:0};let j;try{j=await _e(O)}catch(B){j=Re(O,B instanceof Error?B.message:String(B))}return(H=j.manifest)!=null&&H.version||(j.manifest={...j.manifest??{},version:_.version}),j.marketplace=R,j.scope=_.scope,j})}}catch(x){$=`could not read installed_plugins.json: ${x instanceof Error?x.message:String(x)}`}E.current===r&&(l($),$?q.error(`Plugins: ${$}`):(k.sort((x,T)=>x.name.localeCompare(T.name)),C.current=k.length>0,i(k)),a(!1))},[e]);c.useEffect(()=>{b()},[b]),c.useEffect(()=>()=>{E.current+=1},[]),ae(e?[`${e}/.claude/plugins/installed_plugins.json`]:[],b);const f=[{key:"name",header:"name",render:r=>{var g;return t.jsxs("div",{style:{maxWidth:"16rem"},children:[t.jsx("div",{className:"truncate",children:r.name}),(g=r.manifest)!=null&&g.description?t.jsx("div",{className:"truncate text-fg-faint",title:r.manifest.description,children:r.manifest.description}):null]})},width:"16rem"},{key:"origin",header:"origin",render:r=>t.jsx(re,{interactive:!1,input:de(r)}),width:"7rem"},{key:"scope",header:"scope",render:r=>r.scope?t.jsx("span",{"data-testid":"plugin-scope",children:r.scope}):t.jsx("span",{className:"text-fg-faint",children:"—"}),width:"5rem"},{key:"version",header:"version",render:r=>{var g;return((g=r.manifest)==null?void 0:g.version)??t.jsx("span",{className:"text-fg-faint",children:"—"})},width:"6rem"},{key:"manifest",header:"manifest",render:r=>r.hasManifest?"plugin.json":t.jsx("span",{className:"text-fg-faint",children:"—"}),width:"8rem"},{key:"contents",header:"contents",render:r=>t.jsx("span",{className:"font-mono text-fg-faint text-xs",children:[r.agents>0?`${r.agents} agents`:null,r.commands>0?`${r.commands} commands`:null,r.skills>0?`${r.skills} skills`:null,r.hooks>0?`${r.hooks} hooks`:null,r.monitors>0?`${r.monitors} monitors`:null,r.binCount>0?`${r.binCount} bin`:null,r.hasLsp?"lsp":null,r.hasMcp?"mcp":null,r.error?"inspection failed":null].filter(Boolean).join(" · ")||"—"})},{key:"path",header:"path",render:r=>t.jsx("span",{className:"font-mono text-fg-faint truncate",children:r.path})}],p=c.useMemo(()=>m?Object.keys(m).filter(r=>m[r].status==="exhausted"&&!D.has(r)):[],[m,D]),w=p.length>0?t.jsx(Pe,{seeders:p,seedStatus:m,onDismiss:r=>F(g=>new Set(g).add(r)),onOpenLibrary:()=>N("library")}):null;if(u==="library")return t.jsxs(ee,{toolbar:t.jsx(ne,{active:u,onChange:N}),children:[w,t.jsx(ge,{})]});const y=h?n.find(r=>r.path===h)??null:null;return t.jsxs(ee,{toolbar:t.jsxs(t.Fragment,{children:[t.jsx(ne,{active:u,onChange:N}),t.jsx("span",{className:"mx-2 text-fg-faint",children:"·"}),t.jsxs("span",{className:"text-fg-faint",children:[n.length," plugins"]}),t.jsx("div",{className:"flex-1"}),t.jsx("span",{className:"text-fg-faint font-mono truncate",children:"~/.claude/plugins/installed_plugins.json"})]}),children:[w,d?t.jsxs("div",{role:"alert",className:"shrink-0 px-3 py-2 border-b border-line bg-red-950/20 text-xs text-red-300",children:[d,n.length>0?" — showing the last known list":null]}):null,s&&n.length===0?t.jsx(S,{title:"scanning plugins…"}):d&&n.length===0?null:y?t.jsx(Ae,{row:y,home:e,onBack:()=>o(null)},y.path):t.jsx("div",{className:"flex flex-col h-full",children:t.jsx("div",{className:"flex-1 min-h-0 overflow-auto",children:t.jsx(ke,{columns:f,rows:n,getKey:r=>r.path,activeKey:h,onRowClick:r=>o(r.path),empty:t.jsxs(t.Fragment,{children:["no plugins installed",t.jsxs("div",{className:"mt-2 text-fg-faint",children:["install one from the Library view or run ",t.jsx("code",{children:"claude plugin install"})]})]})})})})]})}const Ge=c.memo($e),te={"dev-plugin":"session-manager-dev plugin","scheduler-mcp":"Scheduler MCP server","agent-personas":"Agent personas (Architect, Dev Lead)"};function Pe({seeders:e,seedStatus:n,onDismiss:i,onOpenLibrary:s}){return t.jsx("div",{className:"shrink-0 flex flex-col gap-1.5 px-3 py-2 border-b border-line bg-yellow-950/20",children:e.map(a=>t.jsxs("div",{className:"flex items-start gap-2 text-xs text-yellow-300",children:[t.jsxs("div",{className:"flex-1 min-w-0",children:[t.jsxs("div",{className:"font-medium",children:[te[a]," setup failed after retrying — manual fix needed"]}),a==="dev-plugin"?t.jsxs("div",{className:"text-yellow-400/80 mt-0.5",children:["Click ",t.jsx("button",{onClick:s,className:"underline hover:no-underline",children:"here"}),' to open the Library tab, then click Install next to "session-manager-dev".']}):t.jsx("div",{className:"text-yellow-400/80 mt-0.5 font-mono",children:n[a].fix})]}),t.jsx("button",{onClick:()=>i(a),className:"shrink-0 text-yellow-400/70 hover:text-yellow-300","aria-label":`Dismiss ${te[a]} warning`,children:"✕"})]},a))})}function ne({active:e,onChange:n}){const i=[["installed","Installed"],["library","Library"]];return t.jsx("div",{className:"flex rounded border border-line overflow-hidden",role:"tablist","aria-label":"Plugins view",children:i.map(([s,a])=>t.jsx("button",{onClick:()=>n(s),role:"tab","aria-selected":e===s,className:`px-2 py-0.5 text-xs ${e===s?"bg-bg-hi text-fg":"text-fg-dim hover:text-fg hover:bg-bg-hi"}`,children:a},s))})}const Ee=250,Ce=["hooks/hooks.json",".mcp.json",".lsp.json","agents","skills","commands",".claude-plugin/plugin.json"];function Ae({row:e,home:n,onBack:i}){var O,j,H,B,U;const[s,a]=c.useState([]),[d,l]=c.useState([]),[h,o]=c.useState([]),[u,N]=c.useState([]),[m,I]=c.useState([]),[D,F]=c.useState("skills"),[E,C]=c.useState(null),[b,f]=c.useState(!0),[p,w]=c.useState([]),y=c.useRef(0),r=c.useRef(!1),g=c.useCallback(async()=>{if(!n)return;const v=++y.current;try{const{manifest:M}=await ue(e.path),[z,V,he]=await Promise.all([oe(e.path),me(e.path,M),K(`${e.path}/bin`,{filesOnly:!0})]),G=z?await ce(z):[],[X,Y]=await Promise.all([ie(V.agentFiles),ie(V.commandFiles)]),Q=V.mcpServers,fe=await Promise.all([...new Set([...Ce.map(A=>`${e.path}/${A}`),...V.sourcePaths])].map(async A=>await window.api.config.exists(A)?A:null));if(v!==y.current)return;a(G),l(X),o(Y),N(Q),I(he);const Z=fe.filter(A=>A!==null);w(A=>A.join("\0")===Z.join("\0")?A:Z),r.current||(r.current=!0,F(G.length>0?"skills":X.length>0?"agents":Y.length>0?"commands":Q.length>0?"mcp":e.hooks>0?"hooks":e.monitors>0?"monitors":e.hasLsp?"lsp":"files"))}catch(M){if(v!==y.current)return;q.error(`Failed to load plugin contents: ${M instanceof Error?M.message:String(M)}`)}finally{v===y.current&&f(!1)}},[e.path,e.name,e.hooks,e.monitors,e.hasLsp,n]);c.useEffect(()=>(f(!0),g(),()=>{y.current+=1}),[g]);const k=c.useRef(null),$=c.useRef(!1),x=c.useRef(!1),T=c.useCallback(async()=>{if($.current){x.current=!0;return}$.current=!0;try{do x.current=!1,await g();while(x.current)}finally{$.current=!1}},[g]),J=c.useCallback(()=>{k.current&&clearTimeout(k.current),k.current=setTimeout(()=>{k.current=null,T()},Ee)},[T]);c.useEffect(()=>()=>{k.current&&clearTimeout(k.current)},[]),ae(p,J,{depth:0});const W=[{key:"skills",label:"Skills",count:s.length},{key:"agents",label:"Agents",count:d.length},{key:"commands",label:"Commands",count:h.length},{key:"mcp",label:"MCP server",count:u.length},{key:"hooks",label:"Hooks",count:e.hooks},{key:"monitors",label:"Monitors",count:e.monitors},{key:"lsp",label:"LSP",count:e.hasLsp?1:0},{key:"files",label:"Bin",count:m.length}],R=(O=e.manifest)!=null&&O.author?typeof e.manifest.author=="string"?e.manifest.author:e.manifest.author.name??null:null,_=async v=>{const M=await window.api.shell.open({as:"external",url:v});M.ok||q.error(M.error??`Failed to open ${v}`)};return E?t.jsx(Se,{pluginName:((j=e.manifest)==null?void 0:j.name)??e.name,skills:s,initialSelectedId:E.id,onBack:()=>C(null)},E.id):t.jsxs("div",{className:"flex flex-col h-full min-h-0 overflow-hidden",children:[t.jsxs("div",{className:"shrink-0 h-11 flex items-baseline gap-3.5 px-3 border-b border-line bg-bg",children:[t.jsx("button",{type:"button",onClick:i,className:"font-mono text-accent hover:underline shrink-0 text-xs",children:"← Plugins"}),t.jsx("span",{className:"font-serif text-[22px] text-fg shrink-0 truncate max-w-[16rem]",children:((H=e.manifest)==null?void 0:H.name)??e.name}),(B=e.manifest)!=null&&B.version?t.jsxs("span",{className:"font-mono text-fg-faint text-xs shrink-0",children:["v",e.manifest.version]}):null,(U=e.manifest)!=null&&U.description?t.jsx("span",{className:"text-fg-dim text-xs min-w-0 flex-1 overflow-hidden text-ellipsis whitespace-nowrap",children:e.manifest.description}):t.jsx("span",{className:"flex-1"}),t.jsxs("div",{className:"flex items-center gap-1.5 shrink-0",children:[t.jsx(re,{input:de(e)}),e.hasMcp?t.jsx(xe,{tone:"accent",children:"MCP"}):null]})]}),e.manifest?t.jsxs("div",{className:"shrink-0 h-[26px] flex items-center gap-[18px] px-3 bg-bg-elev border-b border-line text-[9px] font-mono uppercase tracking-wide overflow-hidden",children:[R?t.jsxs("span",{className:"text-fg-dim truncate",children:[t.jsx("span",{className:"text-fg-faint",children:"Author "}),R]}):null,e.manifest.license?t.jsxs("span",{className:"text-fg-dim truncate",children:[t.jsx("span",{className:"text-fg-faint",children:"License "}),e.manifest.license]}):null,e.manifest.homepage?t.jsxs("button",{onClick:()=>_(e.manifest.homepage),className:"text-accent hover:underline truncate normal-case",title:e.manifest.homepage,children:[t.jsx("span",{className:"text-fg-faint uppercase",children:"Homepage "}),e.manifest.homepage]}):null,t.jsx("span",{className:"ml-auto text-fg-faint truncate normal-case",children:e.path})]}):t.jsx("div",{className:"shrink-0 h-[26px] flex items-center px-3 bg-bg-elev border-b border-line text-[9px] font-mono uppercase tracking-wide overflow-hidden",children:t.jsx("span",{className:"ml-auto text-fg-faint truncate normal-case",children:e.path})}),t.jsxs("div",{className:"flex-1 min-h-0 grid overflow-hidden",style:{gridTemplateColumns:"170px 1fr"},children:[t.jsx("div",{className:"min-h-0 overflow-auto bg-bg-elev border-r border-line py-1",children:W.map(v=>t.jsxs("button",{type:"button",disabled:v.count===0,onClick:()=>F(v.key),className:`w-full text-left px-3 py-1.5 text-xs flex items-center justify-between ${v.count===0?"text-fg-faint opacity-50 cursor-default":D===v.key?"bg-bg-hi text-fg":"text-fg-dim hover:text-fg hover:bg-bg-hi"}`,children:[t.jsx("span",{children:v.label}),v.count>0?t.jsx("span",{className:"font-mono text-fg-faint",children:v.count}):null]},v.key))}),t.jsx("div",{className:"min-h-0 overflow-auto",children:b?t.jsx(S,{title:"scanning…"}):t.jsx(Me,{active:D,row:e,skills:s,agents:d,commands:h,mcpServers:u,files:m,onOpenSkill:C})})]})]})}function Me({active:e,row:n,skills:i,agents:s,commands:a,mcpServers:d,files:l,onOpenSkill:h}){return e==="skills"?i.length===0?t.jsx(S,{title:"no components"}):t.jsx("div",{children:i.map((o,u)=>t.jsx(L,{n:u+1,name:o.name??o.id,description:o.description,onClick:()=>h(o)},o.id))}):e==="agents"?s.length===0?t.jsx(S,{title:"no components"}):t.jsx("div",{children:s.map((o,u)=>t.jsx(L,{n:u+1,name:o.name??o.id,description:o.description},o.id))}):e==="commands"?a.length===0?t.jsx(S,{title:"no components"}):t.jsx("div",{children:a.map((o,u)=>t.jsx(L,{n:u+1,name:o.name??o.id,description:o.description},o.id))}):e==="mcp"?d.length===0?t.jsx(S,{title:"no components"}):t.jsx("div",{children:d.map((o,u)=>t.jsx(L,{n:u+1,name:o.name,description:o.description},o.id))}):e==="hooks"?n.hooks===0?t.jsx(S,{title:"no components"}):t.jsx("div",{children:t.jsx(L,{n:1,name:`${n.hooks} ${n.hooks===1?"hook":"hooks"} configured`,description:`${n.path}/hooks/hooks.json`})}):e==="monitors"?n.monitors===0?t.jsx(S,{title:"no components"}):t.jsx("div",{children:t.jsx(L,{n:1,name:`${n.monitors} ${n.monitors===1?"monitor":"monitors"} configured`,description:`${n.path}/monitors/monitors.json`})}):e==="lsp"?n.hasLsp?t.jsx("div",{children:t.jsx(L,{n:1,name:"LSP server enabled",description:`${n.path}/.lsp.json`})}):t.jsx(S,{title:"no components"}):l.length===0?t.jsx(S,{title:"no components"}):t.jsx("div",{children:l.map((o,u)=>t.jsx(L,{n:u+1,name:o,description:null},o))})}function L({n:e,name:n,description:i,onClick:s}){const a=s?"button":"div";return t.jsxs(a,{onClick:s,className:`w-full flex items-baseline gap-2.5 py-[9px] px-3 border-b border-line text-left min-w-0 ${s?"hover:bg-bg-hi cursor-pointer":""}`,children:[t.jsx("span",{className:"font-serif text-fg-faint text-xs shrink-0 w-6 text-right",children:String(e).padStart(2,"0")}),t.jsxs("div",{className:"min-w-0 flex-1",children:[t.jsx("div",{className:"font-mono font-semibold text-accent truncate",children:n}),i?t.jsx("div",{className:"text-fg-dim text-xs truncate",children:i}):null]})]})}const Le=4;async function De(e,n,i){const s=new Array(e.length);let a=0;const d=Array.from({length:Math.min(n,e.length)},async()=>{for(;a<e.length;){const l=a++;s[l]=await i(e[l])}});return await Promise.all(d),s}function Re(e,n){return{name:e.name,path:e.path,mtimeMs:e.mtimeMs,hasManifest:!1,manifest:null,hasLsp:!1,monitors:0,hooks:0,agents:0,commands:0,skills:0,binCount:0,hasMcp:!1,error:n}}async function _e(e){const{hasManifest:n,manifest:i}=await ue(e.path),[s,a]=await Promise.all([window.api.config.exists(`${e.path}/.lsp.json`),window.api.config.exists(`${e.path}/monitors/monitors.json`)]);let d=0;if(a){const m=await window.api.config.readJson(`${e.path}/monitors/monitors.json`);Array.isArray(m.data)?d=m.data.length:m.data&&typeof m.data=="object"&&Array.isArray(m.data.monitors)&&(d=m.data.monitors.length)}const[l,h,o]=await Promise.all([me(e.path,i),K(`${e.path}/bin`,{filesOnly:!0}),oe(e.path)]),u=h.length,N=o?(await ce(o)).length:0;return{name:e.name,path:e.path,mtimeMs:e.mtimeMs,hasManifest:n,manifest:i,hasLsp:s,monitors:d,hooks:l.hooks,agents:l.agentFiles.length,commands:l.commandFiles.length,skills:N,binCount:u,hasMcp:l.mcpServers.length>0}}async function ue(e){let n=`${e}/.claude-plugin/plugin.json`,i=await window.api.config.exists(n);if(i||(n=`${e}/plugin.json`,i=await window.api.config.exists(n)),!i)return{hasManifest:i,manifest:null};const s=await window.api.config.readJson(n),a=s.exists&&!s.parseError&&s.data&&typeof s.data=="object"&&!Array.isArray(s.data);return{hasManifest:i,manifest:a?s.data:null}}const P=e=>!!e&&typeof e=="object"&&!Array.isArray(e);function Oe(e,n){const i=n.startsWith("/")?n.startsWith(`${e}/`)?n.slice(e.length+1):null:n;if(i===null)return se(n);const s=[];for(const a of i.split("/"))if(!(a===""||a===".")){if(a!=="..")s.push(a);else if(s.pop()===void 0)return se(n)}return s.length>0?`${e}/${s.join("/")}`:e}function se(e){return console.warn(`[plugins] ignoring manifest path outside the plugin root: ${e}`),null}function Fe(e){return typeof e=="string"?[e]:Array.isArray(e)?e.filter(n=>typeof n=="string"):[]}function Te(e){if(!P(e))return null;if(P(e.mcpServers))return e.mcpServers;const n=Object.values(e);return n.length>0&&n.every(s=>P(s)&&(typeof s.command=="string"||typeof s.url=="string"))?e:null}function Be(e){if(!P(e))return 0;const n=P(e.hooks)?e.hooks:e;return Object.values(n).reduce((i,s)=>Array.isArray(s)?i+s.reduce((a,d)=>a+(P(d)&&Array.isArray(d.hooks)?d.hooks.length:0),0):i,0)}async function me(e,n){const i=(b,f)=>{const p=new Set;for(const w of Fe(b)){const y=Oe(e,w);y&&p.add(y)}return p.add(`${e}/${f}`),[...p]},s=async b=>{const f=new Set;for(const p of b)if(p.endsWith(".md"))f.add(p);else for(const w of await K(p,{filesOnly:!0}))w.endsWith(".md")&&f.add(`${p}/${w}`);return[...f]},a=async b=>{try{const f=await window.api.config.readJson(b);return f.exists&&!f.parseError?f.data:null}catch{return null}},d=i(n==null?void 0:n.commands,"commands"),l=i(n==null?void 0:n.agents,"agents"),h=n==null?void 0:n.hooks,o=i(typeof h=="string"||Array.isArray(h)?h:void 0,"hooks/hooks.json"),u=n==null?void 0:n.mcpServers,N=i(typeof u=="string"||Array.isArray(u)?u:void 0,".mcp.json"),[m,I,D,F]=await Promise.all([s(d),s(l),Promise.all(o.map(a)),Promise.all(N.map(a))]),E=[...P(h)?[h]:[],...D].reduce((b,f)=>b+Be(f),0),C=new Map;for(const b of[...P(u)?[u]:[],...F])for(const[f,p]of Object.entries(Te(b)??{})){if(C.has(f))continue;const w=P(p)?p.command:void 0,y=P(p)?p.url:void 0;C.set(f,{id:f,name:f,description:typeof w=="string"?w:typeof y=="string"?y:null})}return{commandFiles:m,agentFiles:I,hooks:E,mcpServers:[...C.values()],sourcePaths:[...d,...l,...o,...N]}}async function ie(e){const n=await Promise.all(e.map(s=>window.api.config.readText(s))),i=[];return e.forEach((s,a)=>{if(!n[a].exists)return;const d=s.slice(s.lastIndexOf("/")+1),l=le(n[a].text);i.push({id:s,name:l.name??d.replace(/\.md$/,""),description:l.description})}),i}async function K(e,n){try{return(await window.api.config.listDir(e,n)).entries.map(s=>s.name)}catch{return[]}}export{Ge as Plugins};
|