@danypops/jittor 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.
@@ -0,0 +1,232 @@
1
+ import { isAbsolute, relative, resolve, sep } from "node:path";
2
+ import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
3
+ import { truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
4
+ import {
5
+ FOOTER_BAR_MAX_WIDTH,
6
+ FOOTER_BAR_MIN_WIDTH,
7
+ FOOTER_CONTEXT_ACCENT_FRACTION,
8
+ FOOTER_CONTEXT_ERROR_FRACTION,
9
+ FOOTER_CONTEXT_WARNING_FRACTION,
10
+ FOOTER_WIDE_TERMINAL_WIDTH,
11
+ TELEMETRY_STALE_AFTER_MS,
12
+ } from "../../src/constants.ts";
13
+
14
+ type FooterColor = "accent" | "dim" | "warning" | "error";
15
+
16
+ interface FooterTheme {
17
+ fg(color: FooterColor, text: string): string;
18
+ bold(text: string): string;
19
+ }
20
+
21
+ interface FooterData {
22
+ getGitBranch(): string | null | undefined;
23
+ getAvailableProviderCount(): number;
24
+ getExtensionStatuses(): ReadonlyMap<string, string>;
25
+ onBranchChange?(callback: () => void): () => void;
26
+ }
27
+
28
+ interface ContextUsage {
29
+ tokens: number | null;
30
+ percent: number | null;
31
+ contextWindow: number;
32
+ }
33
+
34
+ interface FooterContext {
35
+ model?: { provider: string; id: string; reasoning?: boolean; contextWindow?: number };
36
+ modelRegistry: { isUsingOAuth(model: unknown): boolean };
37
+ getContextUsage(): ContextUsage | undefined;
38
+ sessionManager: {
39
+ getCwd(): string;
40
+ getSessionName(): string | undefined;
41
+ getEntries(): Array<{ type: string; message?: any }>;
42
+ };
43
+ }
44
+
45
+ /** A provider usage value suitable for the footer. Null fraction means no known denominator. */
46
+ export interface ProviderBudget {
47
+ label: string;
48
+ fraction: number | null;
49
+ valueText: string;
50
+ observedAt?: number;
51
+ }
52
+
53
+ interface UsageTotals {
54
+ input: number;
55
+ output: number;
56
+ cacheRead: number;
57
+ cacheWrite: number;
58
+ cost: number;
59
+ cacheHit?: number;
60
+ }
61
+
62
+ function formatTokens(count: number): string {
63
+ if (count < 1_000) return count.toString();
64
+ if (count < 10_000) return `${(count / 1_000).toFixed(1)}k`;
65
+ if (count < 1_000_000) return `${Math.round(count / 1_000)}k`;
66
+ if (count < 10_000_000) return `${(count / 1_000_000).toFixed(1)}M`;
67
+ return `${Math.round(count / 1_000_000)}M`;
68
+ }
69
+
70
+ function footerCwd(cwd: string, home: string | undefined): string {
71
+ if (!home) return cwd;
72
+ const resolvedCwd = resolve(cwd);
73
+ const resolvedHome = resolve(home);
74
+ const relativeToHome = relative(resolvedHome, resolvedCwd);
75
+ const inside = relativeToHome === "" || (relativeToHome !== ".." && !relativeToHome.startsWith(`..${sep}`) && !isAbsolute(relativeToHome));
76
+ if (!inside) return cwd;
77
+ return relativeToHome === "" ? "~" : `~${sep}${relativeToHome}`;
78
+ }
79
+
80
+ function sanitize(value: string): string {
81
+ return value.replace(/[\r\n\t]/g, " ").replace(/ +/g, " ").trim();
82
+ }
83
+
84
+ function usageTotals(context: FooterContext): UsageTotals {
85
+ let input = 0, output = 0, cacheRead = 0, cacheWrite = 0, cost = 0, cacheHit: number | undefined;
86
+ for (const entry of context.sessionManager.getEntries()) {
87
+ if (entry.type !== "message" || entry.message?.role !== "assistant") continue;
88
+ const usage = entry.message.usage;
89
+ input += usage?.input ?? 0;
90
+ output += usage?.output ?? 0;
91
+ cacheRead += usage?.cacheRead ?? 0;
92
+ cacheWrite += usage?.cacheWrite ?? 0;
93
+ cost += usage?.cost?.total ?? 0;
94
+ const prompt = (usage?.input ?? 0) + (usage?.cacheRead ?? 0) + (usage?.cacheWrite ?? 0);
95
+ if (prompt > 0) cacheHit = (usage.cacheRead ?? 0) / prompt * 100;
96
+ }
97
+ return { input, output, cacheRead, cacheWrite, cost, ...(cacheHit === undefined ? {} : { cacheHit }) };
98
+ }
99
+
100
+ function barWidth(width: number): number {
101
+ return width >= FOOTER_WIDE_TERMINAL_WIDTH ? FOOTER_BAR_MAX_WIDTH : FOOTER_BAR_MIN_WIDTH;
102
+ }
103
+
104
+ function progressBar(fraction: number | null, width: number): string {
105
+ if (fraction === null || !Number.isFinite(fraction)) return "░".repeat(width);
106
+ const clamped = Math.min(1, Math.max(0, fraction));
107
+ const filled = Math.round(width * clamped);
108
+ return "█".repeat(filled) + "░".repeat(width - filled);
109
+ }
110
+
111
+ function fillColor(fraction: number | null): FooterColor {
112
+ if (fraction === null || !Number.isFinite(fraction)) return "dim";
113
+ if (fraction > FOOTER_CONTEXT_ERROR_FRACTION) return "error";
114
+ if (fraction > FOOTER_CONTEXT_WARNING_FRACTION) return "warning";
115
+ if (fraction > FOOTER_CONTEXT_ACCENT_FRACTION) return "accent";
116
+ return "dim";
117
+ }
118
+
119
+ function contextSegment(context: FooterContext, theme: FooterTheme, width: number, compact: boolean): string {
120
+ const usage = context.getContextUsage();
121
+ const window = usage?.contextWindow ?? context.model?.contextWindow ?? 0;
122
+ const fraction = usage?.percent === null || usage?.percent === undefined ? null : usage.percent / 100;
123
+ const bar = theme.fg(fillColor(fraction), progressBar(fraction, barWidth(width)));
124
+ if (usage?.tokens === null || usage?.tokens === undefined) return `ctx ${bar} ?/${formatTokens(window)}`;
125
+ const value = compact ? `${Math.round((fraction ?? 0) * 100)}%` : `${formatTokens(usage.tokens)}/${formatTokens(window)}`;
126
+ return `ctx ${bar} ${value}`;
127
+ }
128
+
129
+ function budgetSegment(budget: ProviderBudget | null, theme: FooterTheme, width: number, compact: boolean, now: number): string {
130
+ const w = barWidth(width);
131
+ if (!budget) return `budget ${theme.fg("dim", progressBar(null, w))} ?`;
132
+ if (budget.fraction === null) return `${budget.label} ${budget.valueText}`;
133
+ const bar = theme.fg(fillColor(budget.fraction), progressBar(budget.fraction, w));
134
+ const value = compact ? `${Math.round(budget.fraction * 100)}%` : budget.valueText;
135
+ const stale = budget.observedAt !== undefined && now - budget.observedAt > TELEMETRY_STALE_AFTER_MS;
136
+ return `${budget.label} ${bar} ${value}${stale ? ` ${theme.fg("warning", "stale")}` : ""}`;
137
+ }
138
+
139
+ function usageSegment(context: FooterContext): string {
140
+ const totals = usageTotals(context);
141
+ const parts: string[] = [];
142
+ if (totals.input) parts.push(`↑${formatTokens(totals.input)}`);
143
+ if (totals.output) parts.push(`↓${formatTokens(totals.output)}`);
144
+ if (totals.cacheRead) parts.push(`R${formatTokens(totals.cacheRead)}`);
145
+ if (totals.cacheWrite) parts.push(`W${formatTokens(totals.cacheWrite)}`);
146
+ if ((totals.cacheRead || totals.cacheWrite) && totals.cacheHit !== undefined) parts.push(`CH${totals.cacheHit.toFixed(1)}%`);
147
+ if (totals.cost || (context.model && context.modelRegistry.isUsingOAuth(context.model))) {
148
+ parts.push(`$${totals.cost.toFixed(3)}${context.model && context.modelRegistry.isUsingOAuth(context.model) ? " (sub)" : ""}`);
149
+ }
150
+ return parts.join(" ");
151
+ }
152
+
153
+ function identityLines(context: FooterContext, footerData: FooterData, theme: FooterTheme, thinkingLevel: string, width: number): string[] {
154
+ let cwd = footerCwd(context.sessionManager.getCwd(), process.env.HOME ?? process.env.USERPROFILE);
155
+ const branch = footerData.getGitBranch();
156
+ if (branch) cwd += ` (${branch})`;
157
+ const sessionName = context.sessionManager.getSessionName();
158
+ if (sessionName) cwd += ` · ${sessionName}`;
159
+ const repo = `${theme.bold("Repo")} ${theme.fg("dim", cwd)}`;
160
+
161
+ const model = context.model;
162
+ const provider = model && footerData.getAvailableProviderCount() > 1 ? `(${model.provider}) ` : "";
163
+ const thinking = model?.reasoning ? ` · ${thinkingLevel === "off" ? "thinking off" : thinkingLevel}` : "";
164
+ const ai = `${theme.bold("AI")} ${provider}${model?.id ?? "no-model"}${thinking}`;
165
+ const gap = width - visibleWidth(repo) - visibleWidth(ai);
166
+ if (gap >= 2) return [`${repo}${" ".repeat(gap)}${ai}`];
167
+ return [truncateToWidth(repo, width, "…"), truncateToWidth(ai, width, "…")];
168
+ }
169
+
170
+ function statusLines(context: FooterContext, budget: ProviderBudget | null, theme: FooterTheme, width: number, now: number): string[] {
171
+ const usage = usageSegment(context);
172
+ const fullContext = contextSegment(context, theme, width, false);
173
+ const fullBudget = budgetSegment(budget, theme, width, false, now);
174
+ const fullParts = [usage, fullContext, fullBudget].filter(Boolean);
175
+ const full = `${theme.bold("LLM")} ${fullParts.join(" · ")}`;
176
+ if (visibleWidth(full) <= width) return [full];
177
+
178
+ const compactContext = contextSegment(context, theme, width, true);
179
+ const compactBudget = budgetSegment(budget, theme, width, true, now);
180
+ const compact = `${theme.bold("LLM")} ${compactContext} · ${compactBudget}`;
181
+ if (visibleWidth(compact) <= width) return [compact];
182
+ return [
183
+ truncateToWidth(`${theme.bold("LLM")} ${compactContext}`, width, ""),
184
+ truncateToWidth(`${theme.bold("LLM")} ${compactBudget}`, width, ""),
185
+ ];
186
+ }
187
+
188
+ export function renderFooterLines(
189
+ context: FooterContext,
190
+ footerData: FooterData,
191
+ theme: FooterTheme,
192
+ providerBudget: ProviderBudget | null,
193
+ thinkingLevel: string,
194
+ width: number,
195
+ now = Date.now(),
196
+ ): string[] {
197
+ const safeWidth = Math.max(1, width);
198
+ const lines = [
199
+ ...identityLines(context, footerData, theme, thinkingLevel, safeWidth),
200
+ ...statusLines(context, providerBudget, theme, safeWidth, now),
201
+ ];
202
+ const statuses = [...footerData.getExtensionStatuses().entries()]
203
+ .filter(([key]) => key !== "jittor")
204
+ .sort(([leftKey], [rightKey]) => leftKey.localeCompare(rightKey))
205
+ .map(([, text]) => sanitize(text));
206
+ if (statuses.length > 0) lines.push(truncateToWidth(statuses.join(" "), safeWidth, theme.fg("dim", "…")));
207
+ return lines.map((line) => truncateToWidth(line, safeWidth, ""));
208
+ }
209
+
210
+ export interface IntegratedFooterState {
211
+ providerBudget: ProviderBudget | null;
212
+ requestRender?: () => void;
213
+ }
214
+
215
+ export function installIntegratedFooter(ctx: ExtensionContext, state: IntegratedFooterState, getThinkingLevel: () => string): void {
216
+ ctx.ui.setStatus("jittor", undefined);
217
+ ctx.ui.setFooter((tui, theme, footerData) => {
218
+ state.requestRender = () => tui.requestRender();
219
+ const unsubscribe = (footerData as FooterData).onBranchChange?.(() => tui.requestRender());
220
+ return {
221
+ invalidate() {},
222
+ render(width: number): string[] {
223
+ return renderFooterLines(ctx as unknown as FooterContext, footerData, theme, state.providerBudget, getThinkingLevel(), width);
224
+ },
225
+ dispose() {
226
+ unsubscribe?.();
227
+ state.requestRender = undefined;
228
+ tui.requestRender();
229
+ },
230
+ };
231
+ });
232
+ }
@@ -0,0 +1,317 @@
1
+ import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
2
+ import { MAX_DYNAMIC_ROUTES } from "../../src/constants.ts";
3
+ import type { MetricObservation, StoredMetricObservation } from "../../src/domain/metric.ts";
4
+ import type { PolicyDecision, Route } from "../../src/policy.ts";
5
+ import type { RouterStatus } from "../../src/ports/router-controller.ts";
6
+ import { parseCodexRateLimitHeaders } from "../../src/providers/codex.ts";
7
+ import { installIntegratedFooter, type IntegratedFooterState } from "./footer.ts";
8
+ import { callJittor } from "./service-client.ts";
9
+ import { persistentEnforcementControl, type EnforcementControl } from "./settings.ts";
10
+ import { buildFooterBudget, formatFooterStatus, showJittorPanel } from "./tui.ts";
11
+ import { showUsagePanel } from "./usage.ts";
12
+
13
+ export { formatFooterStatus } from "./tui.ts";
14
+
15
+ const THINKING_LEVELS = new Set(["off", "minimal", "low", "medium", "high", "xhigh", "max"]);
16
+ const RECOVERY_GUIDANCE = "Run /jittor off to disable blocking, or restart the daemon with: systemctl --user restart jittor.service";
17
+
18
+ export interface JittorExtensionClient {
19
+ call(operation: string, input: unknown): Promise<any>;
20
+ }
21
+
22
+ const daemonClient: JittorExtensionClient = {
23
+ call: (operation, input) => callJittor(operation as Parameters<typeof callJittor>[0], input as never),
24
+ };
25
+
26
+ async function recordMetrics(client: JittorExtensionClient, metrics: MetricObservation[]): Promise<void> {
27
+ for (const metric of metrics) await client.call("metrics.record", metric);
28
+ }
29
+
30
+ async function refreshFooter(client: JittorExtensionClient, state: IntegratedFooterState): Promise<void> {
31
+ const status = await client.call("router.status", {}) as RouterStatus;
32
+ const provider = status.currentRoute?.provider;
33
+ const query = provider === "openai-codex"
34
+ ? { source: "codex-subscription", metric: "used-fraction", limit: 100, order: "desc" }
35
+ : provider === "openrouter" ? { source: "openrouter", metric: "usage", limit: 10, order: "desc" } : null;
36
+ const metrics = query ? await client.call("metrics.query", query) as StoredMetricObservation[] : [];
37
+ state.providerBudget = buildFooterBudget(status, metrics);
38
+ state.requestRender?.();
39
+ }
40
+
41
+ function delay(milliseconds: number, signal?: AbortSignal): Promise<void> {
42
+ if (milliseconds <= 0) return Promise.resolve();
43
+ return new Promise((resolve, reject) => {
44
+ const timer = setTimeout(resolve, milliseconds);
45
+ signal?.addEventListener("abort", () => {
46
+ clearTimeout(timer);
47
+ reject(new Error("Jittor throttle cancelled"));
48
+ }, { once: true });
49
+ });
50
+ }
51
+
52
+ function routeModelAvailable(ctx: ExtensionContext, route: Route): boolean {
53
+ return ctx.modelRegistry.getAvailable().some((model) => model.provider === route.provider && model.id === route.model);
54
+ }
55
+
56
+ async function applyRoute(pi: ExtensionAPI, ctx: ExtensionContext, route: Route): Promise<boolean> {
57
+ if (!routeModelAvailable(ctx, route)) return false;
58
+ const model = ctx.modelRegistry.find(route.provider, route.model);
59
+ if (!model) return false;
60
+ if (!ctx.model || ctx.model.provider !== route.provider || ctx.model.id !== route.model) {
61
+ if (!await pi.setModel(model)) return false;
62
+ }
63
+ if (THINKING_LEVELS.has(route.thinking)) pi.setThinkingLevel(route.thinking as Parameters<ExtensionAPI["setThinkingLevel"]>[0]);
64
+ return true;
65
+ }
66
+
67
+ interface PiRouteModel {
68
+ provider: string;
69
+ id: string;
70
+ reasoning?: boolean;
71
+ thinkingLevelMap?: Partial<Record<string, unknown>>;
72
+ cost?: { input?: number; output?: number };
73
+ }
74
+
75
+ const THINKING_DESCENDING = ["max", "xhigh", "high", "medium", "low", "minimal", "off"] as const;
76
+
77
+ function supportsThinking(model: PiRouteModel, level: string): boolean {
78
+ if (!model.reasoning) return level === "off";
79
+ return model.thinkingLevelMap?.[level] !== null;
80
+ }
81
+
82
+ function modelCost(model: PiRouteModel): number {
83
+ return (model.cost?.input ?? 0) + (model.cost?.output ?? 0);
84
+ }
85
+
86
+ export function routesFromPi(models: PiRouteModel[], current: PiRouteModel, thinking: string): Route[] {
87
+ const sameProvider = models
88
+ .filter((model) => model.provider === current.provider)
89
+ .filter((model, index, rows) => rows.findIndex((candidate) => candidate.id === model.id) === index);
90
+ if (!sameProvider.some((model) => model.id === current.id)) sameProvider.push(current);
91
+ const routes: Route[] = [{ provider: current.provider, model: current.id, thinking }];
92
+ const currentLevel = THINKING_DESCENDING.indexOf(thinking as typeof THINKING_DESCENDING[number]);
93
+ const lowerLevels = THINKING_DESCENDING.slice(currentLevel >= 0 ? currentLevel + 1 : 0);
94
+ for (const level of lowerLevels) {
95
+ if (supportsThinking(current, level)) routes.push({ provider: current.provider, model: current.id, thinking: level });
96
+ }
97
+ const alternatives = sameProvider
98
+ .filter((model) => model.id !== current.id)
99
+ .sort((left, right) => modelCost(left) - modelCost(right) || left.id.localeCompare(right.id));
100
+ for (const model of alternatives) {
101
+ const level = [thinking, ...lowerLevels].find((candidate) => supportsThinking(model, candidate)) ?? "off";
102
+ routes.push({ provider: model.provider, model: model.id, thinking: level });
103
+ if (routes.length >= MAX_DYNAMIC_ROUTES) break;
104
+ }
105
+ return routes;
106
+ }
107
+
108
+ async function syncAvailableRoutes(pi: ExtensionAPI, client: JittorExtensionClient, ctx: ExtensionContext): Promise<void> {
109
+ if (!ctx.model) { await client.call("router.available_routes", { routes: [] }); return; }
110
+ const models = ctx.modelRegistry.getAvailable() as PiRouteModel[];
111
+ const routes = routesFromPi(models, ctx.model as PiRouteModel, pi.getThinkingLevel());
112
+ await client.call("router.available_routes", { routes });
113
+ }
114
+
115
+ async function syncCurrentRoute(
116
+ pi: ExtensionAPI,
117
+ client: JittorExtensionClient,
118
+ ctx: ExtensionContext,
119
+ model = ctx.model,
120
+ thinking = pi.getThinkingLevel(),
121
+ ): Promise<void> {
122
+ if (!model) return;
123
+ await client.call("router.current_route", { provider: model.provider, model: model.id, thinking });
124
+ }
125
+
126
+ function halt(ctx: ExtensionContext, reason: string): false {
127
+ ctx.ui.notify(`${reason}. ${RECOVERY_GUIDANCE}.`, "warning");
128
+ ctx.abort();
129
+ return false;
130
+ }
131
+
132
+ async function applyDecision(
133
+ pi: ExtensionAPI,
134
+ client: JittorExtensionClient,
135
+ ctx: ExtensionContext,
136
+ decision: PolicyDecision,
137
+ allowResync = true,
138
+ ): Promise<boolean> {
139
+ if (decision.action === "halt") return halt(ctx, `Jittor blocked this provider request: ${decision.reason}`);
140
+ if (decision.action === "throttle") await delay(decision.delayMs ?? 0, ctx.signal);
141
+ if (!decision.route || await applyRoute(pi, ctx, decision.route)) return true;
142
+ if (allowResync) {
143
+ await syncAvailableRoutes(pi, client, ctx);
144
+ return applyDecision(pi, client, ctx, await client.call("router.decide", {}) as PolicyDecision, false);
145
+ }
146
+ return halt(ctx, `Jittor could not apply any authenticated Pi route after ${decision.route.provider}/${decision.route.model} became unavailable`);
147
+ }
148
+
149
+ function assistantUsageMetrics(message: unknown, observedAt: number): MetricObservation[] {
150
+ if (typeof message !== "object" || message === null || Array.isArray(message)) return [];
151
+ const value = message as Record<string, unknown>;
152
+ if (value["role"] !== "assistant" || typeof value["usage"] !== "object" || value["usage"] === null) return [];
153
+ const usage = value["usage"] as Record<string, unknown>;
154
+ const provider = typeof value["provider"] === "string" ? value["provider"] : "unknown";
155
+ const model = typeof value["model"] === "string" ? value["model"] : "unknown";
156
+ const scope = `${provider}:${model}`;
157
+ const attributes = { provider, model };
158
+ const metrics: MetricObservation[] = [];
159
+ for (const [field, metric] of [["input", "input-tokens"], ["output", "output-tokens"], ["cacheRead", "cache-read-tokens"], ["cacheWrite", "cache-write-tokens"]] as const) {
160
+ const amount = usage[field];
161
+ if (typeof amount === "number" && Number.isFinite(amount)) metrics.push({ source: "pi", scope, metric, value: amount, unit: "tokens", observedAt, attributes });
162
+ }
163
+ const cost = typeof usage["cost"] === "object" && usage["cost"] !== null ? (usage["cost"] as Record<string, unknown>)["total"] : undefined;
164
+ if (typeof cost === "number" && Number.isFinite(cost)) metrics.push({ source: "pi", scope, metric: "cost", value: cost, unit: "usd", observedAt, attributes });
165
+ return metrics;
166
+ }
167
+
168
+ export function registerJittorExtension(
169
+ pi: ExtensionAPI,
170
+ client: JittorExtensionClient = daemonClient,
171
+ enforcement: EnforcementControl = persistentEnforcementControl(),
172
+ ): void {
173
+ const footerState: IntegratedFooterState = { providerBudget: null };
174
+ const showFooter = (ctx: ExtensionContext): void => {
175
+ if (enforcement.isFooterEnabled()) installIntegratedFooter(ctx, footerState, () => pi.getThinkingLevel());
176
+ else ctx.ui.setFooter(undefined);
177
+ };
178
+ const disable = (ctx: ExtensionContext): void => {
179
+ enforcement.setEnabled(false);
180
+ ctx.ui.setStatus("jittor", undefined);
181
+ showFooter(ctx);
182
+ ctx.ui.notify("Jittor enforcement is off (monitor-only); the informational footer remains independent and provider requests will not be blocked.", "warning");
183
+ };
184
+ const enable = async (ctx: ExtensionContext): Promise<void> => {
185
+ try {
186
+ await syncCurrentRoute(pi, client, ctx);
187
+ await syncAvailableRoutes(pi, client, ctx);
188
+ await client.call("telemetry.poll", {});
189
+ const readinessDecision = await client.call("router.decide", {}) as PolicyDecision;
190
+ if (readinessDecision.action === "halt") throw new Error(readinessDecision.reason);
191
+ enforcement.setEnabled(true);
192
+ showFooter(ctx);
193
+ await refreshFooter(client, footerState);
194
+ ctx.ui.notify("Jittor enforcement enabled.", "info");
195
+ } catch (error) {
196
+ enforcement.setEnabled(false);
197
+ showFooter(ctx);
198
+ const reason = error instanceof Error ? error.message : "readiness failed";
199
+ ctx.ui.notify(`Jittor remains monitor-only: ${reason}. ${RECOVERY_GUIDANCE}.`, "error");
200
+ }
201
+ };
202
+
203
+ pi.registerCommand("jittor", {
204
+ description: "Inspect, enable, or disable Jittor routing",
205
+ handler: async (args, ctx) => {
206
+ const action = args.trim().toLowerCase();
207
+ if (action === "off" || action === "disable") { disable(ctx); return; }
208
+ if (action === "on" || action === "enable") { await enable(ctx); return; }
209
+ if (action === "footer off" || action === "footer disable") {
210
+ enforcement.setFooterEnabled(false);
211
+ ctx.ui.setFooter(undefined);
212
+ ctx.ui.notify("Jittor footer disabled; routing enforcement is unchanged.", "info");
213
+ return;
214
+ }
215
+ if (action === "footer on" || action === "footer enable") {
216
+ enforcement.setFooterEnabled(true);
217
+ showFooter(ctx);
218
+ await refreshFooter(client, footerState).catch(() => undefined);
219
+ ctx.ui.notify("Jittor informational footer enabled; routing enforcement is unchanged.", "info");
220
+ return;
221
+ }
222
+ if (!enforcement.isEnabled()) {
223
+ ctx.ui.notify("Jittor is monitor-only. Run /jittor on to re-enable blocking.", "info");
224
+ return;
225
+ }
226
+ await showJittorPanel(ctx, client);
227
+ },
228
+ });
229
+ pi.registerCommand("jittor-off", {
230
+ description: "Emergency local bypass: disable Jittor blocking without daemon access",
231
+ handler: async (_args, ctx) => { disable(ctx); },
232
+ });
233
+ pi.registerCommand("jittor-on", {
234
+ description: "Enable Jittor only after telemetry and routes pass readiness",
235
+ handler: async (_args, ctx) => { await enable(ctx); },
236
+ });
237
+ pi.registerCommand("usage", {
238
+ description: "Show Jittor token usage over time",
239
+ handler: async (_args, ctx) => { await showUsagePanel(ctx, client); },
240
+ });
241
+
242
+ pi.on("session_start", async (_event, ctx) => {
243
+ ctx.ui.setStatus("jittor", undefined);
244
+ showFooter(ctx);
245
+ try {
246
+ await syncCurrentRoute(pi, client, ctx);
247
+ await syncAvailableRoutes(pi, client, ctx);
248
+ await client.call("telemetry.poll", {});
249
+ await refreshFooter(client, footerState);
250
+ } catch {
251
+ footerState.providerBudget = null;
252
+ footerState.requestRender?.();
253
+ }
254
+ });
255
+
256
+ pi.on("input", async (event, ctx) => {
257
+ if (event.source === "extension" || !enforcement.isEnabled()) return { action: "continue" as const };
258
+ try {
259
+ const next = await client.call("router.decide", {}) as PolicyDecision;
260
+ if (next.action === "halt") {
261
+ ctx.ui.notify(`Jittor blocked input: ${next.reason}. ${RECOVERY_GUIDANCE}.`, "warning");
262
+ return { action: "handled" as const };
263
+ }
264
+ return { action: "continue" as const };
265
+ } catch {
266
+ ctx.ui.notify(`Jittor could not verify budget telemetry, so fail-closed enforcement blocked input. ${RECOVERY_GUIDANCE}.`, "error");
267
+ return { action: "handled" as const };
268
+ }
269
+ });
270
+
271
+ pi.on("model_select", async (event, ctx) => {
272
+ await syncCurrentRoute(pi, client, ctx, event.model).then(() => syncAvailableRoutes(pi, client, ctx)).catch(() => undefined);
273
+ if (enforcement.isFooterEnabled()) await refreshFooter(client, footerState).catch(() => undefined);
274
+ });
275
+
276
+ pi.on("thinking_level_select", async (event, ctx) => {
277
+ await syncCurrentRoute(pi, client, ctx, ctx.model, event.level).catch(() => undefined);
278
+ });
279
+
280
+ pi.on("turn_start", async (_event, ctx) => {
281
+ if (!enforcement.isEnabled()) return;
282
+ try {
283
+ await syncCurrentRoute(pi, client, ctx);
284
+ await syncAvailableRoutes(pi, client, ctx);
285
+ await applyDecision(pi, client, ctx, await client.call("router.decide", {}) as PolicyDecision);
286
+ await refreshFooter(client, footerState);
287
+ } catch {
288
+ halt(ctx, "Jittor could not verify or apply a safe route");
289
+ }
290
+ });
291
+
292
+ pi.on("after_provider_response", async (event, ctx) => {
293
+ if (!Object.keys(event.headers).some((name) => name.toLowerCase().startsWith("x-codex-"))) return;
294
+ try {
295
+ const updates = parseCodexRateLimitHeaders(new Headers(event.headers), Date.now());
296
+ await recordMetrics(client, updates.flatMap((update) => update.metrics));
297
+ } catch {
298
+ if (enforcement.isEnabled()) ctx.ui.notify(`Jittor detected Codex telemetry schema drift. ${RECOVERY_GUIDANCE}.`, "error");
299
+ }
300
+ if (enforcement.isFooterEnabled()) await refreshFooter(client, footerState).catch(() => undefined);
301
+ });
302
+
303
+ pi.on("message_end", async (event, _ctx) => {
304
+ const metrics = assistantUsageMetrics(event.message, Date.now());
305
+ if (metrics.length > 0) await recordMetrics(client, metrics).catch(() => undefined);
306
+ if (enforcement.isFooterEnabled()) await refreshFooter(client, footerState).catch(() => undefined);
307
+ });
308
+
309
+ pi.on("session_shutdown", async (_event, ctx) => {
310
+ ctx.ui.setStatus("jittor", undefined);
311
+ ctx.ui.setFooter(undefined);
312
+ });
313
+ }
314
+
315
+ export default function jittorExtension(pi: ExtensionAPI): void {
316
+ registerJittorExtension(pi);
317
+ }
@@ -0,0 +1,26 @@
1
+ import { connectJittorClient } from "../../src/client.ts";
2
+ import type { OperationInputs, OperationName, OperationOutputs } from "../../src/service.ts";
3
+
4
+ let cached = connectJittorClient;
5
+ let client: ReturnType<typeof connectJittorClient> | undefined;
6
+
7
+ export async function callJittor<Name extends OperationName>(
8
+ operation: Name,
9
+ input: OperationInputs[Name],
10
+ ): Promise<OperationOutputs[Name]> {
11
+ for (let attempt = 0; attempt < 2; attempt++) {
12
+ try {
13
+ client ??= cached();
14
+ return await client.call(operation, input);
15
+ } catch (error) {
16
+ client = undefined;
17
+ if (attempt === 1) throw error;
18
+ }
19
+ }
20
+ throw new Error("Jittor client retry exhausted");
21
+ }
22
+
23
+ export function resetJittorClientForTests(): void {
24
+ client = undefined;
25
+ cached = connectJittorClient;
26
+ }
@@ -0,0 +1,59 @@
1
+ import { chmodSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
2
+ import { dirname, join } from "node:path";
3
+ import { JITTOR_EXTENSION_SETTINGS_FILENAME, JITTOR_STATE_DIRECTORY } from "../../src/constants.ts";
4
+
5
+ export interface EnforcementControl {
6
+ isEnabled(): boolean;
7
+ setEnabled(enabled: boolean): void;
8
+ isFooterEnabled(): boolean;
9
+ setFooterEnabled(enabled: boolean): void;
10
+ }
11
+
12
+ interface ExtensionSettings {
13
+ enforcementEnabled: boolean;
14
+ footerEnabled: boolean;
15
+ }
16
+
17
+ function settingsPath(env: Record<string, string | undefined> = process.env): string {
18
+ const config = env["XDG_CONFIG_HOME"] ?? join(env["HOME"] ?? ".", ".config");
19
+ return join(config, JITTOR_STATE_DIRECTORY, JITTOR_EXTENSION_SETTINGS_FILENAME);
20
+ }
21
+
22
+ function loadSettings(path: string): ExtensionSettings {
23
+ try {
24
+ const value = JSON.parse(readFileSync(path, "utf8")) as unknown;
25
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return { enforcementEnabled: true, footerEnabled: true };
26
+ const record = value as Record<string, unknown>;
27
+ return {
28
+ enforcementEnabled: record["enforcementEnabled"] !== false,
29
+ footerEnabled: record["footerEnabled"] !== false,
30
+ };
31
+ } catch {
32
+ return { enforcementEnabled: true, footerEnabled: true };
33
+ }
34
+ }
35
+
36
+ function persistSettings(path: string, settings: ExtensionSettings): void {
37
+ mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
38
+ const temporary = `${path}.${process.pid}.tmp`;
39
+ writeFileSync(temporary, `${JSON.stringify(settings, null, 2)}\n`, { mode: 0o600 });
40
+ chmodSync(temporary, 0o600);
41
+ renameSync(temporary, path);
42
+ }
43
+
44
+ export function persistentEnforcementControl(env: Record<string, string | undefined> = process.env): EnforcementControl {
45
+ const path = settingsPath(env);
46
+ const settings = loadSettings(path);
47
+ return {
48
+ isEnabled: () => settings.enforcementEnabled,
49
+ setEnabled(value: boolean): void {
50
+ settings.enforcementEnabled = value;
51
+ persistSettings(path, settings);
52
+ },
53
+ isFooterEnabled: () => settings.footerEnabled,
54
+ setFooterEnabled(value: boolean): void {
55
+ settings.footerEnabled = value;
56
+ persistSettings(path, settings);
57
+ },
58
+ };
59
+ }