@agimon-ai/doompi-log 0.0.1-alpha.67 → 0.0.1-alpha.69

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agimon-ai/doompi-log",
3
- "version": "0.0.1-alpha.67",
3
+ "version": "0.0.1-alpha.69",
4
4
  "description": "Pi session metrics, findings, sink status, and a Log Metrics overlay for agent observability.",
5
5
  "keywords": [
6
6
  "agent-observability",
@@ -31,7 +31,8 @@
31
31
  "src/web",
32
32
  "src/exports/webClient.ts",
33
33
  "src/types/webMetrics.ts",
34
- "src/types/issueGrouping.ts"
34
+ "src/types/issueGrouping.ts",
35
+ "!src/web/**/*.stories.tsx"
35
36
  ],
36
37
  "type": "module",
37
38
  "main": "./dist/index.cjs",
@@ -78,11 +79,11 @@
78
79
  "@agimon-ai/log-sink-mcp": "0.29.19",
79
80
  "@deepseek-ai/cordis": "4.0.2",
80
81
  "hono": "4.13.5",
81
- "@agimon-ai/doompi-extension-contracts": "0.0.1-alpha.66",
82
- "@agimon-ai/doompi-telemetry": "0.0.1-alpha.65",
83
- "@agimon-ai/doompi-web-security": "0.0.1-alpha.28",
84
- "@agimon-ai/doompi-web-contracts": "0.0.1-alpha.29",
85
- "@agimon-ai/doompi-web-components": "0.0.1-alpha.26"
82
+ "@agimon-ai/doompi-extension-contracts": "0.0.1-alpha.68",
83
+ "@agimon-ai/doompi-web-contracts": "0.0.1-alpha.31",
84
+ "@agimon-ai/doompi-telemetry": "0.0.1-alpha.67",
85
+ "@agimon-ai/doompi-web-security": "0.0.1-alpha.30",
86
+ "@agimon-ai/doompi-web-components": "0.0.1-alpha.28"
86
87
  },
87
88
  "devDependencies": {
88
89
  "@earendil-works/pi-coding-agent": "0.85.1",
@@ -93,10 +94,11 @@
93
94
  "@types/react": "19.2.18",
94
95
  "@vitest/coverage-v8": "5.0.0",
95
96
  "react": "19.2.8",
97
+ "react-dom": "19.2.8",
96
98
  "tsdown": "0.23.0",
97
99
  "typescript": "7.0.2",
98
100
  "vitest": "5.0.0",
99
- "@agimon-ai/doompi-ui": "0.0.1-alpha.67"
101
+ "@agimon-ai/doompi-ui": "0.0.1-alpha.69"
100
102
  },
