@cesarus777/opencode-cgp 0.4.1 → 0.4.3

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/dist/tui.js CHANGED
@@ -1178,7 +1178,7 @@ function performanceLines(row2, width) {
1178
1178
  return [];
1179
1179
  const value = (n) => n === undefined ? "?" : n.toFixed(1);
1180
1180
  return [
1181
- ...wrap(`TPS ${p.status === "waiting" ? "waiting" : `${p.status === "streaming" ? "~" : ""}${value(p.liveTps)}`} \xB7 ${p.status}${p.partial ? " \xB7 partial" : ""}`, width),
1181
+ ...wrap(`Live TPS ${p.status === "waiting" ? "waiting" : `${p.status === "streaming" ? "~" : ""}${value(p.liveTps)}`} \xB7 ${p.status}${p.partial ? " \xB7 partial" : ""}`, width),
1182
1182
  ...wrap(`Avg model ${value(p.averageModelTps)} \xB7 Avg session ${value(p.averageSessionTps)}`, width),
1183
1183
  ...wrap(`TTFT ${p.ttftMs === undefined ? "?" : `~${(p.ttftMs / 1000).toFixed(2)}s`}${p.latestRequestTps === undefined ? "" : ` \xB7 Last ${value(p.latestRequestTps)} t/s`}`, width)
1184
1184
  ];
@@ -1242,6 +1242,7 @@ function panelRowLines(row2, width, selected) {
1242
1242
  `${pad(identity, Math.max(1, width - status.length - 1))} ${status}`,
1243
1243
  clip(`${percent} context \xB7 ${distance}`, width)
1244
1244
  ];
1245
+ lines.push(...performanceLines(row2, width));
1245
1246
  const exception = [
1246
1247
  freshnessLabel(row2),
1247
1248
  compactionLabel(row2),
@@ -2010,6 +2011,7 @@ function mainSections(row2, width, age) {
2010
2011
  lines: columns(row2.freshness === "stale" ? "Last measured" : "Context", `${m?.confidence === "approximate" && valid2 ? "~" : ""}${tokens(measured)} / ${tokens(s?.capacityTokens)}`, width)
2011
2012
  },
2012
2013
  { tone: "measurement", lines: [progress(ratio, width)] },
2014
+ { tone: "base", lines: performanceLines(row2, width) },
2013
2015
  {
2014
2016
  tone: "pressure",
2015
2017
  lines: [
@@ -2070,7 +2072,9 @@ function agentLines(row2, width) {
2070
2072
  const short = `${row2.freshness === "stale" ? "Last measured" : "Ctx"} ${estimate}${percent} \xB7 ${pressure === "Below threshold" ? "Threshold below" : pressure}`;
2071
2073
  const lifecycle = compactionLabel(row2);
2072
2074
  return [
2075
+ progress(valid2 && row2.utilizationPercent !== undefined ? row2.utilizationPercent / 100 : undefined, width),
2073
2076
  ...wrap(cells(full) <= width ? full : short, width),
2077
+ ...performanceLines(row2, width),
2074
2078
  ...row2.node.status === "failed" || row2.node.status === "unknown" ? wrap(row2.node.status.toUpperCase(), width) : [],
2075
2079
  ...row2.freshness !== "fresh" ? wrap(freshnessLabel(row2) ?? "", width) : [],
2076
2080
  ...row2.node.interrupted ? wrap("Interrupted", width) : [],
@@ -2184,12 +2188,12 @@ function CompactSidebar(props) {
2184
2188
  const width = () => Math.max(1, Math.min(props.width, measuredWidth()) - 4);
2185
2189
  const [collapsed, setCollapsed] = createSignal2(new Set);
2186
2190
  const [hideCompleted, setHideCompleted] = createSignal2(true);
2187
- const [showHistory, setShowHistory] = createSignal2(false);
2191
+ const [showHistory, setShowHistory] = createSignal2(true);
2188
2192
  const [byPressure, setByPressure] = createSignal2(true);
2189
2193
  createEffect(() => {
2190
2194
  props.sessionID;
2191
2195
  setCollapsed(new Set);
2192
- setShowHistory(false);
2196
+ setShowHistory(true);
2193
2197
  });
2194
2198
  const current = createMemo(() => props.rows.find((r) => r.node.sessionId === props.sessionID));
2195
2199
  const trace = createMemo(() => props.state.contextTrace(current()));
@@ -0,0 +1,40 @@
1
+ import { type HistoryFilter, type HistoryMetadata, type HistoryRecord, type ScanOptions } from "./history.js";
2
+ export interface ArchiveSnapshot {
3
+ revision: string;
4
+ metadata: HistoryMetadata;
5
+ records: HistoryRecord[];
6
+ iterateRecords?: () => Iterable<HistoryRecord>;
7
+ }
8
+ interface ArchiveOptions extends ScanOptions {
9
+ maxCacheBytes?: number;
10
+ maxCacheRecords?: number;
11
+ maxCacheSegments?: number;
12
+ }
13
+ /** Location-owned cache. Metadata validation assumes external writers do not restore timestamps. */
14
+ export declare class PerformanceArchive {
15
+ readonly path: string;
16
+ private readonly options;
17
+ private entries;
18
+ private generation;
19
+ private stopped;
20
+ private dirty;
21
+ private forcedGeneration;
22
+ private job;
23
+ readonly stats: {
24
+ readBytes: number;
25
+ parsedRecords: number;
26
+ cacheBytes: number;
27
+ cacheRecords: number;
28
+ };
29
+ constructor(path: string, options?: ArchiveOptions);
30
+ /** Writer notifications invalidate even metadata-invisible mutations. */
31
+ invalidate(name?: string): void;
32
+ dispose(): void;
33
+ private account;
34
+ private retain;
35
+ private validCapture;
36
+ private scan;
37
+ read(filter?: HistoryFilter): Promise<ArchiveSnapshot>;
38
+ private wait;
39
+ }
40
+ export {};
@@ -8,5 +8,5 @@ export * from "./snapshot.js";
8
8
  export * from "./family.js";
9
9
  export * from "./performance.js";
10
10
  export * from "./charts.js";
11
- export * from "./modelanalytics.js";
11
+ export { analyzeModelRequests, aggregateModels, summarizeModelRequests, type ModelAnalyticsOptions, type AnalyticsRequest, type ModelSummary, type ModelAnalyticsResult, type CompletedAnalyticsRequest, } from "./modelanalytics.js";
12
12
  export * from "./modelseries.js";
@@ -11,6 +11,7 @@ export interface DashboardControllerOptions {
11
11
  }
12
12
  /** Shared application state; subscribers never acquire additional upstream streams. */
13
13
  export declare class DashboardController {
14
+ private readonly snapshots;
14
15
  private readonly locations;
15
16
  private readonly cache;
16
17
  private readonly listeners;
@@ -14,4 +14,4 @@ export interface DashboardInventory {
14
14
  export declare const inventoryLimits: InventoryLimits;
15
15
  export declare function validateInventoryLimits(limits: InventoryLimits): void;
16
16
  /** Bounded breadth-first discovery of a whole location, without transcript reads. */
17
- export declare function discoverInventory(port: Pick<DashboardPort, "location" | "listSessions">, signal: AbortSignal, limits?: InventoryLimits): Promise<DashboardInventory>;
17
+ export declare function discoverInventory(port: Pick<DashboardPort, "location" | "listSessions">, signal: AbortSignal, limits?: InventoryLimits, progress?: (inventory: DashboardInventory) => void): Promise<DashboardInventory>;
@@ -12,6 +12,9 @@ export interface TerminalKey {
12
12
  export declare class TerminalShell {
13
13
  readonly controller: DashboardController;
14
14
  private readonly quit;
15
+ readonly work: {
16
+ formattedOverviewRows: number;
17
+ };
15
18
  scroll: number;
16
19
  metric: number;
17
20
  sample: number;
@@ -27,6 +30,9 @@ export declare class TerminalShell {
27
30
  private rowOffset;
28
31
  private overviewScope;
29
32
  private overviewPage;
33
+ private labelKey;
34
+ private labels;
35
+ private layouts;
30
36
  private historyIdentity;
31
37
  constructor(controller: DashboardController, quit: () => void);
32
38
  private task;
@@ -3,6 +3,8 @@ export declare function diagnosticRow(row: DashboardRow): string;
3
3
  export declare function overviewHeading(width: number): string[];
4
4
  /** Stable ID suffixes when unique; position is the bounded fallback. */
5
5
  export declare function overviewLabels(rows: readonly DashboardRow[]): string[];
6
+ /** Lightweight line count; identity clipping and exception text are viewport work. */
7
+ export declare function overviewRowHeight(row: DashboardRow, width: number, maxLines: number): number;
6
8
  /** Each row is already cell-bounded; overview cards never wrap diagnostics. */
7
9
  export declare function overviewRowLines(row: DashboardRow, width: number, selected: boolean, label: string, position: number, maxLines?: number): string[];
8
10
  export declare const snapshotFields: readonly ["sessionId", "parentId", "agent", "model", "revision", "observedAt", "measurement.tokens", "measurement.at", "measurement.model", "measurement.provenance", "measurement.scope", "measurement.confidence", "measurement.requestId", "limits.input", "limits.context", "limits.output", "capacityTokens", "outputReserveTokens", "peakTokens", "policy.id", "policy.configured.type", "policy.configured.value", "policy.triggerTokens", "policy.comparison", "policy.reason", "policy.crossed", "compaction.phase", "compaction.count", "compaction.armed", "compaction.blockedReason", "compaction.lastAttempt", "compaction.lastCompleted", "compaction.cooldownUntil", "cumulativeScope", "cumulative.input", "cumulative.output", "cumulative.reasoning", "cumulative.cache.read", "cumulative.cache.write", "lastObservedActive", "performance.sessionCreatedAt", "performance.sessionOutputTokens", "performance.observedSince", "performance.at", "performance.status", "performance.partial", "performance.liveTps", "performance.averageModelTps", "performance.averageSessionTps", "performance.ttftMs", "performance.latestRequestTps", "performance.requestId", "performance.requestAgent", "performance.requestModel", "performance.requestOutputTokens", "performance.requestStartedAt", "performance.firstOutputAt", "performance.streamEndedAt", "performance.estimatedOutputTokens", "performance.modelOutputTokens", "performance.modelDurationMs", "performance.completedRequests", "performance.tokenSource"];
@@ -79,7 +79,7 @@ export type DashboardView = Immutable<{
79
79
  models: DashboardModels;
80
80
  notices: readonly string[];
81
81
  }>;
82
- /** Clone before freezing so transport-owned objects never become UI-owned state. */
82
+ /** Copy transport objects once; already-owned immutable subtrees can be shared. */
83
83
  export declare function immutableView<T>(value: T): T;
84
84
  export declare function projectHistory(result: HistoryChartResult, filters: DashboardFilters): {
85
85
  result: HistoryChartResult;
@@ -1,3 +1,5 @@
1
+ import type { Stats } from "node:fs";
2
+ import { open } from "node:fs/promises";
1
3
  import type { Identity, Config } from "./types.js";
2
4
  import type { PerformanceSnapshot } from "./performance.js";
3
5
  export interface HistoryRecord extends Identity {
@@ -9,12 +11,47 @@ export interface HistoryRecord extends Identity {
9
11
  event?: string;
10
12
  droppedRecords?: number;
11
13
  }
14
+ export declare function segments(directory: string): Promise<{
15
+ bytes: number;
16
+ dev: number;
17
+ ino: number;
18
+ mtimeMs: number;
19
+ ctimeMs: number;
20
+ name: string;
21
+ time: number;
22
+ }[]>;
23
+ export declare function fileIdentity(info: Stats): {
24
+ bytes: number;
25
+ dev: number;
26
+ ino: number;
27
+ mtimeMs: number;
28
+ ctimeMs: number;
29
+ };
30
+ export interface ScanOptions {
31
+ now?: () => number;
32
+ yield?: () => Promise<void>;
33
+ chunkBytes?: number;
34
+ onRead?: (bytes: number) => void;
35
+ onParse?: () => void;
36
+ }
37
+ /** Cooperative scheduling is independent of cancellation. */
38
+ export declare function scanScheduler(signal?: AbortSignal, options?: ScanOptions): () => Promise<void> | undefined;
39
+ export declare function matchesHistory(value: HistoryRecord, filter: HistoryFilter): boolean;
40
+ /** Reads captured bytes only. Byte boundaries retain UTF-8 exactly, including tails. */
41
+ export declare function scanHistorySegment(handle: Awaited<ReturnType<typeof open>>, size: number, filter?: HistoryFilter, options?: ScanOptions, start?: number): Promise<{
42
+ records: HistoryRecord[];
43
+ malformedRecords: number;
44
+ boundary: number;
45
+ completeRecords: number;
46
+ completeMalformed: number;
47
+ }>;
12
48
  /** Separate bounded journal; the API accepts only projected scalar measurements. */
13
49
  export declare class PerformanceHistory {
14
50
  readonly path: string;
15
51
  private readonly config;
16
52
  private readonly now;
17
53
  private readonly report;
54
+ private readonly changed;
18
55
  private pending;
19
56
  private working;
20
57
  private active;
@@ -23,7 +60,7 @@ export declare class PerformanceHistory {
23
60
  private disabled;
24
61
  private dropped;
25
62
  private droppedTotal;
26
- constructor(path: string, config: Config["history"], now?: () => number, report?: (event: string) => void);
63
+ constructor(path: string, config: Config["history"], now?: () => number, report?: (event: string) => void, changed?: (name: string) => void);
27
64
  emit(record: HistoryRecord): void;
28
65
  private kick;
29
66
  private prune;
@@ -54,7 +91,7 @@ export interface HistoryMetadata {
54
91
  malformedRecords: number;
55
92
  completeness: string;
56
93
  }
57
- export declare function readPerformanceHistory(directory: string, filter?: HistoryFilter): Promise<{
94
+ export declare function readPerformanceHistory(directory: string, filter?: HistoryFilter, options?: ScanOptions): Promise<{
58
95
  metadata: HistoryMetadata;
59
96
  records: HistoryRecord[];
60
97
  }>;
@@ -1,7 +1,8 @@
1
+ import { readPerformanceHistory } from "./history.js";
1
2
  import { historyRpc } from "./rpc.js";
2
3
  import type { RpcHandlers, RpcRegistration } from "@opencode/plugin/promise/rpc";
3
4
  export interface HistoryRpcPort {
4
5
  register(definition: typeof historyRpc, handlers: RpcHandlers<typeof historyRpc>): Promise<Pick<RpcRegistration<typeof historyRpc>, "dispose">>;
5
6
  }
6
7
  /** Read-only archive service. Clients can select an ID/time range, never a filesystem path. */
7
- export declare function serveHistory(rpc: HistoryRpcPort | undefined, path: string, enabled: boolean, now?: () => number, authorize?: (sessionId: string, signal: AbortSignal) => Promise<boolean>): Promise<() => void>;
8
+ export declare function serveHistory(rpc: HistoryRpcPort | undefined, path: string, enabled: boolean, now?: () => number, authorize?: (sessionId: string, signal: AbortSignal) => Promise<boolean>, reader?: typeof readPerformanceHistory): Promise<() => void>;
@@ -60,9 +60,20 @@ export interface ModelAnalyticsResult {
60
60
  export declare function analyzeModelRequests(records: readonly HistoryRecord[], options: ModelAnalyticsOptions): ModelAnalyticsResult & {
61
61
  requests: CompletedAnalyticsRequest[];
62
62
  };
63
+ /** Canonical reconciliation state, shared by full and proven-prefix append paths. */
64
+ export declare function createModelAccumulator(options: ModelAnalyticsOptions): {
65
+ append: (records: readonly HistoryRecord[]) => void;
66
+ steps: () => Generator<void, ModelAnalyticsResult & {
67
+ requests: CompletedAnalyticsRequest[];
68
+ }>;
69
+ result: () => ModelAnalyticsResult & {
70
+ requests: CompletedAnalyticsRequest[];
71
+ };
72
+ };
63
73
  export interface CompletedAnalyticsRequest extends AnalyticsRequest {
64
74
  completedAt: number;
65
75
  }
66
76
  /** Summarize already reconciled requests, including independent metric eligibility. */
67
77
  export declare function summarizeModelRequests(requests: readonly CompletedAnalyticsRequest[]): ModelSummary[];
78
+ export declare function summarizeModelRequestSteps(requests: readonly CompletedAnalyticsRequest[]): Generator<void, ModelSummary[]>;
68
79
  export declare function aggregateModels(records: readonly HistoryRecord[], options: ModelAnalyticsOptions): ModelAnalyticsResult;
@@ -9,8 +9,9 @@ export interface AnalyticsRpcPort {
9
9
  export declare function createAnalyticsService(path: string, location: string, enabled: boolean, options?: {
10
10
  now?: () => number;
11
11
  read?: typeof readPerformanceHistory;
12
+ revisioned?: boolean;
12
13
  }): {
13
14
  read(input: AnalyticsRead, signal: AbortSignal): Promise<AnalyticsResult>;
14
15
  dispose(): void;
15
16
  };
16
- export declare function serveModelAnalytics(port: AnalyticsRpcPort | undefined, path: string, location: string, enabled: boolean): Promise<() => void>;
17
+ export declare function serveModelAnalytics(port: AnalyticsRpcPort | undefined, path: string, location: string, enabled: boolean, options?: Parameters<typeof createAnalyticsService>[3]): Promise<() => void>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cesarus777/opencode-cgp",
3
- "version": "0.4.1",
3
+ "version": "0.4.3",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
@@ -38,6 +38,7 @@
38
38
  "format:check": "prettier --check src tests scripts docs README.md examples package.json tsconfig.json server.ts tui.tsx rpc.ts tsconfig.build.json .github AGENTS.md",
39
39
  "test:tui-live": "bun scripts/tui-live.ts",
40
40
  "bench:tui": "bun scripts/tui-bench.ts",
41
+ "bench:dashboard": "bun scripts/dashboard-bench.ts",
41
42
  "build": "bun scripts/build.ts",
42
43
  "prepack": "bun run build",
43
44
  "prepare": "bun run build",