@cesarus777/opencode-cgp 0.1.0 → 0.2.2

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.
@@ -1,8 +1,10 @@
1
+ import { type HistoryRpcPort } from "./historyserver.js";
1
2
  import { type SnapshotRpcPort } from "./snapshotserver.js";
2
3
  import type { Plugin } from "@opencode/plugin";
3
4
  import type { TelemetrySink } from "./types.js";
4
5
  export interface Host {
5
6
  rpc?: SnapshotRpcPort;
7
+ historyRpc?: HistoryRpcPort;
6
8
  app: {
7
9
  version: string;
8
10
  };
@@ -0,0 +1,14 @@
1
+ import type { ChartData } from "./charts.js";
2
+ import type { readPerformanceHistory } from "./history.js";
3
+ type ReportMetadata = Awaited<ReturnType<typeof readPerformanceHistory>>["metadata"];
4
+ interface ChartReport {
5
+ data: ChartData;
6
+ metadata: ReportMetadata;
7
+ agent?: string;
8
+ model?: string;
9
+ from?: number;
10
+ to?: number;
11
+ }
12
+ /** Offline, self-contained SVG report. Generated identities only enter text nodes or escaped JSON. */
13
+ export declare function renderChartReport(report: ChartReport): string;
14
+ export {};
@@ -0,0 +1,54 @@
1
+ import type { HistoryRecord } from "./history.js";
2
+ export interface ChartPoint {
3
+ time: number;
4
+ agent?: string;
5
+ model?: string;
6
+ breakBefore: boolean;
7
+ partial: boolean;
8
+ liveTps?: number;
9
+ averageModelTps?: number;
10
+ averageSessionTps?: number;
11
+ sessionOutputTokens?: number;
12
+ }
13
+ export interface ChartRequest {
14
+ time: number;
15
+ requestId: string;
16
+ started: number;
17
+ agent?: string;
18
+ model?: string;
19
+ ttftMs?: number;
20
+ outputTokens?: number;
21
+ durationMs?: number;
22
+ tps?: number;
23
+ partial: boolean;
24
+ }
25
+ export interface ChartSeries {
26
+ sessionId: string;
27
+ parentId?: string;
28
+ agents: string[];
29
+ models: string[];
30
+ points: ChartPoint[];
31
+ requests: ChartRequest[];
32
+ originalPoints: number;
33
+ }
34
+ export interface ChartGap {
35
+ time: number;
36
+ sessionId: string;
37
+ reason: string;
38
+ }
39
+ export interface ChartData {
40
+ schema: 1;
41
+ series: ChartSeries[];
42
+ gaps: ChartGap[];
43
+ omittedSessions: number;
44
+ omittedGaps?: number;
45
+ maxPoints: number;
46
+ }
47
+ export interface ChartOptions {
48
+ sessionId?: string;
49
+ maxPoints?: number;
50
+ maxSessions?: number;
51
+ }
52
+ /** Preserve actual timestamps and extrema; never average a bucket's rates or bridge a gap. */
53
+ export declare function downsamplePoints(points: readonly ChartPoint[], limit: number): ChartPoint[];
54
+ export declare function buildChartData(records: readonly HistoryRecord[], options?: ChartOptions): ChartData;
@@ -6,3 +6,5 @@ export * from "./scheduler.js";
6
6
  export * from "./estimate.js";
7
7
  export * from "./snapshot.js";
8
8
  export * from "./family.js";
9
+ export * from "./performance.js";
10
+ export * from "./charts.js";
@@ -24,7 +24,7 @@ export declare function metric(snapshot: ContextSnapshot | undefined, now: numbe
24
24
  readonly triggerDeltaTokens?: number;
25
25
  readonly utilizationPercent?: number;
26
26
  readonly pressureRatio?: number;
27
- readonly freshness: "fresh" | "stale" | "missing" | "invalid";
27
+ readonly freshness: "invalid" | "fresh" | "stale" | "missing";
28
28
  readonly pressure: "unknown" | "crossed" | "normal" | "near";
29
29
  };
30
30
  export declare function familyRows(nodes: readonly SessionNode[], snapshots: ReadonlyMap<string, ContextSnapshot>, current: string, now: number, staleMs: number, expanded?: ReadonlySet<string>, limit?: number, timing?: (id: string) => {
@@ -0,0 +1,59 @@
1
+ import type { Identity, Config } from "./types.js";
2
+ import type { PerformanceSnapshot } from "./performance.js";
3
+ export interface HistoryRecord extends Identity {
4
+ schema: 1;
5
+ recordId: string;
6
+ time: number;
7
+ type: "sample" | "request" | "lifecycle" | "gap" | "terminal";
8
+ performance?: PerformanceSnapshot;
9
+ event?: string;
10
+ droppedRecords?: number;
11
+ }
12
+ /** Separate bounded journal; the API accepts only projected scalar measurements. */
13
+ export declare class PerformanceHistory {
14
+ readonly path: string;
15
+ private readonly config;
16
+ private readonly now;
17
+ private readonly report;
18
+ private pending;
19
+ private working;
20
+ private active;
21
+ private bytes;
22
+ private started;
23
+ private disabled;
24
+ private dropped;
25
+ private droppedTotal;
26
+ constructor(path: string, config: Config["history"], now?: () => number, report?: (event: string) => void);
27
+ emit(record: HistoryRecord): void;
28
+ private kick;
29
+ private prune;
30
+ private gapLine;
31
+ private drain;
32
+ health(): {
33
+ unavailable: boolean;
34
+ droppedRecords: number;
35
+ };
36
+ flush(): Promise<void>;
37
+ initialize(): Promise<void>;
38
+ }
39
+ export declare function scalarPerformance(p: PerformanceSnapshot): PerformanceSnapshot;
40
+ export interface HistoryFilter {
41
+ sessionId?: string;
42
+ agent?: string;
43
+ model?: string;
44
+ from?: number;
45
+ to?: number;
46
+ maxBytes?: number;
47
+ }
48
+ export interface HistoryMetadata {
49
+ schema: number;
50
+ retainedFrom?: number;
51
+ retainedBytes: number;
52
+ skippedBytes: number;
53
+ malformedRecords: number;
54
+ completeness: string;
55
+ }
56
+ export declare function readPerformanceHistory(directory: string, filter?: HistoryFilter): Promise<{
57
+ metadata: HistoryMetadata;
58
+ records: HistoryRecord[];
59
+ }>;
@@ -0,0 +1,17 @@
1
+ import type { ChartData } from "./charts.js";
2
+ import type { readPerformanceHistory } from "./history.js";
3
+ export interface HistoryChartRead {
4
+ schemaVersion: 1;
5
+ sessionId: string;
6
+ from: number;
7
+ to: number;
8
+ maxPoints: number;
9
+ }
10
+ export interface HistoryChartResult {
11
+ schemaVersion: 1;
12
+ generatedAt: number;
13
+ enabled: boolean;
14
+ truncated: boolean;
15
+ metadata: Awaited<ReturnType<typeof readPerformanceHistory>>["metadata"];
16
+ data: ChartData;
17
+ }
@@ -0,0 +1,7 @@
1
+ import { historyRpc } from "./rpc.js";
2
+ import type { RpcHandlers, RpcRegistration } from "@opencode/plugin/promise/rpc";
3
+ export interface HistoryRpcPort {
4
+ register(definition: typeof historyRpc, handlers: RpcHandlers<typeof historyRpc>): Promise<Pick<RpcRegistration<typeof historyRpc>, "dispose">>;
5
+ }
6
+ /** 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>;
@@ -0,0 +1,57 @@
1
+ import type { Tokens } from "./types.js";
2
+ export interface PerformanceSnapshot {
3
+ readonly sessionCreatedAt: number;
4
+ readonly sessionOutputTokens?: number;
5
+ readonly observedSince: number;
6
+ readonly at: number;
7
+ readonly status: "waiting" | "streaming" | "idle" | "unavailable";
8
+ readonly partial: boolean;
9
+ readonly liveTps?: number;
10
+ readonly averageModelTps?: number;
11
+ readonly averageSessionTps?: number;
12
+ readonly ttftMs?: number;
13
+ readonly latestRequestTps?: number;
14
+ readonly requestId?: string;
15
+ readonly requestAgent?: string;
16
+ readonly requestModel?: string;
17
+ readonly requestOutputTokens?: number;
18
+ readonly requestStartedAt?: number;
19
+ readonly firstOutputAt?: number;
20
+ readonly streamEndedAt?: number;
21
+ readonly estimatedOutputTokens: number;
22
+ readonly modelOutputTokens: number;
23
+ readonly modelDurationMs: number;
24
+ readonly completedRequests: number;
25
+ readonly tokenSource: "estimated" | "reported" | "unavailable";
26
+ }
27
+ export interface PerformanceCheckpoint {
28
+ sessionId: string;
29
+ observedSince: number;
30
+ created: number;
31
+ output: number;
32
+ duration: number;
33
+ completed: number;
34
+ sequence: number;
35
+ }
36
+ export declare function outputTokens(tokens: Pick<Tokens, "output" | "reasoning">): number | undefined;
37
+ /** Scalar-only collection. No harness types or generated content are retained. */
38
+ export declare class PerformanceTracker {
39
+ private readonly maxSessions;
40
+ private readonly windowMs;
41
+ private readonly now;
42
+ private rows;
43
+ constructor(maxSessions: number, windowMs?: number, now?: () => number);
44
+ observe(id: string, created: number, cumulative: number | undefined): void;
45
+ accept(id: string, sequence: number): boolean;
46
+ start(id: string, requestId: string, agent: string, model: string, started: number): void;
47
+ delta(id: string, requestId: string, eventId: string, at: number, characters: number): void;
48
+ streamed(id: string, requestId: string, at: number): void;
49
+ settle(id: string, requestId: string, tokens: number | undefined): void;
50
+ gap(id?: string): void;
51
+ private prune;
52
+ snapshot(id: string): PerformanceSnapshot | undefined;
53
+ checkpoint(): PerformanceCheckpoint[];
54
+ restore(value: unknown): void;
55
+ remove(id: string): void;
56
+ ids(): MapIterator<string>;
57
+ }
@@ -46,6 +46,84 @@ export declare const monitorRpc: {
46
46
  };
47
47
  };
48
48
  };
49
+ export declare const performanceSchema: {
50
+ type: "object";
51
+ properties: Record<string, object>;
52
+ required: string[];
53
+ additionalProperties: boolean;
54
+ };
55
+ export declare const performanceBatchSchema: {
56
+ type: "object";
57
+ properties: Record<string, object>;
58
+ required: string[];
59
+ additionalProperties: boolean;
60
+ };
61
+ export declare const performanceResultSchema: {
62
+ type: "object";
63
+ properties: Record<string, object>;
64
+ required: string[];
65
+ additionalProperties: boolean;
66
+ };
67
+ export declare const performanceRpc: {
68
+ readonly id: "context-guard.monitor.v2";
69
+ readonly methods: {
70
+ readonly read: {
71
+ readonly input: {
72
+ type: "object";
73
+ properties: Record<string, object>;
74
+ required: string[];
75
+ additionalProperties: boolean;
76
+ };
77
+ readonly output: {
78
+ type: "object";
79
+ properties: Record<string, object>;
80
+ required: string[];
81
+ additionalProperties: boolean;
82
+ };
83
+ };
84
+ };
85
+ readonly events: {
86
+ readonly changed: {
87
+ readonly schema: {
88
+ type: "object";
89
+ properties: Record<string, object>;
90
+ required: string[];
91
+ additionalProperties: boolean;
92
+ };
93
+ };
94
+ };
95
+ };
96
+ export declare function isPerformanceBatch(value: unknown): value is SnapshotBatch;
97
+ export declare function isPerformanceResult(value: unknown): value is SnapshotReadResult;
98
+ export declare function isPerformanceSnapshot(value: unknown): value is import("./performance.js").PerformanceSnapshot;
99
+ export declare const historyReadSchema: {
100
+ type: "object";
101
+ properties: Record<string, object>;
102
+ required: string[];
103
+ additionalProperties: boolean;
104
+ };
105
+ export declare const historyRpc: {
106
+ readonly id: "context-guard.history.v1";
107
+ readonly methods: {
108
+ readonly read: {
109
+ readonly input: {
110
+ type: "object";
111
+ properties: Record<string, object>;
112
+ required: string[];
113
+ additionalProperties: boolean;
114
+ };
115
+ readonly output: {
116
+ type: "object";
117
+ properties: Record<string, object>;
118
+ required: string[];
119
+ additionalProperties: boolean;
120
+ };
121
+ };
122
+ };
123
+ readonly events: {};
124
+ };
125
+ export declare function isHistoryRead(value: unknown): value is import("./historycharts.js").HistoryChartRead;
126
+ export declare function isHistoryResult(value: unknown): value is import("./historycharts.js").HistoryChartResult;
49
127
  export declare function isRead(value: unknown): value is SnapshotRead;
50
128
  export declare function isBatch(value: unknown): value is SnapshotBatch;
51
129
  export declare function isResult(value: unknown): value is SnapshotReadResult;
@@ -1,5 +1,7 @@
1
+ import type { PerformanceSnapshot } from "./performance.js";
1
2
  import type { Config, SessionState, Measurement, ModelLimits, Threshold, Tokens, CompactionPhase } from "./types.js";
2
3
  export interface ContextSnapshot {
4
+ readonly performance?: PerformanceSnapshot;
3
5
  readonly sessionId: string;
4
6
  readonly revision: number;
5
7
  readonly observedAt: number;
@@ -72,6 +74,7 @@ export declare class SnapshotStore {
72
74
  private readonly config;
73
75
  private readonly sessions;
74
76
  private readonly now;
77
+ private readonly performanceSnapshot?;
75
78
  readonly epoch: string;
76
79
  private sequence;
77
80
  private revision;
@@ -81,7 +84,7 @@ export declare class SnapshotStore {
81
84
  private listeners;
82
85
  private healthKey;
83
86
  private reasons;
84
- constructor(config: Config, sessions: () => ReadonlyMap<string, SessionState>, now?: () => number, epoch?: string);
87
+ constructor(config: Config, sessions: () => ReadonlyMap<string, SessionState>, now?: () => number, epoch?: string, performanceSnapshot?: ((id: string) => PerformanceSnapshot | undefined) | undefined);
85
88
  health(): MonitorHealth;
86
89
  degrade(reason: "event-stream-gap" | "persistence-unavailable" | "capacity-exceeded" | "model-metadata-unavailable"): void;
87
90
  recover(reason: "capacity-exceeded" | "model-metadata-unavailable"): void;
@@ -1,7 +1,7 @@
1
1
  import type { RpcHandlers, RpcRegistration } from "@opencode/plugin/promise/rpc";
2
2
  export interface SnapshotRpcPort {
3
- register(definition: typeof monitorRpc, handlers: RpcHandlers<typeof monitorRpc>): Promise<RpcRegistration<typeof monitorRpc>>;
3
+ register(definition: typeof monitorRpc | typeof performanceRpc, handlers: RpcHandlers<typeof monitorRpc>): Promise<RpcRegistration<typeof monitorRpc>>;
4
4
  }
5
- import { monitorRpc } from "./rpc.js";
5
+ import { monitorRpc, performanceRpc } from "./rpc.js";
6
6
  import type { SnapshotStore } from "./snapshot.js";
7
- export declare function serveSnapshots(rpc: SnapshotRpcPort | undefined, store: SnapshotStore): Promise<() => void>;
7
+ export declare function serveSnapshots(rpc: SnapshotRpcPort | undefined, store: SnapshotStore, performance?: boolean): Promise<() => void>;
@@ -0,0 +1,46 @@
1
+ import type { HistoryChartResult } from "../historycharts.js";
2
+ export declare function sparkline(points: readonly {
3
+ time: number;
4
+ value?: number;
5
+ }[], from: number, to: number, width: number, gaps?: readonly number[]): {
6
+ line: string;
7
+ min?: number;
8
+ max?: number;
9
+ };
10
+ export declare const chartMetrics: readonly [{
11
+ readonly label: "Live TPS ~";
12
+ readonly unit: "t/s";
13
+ readonly key: "liveTps";
14
+ readonly source: "points";
15
+ }, {
16
+ readonly label: "Avg model";
17
+ readonly unit: "t/s";
18
+ readonly key: "averageModelTps";
19
+ readonly source: "points";
20
+ }, {
21
+ readonly label: "Avg session";
22
+ readonly unit: "t/s";
23
+ readonly key: "averageSessionTps";
24
+ readonly source: "points";
25
+ }, {
26
+ readonly label: "TTFT ~";
27
+ readonly unit: "s";
28
+ readonly key: "ttftMs";
29
+ readonly source: "requests";
30
+ }, {
31
+ readonly label: "Request throughput";
32
+ readonly unit: "t/s";
33
+ readonly key: "tps";
34
+ readonly source: "requests";
35
+ }, {
36
+ readonly label: "Cumulative output";
37
+ readonly unit: "tokens";
38
+ readonly key: "sessionOutputTokens";
39
+ readonly source: "points";
40
+ }];
41
+ /** Plot only observed column peaks; leave missing data and gaps disconnected. */
42
+ export declare function metricPlot(points: readonly {
43
+ time: number;
44
+ value?: number;
45
+ }[], from: number, to: number, width: number, gaps?: readonly number[]): string[];
46
+ export declare function historyChartLines(result: HistoryChartResult, width: number, from: number, to: number, metricIndex?: number): string[];
@@ -0,0 +1,11 @@
1
+ import type { Plugin } from "@opencode/plugin/tui";
2
+ import type { GuardState } from "./state.js";
3
+ export declare function HistoryCharts(props: {
4
+ sessionId: string;
5
+ windowMs: number;
6
+ metricIndex: number;
7
+ refresh: number;
8
+ width: number;
9
+ state: GuardState;
10
+ context: Plugin.Context;
11
+ }): import("solid-js").JSX.Element;
@@ -1,12 +1,13 @@
1
+ import { type ContextSample } from "./contextchart.js";
1
2
  import type { GuardRow } from "../family.js";
2
3
  export declare function tokens(value: number | undefined): string;
3
4
  export declare function columns(left: string, right: string, width: number): string[];
4
5
  export declare function progress(ratio: number | undefined, width: number): string;
5
6
  export interface MainSection {
6
- readonly tone: "base" | "execution" | "pressure" | "measurement";
7
+ readonly tone: "base" | "execution" | "pressure" | "measurement" | "threshold";
7
8
  readonly lines: readonly string[];
8
9
  }
9
- export declare function mainSections(row: GuardRow | undefined, width: number, age: number): MainSection[];
10
+ export declare function mainSections(row: GuardRow | undefined, width: number, age: number, samples?: readonly ContextSample[]): MainSection[];
10
11
  export declare function mainLines(row: GuardRow | undefined, width: number, age: number): string[];
11
12
  export declare const statusSymbol: {
12
13
  readonly running: "●";
@@ -0,0 +1,19 @@
1
+ import type { GuardRow } from "../family.js";
2
+ export interface ContextSample {
3
+ readonly at: number;
4
+ readonly tokens?: number;
5
+ }
6
+ export interface ContextTrace {
7
+ readonly sessionId: string;
8
+ readonly model: string | undefined;
9
+ readonly capacity: number | undefined;
10
+ readonly samples: readonly ContextSample[];
11
+ }
12
+ /** Keep only actual measurements, never copies made by age/render ticks. */
13
+ export declare function updateContextTrace(previous: ContextTrace | undefined, row: GuardRow | undefined): ContextTrace;
14
+ export interface ContextChartLine {
15
+ readonly line: string;
16
+ readonly threshold: boolean;
17
+ }
18
+ /** Fixed capacity scale and observation order; no interpolation across missing samples. */
19
+ export declare function contextChart(samples: readonly ContextSample[], capacity: number | undefined, trigger: number | undefined, width: number): ContextChartLine[];
@@ -5,3 +5,4 @@ export declare function clip(value: string, width: number): string;
5
5
  export declare function rowLines(row: GuardRow, width: number): string[];
6
6
  export declare function detailLines(row: GuardRow | undefined, width: number, expanded?: boolean, ageMs?: number): string[];
7
7
  export declare function wrap(value: string, width: number): string[];
8
+ export declare function performanceLines(row: GuardRow, width: number): string[];
@@ -5,6 +5,7 @@ export declare function createGuardState(context: Plugin.Context): {
5
5
  update(next: string): void;
6
6
  release(): void;
7
7
  };
8
+ history(id: string, from: number, to: number, signal: AbortSignal): Promise<import("../historycharts.js").HistoryChartResult>;
8
9
  rows: (stableOrder?: readonly string[], allDescendants?: boolean) => import("../family.js").GuardRow[];
9
10
  dispose: () => void;
10
11
  age(id: string): number;
@@ -28,6 +28,17 @@ export interface Config {
28
28
  sessionTtlMs: number;
29
29
  outputReserveTokens?: number;
30
30
  };
31
+ metrics: {
32
+ enabled: boolean;
33
+ sampleIntervalMs: number;
34
+ rollingWindowMs: number;
35
+ };
36
+ history: {
37
+ enabled: boolean;
38
+ retentionDays: number;
39
+ maxBytes: number;
40
+ path?: string;
41
+ };
31
42
  telemetry: {
32
43
  enabled: boolean;
33
44
  jsonl: boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cesarus777/opencode-cgp",
3
- "version": "0.1.0",
3
+ "version": "0.2.2",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
@@ -42,7 +42,10 @@
42
42
  "prepack": "bun run build",
43
43
  "prepare": "bun run build",
44
44
  "test:package": "bun scripts/package-smoke.ts",
45
- "validate": "bun run format:check && bun run typecheck && bun test && bun run test:package"
45
+ "validate": "bun run format:check && bun run typecheck && bun test && bun run test:package",
46
+ "test:metrics-live": "bun scripts/metrics-live.ts",
47
+ "charts": "bun src/cli.ts charts",
48
+ "test:metrics-server-live": "bun scripts/metrics-server-live.ts"
46
49
  },
47
50
  "dependencies": {
48
51
  "@opencode/plugin": "2.0.29",
@@ -102,5 +105,8 @@
102
105
  "dist",
103
106
  "LICENSE",
104
107
  "README.md"
105
- ]
108
+ ],
109
+ "bin": {
110
+ "context-guard": "./dist/cli.js"
111
+ }
106
112
  }