101
103
  "peerDependencies": {
102
104
  "@earendil-works/pi-coding-agent": "0.85.1",
@@ -40,13 +40,13 @@ function IssueRow({ group, max, tools }: IssueRowProps) {
40
40
  return (
41
41
  <li className="flex flex-col">
42
42
  <div className="relative">
43
- <span aria-hidden="true" className="absolute inset-y-0 left-0 rounded-[2px] bg-doom-red/20" style={{ width }} />
43
+ <span aria-hidden="true" className="absolute inset-y-0 left-0 rounded-xs bg-doom-red/20" style={{ width }} />
44
44
  <button
45
45
  type="button"
46
46
  onClick={() => setOpen(!open)}
47
47
  aria-expanded={open}
48
48
  data-testid={`metrics-issue-${group.key}`}
49
- className="relative flex w-full items-center gap-2 rounded-[2px] px-1 py-[3px] text-left text-[10px] hover:bg-doom-tint focus-visible:outline focus-visible:outline-1 focus-visible:outline-doom-blue"
49
+ className="relative flex w-full items-center gap-2 rounded-xs px-1 py-[3px] text-left text-xs hover:bg-doom-tint focus-visible:outline focus-visible:outline-1 focus-visible:outline-doom-blue"
50
50
  >
51
51
  <span className="w-8 shrink-0 text-right font-bold text-doom-red">{group.occurrences}</span>
52
52
  <span className="w-24 shrink-0 truncate text-doom-hi">{titleOf(group)}</span>
@@ -56,8 +56,8 @@ function IssueRow({ group, max, tools }: IssueRowProps) {
56
56
  </div>
57
57
 
58
58
  {open ? (
59
- <div className="flex flex-col gap-1 px-2 py-2 text-[10px]" data-testid={`metrics-issue-body-${group.key}`}>
60
- <div className="flex flex-wrap gap-x-3 gap-y-1 text-[9px] text-doom-faint">
59
+ <div className="flex flex-col gap-1 px-2 py-2 text-xs" data-testid={`metrics-issue-body-${group.key}`}>
60
+ <div className="flex flex-wrap gap-x-3 gap-y-1 text-2xs text-doom-faint">
61
61
  <span>category {group.category}</span>
62
62
  {group.tool === null ? null : <span>tool {group.tool}</span>}
63
63
  {group.errorType === null ? null : <span>error {group.errorType}</span>}
@@ -67,7 +67,7 @@ function IssueRow({ group, max, tools }: IssueRowProps) {
67
67
  <span>last seen {group.lastSeen}</span>
68
68
  </div>
69
69
  <span className="break-words text-doom-dim">{group.detail}</span>
70
- <ul className="flex flex-col gap-[1px] text-[9px] text-doom-faint">
70
+ <ul className="flex flex-col gap-[1px] text-2xs text-doom-faint">
71
71
  {group.members.map((member, index) => (
72
72
  <li key={`${member.timestamp}-${String(index)}`} className="flex flex-wrap gap-x-2">
73
73
  <span>{member.timestamp}</span>
@@ -99,7 +99,7 @@ export function IssuesDetail({ view, tools }: IssuesDetailProps) {
99
99
 
100
100
  return (
101
101
  <div className="flex flex-col gap-3">
102
- <span className="text-[10px] text-doom-dim">
102
+ <span className="text-xs text-doom-dim">
103
103
  <span className="text-doom-hi">{view.totalIssues}</span> occurrences of{' '}
104
104
  <span className="text-doom-hi">{groups.length}</span> distinct problems, worst first
105
105
  </span>
@@ -113,8 +113,8 @@ export function IssuesDetail({ view, tools }: IssuesDetailProps) {
113
113
  )}
114
114
 
115
115
  <div className="flex flex-col gap-1">
116
- <span className="text-[9px] font-bold text-doom-faint">failures by tool</span>
117
- <table className="w-full text-[10px]" data-testid="metrics-issues-tools">
116
+ <span className="text-2xs font-bold text-doom-faint">failures by tool</span>
117
+ <table className="w-full text-xs" data-testid="metrics-issues-tools">
118
118
  <tbody>
119
119
  {countRows(view.byTool).map(([name, failures]) => {
120
120
  const calls = callsByTool.get(name);
@@ -134,8 +134,8 @@ export function IssuesDetail({ view, tools }: IssuesDetailProps) {
134
134
  </table>
135
135
  </div>
136
136
 
137
- <div className="flex flex-wrap gap-x-4 gap-y-1 text-[10px] text-doom-dim">
138
- <span className="text-[9px] font-bold text-doom-faint">by category</span>
137
+ <div className="flex flex-wrap gap-x-4 gap-y-1 text-xs text-doom-dim">
138
+ <span className="text-2xs font-bold text-doom-faint">by category</span>
139
139
  {countRows(view.byCategory).map(([name, count]) => (
140
140
  <span key={name}>
141
141
  {name} <span className="text-doom-hi">{count}</span>
@@ -50,14 +50,14 @@ export function IssuesSection({ tools, focus }: IssuesSectionProps) {
50
50
  return (
51
51
  <section className="flex flex-col gap-1" data-testid="metrics-issues">
52
52
  <div className="flex items-center gap-2">
53
- <span className="text-[9px] font-bold text-doom-faint">issues</span>
53
+ <span className="text-2xs font-bold text-doom-faint">issues</span>
54
54
  {open ? null : (
55
- <Button variant="ghost" size="xs" className="text-[9px]" onClick={load} data-testid="metrics-issues-open">
55
+ <Button variant="ghost" size="xs" className="text-2xs" onClick={load} data-testid="metrics-issues-open">
56
56
  show detail
57
57
  </Button>
58
58
  )}
59
59
  {open && !loading ? (
60
- <Button variant="ghost" size="xs" className="text-[9px]" onClick={load} data-testid="metrics-issues-reload">
60
+ <Button variant="ghost" size="xs" className="text-2xs" onClick={load} data-testid="metrics-issues-reload">
61
61
  reload
62
62
  </Button>
63
63
  ) : null}
@@ -66,13 +66,13 @@ export function IssuesSection({ tools, focus }: IssuesSectionProps) {
66
66
  {/* Reading this scans the whole window in a subprocess, so the reader is
67
67
  told why it is behind a click rather than left wondering. */}
68
68
  {open ? null : (
69
- <span className="text-[9px] text-doom-faint/70">
69
+ <span className="text-2xs text-doom-faint/70">
70
70
  the log sink has no issues endpoint, so this is read separately and takes a moment
71
71
  </span>
72
72
  )}
73
73
 
74
74
  {message === '' ? null : (
75
- <span className="text-[10px] text-doom-yellow" data-testid="metrics-issues-message">
75
+ <span className="text-xs text-doom-yellow" data-testid="metrics-issues-message">
76
76
  {message}
77
77
  </span>
78
78
  )}
@@ -39,19 +39,19 @@ export function FocusNotice({ requested, applied, dimension, onClear }: FocusNot
39
39
  // whole numbers. Saying "showing model X" over them would be a lie, so the
40
40
  // drill-down is reported as refused instead.
41
41
  return (
42
- <span className="text-[10px] text-doom-yellow" data-testid="metrics-focus-refused">
42
+ <span className="text-xs text-doom-yellow" data-testid="metrics-focus-refused">
43
43
  this log sink does not support narrowing by {DIMENSION_LABELS[dimension]}, so the numbers below are still
44
44
  everything
45
- <Button variant="ghost" size="xs" className="ml-2 text-[9px]" onClick={onClear}>
45
+ <Button variant="ghost" size="xs" className="ml-2 text-2xs" onClick={onClear}>
46
46
  clear
47
47
  </Button>
48
48
  </span>
49
49
  );
50
50
  }
51
51
  return (
52
- <span className="text-[10px] text-doom-dim" data-testid="metrics-focus">
52
+ <span className="text-xs text-doom-dim" data-testid="metrics-focus">
53
53
  narrowed to <span className="text-doom-hi">{applied}</span>
54
- <Button variant="ghost" size="xs" className="ml-2 text-[9px]" onClick={onClear}>
54
+ <Button variant="ghost" size="xs" className="ml-2 text-2xs" onClick={onClear}>
55
55
  clear
56
56
  </Button>
57
57
  </span>
@@ -73,7 +73,7 @@ export function MetricsPanel(_props: SettingsPanelProps) {
73
73
  setDimension(next as MetricsDimension);
74
74
  }}
75
75
  >
76
- <SelectTrigger data-testid="metrics-dimension" className="w-[140px] text-[10px]">
76
+ <SelectTrigger data-testid="metrics-dimension" className="w-[140px] text-xs">
77
77
  <SelectValue />
78
78
  </SelectTrigger>
79
79
  <SelectContent>
@@ -85,7 +85,7 @@ export function MetricsPanel(_props: SettingsPanelProps) {
85
85
  </SelectContent>
86
86
  </Select>
87
87
  <Select value={period} onValueChange={(next) => setPeriod(next as MetricsPeriod)}>
88
- <SelectTrigger data-testid="metrics-period" className="w-[110px] text-[10px]">
88
+ <SelectTrigger data-testid="metrics-period" className="w-[110px] text-xs">
89
89
  <SelectValue />
90
90
  </SelectTrigger>
91
91
  <SelectContent>
@@ -100,7 +100,7 @@ export function MetricsPanel(_props: SettingsPanelProps) {
100
100
  <Button
101
101
  variant="ghost"
102
102
  size="xs"
103
- className="ml-auto text-[9px]"
103
+ className="ml-auto text-2xs"
104
104
  onClick={() => setPeriod((current) => current)}
105
105
  disabled={loading}
106
106
  >
@@ -109,7 +109,7 @@ export function MetricsPanel(_props: SettingsPanelProps) {
109
109
  </div>
110
110
 
111
111
  {error === '' ? null : (
112
- <span className="text-[10px] text-doom-red" data-testid="metrics-error">
112
+ <span className="text-xs text-doom-red" data-testid="metrics-error">
113
113
  {error}
114
114
  </span>
115
115
  )}
@@ -39,7 +39,7 @@ export function MetricsReportView({ report, onFocus }: MetricsReportViewProps) {
39
39
  return (
40
40
  <div className="flex flex-col gap-4">
41
41
  <div className="flex flex-col gap-1">
42
- <div className="flex flex-wrap items-center gap-3 text-[10px] text-doom-dim">
42
+ <div className="flex flex-wrap items-center gap-3 text-xs text-doom-dim">
43
43
  <span>
44
44
  <span className="text-doom-hi">{formatTokens(report.totals.totalTokens)}</span> total
45
45
  </span>
@@ -70,41 +70,41 @@ export function MetricsReportView({ report, onFocus }: MetricsReportViewProps) {
70
70
  beside it without this line reads as a breakdown that does not
71
71
  add up, which is worse than not showing them.
72
72
  */}
73
- <span className="text-[9px] text-doom-faint/70">
73
+ <span className="text-2xs text-doom-faint/70">
74
74
  total is what the providers reported and is dominated by cache traffic; the parts beside it are counted
75
75
  separately and do not sum to it
76
76
  </span>
77
77
  </div>
78
78
 
79
79
  <section className="flex flex-col gap-1">
80
- <span className="text-[9px] font-bold text-doom-faint">tokens over time</span>
80
+ <span className="text-2xs font-bold text-doom-faint">tokens over time</span>
81
81
  <TimelineChart buckets={report.timeline} bucketUnit={report.bucketUnit} />
82
82
  </section>
83
83
 
84
84
  <section className="flex flex-col gap-1">
85
- <span className="text-[9px] font-bold text-doom-faint">tokens by {DIMENSION_LABELS[report.dimension]}</span>
85
+ <span className="text-2xs font-bold text-doom-faint">tokens by {DIMENSION_LABELS[report.dimension]}</span>
86
86
  {DIMENSION_NOTES[report.dimension] === undefined ? null : (
87
- <span className="text-[9px] text-doom-faint/70">{DIMENSION_NOTES[report.dimension]}</span>
87
+ <span className="text-2xs text-doom-faint/70">{DIMENSION_NOTES[report.dimension]}</span>
88
88
  )}
89
89
  <GroupBars groups={report.groups} focus={report.focus} onFocus={onFocus} />
90
90
  </section>
91
91
 
92
92
  <section className="flex flex-col gap-1">
93
- <span className="text-[9px] font-bold text-doom-faint">tool calls</span>
93
+ <span className="text-2xs font-bold text-doom-faint">tool calls</span>
94
94
  {/*
95
95
  The token column is a ranking hint, not a measurement. The sink
96
96
  attributes a turn's whole total to every tool that ran in that
97
97
  turn, so saying otherwise here would be a lie the chart repeats.
98
98
  */}
99
- <span className="text-[9px] text-doom-faint/70">
99
+ <span className="text-2xs text-doom-faint/70">
100
100
  call counts are exact; the token column ranks tools by the turns they ran in, and is not each tool&apos;s own
101
101
  consumption
102
102
  </span>
103
- <table className="w-full text-[10px]" data-testid="metrics-tools">
103
+ <table className="w-full text-xs" data-testid="metrics-tools">
104
104
  {/* Without heads the two right columns are just numbers; "1006" and
105
105
  "325.9k" do not say which is a call count and which is tokens. */}
106
106
  <thead>
107
- <tr className="text-[9px] text-doom-faint/70">
107
+ <tr className="text-2xs text-doom-faint/70">
108
108
  <th className="py-1 text-left font-normal">tool</th>
109
109
  <th className="w-20 py-1 text-right font-normal">calls</th>
110
110
  <th className="w-20 py-1 text-right font-normal">tokens</th>
@@ -124,7 +124,7 @@ export function MetricsReportView({ report, onFocus }: MetricsReportViewProps) {
124
124
 
125
125
  <IssuesSection tools={report.tools} focus={report.dimension === 'session' ? report.focus : undefined} />
126
126
 
127
- <span className="text-[9px] text-doom-faint/70" data-testid="metrics-provenance">
127
+ <span className="text-2xs text-doom-faint/70" data-testid="metrics-provenance">
128
128
  read over {report.transport ?? 'an unreported transport'} · generated {report.generatedAt}
129
129
  </span>
130
130
  </div>
@@ -28,7 +28,7 @@ export function GroupBars({ groups, focus, onFocus }: GroupBarsProps) {
28
28
  {/* The two right-hand columns were bare numbers. A row reading "11.0M 12"
29
29
  gave no way to know the second figure counted issues. Same widths and
30
30
  padding as a row, so the heads sit over their own columns. */}
31
- <div aria-hidden className="flex items-center gap-2 px-1 text-[9px] text-doom-faint/70">
31
+ <div aria-hidden className="flex items-center gap-2 px-1 text-2xs text-doom-faint/70">
32
32
  <span className="min-w-0 flex-1" />
33
33
  <span className="w-14 shrink-0 text-right">tokens</span>
34
34
  <span className="w-10 shrink-0 text-right">issues</span>
@@ -58,18 +58,18 @@ export function GroupBars({ groups, focus, onFocus }: GroupBarsProps) {
58
58
  track for horizontal space. */}
59
59
  <span
60
60
  aria-hidden="true"
61
- className={`absolute inset-y-0 left-0 rounded-[2px] ${selected ? 'bg-doom-blue/30' : 'bg-doom-blue/15'}`}
61
+ className={`absolute inset-y-0 left-0 rounded-xs ${selected ? 'bg-doom-blue/30' : 'bg-doom-blue/15'}`}
62
62
  style={{ width }}
63
63
  />
64
64
  {onFocus === undefined ? (
65
- <span className="relative flex items-center gap-2 px-1 py-[3px] text-[10px]">{row}</span>
65
+ <span className="relative flex items-center gap-2 px-1 py-[3px] text-xs">{row}</span>
66
66
  ) : (
67
67
  <button
68
68
  type="button"
69
69
  onClick={() => onFocus(selected ? '' : group.key)}
70
70
  aria-pressed={selected}
71
71
  data-testid={`metrics-group-${group.key}`}
72
- className="relative flex w-full items-center gap-2 rounded-[2px] px-1 py-[3px] text-[10px] hover:bg-doom-tint focus-visible:outline focus-visible:outline-1 focus-visible:outline-doom-blue"
72
+ className="relative flex w-full items-center gap-2 rounded-xs px-1 py-[3px] text-xs hover:bg-doom-tint focus-visible:outline focus-visible:outline-1 focus-visible:outline-doom-blue"
73
73
  >
74
74
  {row}
75
75
  </button>
@@ -62,7 +62,7 @@ export function TimelineChart({ buckets, bucketUnit }: TimelineChartProps) {
62
62
  );
63
63
  })}
64
64
  </svg>
65
- <div className="flex flex-wrap justify-between gap-x-3 text-[9px] text-doom-faint">
65
+ <div className="flex flex-wrap justify-between gap-x-3 text-2xs text-doom-faint">
66
66
  <span>{buckets[0]?.label ?? ''}</span>
67
67
  {buckets.length > 1 ? <span>peak {formatTokens(max)}</span> : null}
68
68
  <span>