@illuminis/comprism 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/LICENSE +15 -0
  2. package/README.md +281 -0
  3. package/out/agent/command.d.ts +86 -0
  4. package/out/agent/command.js +259 -0
  5. package/out/agent/render.d.ts +97 -0
  6. package/out/agent/render.js +255 -0
  7. package/out/agent/session.d.ts +175 -0
  8. package/out/agent/session.js +573 -0
  9. package/out/commands/ask.d.ts +1 -0
  10. package/out/commands/ask.js +146 -0
  11. package/out/commands/codemap.d.ts +2 -0
  12. package/out/commands/codemap.js +151 -0
  13. package/out/commands/commands-thin.d.ts +39 -0
  14. package/out/commands/commands-thin.js +182 -0
  15. package/out/commands/install.d.ts +163 -0
  16. package/out/commands/install.js +543 -0
  17. package/out/commands/keys.d.ts +55 -0
  18. package/out/commands/keys.js +344 -0
  19. package/out/commands/login.d.ts +9 -0
  20. package/out/commands/login.js +384 -0
  21. package/out/commands/repl.d.ts +1 -0
  22. package/out/commands/repl.js +752 -0
  23. package/out/commands/settings.d.ts +21 -0
  24. package/out/commands/settings.js +244 -0
  25. package/out/commands/welcome.d.ts +1 -0
  26. package/out/commands/welcome.js +196 -0
  27. package/out/executor/documents.d.ts +40 -0
  28. package/out/executor/documents.js +170 -0
  29. package/out/executor/files.d.ts +2 -0
  30. package/out/executor/files.js +360 -0
  31. package/out/executor/git.d.ts +48 -0
  32. package/out/executor/git.js +132 -0
  33. package/out/executor/hooks.d.ts +67 -0
  34. package/out/executor/hooks.js +247 -0
  35. package/out/executor/index.d.ts +29 -0
  36. package/out/executor/index.js +221 -0
  37. package/out/executor/notebook.d.ts +2 -0
  38. package/out/executor/notebook.js +147 -0
  39. package/out/executor/paths.d.ts +15 -0
  40. package/out/executor/paths.js +126 -0
  41. package/out/executor/shell.d.ts +41 -0
  42. package/out/executor/shell.js +336 -0
  43. package/out/graph/build.d.ts +45 -0
  44. package/out/graph/build.js +91 -0
  45. package/out/graph/facts.d.ts +47 -0
  46. package/out/graph/facts.js +12 -0
  47. package/out/graph/files.d.ts +45 -0
  48. package/out/graph/files.js +207 -0
  49. package/out/graph/read-locales.d.ts +29 -0
  50. package/out/graph/read-locales.js +246 -0
  51. package/out/graph/read-python.d.ts +11 -0
  52. package/out/graph/read-python.js +115 -0
  53. package/out/graph/read-typescript.d.ts +16 -0
  54. package/out/graph/read-typescript.js +292 -0
  55. package/out/graph/sync.d.ts +66 -0
  56. package/out/graph/sync.js +242 -0
  57. package/out/lib/attach.d.ts +62 -0
  58. package/out/lib/attach.js +228 -0
  59. package/out/lib/config.d.ts +93 -0
  60. package/out/lib/config.js +198 -0
  61. package/out/lib/connection.d.ts +73 -0
  62. package/out/lib/connection.js +188 -0
  63. package/out/lib/gateway.d.ts +239 -0
  64. package/out/lib/gateway.js +171 -0
  65. package/out/lib/prompt.d.ts +34 -0
  66. package/out/lib/prompt.js +108 -0
  67. package/out/lib/types.d.ts +417 -0
  68. package/out/lib/types.js +21 -0
  69. package/out/lib/ui.d.ts +114 -0
  70. package/out/lib/ui.js +265 -0
  71. package/out/lib/version.d.ts +24 -0
  72. package/out/lib/version.js +27 -0
  73. package/out/lib/voice.d.ts +50 -0
  74. package/out/lib/voice.js +218 -0
  75. package/out/postinstall.d.ts +2 -0
  76. package/out/postinstall.js +92 -0
  77. package/out/thin.d.ts +2 -0
  78. package/out/thin.js +259 -0
  79. package/package.json +101 -0
  80. package/scripts/read_python.py +270 -0
