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.
Files changed (79) hide show
  1. package/dist/assets/{AgentLibrary-LBg3mVL8.js → AgentLibrary-BmJ8hIPw.js} +1 -1
  2. package/dist/assets/{Button-C4BN5ISR.js → Button-BS4kmz4p.js} +1 -1
  3. package/dist/assets/{DataModel-CHhjk61s.js → DataModel-DZHBZrfL.js} +1 -1
  4. package/dist/assets/History-pg00b2Gd.js +2 -0
  5. package/dist/assets/{Hooks-ByWVgXIf.js → Hooks-BTEs0UZY.js} +1 -1
  6. package/dist/assets/{Library-QvYVAEmY.js → Library-DuaJ-VSn.js} +1 -1
  7. package/dist/assets/{ListDetail-FvNe6fo5.js → ListDetail-Cud72s-O.js} +1 -1
  8. package/dist/assets/{McpServers-C7EmPm8B.js → McpServers-Dy-wnG_X.js} +1 -1
  9. package/dist/assets/{Memory-nyLR4Yw4.js → Memory-Bs1T1Jo7.js} +1 -1
  10. package/dist/assets/{Panel-thElCbLX.js → Panel-8UhLXEOW.js} +1 -1
  11. package/dist/assets/{Permissions-FQ9GM6Ca.js → Permissions-BfwzvmBS.js} +1 -1
  12. package/dist/assets/Plugins-McjyvvKh.js +2 -0
  13. package/dist/assets/{ProvenanceBadge-lAViG8yV.js → ProvenanceBadge-D0Ov_6WJ.js} +1 -1
  14. package/dist/assets/{RemoteMachines-AWpARk7N.js → RemoteMachines-gOlFTvWq.js} +1 -1
  15. package/dist/assets/{SaveBar-c15EEGB_.js → SaveBar-Cd6hJR6K.js} +1 -1
  16. package/dist/assets/Scheduler-BZXKqYJP.js +16 -0
  17. package/dist/assets/{ScopeSwitcher-BLep1rtB.js → ScopeSwitcher-C24ysV1K.js} +1 -1
  18. package/dist/assets/{Settings-D1kTUIDB.js → Settings-DWnN2qxn.js} +1 -1
  19. package/dist/assets/{SkillReferenceGraph-_40_f0t3.js → SkillReferenceGraph-BsWuiTbw.js} +1 -1
  20. package/dist/assets/{Skills-DaTkSOuU.js → Skills-6pHn6glu.js} +1 -1
  21. package/dist/assets/{SystemPrompt-DxNf-soM.js → SystemPrompt-DT0LBH-K.js} +1 -1
  22. package/dist/assets/{TagLibrary-L6KpBV-x.js → TagLibrary-DbJ0zbYL.js} +1 -1
  23. package/dist/assets/{TiptapBody-C_XjtJ82.js → TiptapBody-C4kIvIMH.js} +1 -1
  24. package/dist/assets/{Toggle-H0rERKNI.js → Toggle-pP19zlyk.js} +1 -1
  25. package/dist/assets/{ViewTabs-ZUWphDat.js → ViewTabs-CpzN8e5I.js} +1 -1
  26. package/dist/assets/{historyTotals-BxFKOztb.js → historyTotals-Caq78bb5.js} +1 -1
  27. package/dist/assets/{index-B5wj0DEX.js → index-Bjtguv6I.js} +434 -434
  28. package/dist/assets/{settingsSchema-BRcYkXJN.js → settingsSchema-CC2ySu3d.js} +1 -1
  29. package/dist/assets/{skillFrontmatter-DFGp4DST.js → skillFrontmatter-hDhNo8jE.js} +1 -1
  30. package/dist/assets/{useAgentsDirWatch-VvrgalfC.js → useAgentsDirWatch-BuOtY25U.js} +1 -1
  31. package/dist/assets/{useRemotePeers-mvXKNEE3.js → useRemotePeers-CNQmRBpt.js} +1 -1
  32. package/dist/index.html +1 -1
  33. package/package.json +1 -1
  34. package/plugins/session-manager-dev/skills/develop/SKILL.md +7 -7
  35. package/plugins/session-manager-dev/skills/develop/standards.md +4 -10
  36. package/scripts/scheduler-mcp-server.cjs +2 -2
  37. package/src/main/build-info.json +4 -4
  38. package/src/main/chatRunner.cjs +56 -43
  39. package/src/main/docEdit.cjs +1 -0
  40. package/src/main/index.cjs +12 -13
  41. package/src/main/ipcSchemas.cjs +17 -3
  42. package/src/main/lib/classifyPromptTicket.cjs +1 -0
  43. package/src/main/lib/claude/effectiveModelInfo.cjs +9 -21
  44. package/src/main/lib/claude/personaToolScope.cjs +7 -1
  45. package/src/main/lib/claude/runClaudeP.cjs +1 -0
  46. package/src/main/lib/epic/delegationReadiness.cjs +75 -8
  47. package/src/main/lib/mcpToolCatalog.cjs +0 -1
  48. package/src/main/lib/persona-macro/macroLibrary.cjs +75 -0
  49. package/src/main/lib/persona-macro/shippedPersonaSeeds.cjs +11 -0
  50. package/src/main/lib/prd/prdCreate.cjs +28 -1
  51. package/src/main/lib/prd/prdSizing.cjs +1 -8
  52. package/src/main/lib/remoteTranscriptTail.cjs +69 -2
  53. package/src/main/lib/runSeeders.cjs +21 -0
  54. package/src/main/lib/scheduler/loopEfficiency.cjs +109 -0
  55. package/src/main/lib/scheduler/queueHistory.cjs +44 -1
  56. package/src/main/lib/scheduler/queueStore.cjs +4 -72
  57. package/src/main/lib/scheduler/rcaReport.cjs +1 -1
  58. package/src/main/lib/scheduler/refireCap.cjs +40 -0
  59. package/src/main/lib/scheduler/reviewNotice.cjs +1 -1
  60. package/src/main/lib/scheduler/schedulerConfig.cjs +1 -2
  61. package/src/main/lib/scheduler/schedulerPaths.cjs +0 -2
  62. package/src/main/lib/scheduler/sessionSlots.cjs +1 -1
  63. package/src/main/lib/telemetry/auditLog.cjs +65 -14
  64. package/src/main/loopEfficiencyHandlers.cjs +160 -0
  65. package/src/main/queueOps.cjs +4 -9
  66. package/src/main/runVerify.cjs +22 -454
  67. package/src/main/scheduler/reviewLadder.cjs +12 -2
  68. package/src/main/scheduler.cjs +103 -177
  69. package/src/main/seedDevPlugin.cjs +49 -22
  70. package/src/main/seedStatus.cjs +3 -2
  71. package/src/main/supervisor.cjs +1 -0
  72. package/src/main/templates/PRD_AUTHORING.md +16 -31
  73. package/src/main/webRemote.cjs +82 -91
  74. package/src/preload/api.d.ts +39 -6
  75. package/src/preload/index.cjs +3 -0
  76. package/src/seed/agents/dev-lead.md +2 -9
  77. package/dist/assets/History-CL-T6Lv3.js +0 -2
  78. package/dist/assets/Plugins-D9KE7XTI.js +0 -2
  79. package/dist/assets/Scheduler-FvduP1FG.js +0 -16
@@ -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' | 'on-reset' | 'when-available';
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
- * Used by 'on-reset'. Ignored by 'when-available' and 'manual'. */
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 / retrying),
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
+ }
@@ -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: 3
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
- Verifier traps — each one has parked a green run before:
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};