@walwal-harness/cli 7.1.41 → 7.1.43

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.
@@ -0,0 +1,247 @@
1
+ /* =============================================================
2
+ walwal-harness · BRICK OFFICE Data Contract
3
+ The single state shape every view renders from. Ported from the
4
+ design-handoff simulation (harness/sim.jsx, harness/ui.jsx) — but
5
+ here it is produced from REAL harness data by lib/brick/adapter.ts.
6
+
7
+ This module is pure (no React, no DOM). It exports:
8
+ - the Contract TypeScript interfaces
9
+ - AGENT_DEFS (the 6 CXX roles with id/name/role/hue)
10
+ - fmt utils (time, hm, ago, k, money)
11
+ - statusColor + STATUS_COLOR
12
+ ============================================================= */
13
+
14
+ /** The role ids of the 6 exec agents, in canonical display order. */
15
+ export type AgentRole = "ceo" | "coo" | "cdo" | "cto" | "cqo" | "ops";
16
+
17
+ /**
18
+ * Status enum shared by agents and workers. The simulation used the full set
19
+ * (idle | typing | talking | active | alert | live); the real adapter only
20
+ * emits the subset {live, active, alert, idle}, but the renderer/statusColor
21
+ * still understands every value so the design's legend stays faithful.
22
+ */
23
+ export type AgentStatus =
24
+ | "idle"
25
+ | "typing"
26
+ | "talking"
27
+ | "active"
28
+ | "alert"
29
+ | "live";
30
+
31
+ /** The agent's autonomous loop state. */
32
+ export type LoopState = "running" | "idle";
33
+
34
+ /** Task lifecycle, as rendered by the task panel. */
35
+ export type TaskStatus = "running" | "queued" | "done";
36
+
37
+ /** Attention-queue severity. */
38
+ export type AlertLevel = "stale" | "attention";
39
+
40
+ /** A reference to a document the DocViewer can render. */
41
+ export type DocTarget =
42
+ | { type: "agent"; agent: AgentRole }
43
+ | { type: "worker"; agent: AgentRole; worker: ContractWorker };
44
+
45
+ /** Static, design-fixed definition of one exec agent. */
46
+ export interface AgentDef {
47
+ id: AgentRole;
48
+ name: string;
49
+ role: string;
50
+ hue: string;
51
+ }
52
+
53
+ /** One exec agent row in the live state. */
54
+ export interface ContractAgent {
55
+ id: AgentRole;
56
+ name: string;
57
+ role: string;
58
+ hue: string;
59
+ status: AgentStatus;
60
+ loop: LoopState;
61
+ /** One-line "current work" string. "—" when there is no live work string. */
62
+ work: string;
63
+ /** Open todo count. */
64
+ todos: number;
65
+ /** Count of live workers (derived from `workers` below). */
66
+ workers: number;
67
+ /** ~24 ints, recent activity, drives the bar sparkline. */
68
+ spark: number[];
69
+ /** epoch ms of last visible movement -> drives "stale"; null when unknown. */
70
+ heartbeat: number | null;
71
+ /** Full report markdown for this agent (mission[role]); undefined when none. */
72
+ report?: string;
73
+ }
74
+
75
+ /** One spawned worker across all agents. */
76
+ export interface ContractWorker {
77
+ id: string;
78
+ agent: AgentRole;
79
+ name: string;
80
+ status: AgentStatus;
81
+ /** epoch ms; null when unknown. */
82
+ started: number | null;
83
+ /** 0..100, or null when there is no real granular progress source. */
84
+ progress: number | null;
85
+ /** Full worker report/brief markdown (worker.content); undefined when none. */
86
+ report?: string;
87
+ }
88
+
89
+ /** One task in the running/queued/done lanes. */
90
+ export interface ContractTask {
91
+ id: string;
92
+ /** Owner display label, e.g. "CTO". */
93
+ owner: string;
94
+ title: string;
95
+ agent: AgentRole;
96
+ status: TaskStatus;
97
+ /** 0..100, or null — there is no real granular progress source. */
98
+ progress: number | null;
99
+ /** epoch ms the task started, or null. */
100
+ started?: number | null;
101
+ /** epoch ms the task completed (done lane only), or null. */
102
+ at?: number | null;
103
+ }
104
+
105
+ /** The three task lanes. */
106
+ export interface ContractTasks {
107
+ running: ContractTask[];
108
+ queued: ContractTask[];
109
+ done: ContractTask[];
110
+ }
111
+
112
+ /** One activity-stream event. */
113
+ export interface ContractEvent {
114
+ id: string;
115
+ /** epoch ms; null when unknown. */
116
+ at: number | null;
117
+ agent: AgentRole | "";
118
+ worker: string;
119
+ /** The verb; "COMPLETE"/"complete" renders green. */
120
+ verb: string;
121
+ /** The object the verb acted on. */
122
+ obj: string;
123
+ }
124
+
125
+ /** One attention-queue alert. */
126
+ export interface ContractAlert {
127
+ id: string;
128
+ level: AlertLevel;
129
+ agent: AgentRole;
130
+ msg: string;
131
+ /** epoch ms; null when unknown. */
132
+ at: number | null;
133
+ }
134
+
135
+ /**
136
+ * System-health metrics. Values with no real telemetry source are `null`
137
+ * and MUST render as "—" (never a fabricated number).
138
+ */
139
+ export interface ContractMetrics {
140
+ /** "open" when the SSE stream is connected, else "closed". */
141
+ sse: "open" | "closed";
142
+ /** Rolling tokens/min from /api/metrics ring buffer; null until sourced. */
143
+ tokensPerMin: number | null;
144
+ /** USD cost; an ESTIMATE from /api/metrics (see costEstimated); null when unsourced. */
145
+ costToday: number | null;
146
+ /** True when costToday is a price-table estimate (not a billed figure). */
147
+ costEstimated?: boolean;
148
+ /** 0..100 context-window occupancy of the most-active session; null when unknown. */
149
+ contextPct?: number | null;
150
+ /** Count of events in the last 60s (derived). */
151
+ throughput: number | null;
152
+ /** Summed %cpu of discovered company PIDs; null when no telemetry. */
153
+ cpu: number | null;
154
+ /** Count of missions of type 'hotfix'. */
155
+ hotfix: number;
156
+ /** Total events in the snapshot. */
157
+ eventsTotal: number;
158
+ }
159
+
160
+ /** The single source-of-truth state every view renders from. */
161
+ export interface ContractState {
162
+ /** epoch ms, ticked ~1/s by the shell. */
163
+ now: number;
164
+ agents: ContractAgent[];
165
+ workers: ContractWorker[];
166
+ tasks: ContractTasks;
167
+ events: ContractEvent[];
168
+ /** 24 hourly buckets = owner prompts/hour -> heatmap. */
169
+ cadence: number[];
170
+ alerts: ContractAlert[];
171
+ metrics: ContractMetrics;
172
+ /** tokens/min sparkline samples; [] when no source. */
173
+ mtrend: number[];
174
+ /** cost sparkline samples; [] when no source. */
175
+ ctrend: number[];
176
+ }
177
+
178
+ /* ---- agent (exec) definitions -----------------------------------------
179
+ The 6 CXX roles in canonical order, with per-role accent hue.
180
+ Ported from sim.jsx AGENTS, with hues per the adapter spec. */
181
+ export const AGENT_DEFS: readonly AgentDef[] = [
182
+ { id: "ceo", name: "CEO", role: "Chief Executive", hue: "#4cc2ff" },
183
+ { id: "coo", name: "COO", role: "Operations", hue: "#3fd17a" },
184
+ { id: "cdo", name: "CDO", role: "Design", hue: "#8b95a4" },
185
+ { id: "cto", name: "CTO", role: "Technology", hue: "#f0a23b" },
186
+ { id: "cqo", name: "CQO", role: "Quality", hue: "#c084fc" },
187
+ { id: "ops", name: "OPS", role: "Runtime Watch", hue: "#f97e4d" },
188
+ ] as const;
189
+
190
+ /** The 6 role ids in canonical order. */
191
+ export const AGENT_ROLES: readonly AgentRole[] = AGENT_DEFS.map((a) => a.id);
192
+
193
+ /** Quick lookup by role id. */
194
+ export const AGENT_DEF_BY_ID: Record<AgentRole, AgentDef> = AGENT_DEFS.reduce(
195
+ (acc, def) => {
196
+ acc[def.id] = def;
197
+ return acc;
198
+ },
199
+ {} as Record<AgentRole, AgentDef>
200
+ );
201
+
202
+ /* ---- status colors (ported from ui.jsx) ------------------------------- */
203
+ export const STATUS_COLOR: Record<string, string> = {
204
+ live: "#3fd17a",
205
+ active: "#3fd17a",
206
+ typing: "#4cc2ff",
207
+ talking: "#c084fc",
208
+ idle: "#5a6472",
209
+ alert: "#f0506b",
210
+ running: "#3fd17a",
211
+ stale: "#f0a23b",
212
+ };
213
+
214
+ export const statusColor = (s: string): string => STATUS_COLOR[s] ?? "#5a6472";
215
+
216
+ /* ---- fmt utils (ported from sim.jsx) ----------------------------------
217
+ Pure formatting helpers. `time`/`hm` take a Date; `ago` takes a ms delta;
218
+ `k`/`money` take numbers (and tolerate null -> "—" for honest blanks). */
219
+ export const fmt = {
220
+ /** "HH:MM:SS" */
221
+ time: (d: Date): string => d.toTimeString().slice(0, 8),
222
+ /** "HH:MM" */
223
+ hm: (d: Date): string => d.toTimeString().slice(0, 5),
224
+ /** humanize a ms delta -> "Ns ago" / "Nm ago" / "Nh ago" */
225
+ ago: (ms: number): string => {
226
+ const s = Math.floor(ms / 1000);
227
+ if (s < 60) return s + "s ago";
228
+ const m = Math.floor(s / 60);
229
+ if (m < 60) return m + "m ago";
230
+ const h = Math.floor(m / 60);
231
+ return h + "h ago";
232
+ },
233
+ /** compact thousands: 11200 -> "11.2k"; null -> "—" */
234
+ k: (n: number | null | undefined): string => {
235
+ if (n == null || !Number.isFinite(n)) return "—";
236
+ return n >= 1000 ? (n / 1000).toFixed(1) + "k" : String(Math.round(n));
237
+ },
238
+ /** "$42.18"; null -> "—" */
239
+ money: (n: number | null | undefined): string => {
240
+ if (n == null || !Number.isFinite(n)) return "—";
241
+ return "$" + n.toFixed(2);
242
+ },
243
+ };
244
+
245
+ /** Render a possibly-null number as the design's em-dash blank. */
246
+ export const dashIfNull = (n: number | null | undefined): string =>
247
+ n == null || !Number.isFinite(n) ? "—" : String(n);