~bigbes/lethe

ref: 934cfa2872e9be876dbfc2e8b087a0759588d1c2 lethe/docs/design_handoff_assistant_log/proto-data.jsx -rw-r--r-- 11.1 KiB
934cfa28 — Eugene Blikh oidcstub: implement /authorize + /token auth-code+PKCE; inject window.__LETHE_CONFIG__ into SPA a month ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// Mock data for the prototype

const TOOLS = ['claude-code', 'opencode', 'crush', 'pi', 'kimi'];
const HOSTS = ['laptop', 'workpc'];

// Authenticated identity. Server derives `owner` from this on every ingest;
// the wire format has no `owner` field. Admins can switch with ?owner=
const ME = { user: 'bigbes', isAdmin: true, via: 'forward-auth' };

// Other owners (visible only when current user is admin and ?owner=* is set)
const OWNERS = [
  { user: 'bigbes', sessions: 121, ktok: 482, last: 'Today 14:22', via: 'forward-auth' },
  { user: 'rin',    sessions:  34, ktok:  61, last: 'Today 09:51', via: 'oidc-bearer' },
  { user: 'noor',   sessions:  18, ktok:  22, last: 'Apr 23 18:14', via: 'oidc-bearer' },
];
const TOOL_COLORS = {
  'claude-code': '#c96442',
  'opencode':    '#3b6e3b',
  'crush':       '#7a4ea8',
  'pi':          '#b8902a',
  'kimi':        '#2a6e9c',
};

const SESSIONS = [
  { id: 'a1',  tool: 'claude-code', host: 'laptop', cwd: '~/code/tt-bundle',          q: 'lockfile design for the tt bundle — should we hash inputs or outputs?',           turns: 84, tok: '12.4k', when: 'Today 14:22', day: 0,  model: 'claude-opus-4-7' },
  { id: 'a2',  tool: 'opencode',    host: 'workpc', cwd: '~/work/atelier/migrations', q: 'why does the v3 migration drop the partial index on (org, ts)',                  turns: 12, tok: '2.1k',  when: 'Today 11:08', day: 0,  model: 'gpt-5-mini' },
  { id: 'a3',  tool: 'claude-code', host: 'workpc', cwd: '~/work/scarlet-svc',        q: 'is there a way to make this retry loop tolerate 429s without a sleep',           turns: 41, tok: '7.7k',  when: 'Today 10:52', day: 0,  model: 'claude-opus-4-7' },
  { id: 'a4',  tool: 'crush',       host: 'laptop', cwd: '~/code/dotfiles',           q: 'rewrite this zsh prompt to show ssh host only when on a remote',                  turns: 6,  tok: '0.9k',  when: 'Today 09:14', day: 0,  model: 'gemini-2-flash' },
  { id: 'a5',  tool: 'pi',          host: 'laptop', cwd: '~/notes',                   q: 'help me draft a one-pager for the offsite session on incident response',          turns: 19, tok: '4.0k',  when: 'Yest. 22:01', day: 1,  model: 'inflection-3' },
  { id: 'a6',  tool: 'claude-code', host: 'laptop', cwd: '~/code/tt-bundle',          q: 'when do we need to re-resolve transitive deps after a lock bump',                 turns: 28, tok: '5.3k',  when: 'Yest. 18:40', day: 1,  model: 'claude-opus-4-7' },
  { id: 'a7',  tool: 'kimi',        host: 'workpc', cwd: '~/work/atelier',            q: 'translate these comments to english but keep the tone',                           turns: 4,  tok: '0.7k',  when: 'Yest. 15:12', day: 1,  model: 'kimi-k2' },
  { id: 'a8',  tool: 'claude-code', host: 'workpc', cwd: '~/work/scarlet-svc',        q: 'add a structured logging adapter for the worker pool',                            turns: 22, tok: '4.8k',  when: 'Yest. 11:30', day: 1,  model: 'claude-opus-4-7' },
  { id: 'a9',  tool: 'opencode',    host: 'workpc', cwd: '~/work/atelier/migrations', q: 'rollback strategy for v3 if we hit prod with the wrong index',                    turns: 8,  tok: '1.4k',  when: 'Apr 23 16:42', day: 2,  model: 'gpt-5-mini' },
  { id: 'a10', tool: 'claude-code', host: 'laptop', cwd: '~/code/tt-bundle',          q: 'sketch a content-addressed cache for the build outputs',                          turns: 51, tok: '9.1k',  when: 'Apr 23 09:18', day: 2,  model: 'claude-opus-4-7' },
  { id: 'a11', tool: 'pi',          host: 'laptop', cwd: '~/notes',                   q: 'expand my standup notes into a proper status email',                              turns: 3,  tok: '0.5k',  when: 'Apr 22 19:00', day: 3,  model: 'inflection-3' },
  { id: 'a12', tool: 'crush',       host: 'laptop', cwd: '~/code/dotfiles',           q: 'fix this nvim mapping that breaks in tmux',                                       turns: 4,  tok: '0.6k',  when: 'Apr 22 13:22', day: 3,  model: 'gemini-2-flash' },
  { id: 'a13', tool: 'claude-code', host: 'workpc', cwd: '~/work/scarlet-svc',        q: 'redo the connection pool to support graceful drain',                              turns: 38, tok: '6.9k',  when: 'Apr 21 14:00', day: 4,  model: 'claude-opus-4-7' },
  { id: 'a14', tool: 'claude-code', host: 'laptop', cwd: '~/code/tt-bundle',          q: 'why does build.zig double-resolve when I touch only README',                      turns: 17, tok: '3.4k',  when: 'Apr 21 10:11', day: 4,  model: 'claude-opus-4-7' },
  { id: 'a15', tool: 'opencode',    host: 'workpc', cwd: '~/work/atelier',            q: 'is there a cleaner way to express this state machine',                            turns: 11, tok: '1.8k',  when: 'Apr 20 17:42', day: 5,  model: 'gpt-5-mini' },
];

