session-steward 0.7.0 → 0.8.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/CHANGELOG.md +8 -0
- package/README.md +16 -0
- package/bin/session-steward-cli.mjs +4 -0
- package/dist/assets/index-C94A1O5c.js +9 -0
- package/dist/assets/index-CXq8Tw8T.css +2 -0
- package/dist/index.html +2 -2
- package/lib/cli.mjs +102 -2
- package/lib/providers/claude-code/events.mjs +17 -1
- package/lib/providers/claude-code/index.mjs +2 -0
- package/lib/providers/claude-code/tokens.mjs +174 -0
- package/lib/providers/codex/events.mjs +17 -1
- package/lib/providers/codex/index.mjs +2 -0
- package/lib/providers/codex/tokens.mjs +317 -0
- package/lib/server.mjs +30 -0
- package/lib/session-events.mjs +4 -0
- package/lib/session-token-cache.mjs +76 -0
- package/lib/session-tokens.mjs +73 -0
- package/package.json +2 -1
- package/dist/assets/index-BOACkzUI.js +0 -9
- package/dist/assets/index-DFAWGcgb.css +0 -2
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
|
|
2
|
+
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial}}}@layer theme{:root,:host{--font-sans:Inter, ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--spacing:.25rem;--animate-spin:spin 1s linear infinite;--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.sr-only{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.relative{position:relative}.mx-auto{margin-inline:auto}.mt-1{margin-top:var(--spacing)}.mt-1\.5{margin-top:calc(var(--spacing) * 1.5)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mt-5{margin-top:calc(var(--spacing) * 5)}.mt-6{margin-top:calc(var(--spacing) * 6)}.mb-5{margin-bottom:calc(var(--spacing) * 5)}.block{display:block}.flex{display:flex}.grid{display:grid}.hidden{display:none}.size-4{width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4)}.h-3{height:calc(var(--spacing) * 3)}.h-3\.5{height:calc(var(--spacing) * 3.5)}.h-5{height:calc(var(--spacing) * 5)}.h-9{height:calc(var(--spacing) * 9)}.min-h-\[360px\]{min-height:360px}.min-h-screen{min-height:100vh}.w-16{width:calc(var(--spacing) * 16)}.w-32{width:calc(var(--spacing) * 32)}.w-\[min\(50\%\,20rem\)\]{width:min(50%,20rem)}.w-\[min\(75\%\,30rem\)\]{width:min(75%,30rem)}.max-w-\[1380px\]{max-width:1380px}.min-w-0{min-width:0}.min-w-40{min-width:calc(var(--spacing) * 40)}.shrink-0{flex-shrink:0}.animate-spin{animation:var(--animate-spin)}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-col-reverse{flex-direction:column-reverse}.flex-wrap{flex-wrap:wrap}.items-baseline{align-items:baseline}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-end{justify-content:flex-end}.gap-1{gap:var(--spacing)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-2\.5{gap:calc(var(--spacing) * 2.5)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-3\.5{gap:calc(var(--spacing) * 3.5)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-5{gap:calc(var(--spacing) * 5)}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-hidden{overflow:hidden}.rounded{border-radius:.25rem}.rounded-full{border-radius:2147483647px}.px-4{padding-inline:calc(var(--spacing) * 4)}.py-5{padding-block:calc(var(--spacing) * 5)}.text-left{text-align:left}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}@media (width>=40rem){.sm\:flex{display:flex}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.sm\:flex-row{flex-direction:row}.sm\:items-center{align-items:center}.sm\:justify-end{justify-content:flex-end}.sm\:px-6{padding-inline:calc(var(--spacing) * 6)}.sm\:py-8{padding-block:calc(var(--spacing) * 8)}}@media (width>=64rem){.lg\:hidden{display:none}.lg\:grid-cols-\[minmax\(0\,1fr\)_340px\]{grid-template-columns:minmax(0,1fr) 340px}.lg\:px-8{padding-inline:calc(var(--spacing) * 8)}}@media (width>=80rem){.xl\:grid-cols-\[minmax\(0\,1fr\)_420px\]{grid-template-columns:minmax(0,1fr) 420px}}@media (width>=96rem){.\32 xl\:grid-cols-\[minmax\(0\,1fr\)_480px\]{grid-template-columns:minmax(0,1fr) 480px}}}:root{--scrollbar-thumb:#404040;--scrollbar-thumb-hover:#525252;--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark;font-synthesis:none;text-rendering:optimizelegibility}*{box-sizing:border-box}html,.app-shell,.app-shell *{scrollbar-color:var(--scrollbar-thumb) transparent;scrollbar-width:thin}html::-webkit-scrollbar{width:8px;height:8px}.app-shell::-webkit-scrollbar{width:8px;height:8px}.app-shell ::-webkit-scrollbar{width:8px;height:8px}html::-webkit-scrollbar-track{background:0 0}.app-shell::-webkit-scrollbar-track{background:0 0}.app-shell ::-webkit-scrollbar-track{background:0 0}html::-webkit-scrollbar-thumb{background:var(--scrollbar-thumb);background-clip:padding-box;border:2px solid #0000;border-radius:999px}.app-shell::-webkit-scrollbar-thumb{background:var(--scrollbar-thumb);background-clip:padding-box;border:2px solid #0000;border-radius:999px}.app-shell ::-webkit-scrollbar-thumb{background:var(--scrollbar-thumb);background-clip:padding-box;border:2px solid #0000;border-radius:999px}html::-webkit-scrollbar-thumb:hover{background-color:var(--scrollbar-thumb-hover)}.app-shell::-webkit-scrollbar-thumb:hover{background-color:var(--scrollbar-thumb-hover)}.app-shell ::-webkit-scrollbar-thumb:hover{background-color:var(--scrollbar-thumb-hover)}body{min-width:320px;margin:0}button,input,select{font:inherit}button{cursor:pointer}button:disabled{cursor:not-allowed}.app-shell{--canvas:#0a0a0a;--surface:#171717;--raised:#262626;--border-subtle:#262626;--border-strong:var(--scrollbar-thumb);--text-primary:#f5f5f5;--text-secondary:#d4d4d4;--text-muted:#a3a3a3;--text-faint:#737373;--accent:#34d399;--accent-soft:#173c2f;--danger:#dc2626;--danger-border:var(--danger)}@supports (color:color-mix(in lab, red, red)){.app-shell{--danger-border:color-mix(in srgb, var(--danger) 40%, var(--border-subtle))}}.app-shell{--danger-text:#fca5a5;--warning:#fbbf24;--success:#34d399;--focus-ring:#d4d4d4;--radius-control:.625rem;--radius-surface:1rem;min-height:100vh;color:var(--text-primary);background:radial-gradient(circle at 50% -12rem, var(--text-primary), transparent 28rem), var(--canvas);position:relative;overflow-x:hidden}@supports (color:color-mix(in lab, red, red)){.app-shell{background:radial-gradient(circle at 50% -12rem, color-mix(in srgb, var(--text-primary) 2%, transparent), transparent 28rem), var(--canvas)}}.app-shell:before{pointer-events:none;content:"";background:linear-gradient(90deg, transparent, var(--border-strong), transparent);height:1px;position:fixed;top:0;left:0;right:0}.app-shell button:focus-visible,.app-shell input:focus-visible,.app-shell select:focus-visible{outline:2px solid var(--focus-ring);outline-offset:2px}.app-shell ::selection{color:var(--text-primary);background:var(--text-primary)}@supports (color:color-mix(in lab, red, red)){.app-shell ::selection{background:color-mix(in srgb, var(--text-primary) 20%, transparent)}}.text-primary{color:var(--text-primary)}.section-title{color:var(--text-primary);font-size:16px;font-weight:650}.shown-count{color:var(--text-muted);font-variant-numeric:tabular-nums;font-size:13px}.surface{border:1px solid var(--border-strong);border-radius:var(--radius-surface);background:var(--surface);box-shadow:0 1px 0 var(--text-primary) inset, 0 16px 44px var(--canvas)}@supports (color:color-mix(in lab, red, red)){.surface{box-shadow:0 1px 0 color-mix(in srgb, var(--text-primary) 3%, transparent) inset, 0 16px 44px color-mix(in srgb, var(--canvas) 48%, transparent)}}.brand-mark{border:1px solid var(--border-strong);width:2.75rem;height:2.75rem;color:var(--text-secondary);background:linear-gradient(145deg, var(--raised), var(--surface));box-shadow:0 8px 24px var(--canvas);border-radius:.875rem;flex:none;place-items:center;display:grid}@supports (color:color-mix(in lab, red, red)){.brand-mark{box-shadow:0 8px 24px color-mix(in srgb, var(--canvas) 40%, transparent)}}.brand-kicker{color:var(--text-muted);margin-bottom:4px;font-size:12px;font-weight:550}.brand-title{letter-spacing:-.035em;color:var(--text-primary);font-size:28px;font-weight:650;line-height:32px}.provider-switch{background:var(--text-primary);border:0;border-radius:.75rem;gap:4px;padding:4px;display:inline-flex}@supports (color:color-mix(in lab, red, red)){.provider-switch{background:color-mix(in srgb, var(--text-primary) 4%, transparent)}}.provider-switch{box-shadow:0 1px 0 var(--text-primary) inset, 0 8px 24px var(--canvas)}@supports (color:color-mix(in lab, red, red)){.provider-switch{box-shadow:0 1px 0 color-mix(in srgb, var(--text-primary) 5%, transparent) inset, 0 8px 24px color-mix(in srgb, var(--canvas) 32%, transparent)}}.provider-switch button{min-height:36px;color:var(--text-muted);background:0 0;border:0;border-radius:.5rem;align-items:center;gap:7px;padding:0 16px;font-size:13px;font-weight:650;transition:color .15s ease-out,background .15s ease-out,box-shadow .15s ease-out;display:inline-flex}.provider-switch button:hover{color:var(--text-primary)}.provider-switch button[aria-pressed=true]{color:var(--text-primary);background:var(--raised);box-shadow:0 1px 4px var(--canvas)}@supports (color:color-mix(in lab, red, red)){.provider-switch button[aria-pressed=true]{box-shadow:0 1px 4px color-mix(in srgb, var(--canvas) 60%, transparent)}}.provider-icon{flex:none}.provider-context{align-items:center;min-height:36px;margin:-4px 4px 8px;padding:0 4px 4px;display:flex}.provider-context-row,.provider-context-main{min-width:0}.provider-context-main{align-items:center;gap:12px;display:flex}.provider-context-heading{flex:none;align-items:center;gap:8px;display:flex}.provider-context-label{color:var(--text-secondary);font-size:12px;font-weight:650}.provider-context code{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--text-muted);font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:12px;overflow:hidden}.provider-context-actions{flex:none;align-items:center;gap:4px;display:flex}.provider-context-editing{border:1px solid var(--border-strong);border-radius:var(--radius-surface);background:var(--raised);box-shadow:0 18px 48px var(--canvas);margin:0 0 12px;padding:16px;display:block}@supports (color:color-mix(in lab, red, red)){.provider-context-editing{box-shadow:0 18px 48px color-mix(in srgb, var(--canvas) 54%, transparent)}}.provider-context-placeholder{border-radius:.75rem;height:48px;margin-bottom:12px}.provider-context-editing .provider-context-main{gap:8px;display:grid}.provider-context-form{border-top:1px solid var(--border-subtle);margin-top:12px;padding-top:12px}.compact-action{border-radius:var(--radius-control);min-height:28px;color:var(--text-muted);background:0 0;border:0;padding:4px 8px;font-size:11px;font-weight:650}.compact-action:hover:not(:disabled){color:var(--text-primary);background:var(--text-primary)}@supports (color:color-mix(in lab, red, red)){.compact-action:hover:not(:disabled){background:color-mix(in srgb, var(--text-primary) 6%, transparent)}}.compact-action:disabled{opacity:.42}.source-badge{border:1px solid var(--border-strong);color:var(--text-muted);background:var(--surface);border-radius:999px;padding:2px 8px;font-size:11px;font-weight:650}.overview-strip{--overview-columns:5;border-top:1px solid var(--border-subtle);border-bottom:1px solid var(--border-subtle);grid-template-columns:repeat(2,minmax(0,1fr));margin-bottom:16px;display:grid}.overview-item{min-width:0;color:var(--text-muted);grid-template-columns:auto minmax(0,1fr);align-items:center;gap:8px;padding:8px 12px 12px;display:grid}.overview-item-primary{color:var(--text-secondary);grid-column:1/-1}.overview-item:not(.overview-item-primary):nth-child(2n){border-right:1px solid var(--border-subtle)}.overview-strip>.overview-item:last-child{border-right:0}.overview-label{text-overflow:ellipsis;white-space:nowrap;color:var(--text-muted);font-size:11px;font-weight:600;line-height:16px;overflow:hidden}.overview-value{letter-spacing:-.015em;text-overflow:ellipsis;white-space:nowrap;color:var(--text-secondary);font-variant-numeric:tabular-nums;font-size:16px;font-weight:650;line-height:20px;overflow:hidden}.overview-item-primary .overview-value{color:var(--text-primary);font-size:20px;line-height:24px}.panel-label{color:var(--text-secondary);font-size:12px;font-weight:650}.cleanup-eyebrow{letter-spacing:.12em;text-transform:uppercase;color:var(--danger-text);align-items:center;gap:8px;margin-bottom:8px;font-size:11px;font-weight:700;display:flex}.button{border-radius:var(--radius-control);border:1px solid #0000;justify-content:center;align-items:center;gap:8px;min-height:36px;padding:8px 12px;font-size:13px;font-weight:650;line-height:16px;display:inline-flex}.button:disabled{opacity:.42}.button.secondary{border-color:var(--border-strong);color:var(--text-primary);background:var(--text-primary)}@supports (color:color-mix(in lab, red, red)){.button.secondary{background:color-mix(in srgb, var(--text-primary) 6%, transparent)}}.button.secondary:hover:not(:disabled){background:var(--text-primary)}@supports (color:color-mix(in lab, red, red)){.button.secondary:hover:not(:disabled){background:color-mix(in srgb, var(--text-primary) 10%, transparent)}}.button.ghost{border-color:var(--border-subtle);color:var(--text-secondary);background:0 0}.button.ghost:hover:not(:disabled){border-color:var(--border-strong);color:var(--text-primary);background:var(--text-primary)}@supports (color:color-mix(in lab, red, red)){.button.ghost:hover:not(:disabled){background:color-mix(in srgb, var(--text-primary) 5%, transparent)}}.button.primary{border-color:var(--focus-ring);color:var(--canvas);background:var(--focus-ring);box-shadow:0 8px 24px var(--canvas)}@supports (color:color-mix(in lab, red, red)){.button.primary{box-shadow:0 8px 24px color-mix(in srgb, var(--canvas) 46%, transparent)}}.button.primary:hover:not(:disabled){background:var(--text-primary)}.button.danger{border-color:var(--danger);color:#fff;background:var(--danger);box-shadow:0 8px 24px var(--danger)}@supports (color:color-mix(in lab, red, red)){.button.danger{box-shadow:0 8px 24px color-mix(in srgb, var(--danger) 18%, transparent)}}.button.danger:hover:not(:disabled){background:#b91c1c;border-color:#b91c1c}.icon-button{border-radius:var(--radius-control);width:32px;height:32px;color:var(--text-muted);background:0 0;border:1px solid #0000;flex:none;place-items:center;display:grid}.icon-button:hover:not(:disabled){border-color:var(--border-strong);color:var(--text-primary);background:var(--text-primary)}@supports (color:color-mix(in lab, red, red)){.icon-button:hover:not(:disabled){background:color-mix(in srgb, var(--text-primary) 6%, transparent)}}.refresh-button{border-color:var(--border-subtle);background:var(--surface);width:40px;height:40px}.status-pill{border:1px solid;border-radius:999px;align-items:center;gap:8px;min-height:28px;padding:4px 8px;font-size:11px;font-weight:650;display:inline-flex}.status-pill:hover{filter:brightness(1.12)}.status-pill>span{background:currentColor;border-radius:999px;width:6px;height:6px}.status-ready{border-color:var(--success)}@supports (color:color-mix(in lab, red, red)){.status-ready{border-color:color-mix(in srgb, var(--success) 28%, transparent)}}.status-ready{color:var(--success);background:var(--success)}@supports (color:color-mix(in lab, red, red)){.status-ready{background:color-mix(in srgb, var(--success) 8%, transparent)}}.status-partial{border-color:var(--border-subtle);color:var(--text-secondary);background:var(--surface)}.status-warning{border-color:var(--warning)}@supports (color:color-mix(in lab, red, red)){.status-warning{border-color:color-mix(in srgb, var(--warning) 28%, transparent)}}.status-warning{color:var(--warning);background:var(--warning)}@supports (color:color-mix(in lab, red, red)){.status-warning{background:color-mix(in srgb, var(--warning) 8%, transparent)}}.status-error{border-color:var(--danger-border);color:var(--danger-text);background:var(--danger)}@supports (color:color-mix(in lab, red, red)){.status-error{background:color-mix(in srgb, var(--danger) 8%, transparent)}}.field{min-width:0;color:var(--text-muted);gap:4px;font-size:12px;font-weight:650;display:grid}.field>span{align-items:center;gap:4px;display:flex}.field input,.field select,.input-wrap,.sort-control select{border:1px solid var(--border-subtle);border-radius:var(--radius-control);width:100%;min-height:40px;color:var(--text-primary);background-color:var(--raised)}@supports (color:color-mix(in lab, red, red)){.field input,.field select,.input-wrap,.sort-control select{background-color:color-mix(in srgb, var(--raised) 18%, var(--canvas))}}.field input,.field select,.input-wrap,.sort-control select{box-shadow:inset 0 1px 0 var(--text-primary)}@supports (color:color-mix(in lab, red, red)){.field input,.field select,.input-wrap,.sort-control select{box-shadow:inset 0 1px 0 color-mix(in srgb, var(--text-primary) 3%, transparent)}}.field>input{padding:8px 12px}.field select,.sort-control select{appearance:none;background-image:linear-gradient(45deg, transparent 50%, var(--text-muted) 50%), linear-gradient(135deg, var(--text-muted) 50%, transparent 50%);text-overflow:ellipsis;white-space:nowrap;background-position:calc(100% - 15px) 17px,calc(100% - 11px) 17px;background-repeat:no-repeat;background-size:4px 4px,4px 4px;padding:8px 36px 8px 12px;overflow:hidden}.field input::placeholder{color:var(--text-muted)}.field input:hover,.field select:hover,.input-wrap:hover,.sort-control select:hover{border-color:var(--border-strong)}.field input:focus,.field select:focus,.input-wrap:focus-within,.sort-control select:focus{border-color:var(--text-secondary)}@supports (color:color-mix(in lab, red, red)){.field input:focus,.field select:focus,.input-wrap:focus-within,.sort-control select:focus{border-color:color-mix(in srgb, var(--text-secondary) 58%, var(--border-strong))}}.field input:focus,.field select:focus,.input-wrap:focus-within,.sort-control select:focus{background-color:var(--canvas);box-shadow:0 0 0 3px var(--focus-ring), inset 0 1px 0 var(--text-primary)}@supports (color:color-mix(in lab, red, red)){.field input:focus,.field select:focus,.input-wrap:focus-within,.sort-control select:focus{box-shadow:0 0 0 3px color-mix(in srgb, var(--focus-ring) 7%, transparent), inset 0 1px 0 color-mix(in srgb, var(--text-primary) 3%, transparent)}}.input-wrap{color:var(--text-muted);grid-template-columns:auto minmax(0,1fr) auto;align-items:center;padding:0 12px;display:grid}.input-wrap input{min-height:auto;box-shadow:none;background:0 0;border:0;border-radius:0;outline:0;padding:8px}.app-shell .input-wrap input:focus-visible{outline:0}.input-wrap button{color:var(--text-muted);background:0 0;border:0;place-items:center;display:grid}.session-list-header{border-bottom:1px solid var(--border-subtle);flex-wrap:wrap;justify-content:space-between;align-items:center;gap:12px;min-height:60px;padding:12px 16px;display:flex}.session-list-tools{align-items:center;gap:12px;display:flex}.sort-control{color:var(--text-muted);align-items:center;gap:8px;font-size:11px;font-weight:650;display:flex}.sort-control select{background-position:calc(100% - 15px) 13px,calc(100% - 11px) 13px;width:132px;min-height:32px;padding-top:4px;padding-bottom:4px;font-size:12px}.shortcut-hint{color:var(--text-muted);font-size:11px;display:none}.shortcut-hint kbd{border:1px solid var(--border-strong);background:var(--raised);color:var(--text-secondary);border-radius:.375rem;margin:0 4px;padding:1px 6px;font-family:inherit;font-size:11px}.session-filters{--filter-grid:minmax(0, 1fr) auto;border-bottom:1px solid var(--border-subtle);background:var(--surface);position:relative}@supports (color:color-mix(in lab, red, red)){.session-filters{background:color-mix(in srgb, var(--surface) 88%, var(--canvas))}}.filter-bar,.more-filters-row{grid-template-columns:var(--filter-grid);align-items:end;gap:12px;min-width:0;padding:12px 16px;display:grid}.filter-search{min-width:0}.filter-primary-controls,.filter-overflow-primary,.filter-overflow-controls{display:contents}.more-filters-wrap{min-width:0}.more-filters-button{border:1px solid var(--border-subtle);border-radius:var(--radius-control);min-height:40px;color:var(--text-secondary);background:var(--raised);align-items:center;gap:8px;padding:8px 12px;display:inline-flex}@supports (color:color-mix(in lab, red, red)){.more-filters-button{background:color-mix(in srgb, var(--raised) 18%, var(--canvas))}}.more-filters-button{box-shadow:inset 0 1px 0 var(--text-primary)}@supports (color:color-mix(in lab, red, red)){.more-filters-button{box-shadow:inset 0 1px 0 color-mix(in srgb, var(--text-primary) 3%, transparent)}}.more-filters-button{white-space:nowrap;font-size:12px;font-weight:650}.more-filters-button:hover{border-color:var(--border-strong);color:var(--text-primary);background:var(--raised)}.more-filters-active{border-color:var(--border-strong);color:var(--text-primary)}.more-filters-button strong{min-width:20px;height:20px;color:var(--canvas);background:var(--text-secondary);font-variant-numeric:tabular-nums;border-radius:999px;place-items:center;font-size:11px;display:grid}.more-filters-row{border-top:1px solid var(--border-subtle);animation:.15s ease-out disclosure-in}.active-filter-row{border-top:1px solid var(--border-subtle);justify-content:space-between;align-items:center;gap:12px;min-height:44px;padding:8px 16px;display:flex}.active-filter-chips{flex-wrap:wrap;gap:8px;min-width:0;display:flex}.filter-chip{border:1px solid var(--border-strong);max-width:300px;min-height:28px;color:var(--text-secondary);background:var(--raised);border-radius:999px;align-items:center;gap:8px;padding:4px 8px 4px 12px;font-size:11px;transition:border-color .12s ease-out,background .12s ease-out;display:inline-flex}.filter-chip span{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.filter-chip:hover{border-color:var(--focus-ring)}.filter-chip-exiting{pointer-events:none}.clear-all-filters{color:var(--text-muted);background:0 0;border:0;flex:none;padding:4px;font-size:11px;font-weight:650}.clear-all-filters:hover{color:var(--text-primary)}.unknown-activity-note{border-top:1px solid var(--border-subtle);color:var(--text-muted);padding:8px 16px;font-size:11px;line-height:16px}.toggle{cursor:pointer;border:1px solid var(--border-subtle);border-radius:var(--radius-control);min-width:0;min-height:40px;color:var(--text-secondary);background:var(--raised);align-items:center;gap:8px;padding:8px 12px;display:inline-flex}@supports (color:color-mix(in lab, red, red)){.toggle{background:color-mix(in srgb, var(--raised) 18%, var(--canvas))}}.toggle{box-shadow:inset 0 1px 0 var(--text-primary)}@supports (color:color-mix(in lab, red, red)){.toggle{box-shadow:inset 0 1px 0 color-mix(in srgb, var(--text-primary) 3%, transparent)}}.toggle{font-size:12px;font-weight:600;transition:border-color .15s ease-out,background .15s ease-out,color .15s ease-out}.toggle:hover{border-color:var(--border-strong);color:var(--text-primary)}.toggle input{opacity:0;pointer-events:none;position:absolute}.toggle-track{background:var(--border-strong);border-radius:999px;flex:none;width:28px;height:16px;transition:background .15s ease-out;position:relative}.toggle-track span{background:var(--text-muted);border-radius:999px;width:10px;height:10px;transition:left .15s ease-out,background .15s ease-out;position:absolute;top:3px;left:3px}.toggle-copy{white-space:nowrap;align-items:center;gap:6px;min-width:0;display:flex}.toggle-copy>span{text-overflow:ellipsis;overflow:hidden}.toggle-active{border-color:var(--border-strong);color:var(--text-primary);background:var(--raised)}.toggle-active .toggle-track{background:var(--text-secondary)}.toggle-active .toggle-track span{background:var(--canvas);left:15px}.page-selection-row{border-bottom:1px solid var(--border-subtle);background:var(--text-primary);justify-content:space-between;align-items:center;gap:12px;min-height:44px;padding:8px 16px;display:flex}@supports (color:color-mix(in lab, red, red)){.page-selection-row{background:color-mix(in srgb, var(--text-primary) 1.5%, transparent)}}.selection-control{cursor:pointer;color:var(--text-secondary);align-items:center;gap:8px;font-size:12px;font-weight:600;display:inline-flex}.selection-control input,.session-checkbox input{width:16px;height:16px;accent-color:var(--accent);margin:0}.session-row-block+.session-row-block{border-top:1px solid var(--border-subtle)}.session-row-block-grouped{border-top:0!important}.session-rows>.session-row+.session-row{border-top:1px solid var(--border-subtle)}.date-separator{min-height:30px;color:var(--text-faint);letter-spacing:.035em;align-items:center;gap:10px;padding:6px 16px;font-size:10px;font-weight:650;line-height:16px;display:flex}.date-separator-line{background:var(--border-subtle);flex:auto;height:1px}.session-row{grid-template-columns:32px minmax(0,1fr) auto auto;align-items:center;gap:8px;min-height:60px;padding:8px 16px;transition:background .12s ease-out,box-shadow .12s ease-out;display:grid;position:relative}.session-row:hover{background:var(--text-primary)}@supports (color:color-mix(in lab, red, red)){.session-row:hover{background:color-mix(in srgb, var(--text-primary) 3%, transparent)}}.session-row-cursor:before{background:var(--text-primary);content:"";width:2px;height:28px;box-shadow:0 0 10px var(--text-primary);border-radius:999px;position:absolute;top:50%;left:3px;transform:translateY(-50%)}@supports (color:color-mix(in lab, red, red)){.session-row-cursor:before{box-shadow:0 0 10px color-mix(in srgb, var(--text-primary) 18%, transparent)}}.session-row-inspected{background:var(--accent)}@supports (color:color-mix(in lab, red, red)){.session-row-inspected{background:color-mix(in srgb, var(--accent) 10%, transparent)}}.session-row-selected{background:var(--text-primary)}@supports (color:color-mix(in lab, red, red)){.session-row-selected{background:color-mix(in srgb, var(--text-primary) 6%, transparent)}}.session-row-inspected.session-row-selected{background:var(--accent)}@supports (color:color-mix(in lab, red, red)){.session-row-inspected.session-row-selected{background:color-mix(in srgb, var(--accent) 12%, transparent)}}.session-checkbox{cursor:pointer;border-radius:var(--radius-control);place-items:center;width:40px;height:40px;margin:-4px;display:grid}.session-checkbox:hover{background:var(--text-primary)}@supports (color:color-mix(in lab, red, red)){.session-checkbox:hover{background:color-mix(in srgb, var(--text-primary) 6%, transparent)}}.session-checkbox:focus-within{background:var(--focus-ring)}@supports (color:color-mix(in lab, red, red)){.session-checkbox:focus-within{background:color-mix(in srgb, var(--focus-ring) 8%, transparent)}}.session-checkbox:focus-within{box-shadow:0 0 0 2px var(--focus-ring)}@supports (color:color-mix(in lab, red, red)){.session-checkbox:focus-within{box-shadow:0 0 0 2px color-mix(in srgb, var(--focus-ring) 22%, transparent)}}.session-row>button{min-width:0;color:inherit;background:0 0;border:0;padding:0}.session-title{color:var(--text-primary);text-overflow:ellipsis;white-space:nowrap;font-size:14px;font-weight:500;line-height:20px;display:block;overflow:hidden}.session-workspace{min-width:0;color:var(--text-muted);align-items:center;gap:4px;margin-top:4px;font-size:12px;line-height:16px;display:flex}.session-row-meta{flex-direction:row;flex:none;justify-content:flex-end;align-items:center;gap:4px;display:flex}.time-badge,.kind-label,.size-badge,.archive-tag{border:1px solid var(--border-subtle);min-height:22px;color:var(--text-muted);background:var(--text-primary);border-radius:999px;align-items:center;gap:4px;padding:2px 6px;display:inline-flex}@supports (color:color-mix(in lab, red, red)){.time-badge,.kind-label,.size-badge,.archive-tag{background:color-mix(in srgb, var(--text-primary) 3%, transparent)}}.time-badge,.kind-label,.size-badge,.archive-tag{white-space:nowrap;font-size:11px;font-weight:600;line-height:16px}.archive-tag{min-height:20px;padding:1px 6px}.session-row-chevron{color:var(--text-faint);flex:none;display:none}.session-row:hover .session-row-chevron{color:var(--text-muted);transform:translate(2px)}.session-row-chevron{transition:color .12s ease-out,transform .12s ease-out}.session-row-skeleton{grid-template-columns:32px minmax(0,1fr) auto auto}.badge-skeleton{border-radius:999px;width:56px;height:22px}.inspector{display:none;overflow:hidden}.inspector-backdrop{display:none}.inspector-header{border-bottom:1px solid var(--border-subtle);justify-content:space-between;align-items:center;padding:16px 20px;display:flex}.inspector-content{padding:20px}.inspector-title{overflow-wrap:anywhere;-webkit-line-clamp:2;color:var(--text-primary);-webkit-box-orient:vertical;font-size:14px;font-weight:500;line-height:20px;display:-webkit-box;overflow:hidden}.inspector-id{overflow-wrap:anywhere;color:var(--text-muted);margin-top:4px;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:11px;line-height:16px}.inspector-chips{flex-wrap:wrap;gap:6px;margin:14px 0 0;padding:0;list-style:none;display:flex}.inspector-chip{color:var(--text-secondary);background:var(--raised);border-radius:999px;padding:4px 10px;font-size:11px;font-weight:600;line-height:16px}.inspector-details{grid-template-columns:repeat(2,minmax(0,1fr));gap:18px 16px;margin-top:20px;display:grid}.detail-row-wide{grid-column:1/-1}.detail-row dt{color:var(--text-muted);font-size:11px;font-weight:650;line-height:16px}.detail-row dd{overflow-wrap:anywhere;color:var(--text-secondary);margin-top:4px;font-size:13px;line-height:20px}.inspector-empty{text-align:center;place-items:center;min-height:260px;padding:28px;display:grid}.inspector-empty-icon{width:40px;height:40px;color:var(--text-faint);place-items:center;margin:0 auto;display:grid}.inspector-empty h2{color:var(--text-secondary);margin-top:8px;font-size:13px;font-weight:600}.inspector-empty p{max-width:220px;color:var(--text-muted);margin:8px auto 0;font-size:12px;line-height:16px}.related-sessions,.session-timeline{border-top:1px solid var(--border-subtle)}.inspector-tabs{border-top:1px solid var(--border-subtle);border-bottom:1px solid var(--border-subtle);align-items:stretch;gap:20px;padding:0 20px;display:flex}.inspector-tabs button{min-height:40px;color:var(--text-muted);background:0 0;border:0;padding:0;font-size:12px;font-weight:650;transition:color .15s ease-out;position:relative}.inspector-tabs button:hover{color:var(--text-secondary)}.inspector-tabs button[aria-selected=true]{color:var(--text-primary)}.inspector-tabs button[aria-selected=true]:after{content:"";background:var(--accent);border-radius:999px 999px 0 0;height:2px;position:absolute;bottom:-1px;left:0;right:0}.inspector-tab-count{color:var(--text-muted);font-variant-numeric:tabular-nums;margin-left:6px;font-weight:600}.inspector-tabpanel[hidden]{display:none}.inspector-tabpanel:focus-visible{outline:2px solid var(--focus-ring);outline-offset:-2px}.inspector-tabpanel>.related-sessions,.inspector-tabpanel>.session-timeline{border-top:0}.timeline-heading{justify-content:space-between;align-items:center;gap:12px;padding:16px 20px;display:flex}.timeline-heading>div>p:not(.panel-label){color:var(--text-muted);margin-top:3px;font-size:11px;line-height:16px}.related-session-list{border-top:1px solid var(--border-subtle)}.related-session-list button{border:0;border-bottom:1px solid var(--border-subtle);width:100%;min-width:0;color:var(--text-muted);text-align:left;background:0 0;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:8px;padding:10px 20px;display:grid}.related-session-list button:hover{color:var(--text-primary);background:var(--text-primary)}@supports (color:color-mix(in lab, red, red)){.related-session-list button:hover{background:color-mix(in srgb, var(--text-primary) 3%, transparent)}}.related-session-copy{gap:2px;min-width:0;display:grid;overflow:hidden}.related-session-copy strong,.related-session-copy small,.related-session-copy code{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.related-session-copy strong{color:var(--text-secondary);font-size:11px;font-weight:600;line-height:16px}.related-session-copy small{color:var(--text-muted);font-size:10px;line-height:15px}.related-session-copy code{color:var(--text-faint);font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:9px;line-height:14px}.timeline-region{border-top:1px solid var(--border-subtle);min-height:112px;position:relative}.timeline-initial-loading{min-height:112px;color:var(--text-muted);justify-content:center;align-items:center;gap:8px;font-size:12px;font-weight:600;display:flex}.timeline-events{display:grid}.timeline-event{border-bottom:1px solid var(--border-subtle);background:var(--text-primary);min-width:0;padding:14px 20px}@supports (color:color-mix(in lab, red, red)){.timeline-event{background:color-mix(in srgb, var(--text-primary) 1.5%, transparent)}}.timeline-event header{justify-content:space-between;align-items:center;gap:12px;margin-bottom:8px;display:flex}.timeline-event header span{border:1px solid var(--border-subtle);min-height:20px;color:var(--text-secondary);background:var(--raised);letter-spacing:.07em;text-transform:uppercase;border-radius:999px;align-items:center;padding:1px 7px;font-size:9px;font-weight:750;line-height:16px;display:inline-flex}.timeline-event time{color:var(--text-faint);font-size:10px;line-height:16px}.timeline-event-ran,.timeline-event-edit{background:0 0;padding-top:10px;padding-bottom:10px}.timeline-event-ran header,.timeline-event-edit header{margin-bottom:6px}.timeline-event-failed{border-color:var(--danger-border);background:var(--danger)}@supports (color:color-mix(in lab, red, red)){.timeline-event-failed{background:color-mix(in srgb, var(--danger) 7%, var(--surface))}}.timeline-event-failed header span,.timeline-event-failed .timeline-event-meta{color:var(--danger-text)}.timeline-event-copy p{overflow-wrap:anywhere;color:var(--text-secondary);white-space:pre-wrap;font-size:12px;line-height:19px}.timeline-event-ask{border:1px solid var(--border-strong);border-radius:var(--radius-control);background:var(--raised);justify-self:end;width:fit-content;max-width:85%;margin:12px 20px;padding:14px 16px}.timeline-event-ask header span{border-color:var(--accent)}@supports (color:color-mix(in lab, red, red)){.timeline-event-ask header span{border-color:color-mix(in srgb, var(--accent) 34%, transparent)}}.timeline-event-ask header span{color:var(--accent);background:var(--accent)}@supports (color:color-mix(in lab, red, red)){.timeline-event-ask header span{background:color-mix(in srgb, var(--accent) 16%, transparent)}}.timeline-event-said{padding-top:18px;padding-bottom:18px}.timeline-event-ask.timeline-event-injected{border-color:var(--border-subtle);background:var(--text-primary)}@supports (color:color-mix(in lab, red, red)){.timeline-event-ask.timeline-event-injected{background:color-mix(in srgb, var(--text-primary) 4%, var(--surface))}}.timeline-event-ask.timeline-event-injected header span{border-color:var(--border-subtle);color:var(--text-secondary);background:var(--raised)}.timeline-event-ask .timeline-event-copy p,.timeline-event-said .timeline-event-copy p{color:var(--text-primary);font-size:13px;font-weight:500;line-height:21px}.timeline-event-copy button,.timeline-scroll-copy button{color:var(--text-muted);background:0 0;border:0;margin-top:7px;padding:0;font-size:11px;font-weight:650}.timeline-event-copy button:hover,.timeline-scroll-copy button:hover{color:var(--text-primary)}.timeline-event-copy span{color:var(--text-faint);margin-top:5px;font-size:10px;display:block}.timeline-scroll-copy{min-width:0}.timeline-scroll-copy>div{max-width:100%;color:var(--text-secondary);white-space:pre;padding-bottom:3px;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:11px;line-height:18px;overflow-x:auto}.timeline-event-meta,.timeline-plan-summary{color:var(--text-muted);margin-top:8px;font-size:11px;line-height:17px}.timeline-secondary-value{min-width:0;margin-top:9px}.timeline-secondary-value>span{color:var(--text-faint);margin-bottom:4px;font-size:10px;font-weight:650;line-height:16px;display:block}.injected-events-toggle,.timeline-more{border:0;border-bottom:1px solid var(--border-subtle);width:100%;color:var(--text-muted);background:var(--text-primary);padding:10px 20px}@supports (color:color-mix(in lab, red, red)){.injected-events-toggle,.timeline-more{background:color-mix(in srgb, var(--text-primary) 2%, transparent)}}.injected-events-toggle,.timeline-more{text-align:left;font-size:11px;font-weight:650}.injected-events-toggle:hover,.timeline-more:hover:not(:disabled){color:var(--text-primary);background:var(--text-primary)}@supports (color:color-mix(in lab, red, red)){.injected-events-toggle:hover,.timeline-more:hover:not(:disabled){background:color-mix(in srgb, var(--text-primary) 4%, transparent)}}.timeline-more{text-align:center}.timeline-more:disabled{opacity:.65}.timeline-coverage{color:var(--text-faint);padding:10px 20px;font-size:10px;line-height:16px}.timeline-coverage p+p{overflow-wrap:anywhere;margin-top:3px}.timeline-coverage-notice{border:1px solid var(--border-subtle);color:var(--text-secondary);background:var(--surface);border-radius:.625rem;align-items:flex-start;gap:9px;margin:12px;padding:11px;display:flex}.timeline-coverage-notice>svg{color:var(--text-muted);flex:none;margin-top:1px}.timeline-coverage-notice strong{font-size:12px;font-weight:650}.timeline-coverage-notice p{color:var(--text-muted);margin-top:3px;font-size:10px;line-height:16px}.timeline-empty{min-height:180px;color:var(--text-faint);text-align:center;align-content:center;place-items:center;padding:24px;display:grid}.timeline-empty h3{color:var(--text-secondary);margin-top:10px;font-size:13px;font-weight:650}.timeline-empty p{max-width:320px;color:var(--text-muted);margin-top:6px;font-size:11px;line-height:17px}.timeline-empty .button{margin-top:14px}.timeline-quiet-empty{color:var(--text-muted);text-align:center;padding:16px 20px;font-size:11px}.composition{--token-cachedInput:#199e70;--token-freshInput:#3987e5;--token-cacheWrites:#c98500;--token-output:#9085e9;--segment-toolOutput:#3987e5;--segment-largeRecords:#d95926;--segment-compaction:#199e70;--segment-attachments:#c98500;--segment-messages:#d55181;--segment-edits:#008300;--segment-reasoning:#9085e9;--segment-other:#737373;border-top:1px solid var(--border-subtle);padding:16px 20px}.composition-heading{justify-content:space-between;align-items:baseline;gap:12px;margin-bottom:10px;display:flex}.composition-heading>p:last-child{color:var(--text-secondary);font-variant-numeric:tabular-nums;font-size:12px;font-weight:650}.composition-bar{gap:2px;height:10px;display:flex}.composition-segment{border-radius:2px;min-width:3px;transition:opacity .15s ease-out}.composition-segment:first-child{border-radius:4px 2px 2px 4px}.composition-segment:last-child{border-radius:2px 4px 4px 2px}.composition-segment-muted{opacity:.26}.composition-legend{gap:1px;margin-top:12px;display:grid}.composition-legend-row{border-radius:6px;flex-wrap:wrap;justify-content:space-between;align-items:center;gap:12px;margin:0 -6px;padding:3px 6px;transition:background .15s ease-out,opacity .15s ease-out;display:flex}.composition-legend-row:hover{background:var(--text-primary)}@supports (color:color-mix(in lab, red, red)){.composition-legend-row:hover{background:color-mix(in srgb, var(--text-primary) 4%, transparent)}}.composition-legend-row dt{min-width:0;color:var(--text-secondary);text-overflow:ellipsis;white-space:nowrap;align-items:center;gap:8px;font-size:12px;line-height:18px;display:flex;overflow:hidden}.composition-legend-row dd{color:var(--text-primary);font-variant-numeric:tabular-nums;flex:none;align-items:baseline;gap:8px;font-size:12px;font-weight:600;line-height:18px;display:flex}.composition-legend-row dd span{min-width:30px;color:var(--text-muted);text-align:right;font-weight:500}.composition-swatch{border-radius:2px;flex:none;width:8px;height:8px}.skeleton{vertical-align:-.15em;background:linear-gradient(90deg, var(--raised) 0%, var(--text-primary) 50%, var(--raised) 100%) 0 0 / 200% 100%;border-radius:4px;min-width:24px;height:1em;display:inline-block}@supports (color:color-mix(in lab, red, red)){.skeleton{background:linear-gradient(90deg, var(--raised) 0%, color-mix(in srgb, var(--text-primary) 12%, var(--raised)) 50%, var(--raised) 100%) 0 0 / 200% 100%}}.skeleton{animation:1.5s ease-in-out infinite skeleton-wave}.composition-bar .skeleton{border-radius:2px;height:10px}.composition-swatch.skeleton{min-width:0;height:8px}@keyframes skeleton-wave{0%{background-position:150% 0}to{background-position:-50% 0}}@media (prefers-reduced-motion:reduce){.skeleton{background:var(--raised);animation:none}}.tab-note{color:var(--text-muted);padding:16px 20px;font-size:12px;line-height:18px}.token-split{border:1px solid var(--border-subtle);border-radius:8px;margin-bottom:16px;padding:10px 12px}.token-split>div{justify-content:space-between;align-items:baseline;gap:12px;display:flex}.token-split>div+div{margin-top:4px}.token-split dt{color:var(--text-secondary);font-size:12px;line-height:18px}.token-split dd{color:var(--text-primary);font-variant-numeric:tabular-nums;font-size:12px;font-weight:600;line-height:18px}.token-split p{color:var(--text-muted);margin-top:8px;font-size:11px;line-height:16px}.token-sub-row{color:var(--text-muted);flex:0 0 100%;justify-content:space-between;gap:12px;padding-left:16px;font-size:11px;line-height:16px;display:flex}.token-sub-row span{font-variant-numeric:tabular-nums}.token-insight{color:var(--text-secondary);margin-top:12px;font-size:12px;line-height:18px}.token-models{border-top:1px solid var(--border-subtle);margin-top:16px;padding-top:12px}.token-note{color:var(--text-muted);margin-top:12px;font-size:11px;line-height:16px}.timeline-stats{grid-template-columns:repeat(3,minmax(0,1fr));gap:16px;padding:16px 20px;display:grid}.timeline-stat{min-width:0}.timeline-stat .overview-value{color:var(--text-primary);margin-top:2px}.timeline-window-note{border-top:1px solid var(--border-subtle);color:var(--text-muted);padding:12px 20px 0;font-size:11px;font-weight:600;line-height:16px}.timeline-events .date-separator{z-index:1;color:var(--text-muted);background:var(--surface);padding-top:10px;padding-bottom:10px;font-size:11px;position:sticky;top:0}.pagination{border-top:1px solid var(--border-subtle);flex-wrap:wrap;justify-content:space-between;align-items:center;gap:12px;min-height:56px;padding:8px 16px;display:flex}.pagination>span{color:var(--text-muted);font-variant-numeric:tabular-nums;font-size:12px}.pagination strong{color:var(--text-secondary);font-weight:600}.page-button{border-radius:var(--radius-control);min-width:32px;height:32px;color:var(--text-muted);background:0 0;border:1px solid #0000;place-items:center;padding:0 8px;font-size:11px;display:grid}.page-button:hover:not(:disabled){border-color:var(--border-strong);color:var(--text-primary);background:var(--text-primary)}@supports (color:color-mix(in lab, red, red)){.page-button:hover:not(:disabled){background:color-mix(in srgb, var(--text-primary) 6%, transparent)}}.page-button[aria-current=page]{border-color:var(--focus-ring);color:var(--text-primary);background:var(--raised)}.page-button:disabled{opacity:.28}.empty-state{text-align:center;place-items:center;min-height:360px;padding:24px;display:grid}.empty-state-icon{border:1px solid var(--border-subtle);width:44px;height:44px;color:var(--text-muted);background:var(--text-primary);border-radius:.75rem;place-items:center;margin:0 auto;display:grid}@supports (color:color-mix(in lab, red, red)){.empty-state-icon{background:color-mix(in srgb, var(--text-primary) 4%, transparent)}}.empty-state h3{color:var(--text-secondary);margin-top:16px;font-size:14px;font-weight:650}.empty-state p{max-width:360px;color:var(--text-muted);margin:8px auto 0;font-size:12px;line-height:20px}.compatibility-popover{z-index:30;border:1px solid var(--border-strong);border-radius:var(--radius-surface);background:var(--raised);width:min(400px,100vw - 32px);box-shadow:0 24px 72px var(--canvas);padding:16px;position:absolute;top:calc(100% + 8px);right:0}@supports (color:color-mix(in lab, red, red)){.compatibility-popover{box-shadow:0 24px 72px color-mix(in srgb, var(--canvas) 72%, transparent)}}.compatibility-popover{animation:.15s ease-out raised-in}.popover-title{color:var(--text-primary);font-size:14px;font-weight:650}.popover-copy{color:var(--text-secondary);margin-top:4px;font-size:12px;line-height:20px}.version-list{border-top:1px solid var(--border-subtle);gap:8px;margin-top:16px;padding-top:16px;display:grid}.version-row{border:1px solid var(--border-subtle);border-radius:var(--radius-control);background:var(--surface);justify-content:space-between;align-items:center;gap:16px;padding:8px 12px;display:flex}.version-row p{color:var(--text-secondary);font-size:12px;font-weight:600}.version-row code{color:var(--text-muted);margin-top:2px;font-size:11px;display:block}.version-row>span{color:var(--text-muted);text-align:right;font-size:11px}.compatibility-note{color:var(--text-muted);margin-top:12px;font-size:12px;line-height:20px}.compatibility-details{color:var(--text-secondary);margin-top:12px;font-size:12px;line-height:20px}.compatibility-details li{gap:8px;display:flex}.semantic-dot{border-radius:999px;flex:none;width:4px;height:4px;margin-top:8px}.info-dot{background:var(--text-muted)}.warning-dot{background:var(--warning)}.success-icon{color:var(--success);flex:none;margin-top:2px}.alert{border:1px solid;border-radius:.75rem;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:12px;margin-bottom:20px;padding:12px;font-size:13px;animation:.15s ease-out raised-in;display:grid}.alert button{color:currentColor;opacity:.75;background:0 0;border:0;place-items:center;display:grid}.alert-success{border-color:var(--success)}@supports (color:color-mix(in lab, red, red)){.alert-success{border-color:color-mix(in srgb, var(--success) 28%, transparent)}}.alert-success{color:var(--success);background:var(--success)}@supports (color:color-mix(in lab, red, red)){.alert-success{background:color-mix(in srgb, var(--success) 8%, transparent)}}.alert-warning{border-color:var(--warning)}@supports (color:color-mix(in lab, red, red)){.alert-warning{border-color:color-mix(in srgb, var(--warning) 28%, transparent)}}.alert-warning{color:var(--warning);background:var(--warning)}@supports (color:color-mix(in lab, red, red)){.alert-warning{background:color-mix(in srgb, var(--warning) 8%, transparent)}}.alert-error{border-color:var(--danger-border);color:var(--danger-text);background:var(--danger)}@supports (color:color-mix(in lab, red, red)){.alert-error{background:color-mix(in srgb, var(--danger) 8%, transparent)}}.selection-tray{z-index:38;border:1px solid var(--border-strong);border-radius:var(--radius-surface);background:var(--raised);box-shadow:0 24px 80px var(--canvas);position:fixed;bottom:8px;left:8px;right:8px;overflow:hidden}@supports (color:color-mix(in lab, red, red)){.selection-tray{box-shadow:0 24px 80px color-mix(in srgb, var(--canvas) 76%, transparent)}}.selection-tray{animation:.15s ease-out selection-tray-in}.selection-tray-review{border-bottom:1px solid var(--border-subtle);background:var(--surface)}.selection-tray-review-heading{justify-content:space-between;align-items:center;gap:16px;padding:16px;display:flex}.selection-tray-review-heading>span{border:1px solid var(--border-strong);min-width:28px;height:28px;color:var(--text-secondary);background:var(--raised);font-variant-numeric:tabular-nums;border-radius:999px;place-items:center;font-size:11px;font-weight:650;display:grid}.selection-tray-heading{color:var(--text-primary);font-size:14px;font-weight:650}.selection-tray-copy{color:var(--text-muted);margin-top:4px;font-size:12px}.selection-tray-records{border-top:1px solid var(--border-subtle);max-height:min(272px,42vh);overflow-y:auto}.selection-tray-record{border-bottom:1px solid var(--border-subtle);contain-intrinsic-size:auto 60px;content-visibility:auto;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:12px;min-height:60px;padding:8px 12px 8px 16px;display:grid}.selection-tray-record:last-child{border-bottom:0}.selection-tray-title{color:var(--text-secondary);text-overflow:ellipsis;white-space:nowrap;font-size:13px;font-weight:600;line-height:16px;overflow:hidden}.selection-tray-meta{min-width:0;color:var(--text-muted);align-items:center;gap:4px;margin-top:4px;font-size:11px;display:flex}.selection-tray-bar{flex-direction:column;gap:12px;padding:12px;display:flex}.selection-tray-summary{min-width:0;color:var(--text-primary);font-variant-numeric:tabular-nums;font-size:13px;font-weight:650;line-height:20px}.selection-tray-count,.selection-tray-summary-value{display:inline-block}.selection-tray-actions{grid-template-columns:repeat(3,minmax(0,1fr));gap:8px;display:grid}.has-selection-tray{padding-bottom:144px;transition:padding-bottom .15s ease-out}.has-selection-tray-expanded{padding-bottom:432px}.dialog-backdrop{z-index:50;background:var(--canvas);place-items:center;display:grid;position:fixed;inset:0;overflow-y:auto}@supports (color:color-mix(in lab, red, red)){.dialog-backdrop{background:color-mix(in srgb, var(--canvas) 82%, transparent)}}.dialog-backdrop{-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);padding:16px;animation:.15s ease-out backdrop-in}.dialog-panel,.shortcut-panel{border:1px solid var(--border-strong);border-radius:var(--radius-surface);background:var(--raised);width:100%;max-height:calc(100vh - 32px);box-shadow:0 36px 104px var(--canvas);padding:24px;overflow-y:auto}@supports (color:color-mix(in lab, red, red)){.dialog-panel,.shortcut-panel{box-shadow:0 36px 104px color-mix(in srgb, var(--canvas) 78%, transparent)}}.dialog-panel,.shortcut-panel{animation:.15s ease-out raised-in}.dialog-panel{max-width:624px}.shortcut-panel{max-width:704px}.dialog-title{color:var(--text-primary);letter-spacing:-.015em;margin-top:8px;font-size:20px;font-weight:650;line-height:24px}.dialog-copy{color:var(--text-secondary);margin-top:8px;font-size:14px;line-height:20px}.shortcut-groups{gap:12px;margin-top:20px;display:grid}.shortcut-groups>section{border:1px solid var(--border-subtle);background:var(--surface);border-radius:.75rem;overflow:hidden}.shortcut-groups h3{border-bottom:1px solid var(--border-subtle);color:var(--text-secondary);padding:8px 12px;font-size:12px;font-weight:650}.shortcut-groups dl>div{border-bottom:1px solid var(--border-subtle);justify-content:space-between;align-items:center;gap:12px;min-height:44px;padding:8px 12px;display:flex}.shortcut-groups dl>div:last-child{border-bottom:0}.shortcut-groups dt{color:var(--text-secondary);font-size:12px;line-height:16px}.shortcut-groups dd{flex:none}.shortcut-groups kbd{border:1px solid var(--border-strong);color:var(--text-secondary);background:var(--raised);box-shadow:0 1px 2px var(--canvas);border-radius:.375rem;padding:4px 8px;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:11px;display:inline-block}@supports (color:color-mix(in lab, red, red)){.shortcut-groups kbd{box-shadow:0 1px 2px color-mix(in srgb, var(--canvas) 40%, transparent)}}.scope-card{border:1px solid var(--border-subtle);color:var(--text-secondary);background:var(--surface);text-align:left;border-radius:.75rem;padding:16px;transition:border-color .15s ease-out,background .15s ease-out}.scope-card:hover:not(:disabled){border-color:var(--border-strong);background:var(--surface)}@supports (color:color-mix(in lab, red, red)){.scope-card:hover:not(:disabled){background:color-mix(in srgb, var(--surface) 88%, var(--raised))}}.scope-card-active{border-color:var(--accent)}@supports (color:color-mix(in lab, red, red)){.scope-card-active{border-color:color-mix(in srgb, var(--accent) 52%, var(--border-strong))}}.scope-card-active{color:var(--text-primary);background:var(--accent-soft)}.scope-heading{justify-content:space-between;align-items:center;gap:8px;font-size:14px;font-weight:650;display:flex}.scope-check{border:1px solid var(--border-strong);border-radius:999px;place-items:center;width:20px;height:20px;display:grid}.scope-card-active .scope-check{border-color:var(--accent);color:var(--canvas);background:var(--accent)}.scope-card>p{color:var(--text-secondary);margin-top:8px;font-size:12px;line-height:20px}.metric{border:1px solid var(--border-subtle);background:var(--surface);border-radius:.75rem;padding:12px}.metric>p{min-height:32px;color:var(--text-muted);font-size:11px;font-weight:600;line-height:16px}.metric>strong{color:var(--text-primary);text-overflow:ellipsis;white-space:nowrap;font-variant-numeric:tabular-nums;margin-top:4px;font-size:14px;font-weight:650;display:block;overflow:hidden}.dialog-plan-region{min-height:76px;margin-top:20px;position:relative}.metric-skeleton{border-radius:.75rem;height:76px}.dialog-plan-loading{z-index:1;color:var(--text-secondary);background:var(--raised);border-radius:.75rem;justify-content:center;align-items:center;gap:8px;display:flex;position:absolute;inset:-1px}@supports (color:color-mix(in lab, red, red)){.dialog-plan-loading{background:color-mix(in srgb, var(--raised) 88%, transparent)}}.dialog-plan-loading{-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);font-size:12px;font-weight:650}.dialog-message,.dialog-confirmation{border:1px solid;border-radius:.75rem;margin-top:16px;padding:12px;font-size:13px;line-height:20px}.message-warning{border-color:var(--warning)}@supports (color:color-mix(in lab, red, red)){.message-warning{border-color:color-mix(in srgb, var(--warning) 24%, var(--border-subtle))}}.message-warning{color:var(--text-secondary);background:var(--warning)}@supports (color:color-mix(in lab, red, red)){.message-warning{background:color-mix(in srgb, var(--warning) 5%, transparent)}}.message-danger{border-color:var(--danger-border);color:var(--danger-text);background:var(--danger)}@supports (color:color-mix(in lab, red, red)){.message-danger{background:color-mix(in srgb, var(--danger) 8%, transparent)}}.dialog-note,.dialog-information{color:var(--text-secondary);align-items:flex-start;gap:8px;margin-top:12px;font-size:12px;line-height:20px;display:flex}.dialog-note>svg,.dialog-information>svg{color:var(--text-muted);flex:none;margin-top:2px}.close-session-note{border:1px solid var(--border-subtle);background:var(--surface);border-radius:.75rem;margin-top:20px;padding:12px}.close-session-note strong{color:var(--text-primary);font-weight:650}.operation-panel{border:1px solid var(--border-subtle);background:var(--surface);border-radius:.75rem;margin-top:20px;padding:16px}.operation-heading{color:var(--text-secondary);justify-content:space-between;align-items:center;gap:16px;font-size:14px;display:flex}.operation-heading>span:first-child{font-weight:600}.operation-heading>span:last-child{color:var(--text-muted);font-variant-numeric:tabular-nums}.progress-track{background:var(--border-subtle);border-radius:999px;height:6px;margin-top:12px;overflow:hidden}.progress-value{border-radius:999px;height:100%;transition:width .15s ease-out}.progress-success{background:var(--success)}.progress-warning{background:var(--warning)}.progress-danger{background:var(--danger)}.progress-info{background:var(--text-secondary)}.operation-error{background:0 0;border:0;margin-top:12px;padding:0;font-size:12px;line-height:20px}.restore-copy{color:var(--text-secondary);margin-top:12px;font-size:12px;line-height:20px}.restore-copy>div{margin-top:8px}.restore-copy>div>p{color:var(--text-muted)}.restore-copy code{overflow-wrap:anywhere;color:var(--text-muted);font-size:11px;display:block}.dialog-confirmation>p{color:var(--text-primary);font-size:14px;font-weight:650}.dialog-confirmation>span{margin-top:4px;display:block}.skeleton{background:linear-gradient(90deg, var(--text-primary), var(--text-primary), var(--text-primary))}@supports (color:color-mix(in lab, red, red)){.skeleton{background:linear-gradient(90deg, color-mix(in srgb, var(--text-primary) 4%, transparent), color-mix(in srgb, var(--text-primary) 9%, transparent), color-mix(in srgb, var(--text-primary) 4%, transparent))}}.skeleton{background-size:200% 100%;animation:1.5s ease-in-out infinite shimmer}@keyframes shimmer{0%{background-position:200% 0}to{background-position:-200% 0}}@keyframes selection-tray-in{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}@keyframes raised-in{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}@keyframes backdrop-in{0%{opacity:0}to{opacity:1}}@keyframes disclosure-in{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}@keyframes checkbox-check-in{0%{opacity:.72;transform:scale(.88)}to{opacity:1;transform:scale(1)}}@keyframes filter-chip-in{0%{opacity:0;transform:translateY(2px)}to{opacity:1;transform:translateY(0)}}@keyframes filter-chip-out{0%{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(-2px)}}@keyframes selection-value-in{0%{opacity:.7;transform:translateY(2px)}to{opacity:1;transform:translateY(0)}}@media (prefers-reduced-motion:no-preference){.selection-control input:checked,.session-checkbox input:checked{animation:.12s ease-out checkbox-check-in}.filter-chip{animation:.14s ease-out filter-chip-in}.filter-chip-exiting{animation:.12s ease-out forwards filter-chip-out}.selection-tray-count,.selection-tray-summary-value{animation:.12s ease-out selection-value-in}}@media (width<=1023px){.inspector-open{z-index:40;max-height:min(576px,100vh - 48px);box-shadow:0 28px 90px var(--canvas);display:block;position:fixed;bottom:12px;left:12px;right:12px;overflow-y:auto}@supports (color:color-mix(in lab, red, red)){.inspector-open{box-shadow:0 28px 90px color-mix(in srgb, var(--canvas) 76%, transparent)}}.inspector-backdrop-open{z-index:39;background:var(--canvas);border:0;width:100%;height:100%;display:block;position:fixed;inset:0}@supports (color:color-mix(in lab, red, red)){.inspector-backdrop-open{background:color-mix(in srgb, var(--canvas) 64%, transparent)}}.inspector-backdrop-open{-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}}@media (width>=640px){.session-list-header,.filter-bar,.more-filters-row,.active-filter-row,.unknown-activity-note,.page-selection-row,.pagination,.date-separator,.session-row{padding-left:20px;padding-right:20px}.shortcut-hint{display:block}.selection-tray{width:min(736px,100vw - 48px);bottom:20px;left:50%;right:auto;translate:-50%}.selection-tray-bar{flex-direction:row;align-items:center;padding:12px 12px 12px 16px}.selection-tray-summary{flex:auto}.selection-tray-actions{flex:none;display:flex}.session-row-chevron{display:block}}@media (width>=900px){.session-filters{--filter-grid:minmax(260px, 2fr) minmax(180px, 1fr) auto}.overview-strip{grid-template-columns:repeat(3,minmax(0,1fr))}.overview-item,.overview-item-primary{border-right:1px solid var(--border-subtle);border-bottom:0;grid-column:auto}.overview-item:nth-child(3n),.overview-strip>.overview-item:last-child{border-right:0}.shortcut-groups{grid-template-columns:repeat(3,minmax(0,1fr))}}@media (width>=1024px){.inspector{max-height:calc(100vh - 48px);display:block;position:sticky;top:24px;overflow-y:auto}}@media (width>=900px) and (width<=1179px){.filter-primary-controls .filter-priority-1,.filter-overflow-primary .filter-priority-2{display:none}}@media (width>=1180px){.session-filters{--filter-grid:minmax(220px, 1.5fr) repeat(2, minmax(180px, 1fr)) auto}.overview-strip{grid-template-columns:repeat(var(--overview-columns), minmax(0, 1fr))}.overview-item,.overview-item-primary{border-right:1px solid var(--border-subtle);border-bottom:0}.overview-item:nth-child(3n){border-right:1px solid var(--border-subtle)}.overview-strip>.overview-item:last-child{border-right:0}.filter-overflow-primary{display:none}}@media (width<=639px){.brand-title{font-size:20px;line-height:24px}.brand-mark{width:40px;height:40px}.surface{border-radius:.875rem}.provider-context{align-items:flex-start}.provider-context-main{gap:4px;width:100%;display:grid}.provider-context code{width:100%}.date-separator{padding-left:12px;padding-right:12px}.session-row{grid-template-columns:28px minmax(0,1fr) auto;gap:4px;padding-left:12px;padding-right:12px}.session-row-chevron{display:none}.session-row-meta{gap:2px}.time-badge,.kind-label,.size-badge{padding-left:4px;padding-right:4px}.time-badge svg,.kind-label svg,.size-badge svg{display:none}.compatibility-popover{width:auto;position:fixed;top:72px;left:16px;right:16px}.dialog-backdrop{align-items:end;padding:0}.dialog-panel,.shortcut-panel{border-radius:var(--radius-surface) var(--radius-surface) 0 0;border-bottom:0;border-left:0;border-right:0;max-height:92vh;padding:20px}}@media (width<=899px){.filter-primary-controls{display:none}}@media (width<=519px){.more-filters-button>span{display:none}.filter-bar{gap:8px}.sort-control>span,.shortcut-hint{display:none}}@media (prefers-reduced-motion:reduce){.active-filter-row-clearing,.filter-chip-exiting{display:none!important}*,:before,:after{scroll-behavior:auto!important;transition:none!important;animation:none!important}}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@keyframes spin{to{transform:rotate(360deg)}}
|
package/dist/index.html
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width,initial-scale=1.0"/>
|
|
6
6
|
<link href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' rx='8' fill='%23171717'/%3E%3Cpath d='M16 4 26 8v7c0 6-4 11-10 13C10 26 6 21 6 15V8Z' fill='%23f5f5f5'/%3E%3Cpath d='m9.5 16 2.2-2.2 3 3 6.5-6.5 2.2 2.2-8.7 8.7Z' fill='%23171717'/%3E%3C/svg%3E" rel="icon"/>
|
|
7
7
|
<title>Session Steward</title>
|
|
8
|
-
<script type="module" crossorigin src="/assets/index-
|
|
9
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
8
|
+
<script type="module" crossorigin src="/assets/index-C94A1O5c.js"></script>
|
|
9
|
+
<link rel="stylesheet" crossorigin href="/assets/index-CXq8Tw8T.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
|
12
12
|
<div id="root"></div>
|
package/lib/cli.mjs
CHANGED
|
@@ -35,6 +35,7 @@ Commands
|
|
|
35
35
|
sort <updated|created|name|cwd|size>
|
|
36
36
|
Change sort order
|
|
37
37
|
inspect <index|id-prefix> Show session details
|
|
38
|
+
tokens Toggle token usage in session details
|
|
38
39
|
delete <selector> [...] Delete one or more sessions
|
|
39
40
|
page <number> Jump to a page
|
|
40
41
|
next Next page
|
|
@@ -78,6 +79,7 @@ Options
|
|
|
78
79
|
Choose the session order
|
|
79
80
|
--events Include the distilled session timeline
|
|
80
81
|
--events-limit <number> Limit timeline events (default 100)
|
|
82
|
+
--tokens Include token usage per session
|
|
81
83
|
--limit <number> Limit JSON results
|
|
82
84
|
-h, --help Show this help
|
|
83
85
|
`.trim();
|
|
@@ -205,7 +207,7 @@ function getMarkerText(record) {
|
|
|
205
207
|
return markers.join(", ");
|
|
206
208
|
}
|
|
207
209
|
|
|
208
|
-
function printScreen({ archiveStatus, cleanupMode, inactiveDays, providerHome, providerName, result, search, showInternals, showSupporting, sort, workspace }) {
|
|
210
|
+
function printScreen({ archiveStatus, cleanupMode, inactiveDays, providerHome, providerName, result, search, showInternals, showSupporting, showTokens, sort, workspace }) {
|
|
209
211
|
if (output.isTTY) {
|
|
210
212
|
output.write("\x1Bc");
|
|
211
213
|
}
|
|
@@ -218,7 +220,7 @@ function printScreen({ archiveStatus, cleanupMode, inactiveDays, providerHome, p
|
|
|
218
220
|
`Sort: ${sort} | Search: ${search || "-"} | Cleanup: ${cleanupLabel(cleanupScope(cleanupMode))}\n`,
|
|
219
221
|
);
|
|
220
222
|
output.write(
|
|
221
|
-
`Subagents: ${showInternals ? "shown" : "hidden"} | Supporting: ${showSupporting ? "shown" : "hidden"}\n`,
|
|
223
|
+
`Subagents: ${showInternals ? "shown" : "hidden"} | Supporting: ${showSupporting ? "shown" : "hidden"} | Tokens: ${showTokens ? "shown" : "hidden"}\n`,
|
|
222
224
|
);
|
|
223
225
|
output.write(
|
|
224
226
|
`Last active: ${inactiveDays ? `${inactiveDays}+ days ago` : "any time"} | Workspace: ${workspace || "all"} | Status: ${archiveStatus}\n`,
|
|
@@ -434,6 +436,80 @@ function printSessionEventSummary(summary) {
|
|
|
434
436
|
].join(" · ")}\n`);
|
|
435
437
|
}
|
|
436
438
|
|
|
439
|
+
// Counts run to the hundreds of millions, where digit groups stop being
|
|
440
|
+
// readable. The exact figure stays available in --json.
|
|
441
|
+
function formatTokens(tokens) {
|
|
442
|
+
if (!Number.isFinite(tokens) || tokens < 0) return "-";
|
|
443
|
+
if (tokens < 1000) return String(tokens);
|
|
444
|
+
|
|
445
|
+
const units = [["B", 1e9], ["M", 1e6], ["K", 1e3]];
|
|
446
|
+
const [suffix, size] = units.find(([, value]) => tokens >= value);
|
|
447
|
+
const scaled = tokens / size;
|
|
448
|
+
|
|
449
|
+
return `${scaled >= 100 ? Math.round(scaled) : scaled.toFixed(scaled >= 10 ? 1 : 2)}${suffix}`;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
function formatPercent(share) {
|
|
453
|
+
const percent = share * 100;
|
|
454
|
+
if (percent > 0 && percent < 1) return "<1%";
|
|
455
|
+
return `${Math.round(percent)}%`;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
const TOKEN_UNAVAILABLE = {
|
|
459
|
+
"no-transcript-path": "No transcript location recorded, so tokens cannot be counted.",
|
|
460
|
+
"transcript-missing": "The transcript is no longer on disk, so tokens cannot be counted.",
|
|
461
|
+
};
|
|
462
|
+
|
|
463
|
+
const TOKEN_NOTES = {
|
|
464
|
+
"cache-write-underflow": "Cache-write reporting looked inconsistent, so fresh input is approximate.",
|
|
465
|
+
"fork-parent-missing": "Forked from a session that is no longer on disk, so inherited tokens cannot be separated out.",
|
|
466
|
+
"incomplete-scan": "The transcript could not be read all the way through, so this is a partial count.",
|
|
467
|
+
};
|
|
468
|
+
|
|
469
|
+
function printSessionTokens(tokens) {
|
|
470
|
+
output.write("\nToken usage\n");
|
|
471
|
+
output.write("-----------\n");
|
|
472
|
+
|
|
473
|
+
if (!tokens?.available) {
|
|
474
|
+
output.write(`${TOKEN_UNAVAILABLE[tokens?.reason] ?? "No token usage recorded for this session."}\n`);
|
|
475
|
+
return;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
const segment = (key) => tokens.segments.find((entry) => entry.key === key);
|
|
479
|
+
// A fork's rollout replays its parent's turns, so the two halves are named
|
|
480
|
+
// before the breakdown, which covers own work only.
|
|
481
|
+
if (tokens.inherited) {
|
|
482
|
+
output.write(`Own work: ${formatTokens(tokens.total)}\n`);
|
|
483
|
+
output.write(`Inherited from parent: ${formatTokens(tokens.inherited.tokens)} across ${tokens.inherited.turns.toLocaleString()} ${tokens.inherited.turns === 1 ? "turn" : "turns"}\n`);
|
|
484
|
+
} else {
|
|
485
|
+
output.write(`Total: ${formatTokens(tokens.total)}\n`);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
for (const key of ["freshInput", "cachedInput", "cacheWrites", "output"]) {
|
|
489
|
+
const label = { cachedInput: "Cached input", cacheWrites: "Cache writes", freshInput: "Fresh input", output: "Output" }[key];
|
|
490
|
+
const entry = segment(key);
|
|
491
|
+
output.write(`${label}: ${formatTokens(entry.tokens)} (${formatPercent(entry.share)})\n`);
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
// Reasoning is part of output, so it is stated against output rather than as
|
|
495
|
+
// a line of its own in the breakdown.
|
|
496
|
+
if (tokens.reasoning) {
|
|
497
|
+
output.write(`Reasoning: ${formatTokens(tokens.reasoning.tokens)} (${formatPercent(tokens.reasoning.share)} of output)\n`);
|
|
498
|
+
}
|
|
499
|
+
if (tokens.cacheHitRate !== null) {
|
|
500
|
+
output.write(`Cache hits: ${formatPercent(tokens.cacheHitRate)} of input\n`);
|
|
501
|
+
}
|
|
502
|
+
if (tokens.byModel.length > 0) {
|
|
503
|
+
output.write(`Models: ${tokens.byModel.map(({ model, share }) => `${model} ${formatPercent(share)}`).join(" · ")}\n`);
|
|
504
|
+
}
|
|
505
|
+
if (tokens.compactions > 0) {
|
|
506
|
+
output.write(`Compactions: ${tokens.compactions.toLocaleString()} (each one re-sends the conversation, so the totals include that cost)\n`);
|
|
507
|
+
}
|
|
508
|
+
for (const warning of tokens.warnings) {
|
|
509
|
+
errorOutput.write(`${TOKEN_NOTES[warning] ?? warning}\n`);
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
|
|
437
513
|
function printSessionEvents(result) {
|
|
438
514
|
output.write("\nSession timeline\n");
|
|
439
515
|
output.write("----------------\n");
|
|
@@ -676,6 +752,15 @@ async function printJson(options) {
|
|
|
676
752
|
: {}),
|
|
677
753
|
};
|
|
678
754
|
}
|
|
755
|
+
if (options.tokens) {
|
|
756
|
+
serializedRecord = {
|
|
757
|
+
...serializedRecord,
|
|
758
|
+
tokens: await options.provider.readSessionTokens({
|
|
759
|
+
...providerOptions(options.provider.id, options.providerHome),
|
|
760
|
+
id: record.id,
|
|
761
|
+
}),
|
|
762
|
+
};
|
|
763
|
+
}
|
|
679
764
|
await writeChunk(`${first ? "" : ",\n"}${JSON.stringify(serializedRecord, null, 2)}`);
|
|
680
765
|
first = false;
|
|
681
766
|
written += 1;
|
|
@@ -707,6 +792,7 @@ async function runInteractive(state) {
|
|
|
707
792
|
search: state.search,
|
|
708
793
|
showInternals: state.showInternals,
|
|
709
794
|
showSupporting: state.showSupporting,
|
|
795
|
+
showTokens: state.showTokens,
|
|
710
796
|
sort: state.sort,
|
|
711
797
|
workspace: state.workspace,
|
|
712
798
|
});
|
|
@@ -746,6 +832,13 @@ async function runInteractive(state) {
|
|
|
746
832
|
continue;
|
|
747
833
|
}
|
|
748
834
|
|
|
835
|
+
if (command.name === "tokens") {
|
|
836
|
+
state.showTokens = !state.showTokens;
|
|
837
|
+
output.write(`\nToken usage in session details is ${state.showTokens ? "on" : "off"}.\n`);
|
|
838
|
+
await pause(rl);
|
|
839
|
+
continue;
|
|
840
|
+
}
|
|
841
|
+
|
|
749
842
|
if (command.name === "cleanup") {
|
|
750
843
|
try {
|
|
751
844
|
state.cleanupMode = validateCleanupMode(command.args[0]);
|
|
@@ -936,6 +1029,12 @@ async function runInteractive(state) {
|
|
|
936
1029
|
});
|
|
937
1030
|
|
|
938
1031
|
printInspect(record, deletionPlan);
|
|
1032
|
+
if (state.showTokens) {
|
|
1033
|
+
printSessionTokens(await state.provider.readSessionTokens({
|
|
1034
|
+
...providerOptions(state.provider.id, state.providerHome),
|
|
1035
|
+
id: record.id,
|
|
1036
|
+
}));
|
|
1037
|
+
}
|
|
939
1038
|
if (state.showEvents) {
|
|
940
1039
|
const eventResult = await state.provider.readSessionEvents({
|
|
941
1040
|
...providerOptions(state.provider.id, state.providerHome),
|
|
@@ -1127,6 +1226,7 @@ export async function runCli(options) {
|
|
|
1127
1226
|
search: options.search || "",
|
|
1128
1227
|
showInternals: Boolean(options.includeInternals),
|
|
1129
1228
|
showEvents: Boolean(options.events),
|
|
1229
|
+
showTokens: Boolean(options.tokens),
|
|
1130
1230
|
showSupporting: Boolean(options.includeSupporting),
|
|
1131
1231
|
sort: validateSort(options.sort || "updated"),
|
|
1132
1232
|
workspace: options.workspace,
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
createSessionEventsResult,
|
|
8
8
|
finalizeSessionEventComposition,
|
|
9
9
|
SESSION_EVENT_KIND,
|
|
10
|
+
SESSION_EVENT_READ_MODE,
|
|
10
11
|
SESSION_EVENT_REASON,
|
|
11
12
|
} from "../../session-events.mjs";
|
|
12
13
|
import {
|
|
@@ -16,6 +17,7 @@ import {
|
|
|
16
17
|
} from "../../session-event-reader.mjs";
|
|
17
18
|
import { visitJsonlSnapshotEntries } from "../../storage/jsonl.mjs";
|
|
18
19
|
import { getSessionRecord } from "./store.mjs";
|
|
20
|
+
import { createSessionTokenScan } from "./tokens.mjs";
|
|
19
21
|
|
|
20
22
|
const MAX_PENDING_DECISIONS = 2_048;
|
|
21
23
|
const PROVIDER_ID = "claude-code";
|
|
@@ -100,12 +102,15 @@ function contentText(value) {
|
|
|
100
102
|
return "";
|
|
101
103
|
}
|
|
102
104
|
|
|
103
|
-
function emptyResult({ cwd = null, origin = null, reason }) {
|
|
105
|
+
function emptyResult({ counted = false, cwd = null, origin = null, reason }) {
|
|
104
106
|
return createSessionEventsResult({
|
|
105
107
|
coverage: createSessionEventCoverage(),
|
|
106
108
|
events: [],
|
|
107
109
|
header: createSessionEventHeader({ cwd, origin, provider: PROVIDER_ID }),
|
|
108
110
|
reason,
|
|
111
|
+
// The reason the timeline is empty is the same reason there is no count:
|
|
112
|
+
// no transcript to read. Saying so beats leaving the field to guess.
|
|
113
|
+
tokens: counted ? { available: false, reason } : null,
|
|
109
114
|
window: {
|
|
110
115
|
complete: true,
|
|
111
116
|
end: null,
|
|
@@ -151,6 +156,7 @@ export async function readSessionEvents({
|
|
|
151
156
|
maxLineBytes,
|
|
152
157
|
mode,
|
|
153
158
|
signal,
|
|
159
|
+
tokens = false,
|
|
154
160
|
}) {
|
|
155
161
|
const record = await getSessionRecord({ claudeHome, desktopDataHome, id });
|
|
156
162
|
if (!record) return null;
|
|
@@ -158,12 +164,19 @@ export async function readSessionEvents({
|
|
|
158
164
|
const origin = record.surface ?? record.recordSource ?? null;
|
|
159
165
|
if (!record.rolloutPath) {
|
|
160
166
|
return emptyResult({
|
|
167
|
+
counted: tokens,
|
|
161
168
|
cwd: record.cwd || null,
|
|
162
169
|
origin,
|
|
163
170
|
reason: SESSION_EVENT_REASON.NO_TRANSCRIPT_PATH,
|
|
164
171
|
});
|
|
165
172
|
}
|
|
166
173
|
|
|
174
|
+
// A preview stops as soon as it has enough events, so a count taken from it
|
|
175
|
+
// would be of part of the file while reading as the whole.
|
|
176
|
+
const tokenScan = tokens && mode !== SESSION_EVENT_READ_MODE.PREVIEW
|
|
177
|
+
? await createSessionTokenScan({ record, signal })
|
|
178
|
+
: null;
|
|
179
|
+
|
|
167
180
|
const coverage = createSessionEventCoverage();
|
|
168
181
|
const summary = createSessionEventSummary();
|
|
169
182
|
const composition = createSessionEventComposition();
|
|
@@ -510,6 +523,7 @@ export async function readSessionEvents({
|
|
|
510
523
|
}
|
|
511
524
|
|
|
512
525
|
composition[compositionSegment(entry.parsed)] += entry.bytes;
|
|
526
|
+
tokenScan?.record(entry.parsed);
|
|
513
527
|
const result = handleRecord(entry.parsed, entry.index);
|
|
514
528
|
coverage[result.classification] += 1;
|
|
515
529
|
if (result.classification === RECORD_CLASSIFICATION.UNMAPPED) {
|
|
@@ -522,6 +536,7 @@ export async function readSessionEvents({
|
|
|
522
536
|
} catch (error) {
|
|
523
537
|
if (error?.code === "ENOENT") {
|
|
524
538
|
return emptyResult({
|
|
539
|
+
counted: tokens,
|
|
525
540
|
cwd: record.cwd || null,
|
|
526
541
|
origin,
|
|
527
542
|
reason: SESSION_EVENT_REASON.TRANSCRIPT_MISSING,
|
|
@@ -542,6 +557,7 @@ export async function readSessionEvents({
|
|
|
542
557
|
: null,
|
|
543
558
|
composition: finalizeSessionEventComposition(composition, read.snapshotBytes),
|
|
544
559
|
summary,
|
|
560
|
+
tokens: tokenScan ? tokenScan.summarize(read) : null,
|
|
545
561
|
window: readState.window(read),
|
|
546
562
|
});
|
|
547
563
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { readSessionEvents } from "./events.mjs";
|
|
2
|
+
import { readSessionTokens } from "./tokens.mjs";
|
|
2
3
|
import * as store from "./store.mjs";
|
|
3
4
|
|
|
4
5
|
export const claudeCodeProvider = Object.freeze({
|
|
@@ -6,4 +7,5 @@ export const claudeCodeProvider = Object.freeze({
|
|
|
6
7
|
displayName: "Claude Code",
|
|
7
8
|
...store,
|
|
8
9
|
readSessionEvents,
|
|
10
|
+
readSessionTokens,
|
|
9
11
|
});
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { addTokenTotals, createTokenTotals, summarizeSessionTokens } from "../../session-tokens.mjs";
|
|
2
|
+
import { readCachedTokens, readFileStamp, writeCachedTokens } from "../../session-token-cache.mjs";
|
|
3
|
+
import { visitJsonlSnapshotEntries } from "../../storage/jsonl.mjs";
|
|
4
|
+
import { getSessionRecord } from "./store.mjs";
|
|
5
|
+
|
|
6
|
+
const SYNTHETIC_MODEL = "<synthetic>";
|
|
7
|
+
|
|
8
|
+
// Claude Code reports usage per request rather than as a running total, so there
|
|
9
|
+
// is no counter to reconcile. The catch is the opposite one: a single response is
|
|
10
|
+
// written as several records, one per content block, and every copy repeats the
|
|
11
|
+
// same usage in full. Summing records instead of requests inflates a session by
|
|
12
|
+
// roughly 2.3x.
|
|
13
|
+
function readCount(value) {
|
|
14
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.trunc(value) : 0;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Anthropic reports cached tokens *beside* the input count, where Codex reports
|
|
18
|
+
// them inside it. `input_tokens` is already the uncached remainder, so nothing is
|
|
19
|
+
// subtracted here — doing so is what would drive the fresh-input slice negative.
|
|
20
|
+
function normalizeUsage(value) {
|
|
21
|
+
if (!value || typeof value !== "object") return null;
|
|
22
|
+
|
|
23
|
+
const cachedInput = readCount(value.cache_read_input_tokens);
|
|
24
|
+
const cacheWrites = readCount(value.cache_creation_input_tokens);
|
|
25
|
+
const freshInput = readCount(value.input_tokens);
|
|
26
|
+
const output = readCount(value.output_tokens);
|
|
27
|
+
|
|
28
|
+
return {
|
|
29
|
+
cachedInput,
|
|
30
|
+
cacheWrites,
|
|
31
|
+
freshInput,
|
|
32
|
+
output,
|
|
33
|
+
// Claude Code does not report a reasoning figure; thinking is billed as
|
|
34
|
+
// ordinary output and cannot be separated from it.
|
|
35
|
+
reasoning: 0,
|
|
36
|
+
total: cachedInput + cacheWrites + freshInput + output,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function createClaudeTokenCollector() {
|
|
41
|
+
// One entry per request, not per record. Repeats collapse onto the largest
|
|
42
|
+
// copy: a retried or superseded write reports zeros, and a streaming partial
|
|
43
|
+
// reports less than the finished response.
|
|
44
|
+
const requests = new Map();
|
|
45
|
+
let compactions = 0;
|
|
46
|
+
let observedRecords = 0;
|
|
47
|
+
let sessionId = null;
|
|
48
|
+
let sidechainRequests = 0;
|
|
49
|
+
let syntheticRecords = 0;
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
record(recordValue) {
|
|
53
|
+
if (!recordValue || typeof recordValue !== "object") return;
|
|
54
|
+
|
|
55
|
+
if (recordValue.subtype === "compact_boundary") compactions += 1;
|
|
56
|
+
if (sessionId === null && typeof recordValue.sessionId === "string") {
|
|
57
|
+
sessionId = recordValue.sessionId;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const message = recordValue.message;
|
|
61
|
+
if (!message || typeof message !== "object") return;
|
|
62
|
+
|
|
63
|
+
const usage = normalizeUsage(message.usage);
|
|
64
|
+
if (!usage) return;
|
|
65
|
+
observedRecords += 1;
|
|
66
|
+
|
|
67
|
+
// Synthetic entries stand in for locally generated messages. They carry no
|
|
68
|
+
// usage and no request id, and would otherwise open a model row of zeros.
|
|
69
|
+
if (message.model === SYNTHETIC_MODEL) {
|
|
70
|
+
syntheticRecords += 1;
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const key = recordValue.requestId ?? message.id;
|
|
75
|
+
if (typeof key !== "string") return;
|
|
76
|
+
|
|
77
|
+
const previous = requests.get(key);
|
|
78
|
+
if (previous && previous.usage.total >= usage.total) return;
|
|
79
|
+
if (!previous && recordValue.isSidechain) sidechainRequests += 1;
|
|
80
|
+
|
|
81
|
+
requests.set(key, { model: message.model ?? "Unknown", sidechain: Boolean(recordValue.isSidechain), usage });
|
|
82
|
+
},
|
|
83
|
+
|
|
84
|
+
result() {
|
|
85
|
+
const totals = createTokenTotals();
|
|
86
|
+
const modelTotals = new Map();
|
|
87
|
+
|
|
88
|
+
for (const { model, usage } of requests.values()) {
|
|
89
|
+
addTokenTotals(totals, usage);
|
|
90
|
+
if (!modelTotals.has(model)) modelTotals.set(model, createTokenTotals());
|
|
91
|
+
addTokenTotals(modelTotals.get(model), usage);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return {
|
|
95
|
+
available: requests.size > 0,
|
|
96
|
+
byModel: [...modelTotals]
|
|
97
|
+
.map(([model, modelSpend]) => ({ model, totals: modelSpend }))
|
|
98
|
+
.sort((left, right) => right.totals.total - left.totals.total),
|
|
99
|
+
cacheWriteUnderflow: false,
|
|
100
|
+
compactions,
|
|
101
|
+
countedRequests: requests.size,
|
|
102
|
+
observedRecords,
|
|
103
|
+
sessionId,
|
|
104
|
+
sidechainRequests,
|
|
105
|
+
syntheticRecords,
|
|
106
|
+
totals,
|
|
107
|
+
};
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export async function collectClaudeSessionTokens(filePath, { maxLineBytes, signal } = {}) {
|
|
113
|
+
const collector = createClaudeTokenCollector();
|
|
114
|
+
const { complete, snapshotBytes } = await visitJsonlSnapshotEntries(
|
|
115
|
+
filePath,
|
|
116
|
+
({ parsed }) => {
|
|
117
|
+
// A closed panel should not leave a large transcript being scanned.
|
|
118
|
+
if (signal?.aborted) return false;
|
|
119
|
+
if (parsed && typeof parsed === "object") collector.record(parsed);
|
|
120
|
+
return true;
|
|
121
|
+
},
|
|
122
|
+
maxLineBytes === undefined ? {} : { maxLineBytes },
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
return { ...collector.result(), complete, snapshotBytes };
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Reading the timeline already streams every record of the same file, so the
|
|
129
|
+
// count rides along with that pass instead of paying for a second one.
|
|
130
|
+
export async function createSessionTokenScan({ record, signal }) {
|
|
131
|
+
if (!record?.rolloutPath) return null;
|
|
132
|
+
const stamp = await readFileStamp(record.rolloutPath);
|
|
133
|
+
const cached = readCachedTokens("summary", record.rolloutPath, stamp);
|
|
134
|
+
if (cached !== undefined) return { cached, record() {}, summarize: () => cached };
|
|
135
|
+
|
|
136
|
+
const collector = createClaudeTokenCollector();
|
|
137
|
+
|
|
138
|
+
return {
|
|
139
|
+
cached: null,
|
|
140
|
+
record(value) {
|
|
141
|
+
collector.record(value);
|
|
142
|
+
},
|
|
143
|
+
summarize({ complete }) {
|
|
144
|
+
const summary = summarizeSessionTokens({ ...collector.result(), complete });
|
|
145
|
+
if (signal?.aborted || complete === false) return summary;
|
|
146
|
+
return writeCachedTokens("summary", record.rolloutPath, stamp, summary);
|
|
147
|
+
},
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export async function readSessionTokens({ claudeHome, desktopDataHome, id, maxLineBytes, signal }) {
|
|
152
|
+
const record = await getSessionRecord({ claudeHome, desktopDataHome, id });
|
|
153
|
+
if (!record) return null;
|
|
154
|
+
if (!record.rolloutPath) return { available: false, reason: "no-transcript-path" };
|
|
155
|
+
|
|
156
|
+
const stamp = await readFileStamp(record.rolloutPath);
|
|
157
|
+
const cached = readCachedTokens("summary", record.rolloutPath, stamp);
|
|
158
|
+
if (cached !== undefined) return cached;
|
|
159
|
+
|
|
160
|
+
let collected;
|
|
161
|
+
try {
|
|
162
|
+
collected = await collectClaudeSessionTokens(record.rolloutPath, { maxLineBytes, signal });
|
|
163
|
+
} catch (error) {
|
|
164
|
+
// A transcript can be deleted between the listing and the read. That is an
|
|
165
|
+
// answer about the session, not a failure of the server, and the timeline
|
|
166
|
+
// reader already treats it as one.
|
|
167
|
+
if (error?.code === "ENOENT") return { available: false, reason: "transcript-missing" };
|
|
168
|
+
throw error;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const summary = summarizeSessionTokens(collected);
|
|
172
|
+
if (signal?.aborted || collected.complete === false) return summary;
|
|
173
|
+
return writeCachedTokens("summary", record.rolloutPath, stamp, summary);
|
|
174
|
+
}
|