@@ -0,0 +1,417 @@
1
+ /**
2
+ * Shared types for the CompletionPrism Companion. No logic lives here.
3
+ *
4
+ * Frozen build spec Part C, section 0.5, extended with the v3.2 schema
5
+ * additions the kickoff brief names: `ExecutedArm`, `LedgerRowV32`,
6
+ * `DecisionSnapshotV32`, `ProvenanceMeta`, `PersistedTurn`, `ShadowDecision`.
7
+ *
8
+ * Three rules shape almost every field below, and they are worth stating once
9
+ * rather than repeating in forty comments:
10
+ *
11
+ * 1. Append-only. Nothing here is ever mutated in place. A correction is a
12
+ * new row carrying `supersedes`. `DecisionSnapshot` is stricter still and
13
+ * carries no `supersedes` field at all, because it never has one.
14
+ * 2. Provenance on every derived field. A number says whether it was
15
+ * observed, inferred or estimated, and anything inferred says by what
16
+ * method.
17
+ * 3. Content-blind by default. The record carries a fingerprint of a request
18
+ * and never the request. Response text is a character count, not text.
19
+ */
20
+ import type { TaskRepresentation } from '../internal/representation';
21
+ export type Provider = 'anthropic' | 'openai';
22
+ /** Coarse structural bands. Never the model's lookup key on its own. */
23
+ export type Tier = 'simple' | 'standard' | 'complex';
24
+ export type ContextState = 'fresh' | 'warm';
25
+ /** How a number came to exist. Rule 2 of the frozen spec's ground rules. */
26
+ export type Derivation = 'observed' | 'inferred' | 'estimated';
27
+ /**
28
+ * Where a record came from, which decides what it is allowed to influence.
29
+ *
30
+ * `imported` rows - provider exports, log scans, anything reconstructed after
31
+ * the fact - can be reported on and can never reach an estimator. That
32
+ * separation is enforced by schema rather than by convention, which is why it
33
+ * is a field on every row and not a flag someone remembers to check.
34
+ */
35
+ export type Provenance = 'first_party' | 'imported';
36
+ /** The surface a record entered through, in descending order of fidelity. */
37
+ export type SourceSurface = 'sdk' | 'cli' | 'proxy' | 'vscode' | 'mcp' | 'provider_export' | 'scan';
38
+ /**
39
+ * What a cost figure actually is.
40
+ *
41
+ * A cost the provider billed is not the same object as one we computed from the
42
+ * published catalog, and neither is the same as one a customer's export
43
+ * reported to us. Collapsing the three into a single `cost_usd` column is how a
44
+ * savings figure ends up indefensible.
45
+ */
46
+ export type CostSemantic = 'billed_actual' | 'catalog_computed' | 'imported_reported' | 'unpriced';
47
+ /**
48
+ * How an unsuccessful attempt surfaced. The economics live here: a refusal
49
+ * costs seconds, a plausible wrong answer that survives review costs the most.
50
+ * Phase 2 measures these; Phase 1 records the raw material for them.
51
+ */
52
+ export type FailureMode = 'refusal_or_error' | 'incomplete' | 'plausible_wrong' | 'latent' | 'unknown';
53
+ /** What the policy did at a decision point. */
54
+ export type PolicyAction = 'initial' | 'continue_same' | 'switch_model' | 'abandon_recommended';
55
+ /**
56
+ * Whether the Companion may alter dispatch.
57
+ *
58
+ * `monitor` is the only mode this release ships behavior for: the engine runs,
59
+ * records everything a decision would need, and changes nothing. `active`
60
+ * exists in the schema so a decision made later is permanently distinguishable
61
+ * from one made now. It is not a flag that turns selection on - there is no
62
+ * selection to turn on until the model program delivers tables.
63
+ */
64
+ export type ExecutionMode = 'monitor' | 'active';
65
+ export interface ModelInfo {
66
+ id: string;
67
+ provider: Provider;
68
+ inPerMTok: number;
69
+ outPerMTok: number;
70
+ reportsReasoningTokens: boolean;
71
+ /** The structural band this model is the default candidate for. */
72
+ tier: Tier;
73
+ /** Human label for reports. */
74
+ label: string;
75
+ }
76
+ export interface Usage {
77
+ inputTokens: number | null;
78
+ outputTokens: number | null;
79
+ reasoningTokens?: number | null;
80
+ }
81
+ /**
82
+ * Provenance metadata carried alongside any derived figure (v3.2).
83
+ *
84
+ * `method` is required whenever `derivation` is `inferred`, and `confidence`
85
+ * whenever it is `estimated`. A derived number with neither cannot be restated
86
+ * later and so cannot serve as evidence.
87
+ */
88
+ export interface ProvenanceMeta {
89
+ derivation: Derivation;
90
+ provenance: Provenance;
91
+ /** Required when derivation is 'inferred'. How the number was arrived at. */
92
+ method?: string;
93
+ /** Required when derivation is 'estimated'. 0..1. */
94
+ confidence?: number;
95
+ source_surface: SourceSurface;
96
+ }
97
+ /**
98
+ * One persisted turn of a working conversation (v3.2), content-blind.
99
+ *
100
+ * The frozen spec's section 1.5 stores turn content in `sessions.json`. That
101
+ * conflicts with ground rule 6 and with the Phase 1 canary test that no request
102
+ * text reaches any file, so the persisted form carries the shape of a turn and
103
+ * not its words: role, fingerprint, size, and which model answered. `content`
104
+ * appears only when the tenant has explicitly turned text storage on.
105
+ *
106
+ * The consequence is deliberate and worth knowing: a session resumed in a new
107
+ * process cannot replay what was said unless text storage is enabled. Being
108
+ * content-blind has a cost, and paying it visibly is better than storing the
109
+ * text and describing the product as content-blind anyway.
110
+ */
111
+ export interface PersistedTurn {
112
+ role: 'user' | 'assistant';
113
+ ts: string;
114
+ fingerprint: string;
115
+ chars: number;
116
+ approx_tokens: number;
117
+ model?: string;
118
+ provider?: Provider;
119
+ /** Present only when contentPolicy.storeText is true. Default: absent. */
120
+ content?: string;
121
+ }
122
+ export interface Session {
123
+ session_id: string;
124
+ title: string;
125
+ created: string;
126
+ updated: string;
127
+ source_surface: SourceSurface;
128
+ turns: PersistedTurn[];
129
+ }
130
+ /** An in-memory conversation turn. Never written to disk in this shape. */
131
+ export interface Message {
132
+ role: 'user' | 'assistant';
133
+ content: string;
134
+ }
135
+ /**
136
+ * One row per provider call, or per imported usage record.
137
+ *
138
+ * Absent by design: prompt text, response text, API keys.
139
+ *
140
+ * Token counts and cost are nullable, and that is not laziness. A streamed
141
+ * response whose provider did not report usage has no token count, and writing
142
+ * a zero there would understate a real cost while looking like a measurement.
143
+ * `cost_semantic: 'unpriced'` says so out loud, and the report counts those
144
+ * calls on their own line rather than folding them silently into a total.
145
+ */
146
+ export interface LedgerRowV32 {
147
+ event_id: string;
148
+ /** The DecisionSnapshot that caused this call. Always resolves. */
149
+ decision_id: string;
150
+ ts: string;
151
+ source_system: SourceSurface;
152
+ granularity: 'request' | 'daily_aggregate';
153
+ session_id: string;
154
+ turn_index: number;
155
+ user: string;
156
+ task_tier: Tier;
157
+ context_tokens: number;
158
+ prompt_tokens: number;
159
+ fresh_context: boolean;
160
+ provider: Provider;
161
+ model_dispatched: string;
162
+ attempt_index: number;
163
+ input_tokens: number | null;
164
+ output_tokens: number | null;
165
+ reasoning_tokens?: number | null;
166
+ finish_reason: string;
167
+ latency_ms: number;
168
+ cost_usd: number | null;
169
+ cost_semantic: CostSemantic;
170
+ /** sha256 of the normalized prompt. NOT the prompt. */
171
+ prompt_fingerprint: string;
172
+ /** Length only. */
173
+ response_chars: number;
174
+ catalog_version: string;
175
+ mode: ExecutionMode;
176
+ supersedes?: string;
177
+ meta: ProvenanceMeta;
178
+ comprism_version: string;
179
+ }
180
+ /** The frozen spec's Phase 1 name for the same object. */
181
+ export type LedgerRow = LedgerRowV32;
182
+ /**
183
+ * Per-candidate cost breakdown at decision time.
184
+ *
185
+ * Every figure is zero and `excludedReason` is set in this release: with no
186
+ * estimate tables there is nothing to break down, and inventing a number to
187
+ * fill the shape would be exactly the behavior this product exists to replace.
188
+ * The shape ships now so the record written today has the same schema as the
189
+ * record written the day tables arrive.
190
+ */
191
+ export type EccBreakdown = Record<string, never>;
192
+ /**
193
+ * Why no recommendation was made. Recorded on every decision in this release.
194
+ *
195
+ * Recording the reason rather than a null is what lets a historical request be
196
+ * re-evaluated the day tables exist: we know exactly what was missing.
197
+ */
198
+ export type WithheldReason = 'insufficient_evidence' | 'estimator_inert' | 'confidence_below_floor' | 'component_error' | 'no_decision';
199
+ /**
200
+ * What the system knew and chose at the moment of a decision.
201
+ *
202
+ * Written once. Never updated, never superseded, never backfilled. There is no
203
+ * `supersedes` field and no `chain_id`: chain membership is retrospective
204
+ * knowledge and lives in its own linkage record, because putting it here would
205
+ * either make this record mutable or make it a lie.
206
+ *
207
+ * That single property - this record means one thing forever - is worth a large
208
+ * fraction of the calibration, audit and evidence value of the whole system.
209
+ */
210
+ export interface DecisionSnapshotV32 {
211
+ decision_id: string;
212
+ ts: string;
213
+ session_id: string;
214
+ turn_index: number;
215
+ attempt_index: number;
216
+ action: PolicyAction;
217
+ task_tier: Tier;
218
+ classifier_signals: string[];
219
+ classifier_version: string;
220
+ /**
221
+ * The full task representation as it stood at decision time: structural
222
+ * signals, the locally computed reduced vector, deployment context and the
223
+ * reporting labels, each with its own version.
224
+ *
225
+ * Optional only because records written before the representation shipped do
226
+ * not carry one, and a record is never rewritten to add a field it did not
227
+ * have. Everything written from now on has it.
228
+ */
229
+ task_representation?: TaskRepresentation;
230
+ context_tokens: number;
231
+ fresh_context: boolean;
232
+ /** sha256 of the normalized prompt, never the prompt. */
233
+ prompt_fingerprint: string;
234
+ eligible_candidates: string[];
235
+ chosen_model: string;
236
+ chosen_by: 'policy' | 'caller_override';
237
+ ecc_breakdown: Record<string, EccBreakdown>;
238
+ /** Content hash of every estimate table consulted. Empty while inert. */
239
+ survival_table_hashes: Record<string, string>;
240
+ baseline_version: string | null;
241
+ policy_version: string;
242
+ /** Present on every decision in this release: why nothing was recommended. */
243
+ recommendation_withheld: WithheldReason | null;
244
+ recommendation_withheld_detail?: string;
245
+ fallback_used: boolean;
246
+ fallback_reason?: string;
247
+ mode: ExecutionMode;
248
+ meta: ProvenanceMeta;
249
+ comprism_version: string;
250
+ }
251
+ export type DecisionSnapshot = DecisionSnapshotV32;
252
+ /**
253
+ * What the policy would have done, recorded without acting on it (v3.2).
254
+ *
255
+ * The type ships now so the schema is fixed; the recorder that writes it is
256
+ * Phase 3 work. While the estimator is inert a shadow decision would carry no
257
+ * recommendation, which is why nothing writes one yet.
258
+ */
259
+ export interface ShadowDecision {
260
+ shadow_id: string;
261
+ decision_id: string;
262
+ ts: string;
263
+ would_have_dispatched: string | null;
264
+ actually_dispatched: string;
265
+ ecc_breakdown: Record<string, EccBreakdown>;
266
+ recommendation_withheld: WithheldReason | null;
267
+ policy_version: string;
268
+ meta: ProvenanceMeta;
269
+ }
270
+ /**
271
+ * One arm of a head-to-head observation (v3.2): a model that actually ran on a
272
+ * task, with what it cost and how it turned out.
273
+ */
274
+ export interface ExecutedArm {
275
+ decision_id: string;
276
+ event_id: string;
277
+ model: string;
278
+ provider: Provider;
279
+ attempt_index: number;
280
+ input_tokens: number | null;
281
+ output_tokens: number | null;
282
+ cost_usd: number | null;
283
+ latency_ms: number;
284
+ finish_reason: string;
285
+ failure_mode: FailureMode | null;
286
+ response_chars: number;
287
+ }
288
+ export interface ProviderCall {
289
+ model: string;
290
+ messages: Message[];
291
+ maxTokens?: number;
292
+ }
293
+ export interface ProviderResult {
294
+ text: string;
295
+ usage: Usage;
296
+ finishReason: string;
297
+ latencyMs: number;
298
+ /** True when the provider itself reported the token counts. */
299
+ usageReported: boolean;
300
+ /**
301
+ * Present only on a failure. A status line or transport error - never a
302
+ * response body, because a provider's error body can echo the request back,
303
+ * and the request is the customer's content.
304
+ */
305
+ errorMessage?: string;
306
+ }
307
+ export interface SendOptions {
308
+ sessionId?: string;
309
+ /** Dispatch this model regardless of the policy. Records a caller override. */
310
+ model?: string;
311
+ maxTokens?: number;
312
+ /** Which surface is calling. Defaults to 'sdk'. */
313
+ surface?: SourceSurface;
314
+ }
315
+ /**
316
+ * What a caller gets back. The receipt fields are returned here and rendered by
317
+ * the client, never appended to the message history: a caller holding a result
318
+ * object already has somewhere to put a receipt, so there is nothing to gain by
319
+ * writing one into the conversation.
320
+ *
321
+ * The proxy is the one surface where that is not true - the customer's client
322
+ * renders the message body and nothing else - so it injects a sentinel-wrapped
323
+ * footer and strips it back out of every later request. See `footer.ts`.
324
+ */
325
+ export interface SendResult {
326
+ text: string;
327
+ model: string;
328
+ provider: Provider;
329
+ usage: Usage;
330
+ costUsd: number | null;
331
+ costSemantic: CostSemantic;
332
+ decisionId: string;
333
+ eventId: string;
334
+ sessionId: string;
335
+ attempts: number;
336
+ remediated: boolean;
337
+ taskTier: Tier;
338
+ classifierSignals: string[];
339
+ recommendationWithheld: WithheldReason | null;
340
+ latencyMs: number;
341
+ /** Every ledger row this send produced, in dispatch order. */
342
+ ledger: LedgerRowV32[];
343
+ }
344
+ /** Which of the shipped footer layouts the proxy renders. */
345
+ export type FooterTemplate =
346
+ /** The default: money, attempts and human time - the day-one promise. */
347
+ 'completion'
348
+ /** The patent's four cost mechanics, itemized. For technical demos. */
349
+ | 'mechanics' | 'compact' | 'cumulative' | 'detailed';
350
+ /**
351
+ * A per-model price the tenant states themselves, layered over the catalog.
352
+ *
353
+ * It exists because published list price is not what a large customer pays, and
354
+ * a savings figure computed from a price the customer knows to be wrong is
355
+ * worse than no figure at all. Cache prices are optional: left out, they are
356
+ * derived from the input price by the provider's published multipliers.
357
+ */
358
+ export interface FooterPriceOverride {
359
+ inPerMTok: number;
360
+ outPerMTok: number;
361
+ cacheReadPerMTok?: number;
362
+ cacheWritePerMTok?: number;
363
+ }
364
+ export interface FooterConfig {
365
+ /** Kill switch. Off means the proxy is byte-faithful in both directions. */
366
+ enabled: boolean;
367
+ template: FooterTemplate;
368
+ /**
369
+ * The model the saving is measured against: what the customer would have
370
+ * spent had the company mandated one capable model for everything. Named in
371
+ * the footer itself, because a saving is only meaningful against a stated
372
+ * alternative.
373
+ */
374
+ baselineModel: string;
375
+ /** Model id to price. Empty means the catalog's published prices. */
376
+ pricing: Record<string, FooterPriceOverride>;
377
+ /**
378
+ * How the receipt is delimited.
379
+ *
380
+ * `comment` wraps it in an HTML comment, which renders as nothing. `visible`
381
+ * uses plain text markers instead - needed on any surface whose renderer
382
+ * strips comments before display, and the way to tell the two failures apart.
383
+ */
384
+ marker?: 'comment' | 'visible' | 'none';
385
+ /**
386
+ * The tenant's own portal, linked at the end of every receipt.
387
+ *
388
+ * The receipt is two lines and can never carry the whole story, so it ends
389
+ * with where the whole story is: the tenant's stats, traceable to the records
390
+ * behind them. Empty means no link rather than a broken one.
391
+ */
392
+ tenant?: string;
393
+ /**
394
+ * Let the model choose which model answers.
395
+ *
396
+ * Off means observe and report a counterfactual. On means the request is
397
+ * rewritten to the model with the lowest expected cost to complete, and the
398
+ * receipt describes what actually happened rather than what might have.
399
+ */
400
+ route?: boolean;
401
+ /**
402
+ * Where the receipt's link points.
403
+ *
404
+ * Production is `{tenant}.{app}.illuminis.ai` - the tenant's own subdomain of
405
+ * the app's own subdomain of the company domain. In development it points at
406
+ * the app running on this machine instead, so the link is clickable rather
407
+ * than decorative.
408
+ */
409
+ portal?: {
410
+ /** Set false to link at production. */
411
+ useDev?: boolean;
412
+ /** The app running locally, e.g. http://localhost:5182 */
413
+ devUrl?: string;
414
+ /** The production suffix after the tenant, e.g. completionprism.illuminis.ai */
415
+ domain?: string;
416
+ };
417
+ }
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ /**
3
+ * Shared types for the CompletionPrism Companion. No logic lives here.
4
+ *
5
+ * Frozen build spec Part C, section 0.5, extended with the v3.2 schema
6
+ * additions the kickoff brief names: `ExecutedArm`, `LedgerRowV32`,
7
+ * `DecisionSnapshotV32`, `ProvenanceMeta`, `PersistedTurn`, `ShadowDecision`.
8
+ *
9
+ * Three rules shape almost every field below, and they are worth stating once
10
+ * rather than repeating in forty comments:
11
+ *
12
+ * 1. Append-only. Nothing here is ever mutated in place. A correction is a
13
+ * new row carrying `supersedes`. `DecisionSnapshot` is stricter still and
14
+ * carries no `supersedes` field at all, because it never has one.
15
+ * 2. Provenance on every derived field. A number says whether it was
16
+ * observed, inferred or estimated, and anything inferred says by what
17
+ * method.
18
+ * 3. Content-blind by default. The record carries a fingerprint of a request
19
+ * and never the request. Response text is a character count, not text.
20
+ */
21
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Terminal presentation.
3
+ *
4
+ * This is a developer product, so the terminal IS the interface, and it gets the
5
+ * same care a screen would. Three rules hold it together:
6
+ *
7
+ * 1. **The brand shows up here.** The prism spectrum and the illuminis palette
8
+ * are the same ones the portal and the documents use, rendered in 24-bit
9
+ * color where the terminal supports it.
10
+ * 2. **Color is never the only signal.** Every state that matters also has a
11
+ * glyph and a word, so the output survives `NO_COLOR`, a pipe, a CI log and
12
+ * a color-blind reader unchanged.
13
+ * 3. **Nothing here is decoration for its own sake.** Every panel answers a
14
+ * question the person actually has: what did that cost, what was wasted,
15
+ * and how sure are we of the number.
16
+ */
17
+ export declare function width(): number;
18
+ export declare const c: {
19
+ blue: (s: string) => string;
20
+ deep: (s: string) => string;
21
+ purple: (s: string) => string;
22
+ green: (s: string) => string;
23
+ amber: (s: string) => string;
24
+ red: (s: string) => string;
25
+ muted: (s: string) => string;
26
+ text: (s: string) => string;
27
+ bold: (s: string) => string;
28
+ dim: (s: string) => string;
29
+ };
30
+ /**
31
+ * Any glyph, in one of the eight spectrum colors.
32
+ *
33
+ * Exported so the logo and the rule under it are drawn from the SAME eight
34
+ * values. Two hand-picked palettes in one product drift apart within a release,
35
+ * and the brand is the one thing a customer notices before the engine.
36
+ */
37
+ export declare function spectrumAt(index: number, glyph: string): string;
38
+ export declare function prismRule(w?: number): string;
39
+ export declare function banner(subtitle?: string): string;
40
+ export declare function money(v: number | null): string;
41
+ /** Clip to a visible width, with an ellipsis, so a card never bleeds. */
42
+ export declare function clip(s: string, n: number): string;
43
+ export declare function pad(s: string, n: number): string;
44
+ export declare function padLeft(s: string, n: number): string;
45
+ export declare function stripAnsi(s: string): string;
46
+ /**
47
+ * A row of KPI cards - the same shape the portal's summary tab uses, so the two
48
+ * surfaces read as one product rather than two tools that happen to share a name.
49
+ */
50
+ export declare function kpiCards(cards: {
51
+ label: string;
52
+ value: string;
53
+ note?: string;
54
+ tone?: 'good' | 'warn' | 'plain';
55
+ }[]): string;
56
+ /**
57
+ * A Pareto bar: sorted descending with a running cumulative share.
58
+ *
59
+ * Pareto rather than a plain bar chart because the question a spend screen has
60
+ * to answer is not "how much did each cost" but "how few of these carry most of
61
+ * the bill" - the answer is usually two or three, and that is the whole insight.
62
+ */
63
+ export declare function paretoBars(rows: {
64
+ label: string;
65
+ value: number;
66
+ sub?: string;
67
+ }[], opts?: {
68
+ unit?: (v: number) => string;
69
+ barWidth?: number;
70
+ }): string;
71
+ export declare function table(headers: string[], rows: string[][]): string;
72
+ /**
73
+ * The thing that makes it visible that something is between the person and the
74
+ * provider.
75
+ *
76
+ * Without this, an instrumented session looks exactly like an uninstrumented
77
+ * one, and a product nobody can see is a product nobody renews. It shows the
78
+ * work as it happens - characterising, dispatching, recording - and then gets
79
+ * out of the way, leaving the answer and a one-line receipt.
80
+ */
81
+ export declare class LiveIndicator {
82
+ private timer;
83
+ private frame;
84
+ private label;
85
+ private readonly frames;
86
+ start(label: string): void;
87
+ update(label: string): void;
88
+ stop(): void;
89
+ }
90
+ export interface ReceiptData {
91
+ model: string;
92
+ tier: string;
93
+ signals: string[];
94
+ inputTokens: number | null;
95
+ outputTokens: number | null;
96
+ costUsd: number | null;
97
+ latencyMs: number;
98
+ attempts: number;
99
+ remediated: boolean;
100
+ wastedUsd: number | null;
101
+ withheld: string | null;
102
+ }
103
+ /**
104
+ * The receipt, rendered by the client and never injected into the conversation.
105
+ *
106
+ * Injected text is re-sent on every later turn, so a receipt in the message
107
+ * array is a line item the customer pays for again on every turn for the rest of
108
+ * the session. It belongs on the screen, not in the context window.
109
+ */
110
+ export declare function receipt(r: ReceiptData): string;
111
+ export declare function ok(msg: string): string;
112
+ export declare function warn(msg: string): string;
113
+ export declare function fail(msg: string): string;
114
+ export declare function info(msg: string): string;