// Project rollups
const PROJECTS = [
  { cwd: '~/code/tt-bundle',          sessions: 41, tok: '213k', last: 'Today 14:22', topTool: 'claude-code', tok30: 213 },
  { cwd: '~/work/scarlet-svc',        sessions: 28, tok: '142k', last: 'Today 10:52', topTool: 'claude-code', tok30: 142 },
  { cwd: '~/work/atelier/migrations', sessions: 14, tok: '38k',  last: 'Today 11:08', topTool: 'opencode',    tok30: 38 },
  { cwd: '~/code/dotfiles',           sessions: 7,  tok: '4.1k', last: 'Today 09:14', topTool: 'crush',       tok30: 4.1 },
  { cwd: '~/notes',                   sessions: 5,  tok: '11k',  last: 'Yest 22:01',  topTool: 'pi',          tok30: 11 },
  { cwd: '~/work/atelier',            sessions: 4,  tok: '2.0k', last: 'Yest 15:12',  topTool: 'kimi',        tok30: 2.0 },
];

// Per-tool rollups (30d)
const TOOL_ROLLUPS = [
  { tool: 'claude-code', turns: 1820, ktok: 482, cost: 0,     share: 0.92 },
  { tool: 'opencode',    turns: 211,  ktok: 18,  cost: 4.12,  share: 0.18 },
  { tool: 'crush',       turns: 64,   ktok: 2,   cost: 0.71,  share: 0.08 },
  { tool: 'pi',          turns: 32,   ktok: 7,   cost: 0,     share: 0.05 },
  { tool: 'kimi',        turns: 11,   ktok: 1,   cost: 0,     share: 0.02 },
];

// Health collectors
const COLLECTORS = [
  { host: 'laptop', tool: 'claude-code', src: '~/.claude/projects',          poll: '30s', lag: '4s',  out: 0,   last: 'now', ev: 412, status: 'ok' },
  { host: 'laptop', tool: 'opencode',    src: '~/.local/share/opencode',     poll: '30s', lag: '12s', out: 0,   last: '12s', ev: 38,  status: 'ok' },
  { host: 'laptop', tool: 'crush',       src: '~/.cache/crush',              poll: '60s', lag: '28s', out: 0,   last: '28s', ev: 9,   status: 'ok' },
  { host: 'laptop', tool: 'pi',          src: '~/.config/pi/history',        poll: '60s', lag: '1m',  out: 0,   last: '1m',  ev: 7,   status: 'ok' },
  { host: 'workpc', tool: 'claude-code', src: '~/.claude/projects',          poll: '30s', lag: '7s',  out: 0,   last: 'now', ev: 228, status: 'ok' },
  { host: 'workpc', tool: 'opencode',    src: '~/.local/share/opencode',     poll: '30s', lag: '18s', out: 0,   last: '18s', ev: 54,  status: 'ok' },
  { host: 'workpc', tool: 'kimi',        src: '~/.kimi-cli/history.jsonl',   poll: '60s', lag: '2m',  out: 127, last: '2m',  ev: 3,   status: 'warn' },
  { host: 'workpc', tool: 'crush',       src: '~/.cache/crush',              poll: '60s', lag: '8m',  out: 0,   last: '8m',  ev: 0,   status: 'stale' },
];

// Long sample turns for session view
const TURNS = [
  { role: 'user',      text: 'lockfile design for the tt bundle — should we hash inputs or outputs?' },
  { role: 'assistant', text: "Both, but for different reasons. Input hashes give you the 'should we rebuild' signal; output hashes give you the 'is this artifact equivalent' signal. The input hash lives in the lockfile next to each module entry; the output hash is computed post-build and stored in the artifact index.", model: 'claude-opus-4-7', tIn: 412, tOut: 980 },
  { role: 'tool',      text: 'Read("~/code/tt-bundle/build.zig")', kind: 'read' },
  { role: 'tool',      text: '→ 14.2 KB, 318 lines', kind: 'result' },
  { role: 'assistant', text: "Looking at your current build.zig, the input set is already explicit — module list, compiler flags, target triple. So input-hashing is straightforward: sha256 over the canonical-JSON encoding of (module_list, flags, target).", model: 'claude-opus-4-7', tIn: 530, tOut: 1240 },
  { role: 'user',      text: 'ok so what about transitive deps that come from a vendored dir' },
  { role: 'assistant', text: "Transitive deps need a separate manifest pass. The lockfile records the *resolved* tree, not the declared one — so when you bump a direct dep you re-resolve and rewrite the transitive section. The cache key is sha256(direct + transitive sorted).", model: 'claude-opus-4-7', tIn: 88, tOut: 760 },
  { role: 'tool',      text: 'Grep("vendor/", glob: "*.zig")', kind: 'grep' },
  { role: 'tool',      text: '→ 47 matches across 12 files', kind: 'result' },
  { role: 'assistant', text: "Three of those are header-only style — they don't have their own deps. The other nine each declare 1–4 transitives. So your lock should expand to ~30 entries on first resolve.", model: 'claude-opus-4-7', tIn: 220, tOut: 540 },
  { role: 'user',      text: 'how would the cache key look if I bumped one transitive but nothing else changed' },
  { role: 'assistant', text: "sha256 over the sorted list, so any change ripples up — but only the affected output keys flip. Direct deps that didn't move keep their input hash; their *output* hash also doesn't move because output depends on the resolved-tree slice they actually consume.", model: 'claude-opus-4-7', tIn: 110, tOut: 880 },
];

// Saved searches per project (for tt-bundle)
const SAVED_SEARCHES = ['lockfile', 'retry/backoff', 'vendored deps', 'build.zig', 'transitive'];

// Filter dimensions for popover
const FILTER_DIMS = {
  tool: ['any', 'claude-code', 'opencode', 'crush', 'pi', 'kimi'],
  host: ['any', 'laptop', 'workpc'],
  since: ['24h', '7d', '30d', '90d', 'all'],
  model: ['any', 'claude-opus-4-7', 'gpt-5-mini', 'gemini-2-flash', 'inflection-3', 'kimi-k2'],
};

// Auth config (mirrors internal/config Auth substruct)
const AUTH_CONFIG = {
  bind: '127.0.0.1:8401',
  allowedUsers: ['bigbes', 'rin', 'noor'],
  admins: ['bigbes'],
  forwardAuth: { enabled: true,  userHeader: 'Remote-User' },
  oidc:        { enabled: true,
                 issuer:   'https://auth.example.com',
                 audience: 'lethe',
                 usernameClaim: 'preferred_username',
                 jwksLastFetch: '4m ago' },
};

// Recent auth events for the Auth settings panel
const AUTH_EVENTS = [
  { t: '14:22:14', user: 'bigbes', via: 'forward-auth', path: 'GET /api/v1/sessions',         status: 200 },
  { t: '14:18:02', user: 'rin',    via: 'oidc-bearer', path: 'POST /api/v1/ingest',           status: 200 },
  { t: '14:11:48', user: 'rin',    via: 'oidc-bearer', path: 'GET /api/v1/sessions/.../...',  status: 200 },
  { t: '13:54:30', user: '—',      via: 'oidc-bearer', path: 'POST /api/v1/ingest',           status: 401, note: 'expired jwt' },
  { t: '13:40:19', user: 'noor',   via: 'oidc-bearer', path: 'GET /api/v1/sessions?owner=*',  status: 403, note: 'admin-only param' },
  { t: '13:02:11', user: 'bigbes', via: 'forward-auth', path: 'GET /api/v1/sessions?owner=rin', status: 200 },
];

Object.assign(window, {
  TOOLS, HOSTS, TOOL_COLORS, SESSIONS, PROJECTS, TOOL_ROLLUPS, COLLECTORS,
  TURNS, SAVED_SEARCHES, FILTER_DIMS,
  ME, OWNERS, AUTH_CONFIG, AUTH_EVENTS,
});