@osovv/vv-opencode 1.3.4 → 1.3.6-rc.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.
- package/CHANGELOG.md +37 -0
- package/README.md +378 -384
- package/dist/commands/analytics.js +2 -0
- package/dist/commands/analytics.js.map +1 -1
- package/dist/commands/upgrade.d.ts +13 -6
- package/dist/commands/upgrade.js +31 -25
- package/dist/commands/upgrade.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +6 -5
- package/dist/index.js.map +1 -1
- package/dist/lib/opencode.js +3 -2
- package/dist/lib/opencode.js.map +1 -1
- package/dist/lib/peak-hours.d.ts +53 -0
- package/dist/lib/peak-hours.js +389 -0
- package/dist/lib/peak-hours.js.map +1 -0
- package/dist/lib/plugin-toggle-config.d.ts +71 -1
- package/dist/lib/plugin-toggle-config.js +77 -3
- package/dist/lib/plugin-toggle-config.js.map +1 -1
- package/dist/lib/vvoc-config.d.ts +84 -0
- package/dist/lib/vvoc-config.js +42 -1
- package/dist/lib/vvoc-config.js.map +1 -1
- package/dist/plugins/peak-hours/index.d.ts +31 -0
- package/dist/plugins/peak-hours/index.js +299 -0
- package/dist/plugins/peak-hours/index.js.map +1 -0
- package/dist/tui/analytics/indicator.js.map +1 -1
- package/dist/tui/peak-hours/banner.d.ts +26 -0
- package/dist/tui/peak-hours/banner.js +126 -0
- package/dist/tui/peak-hours/banner.js.map +1 -0
- package/dist/tui.js +13 -6
- package/dist/tui.js.map +1 -1
- package/package.json +7 -3
- package/schemas/vvoc/v3.json +326 -57
- package/templates/skills/vv-execute/SKILL.md +11 -11
- package/templates/skills/vv-plan/SKILL.md +9 -8
- package/templates/skills/vv-plan/references/plan-template.xml +4 -6
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
// FILE: src/plugins/peak-hours/index.ts
|
|
2
|
+
// VERSION: 1.0.0
|
|
3
|
+
// START_MODULE_CONTRACT
|
|
4
|
+
// PURPOSE: Warn or block chat.message requests whose model provider is in configured peak hours, with dynamic off-peak provider suggestions and session-age plus subagent grace.
|
|
5
|
+
// SCOPE: Startup vvoc snapshot resolution and peak-hours entry parsing, internal and subagent-like agent exemptions, persisted-session grace lookup, connected provider enumeration with bounded fallback, soft system-note injection, hard blocking errors, and fail-open degradation.
|
|
6
|
+
// DEPENDS: [@opencode-ai/plugin, src/lib/config-layers.ts, src/lib/plugin-toggle-config.ts, src/lib/managed-agents.ts, src/lib/peak-hours.ts]
|
|
7
|
+
// LINKS: [M-PLUGIN-PEAK-HOURS, M-PEAK-HOURS-SCHEDULES, M-PLUGIN-TOGGLE-CONFIG]
|
|
8
|
+
// ROLE: RUNTIME
|
|
9
|
+
// MAP_MODE: EXPORTS
|
|
10
|
+
// END_MODULE_CONTRACT
|
|
11
|
+
//
|
|
12
|
+
// START_MODULE_MAP
|
|
13
|
+
// PeakHoursPluginDependencies - Injectable clock, entry, session, provider, and logging dependencies for focused tests.
|
|
14
|
+
// SessionGraceInfo - Persisted session fields used for grace decisions.
|
|
15
|
+
// buildHardBlockMessage - Composes the blocking error text with window end, wait, and suggestions.
|
|
16
|
+
// buildSoftSystemNote - Composes the bounded model-facing peak notice.
|
|
17
|
+
// appendSystemNote - Appends the notice once without duplicating it.
|
|
18
|
+
// createPeakHoursPlugin - Builds the peak-hours server plugin with injectable dependencies.
|
|
19
|
+
// PeakHoursPlugin - Default production peak-hours server plugin.
|
|
20
|
+
// END_MODULE_MAP
|
|
21
|
+
//
|
|
22
|
+
// START_CHANGE_SUMMARY
|
|
23
|
+
// LAST_CHANGE: [C-PLUGIN-PEAK-HOURS - Added the peak-hours chat.message plugin with soft notes, hard blocks, suggestions, and grace.]
|
|
24
|
+
// END_CHANGE_SUMMARY
|
|
25
|
+
import { loadVvocConfig } from "../../lib/config-layers.js";
|
|
26
|
+
import { MANAGED_SUBAGENT_NAMES } from "../../lib/managed-agents.js";
|
|
27
|
+
import { isVvocPluginEnabled } from "../../lib/plugin-toggle-config.js";
|
|
28
|
+
import { findActivePeak, formatPeakEndTime, formatWaitMinutes, normalizeProviderId, parsePeakHoursEntry, suggestOffPeakProviders, } from "../../lib/peak-hours.js";
|
|
29
|
+
// OpenCode internal agents that must never be gated; blocking them breaks
|
|
30
|
+
// session machinery itself.
|
|
31
|
+
const INTERNAL_AGENTS = ["compaction", "title", "summary"];
|
|
32
|
+
const BUILT_IN_SUBAGENTS = ["general"];
|
|
33
|
+
const PLUGIN_MANAGED_SUBAGENTS = ["guardian"];
|
|
34
|
+
const PEAK_HOURS_SERVICE = "peak-hours";
|
|
35
|
+
const PEAK_HOURS_NOTE_TAG = "<peak_hours_notice>";
|
|
36
|
+
const PROVIDER_CACHE_TTL_MS = 10 * 60 * 1_000;
|
|
37
|
+
const PROVIDER_FETCH_TIMEOUT_MS = 5_000;
|
|
38
|
+
const MAX_LOG_TEXT_CHARS = 500;
|
|
39
|
+
// START_BLOCK_AGENT_EXEMPTIONS
|
|
40
|
+
function createKnownSubagentSet() {
|
|
41
|
+
return new Set([
|
|
42
|
+
...BUILT_IN_SUBAGENTS,
|
|
43
|
+
...PLUGIN_MANAGED_SUBAGENTS,
|
|
44
|
+
...MANAGED_SUBAGENT_NAMES,
|
|
45
|
+
]);
|
|
46
|
+
}
|
|
47
|
+
function syncConfiguredSubagents(configAgentNames, knownSubagents) {
|
|
48
|
+
for (const [name, definition] of Object.entries(configAgentNames)) {
|
|
49
|
+
if (definition &&
|
|
50
|
+
typeof definition === "object" &&
|
|
51
|
+
definition.mode === "subagent") {
|
|
52
|
+
knownSubagents.add(name);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function isInternalAgent(agentName) {
|
|
57
|
+
return !!agentName && INTERNAL_AGENTS.includes(agentName);
|
|
58
|
+
}
|
|
59
|
+
// END_BLOCK_AGENT_EXEMPTIONS
|
|
60
|
+
// START_CONTRACT: buildHardBlockMessage
|
|
61
|
+
// PURPOSE: Compose the hard-mode blocking error text with window end, wait time, and suggestions.
|
|
62
|
+
// INPUTS: { providerID: string - peak provider id; peak: ActivePeak - active window hit; suggestions: readonly string[] - connected off-peak provider ids }
|
|
63
|
+
// OUTPUTS: { string - complete blocking error message }
|
|
64
|
+
// SIDE_EFFECTS: none
|
|
65
|
+
// LINKS: formatPeakEndTime, formatWaitMinutes
|
|
66
|
+
// END_CONTRACT: buildHardBlockMessage
|
|
67
|
+
export function buildHardBlockMessage(providerID, peak, suggestions) {
|
|
68
|
+
const until = formatPeakEndTime(peak.endsAt);
|
|
69
|
+
const wait = formatWaitMinutes(peak.minutesRemaining);
|
|
70
|
+
const lines = [
|
|
71
|
+
`PEAK_HOURS_BLOCK: provider "${providerID}" is in peak hours until ${until} (about ${wait}).`,
|
|
72
|
+
"Requests to this provider cost more right now.",
|
|
73
|
+
];
|
|
74
|
+
if (suggestions.length > 0) {
|
|
75
|
+
lines.push(`Connected providers outside peak hours right now: ${suggestions.join(", ")}. Switch the model to one of them, or wait.`);
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
lines.push("Every connected provider is currently in peak hours or unscheduled; wait for the window to end or review the plugins[peak-hours] schedules in vvoc.json.");
|
|
79
|
+
}
|
|
80
|
+
return lines.join(" ");
|
|
81
|
+
}
|
|
82
|
+
// START_CONTRACT: buildSoftSystemNote
|
|
83
|
+
// PURPOSE: Compose the bounded model-facing notice for soft mode.
|
|
84
|
+
// INPUTS: { providerID: string - peak provider id; peak: ActivePeak - active window hit }
|
|
85
|
+
// OUTPUTS: { string - single-line tagged system notice }
|
|
86
|
+
// SIDE_EFFECTS: none
|
|
87
|
+
// LINKS: formatPeakEndTime
|
|
88
|
+
// END_CONTRACT: buildSoftSystemNote
|
|
89
|
+
export function buildSoftSystemNote(providerID, peak) {
|
|
90
|
+
const until = formatPeakEndTime(peak.endsAt);
|
|
91
|
+
return `${PEAK_HOURS_NOTE_TAG}Provider "${providerID}" is in peak hours until ${until}; pricing is elevated. Keep responses focused and avoid unnecessary verbosity.</${PEAK_HOURS_NOTE_TAG.slice(1)}`;
|
|
92
|
+
}
|
|
93
|
+
// START_CONTRACT: appendSystemNote
|
|
94
|
+
// PURPOSE: Append the peak notice to an existing system prompt exactly once.
|
|
95
|
+
// INPUTS: { existingSystem: string | undefined - current system prompt; note: string - composed notice }
|
|
96
|
+
// OUTPUTS: { string - system prompt with the notice appended at most once }
|
|
97
|
+
// SIDE_EFFECTS: none
|
|
98
|
+
// LINKS: buildSoftSystemNote
|
|
99
|
+
// END_CONTRACT: appendSystemNote
|
|
100
|
+
export function appendSystemNote(existingSystem, note) {
|
|
101
|
+
if (typeof existingSystem === "string" && existingSystem.includes(PEAK_HOURS_NOTE_TAG)) {
|
|
102
|
+
return existingSystem;
|
|
103
|
+
}
|
|
104
|
+
const parts = [];
|
|
105
|
+
if (typeof existingSystem === "string" && existingSystem.trim()) {
|
|
106
|
+
parts.push(existingSystem.trim());
|
|
107
|
+
}
|
|
108
|
+
parts.push(note);
|
|
109
|
+
return parts.join("\n\n");
|
|
110
|
+
}
|
|
111
|
+
// START_BLOCK_DEFAULT_DEPENDENCIES
|
|
112
|
+
function truncateLogText(value) {
|
|
113
|
+
return value.length > MAX_LOG_TEXT_CHARS ? `${value.slice(0, MAX_LOG_TEXT_CHARS)}...` : value;
|
|
114
|
+
}
|
|
115
|
+
async function lookupSessionGrace(client, directory, sessionID) {
|
|
116
|
+
try {
|
|
117
|
+
const response = (await client.session.get({
|
|
118
|
+
path: { id: sessionID },
|
|
119
|
+
query: directory ? { directory } : undefined,
|
|
120
|
+
}));
|
|
121
|
+
if (response.error || response.data === undefined)
|
|
122
|
+
return undefined;
|
|
123
|
+
const session = response.data;
|
|
124
|
+
return {
|
|
125
|
+
createdMs: typeof session.time?.created === "number" ? session.time.created : undefined,
|
|
126
|
+
parentID: typeof session.parentID === "string" ? session.parentID : undefined,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
return undefined;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
async function listConnectedProviders(client, serverUrl, directory) {
|
|
134
|
+
// Prefer a typed client surface when the host SDK exposes one.
|
|
135
|
+
const configClient = client.config;
|
|
136
|
+
if (typeof configClient?.providers === "function") {
|
|
137
|
+
try {
|
|
138
|
+
const response = await configClient.providers(directory ? { query: { directory } } : undefined);
|
|
139
|
+
const providers = response.data?.providers ?? [];
|
|
140
|
+
return providers
|
|
141
|
+
.map((provider) => provider.id)
|
|
142
|
+
.filter((id) => typeof id === "string");
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
// Fall through to the raw HTTP fallback.
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
try {
|
|
149
|
+
const url = new URL("/config/providers", serverUrl);
|
|
150
|
+
if (directory) {
|
|
151
|
+
url.searchParams.set("directory", directory);
|
|
152
|
+
}
|
|
153
|
+
const response = await fetch(url, {
|
|
154
|
+
signal: AbortSignal.timeout(PROVIDER_FETCH_TIMEOUT_MS),
|
|
155
|
+
});
|
|
156
|
+
if (!response.ok)
|
|
157
|
+
return [];
|
|
158
|
+
const body = (await response.json());
|
|
159
|
+
const providers = body.providers ?? [];
|
|
160
|
+
return providers
|
|
161
|
+
.map((provider) => provider.id)
|
|
162
|
+
.filter((id) => typeof id === "string");
|
|
163
|
+
}
|
|
164
|
+
catch {
|
|
165
|
+
return [];
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
// END_BLOCK_DEFAULT_DEPENDENCIES
|
|
169
|
+
// START_BLOCK_PLUGIN_ENTRY
|
|
170
|
+
/**
|
|
171
|
+
* Builds the peak-hours OpenCode server plugin.
|
|
172
|
+
*
|
|
173
|
+
* chat.message evaluates the message model's provider against the configured
|
|
174
|
+
* schedules. Soft mode appends a bounded system notice; hard mode throws before
|
|
175
|
+
* any LLM request with dynamic off-peak suggestions. Internal agents, subagent
|
|
176
|
+
* agents, sessions with a parentID, and sessions created before the active
|
|
177
|
+
* window start are never hard-blocked. Schedule and lookup failures degrade to
|
|
178
|
+
* soft or no-op and never block.
|
|
179
|
+
*/
|
|
180
|
+
export function createPeakHoursPlugin(dependencies = {}) {
|
|
181
|
+
return async ({ client, directory, serverUrl }) => {
|
|
182
|
+
const providerCache = { at: 0, ids: [] };
|
|
183
|
+
const deps = {
|
|
184
|
+
now: () => new Date(),
|
|
185
|
+
loadEntry: async () => {
|
|
186
|
+
const vvoc = await loadVvocConfig({ cwd: directory });
|
|
187
|
+
if (!isVvocPluginEnabled(vvoc.config, "peak-hours")) {
|
|
188
|
+
return { entry: { ...parsePeakHoursEntry(false).entry }, warnings: [] };
|
|
189
|
+
}
|
|
190
|
+
return parsePeakHoursEntry(vvoc.config.plugins?.["peak-hours"]);
|
|
191
|
+
},
|
|
192
|
+
session: (sessionID) => lookupSessionGrace(client, directory, sessionID),
|
|
193
|
+
connectedProviders: async () => {
|
|
194
|
+
const now = Date.now();
|
|
195
|
+
if (now - providerCache.at < PROVIDER_CACHE_TTL_MS) {
|
|
196
|
+
return providerCache.ids;
|
|
197
|
+
}
|
|
198
|
+
const ids = await listConnectedProviders(client, serverUrl, directory);
|
|
199
|
+
providerCache.at = ids.length > 0 ? Date.now() : 0;
|
|
200
|
+
providerCache.ids = ids;
|
|
201
|
+
return ids;
|
|
202
|
+
},
|
|
203
|
+
log: async (level, message, extra) => {
|
|
204
|
+
try {
|
|
205
|
+
await client.app.log({
|
|
206
|
+
...(directory ? { query: { directory } } : {}),
|
|
207
|
+
body: {
|
|
208
|
+
service: PEAK_HOURS_SERVICE,
|
|
209
|
+
level,
|
|
210
|
+
message: truncateLogText(message),
|
|
211
|
+
extra,
|
|
212
|
+
},
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
catch {
|
|
216
|
+
// Logging must never interfere with message handling.
|
|
217
|
+
}
|
|
218
|
+
},
|
|
219
|
+
...dependencies,
|
|
220
|
+
};
|
|
221
|
+
const { entry, warnings } = await deps.loadEntry();
|
|
222
|
+
if (!entry.enabled)
|
|
223
|
+
return {};
|
|
224
|
+
const knownSubagents = createKnownSubagentSet();
|
|
225
|
+
await deps.log("info", "peak-hours plugin initialized", {
|
|
226
|
+
mode: entry.mode,
|
|
227
|
+
graceActiveSessions: entry.graceActiveSessions,
|
|
228
|
+
scheduledProviders: Object.keys(entry.schedules),
|
|
229
|
+
warningCount: warnings.length,
|
|
230
|
+
});
|
|
231
|
+
for (const warning of warnings) {
|
|
232
|
+
await deps.log("warn", `peak-hours config warning: ${warning}`);
|
|
233
|
+
}
|
|
234
|
+
return {
|
|
235
|
+
config: async (config) => {
|
|
236
|
+
syncConfiguredSubagents((config.agent ?? {}), knownSubagents);
|
|
237
|
+
},
|
|
238
|
+
"chat.message": async (input, output) => {
|
|
239
|
+
const agent = output.message.agent ?? input.agent;
|
|
240
|
+
if (isInternalAgent(agent))
|
|
241
|
+
return;
|
|
242
|
+
const providerID = input.model?.providerID ?? output.message.model?.providerID;
|
|
243
|
+
if (!providerID)
|
|
244
|
+
return;
|
|
245
|
+
const now = deps.now();
|
|
246
|
+
const peak = findActivePeak(now, entry.schedules, providerID);
|
|
247
|
+
if (!peak)
|
|
248
|
+
return;
|
|
249
|
+
const override = entry.schedules[peak.providerKey]?.mode;
|
|
250
|
+
let mode = override ?? entry.mode;
|
|
251
|
+
// Subagent-like agents are continuation of already-admitted work.
|
|
252
|
+
if (agent && knownSubagents.has(agent)) {
|
|
253
|
+
mode = "soft";
|
|
254
|
+
}
|
|
255
|
+
if (mode === "hard") {
|
|
256
|
+
const session = await deps.session(input.sessionID);
|
|
257
|
+
if (!session) {
|
|
258
|
+
// Fail-open: unknown session state never blocks.
|
|
259
|
+
mode = "soft";
|
|
260
|
+
}
|
|
261
|
+
else {
|
|
262
|
+
if (session.parentID) {
|
|
263
|
+
mode = "soft";
|
|
264
|
+
}
|
|
265
|
+
if (entry.graceActiveSessions &&
|
|
266
|
+
session.createdMs !== undefined &&
|
|
267
|
+
session.createdMs < peak.startedAt.getTime()) {
|
|
268
|
+
mode = "soft";
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
if (mode === "hard") {
|
|
273
|
+
const connected = await deps.connectedProviders();
|
|
274
|
+
const suggestions = suggestOffPeakProviders(now, entry.schedules, connected).filter((candidate) => normalizeProviderId(candidate) !== normalizeProviderId(providerID));
|
|
275
|
+
const message = buildHardBlockMessage(providerID, peak, suggestions);
|
|
276
|
+
await deps.log("info", "peak-hours hard block applied", {
|
|
277
|
+
providerID,
|
|
278
|
+
providerKey: peak.providerKey,
|
|
279
|
+
until: formatPeakEndTime(peak.endsAt),
|
|
280
|
+
waitMinutes: peak.minutesRemaining,
|
|
281
|
+
suggestions,
|
|
282
|
+
sessionID: input.sessionID,
|
|
283
|
+
});
|
|
284
|
+
throw new Error(message);
|
|
285
|
+
}
|
|
286
|
+
output.message.system = appendSystemNote(output.message.system, buildSoftSystemNote(providerID, peak));
|
|
287
|
+
await deps.log("info", "peak-hours soft notice applied", {
|
|
288
|
+
providerID,
|
|
289
|
+
providerKey: peak.providerKey,
|
|
290
|
+
until: formatPeakEndTime(peak.endsAt),
|
|
291
|
+
sessionID: input.sessionID,
|
|
292
|
+
});
|
|
293
|
+
},
|
|
294
|
+
};
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
export const PeakHoursPlugin = createPeakHoursPlugin();
|
|
298
|
+
// END_BLOCK_PLUGIN_ENTRY
|
|
299
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/plugins/peak-hours/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"indicator.js","sourceRoot":"","sources":["../../../src/tui/analytics/indicator.tsx"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"indicator.js","sourceRoot":"","sources":["../../../src/tui/analytics/indicator.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { JSX } from "@opentui/solid";
|
|
2
|
+
import type { RGBA } from "@opentui/core";
|
|
3
|
+
import type { TuiPluginApi } from "@opencode-ai/plugin/tui";
|
|
4
|
+
import { type ActivePeak, type PeakHoursClock, type PeakHoursEntryConfig } from "../../lib/peak-hours.js";
|
|
5
|
+
export type PeakBannerModelRef = {
|
|
6
|
+
providerID: string;
|
|
7
|
+
};
|
|
8
|
+
export type PeakHoursBannerDependencies = {
|
|
9
|
+
enabled: (api: TuiPluginApi) => Promise<boolean>;
|
|
10
|
+
now: PeakHoursClock;
|
|
11
|
+
entry: () => PeakHoursEntryConfig;
|
|
12
|
+
currentModel: (api: TuiPluginApi) => PeakBannerModelRef | undefined;
|
|
13
|
+
connectedProviders: (api: TuiPluginApi) => string[];
|
|
14
|
+
renderBanner: (text: string, color: RGBA) => JSX.Element;
|
|
15
|
+
};
|
|
16
|
+
export declare function buildPeakBannerText(providerID: string, peak: ActivePeak, suggestions: readonly string[]): string;
|
|
17
|
+
export declare function resolveBannerModelRef(api: TuiPluginApi): PeakBannerModelRef | undefined;
|
|
18
|
+
/**
|
|
19
|
+
* Registers the persistent peak-hours banner for the app_bottom host slot.
|
|
20
|
+
*
|
|
21
|
+
* The banner renders in warning colors only while the current model's provider
|
|
22
|
+
* is inside an active peak window, naming the provider, the window end, and
|
|
23
|
+
* connected providers that are currently outside peak. Disabled toggle or
|
|
24
|
+
* entry, missing slot API, or registration failure leave the TUI untouched.
|
|
25
|
+
*/
|
|
26
|
+
export declare function registerPeakHoursBanner(api: TuiPluginApi, dependencies?: Partial<PeakHoursBannerDependencies>): Promise<void>;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { jsx as _jsx } from "@opentui/solid/jsx-runtime";
|
|
2
|
+
import { loadVvocConfigForRead } from "../../lib/config-layers.js";
|
|
3
|
+
import { isVvocPluginEnabled } from "../../lib/plugin-toggle-config.js";
|
|
4
|
+
import { findActivePeak, formatPeakEndTime, normalizeProviderId, parsePeakHoursEntry, suggestOffPeakProviders, } from "../../lib/peak-hours.js";
|
|
5
|
+
// START_CONTRACT: buildPeakBannerText
|
|
6
|
+
// PURPOSE: Compose the one-line banner label with window end and suggestions.
|
|
7
|
+
// INPUTS: { providerID: string - peak provider id; peak: ActivePeak - active window hit; suggestions: readonly string[] - connected off-peak provider ids }
|
|
8
|
+
// OUTPUTS: { string - banner label text }
|
|
9
|
+
// SIDE_EFFECTS: none
|
|
10
|
+
// LINKS: formatPeakEndTime
|
|
11
|
+
// END_CONTRACT: buildPeakBannerText
|
|
12
|
+
export function buildPeakBannerText(providerID, peak, suggestions) {
|
|
13
|
+
const until = formatPeakEndTime(peak.endsAt);
|
|
14
|
+
const suffix = suggestions.length > 0
|
|
15
|
+
? ` · off-peak now: ${suggestions.join(", ")}`
|
|
16
|
+
: " · every connected provider is in peak or unscheduled";
|
|
17
|
+
return `⚠ PEAK ${providerID} until ${until} · elevated pricing${suffix}`;
|
|
18
|
+
}
|
|
19
|
+
// START_CONTRACT: resolveBannerModelRef
|
|
20
|
+
// PURPOSE: Resolve the current model reference from the open session's messages with a config default fallback.
|
|
21
|
+
// INPUTS: { api: TuiPluginApi - TUI plugin api }
|
|
22
|
+
// OUTPUTS: { PeakBannerModelRef | undefined - provider id of the most recent model-bearing message, the config default model, or undefined }
|
|
23
|
+
// SIDE_EFFECTS: none
|
|
24
|
+
// LINKS: currentSessionID
|
|
25
|
+
// END_CONTRACT: resolveBannerModelRef
|
|
26
|
+
export function resolveBannerModelRef(api) {
|
|
27
|
+
const sessionID = currentSessionID(api);
|
|
28
|
+
if (!sessionID)
|
|
29
|
+
return undefined;
|
|
30
|
+
const messages = api.state.session.messages(sessionID);
|
|
31
|
+
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
32
|
+
const message = messages[index];
|
|
33
|
+
if (!message)
|
|
34
|
+
continue;
|
|
35
|
+
if (message.role === "assistant" && typeof message.providerID === "string") {
|
|
36
|
+
return { providerID: message.providerID };
|
|
37
|
+
}
|
|
38
|
+
if (typeof message.model?.providerID === "string") {
|
|
39
|
+
return { providerID: message.model.providerID };
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
const configModel = api.state.config.model;
|
|
43
|
+
if (typeof configModel === "string" && configModel.includes("/")) {
|
|
44
|
+
const providerID = configModel.split("/")[0];
|
|
45
|
+
if (providerID)
|
|
46
|
+
return { providerID };
|
|
47
|
+
}
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
/** Reads the currently open sessionID from the TUI route, or "". */
|
|
51
|
+
function currentSessionID(api) {
|
|
52
|
+
const route = api.route.current;
|
|
53
|
+
if (route.name === "session" && "params" in route) {
|
|
54
|
+
const sessionID = route.params?.sessionID;
|
|
55
|
+
return typeof sessionID === "string" ? sessionID : "";
|
|
56
|
+
}
|
|
57
|
+
return "";
|
|
58
|
+
}
|
|
59
|
+
// START_BLOCK_REGISTER_BANNER
|
|
60
|
+
/**
|
|
61
|
+
* Registers the persistent peak-hours banner for the app_bottom host slot.
|
|
62
|
+
*
|
|
63
|
+
* The banner renders in warning colors only while the current model's provider
|
|
64
|
+
* is inside an active peak window, naming the provider, the window end, and
|
|
65
|
+
* connected providers that are currently outside peak. Disabled toggle or
|
|
66
|
+
* entry, missing slot API, or registration failure leave the TUI untouched.
|
|
67
|
+
*/
|
|
68
|
+
export async function registerPeakHoursBanner(api, dependencies = {}) {
|
|
69
|
+
if (typeof api.slots?.register !== "function")
|
|
70
|
+
return;
|
|
71
|
+
// Populated by the default enabled() config read; kept for the sync entry().
|
|
72
|
+
let cachedEntry;
|
|
73
|
+
const deps = {
|
|
74
|
+
enabled: async (apiInstance) => {
|
|
75
|
+
const vvoc = await loadVvocConfigForRead({
|
|
76
|
+
scope: "effective",
|
|
77
|
+
allowDefault: true,
|
|
78
|
+
cwd: apiInstance.state.path.directory,
|
|
79
|
+
});
|
|
80
|
+
if (!isVvocPluginEnabled(vvoc.config, "peak-hours"))
|
|
81
|
+
return false;
|
|
82
|
+
const parsed = parsePeakHoursEntry(vvoc.config.plugins?.["peak-hours"]);
|
|
83
|
+
cachedEntry = parsed.entry;
|
|
84
|
+
return parsed.entry.enabled;
|
|
85
|
+
},
|
|
86
|
+
now: () => new Date(),
|
|
87
|
+
entry: () => cachedEntry ?? parsePeakHoursEntry(undefined).entry,
|
|
88
|
+
currentModel: (apiInstance) => resolveBannerModelRef(apiInstance),
|
|
89
|
+
connectedProviders: (apiInstance) => apiInstance.state.provider
|
|
90
|
+
.map((provider) => provider.id)
|
|
91
|
+
.filter((id) => typeof id === "string"),
|
|
92
|
+
renderBanner: (text, color) => (_jsx("text", { children: _jsx("span", { style: { fg: color }, children: text }) })),
|
|
93
|
+
...dependencies,
|
|
94
|
+
};
|
|
95
|
+
if (!(await deps.enabled(api)))
|
|
96
|
+
return;
|
|
97
|
+
try {
|
|
98
|
+
// OpenCode's runtime requires a string plugin id on slot registrations, while
|
|
99
|
+
// the SDK's TuiSlotPlugin type still types id as never; cast bridges the two.
|
|
100
|
+
const plugin = {
|
|
101
|
+
id: "vvoc-peak-hours",
|
|
102
|
+
order: 100,
|
|
103
|
+
slots: {
|
|
104
|
+
app_bottom: (_ctx) => {
|
|
105
|
+
const entry = deps.entry();
|
|
106
|
+
if (!entry.enabled)
|
|
107
|
+
return undefined;
|
|
108
|
+
const modelRef = deps.currentModel(api);
|
|
109
|
+
if (!modelRef)
|
|
110
|
+
return undefined;
|
|
111
|
+
const now = deps.now();
|
|
112
|
+
const peak = findActivePeak(now, entry.schedules, modelRef.providerID);
|
|
113
|
+
if (!peak)
|
|
114
|
+
return undefined;
|
|
115
|
+
const suggestions = suggestOffPeakProviders(now, entry.schedules, deps.connectedProviders(api)).filter((candidate) => normalizeProviderId(candidate) !== normalizeProviderId(modelRef.providerID));
|
|
116
|
+
return deps.renderBanner(buildPeakBannerText(modelRef.providerID, peak, suggestions), api.theme.current.warning);
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
api.slots.register(plugin);
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
// Fail-soft: no banner for this session.
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=banner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"banner.js","sourceRoot":"","sources":["../../../src/tui/peak-hours/banner.tsx"],"names":[],"mappings":"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"}
|
package/dist/tui.js
CHANGED
|
@@ -1,25 +1,26 @@
|
|
|
1
1
|
// FILE: src/tui.tsx
|
|
2
|
-
// VERSION: 1.
|
|
2
|
+
// VERSION: 1.2.0
|
|
3
3
|
// START_MODULE_CONTRACT
|
|
4
|
-
// PURPOSE: Publish the default @osovv/vv-opencode/tui module containing the managed context inspector, analytics indicator, and
|
|
4
|
+
// PURPOSE: Publish the default @osovv/vv-opencode/tui module containing the managed context inspector, analytics indicator, branding footer, and peak-hours banner.
|
|
5
5
|
// SCOPE: Stable TUI package entrypoint and module identity only.
|
|
6
|
-
// DEPENDS: [@opencode-ai/plugin/tui, @opencode-ai/plugin, src/tui/context/plugin.ts, src/tui/analytics/indicator.tsx, src/tui/branding/footer.tsx]
|
|
7
|
-
// LINKS: [M-PLUGIN-CONTEXT-TUI, M-TUI-ANALYTICS-INDICATOR, M-TUI-BRANDING-FOOTER, V-M-PLUGIN-CONTEXT-TUI]
|
|
6
|
+
// DEPENDS: [@opencode-ai/plugin/tui, @opencode-ai/plugin, src/tui/context/plugin.ts, src/tui/analytics/indicator.tsx, src/tui/branding/footer.tsx, src/tui/peak-hours/banner.tsx]
|
|
7
|
+
// LINKS: [M-PLUGIN-CONTEXT-TUI, M-TUI-ANALYTICS-INDICATOR, M-TUI-BRANDING-FOOTER, M-TUI-PEAK-HOURS-BANNER, V-M-PLUGIN-CONTEXT-TUI]
|
|
8
8
|
// ROLE: BARREL
|
|
9
9
|
// MAP_MODE: SUMMARY
|
|
10
10
|
// END_MODULE_CONTRACT
|
|
11
11
|
//
|
|
12
12
|
// START_MODULE_MAP
|
|
13
|
-
// default - OpenCode TUI plugin module registering /context, the analytics indicator, and the
|
|
13
|
+
// default - OpenCode TUI plugin module registering /context, the analytics indicator, the branding footer, and the peak-hours banner.
|
|
14
14
|
// ContextTuiPlugin - Named TUI plugin factory for direct consumers and tests.
|
|
15
15
|
// END_MODULE_MAP
|
|
16
16
|
//
|
|
17
17
|
// START_CHANGE_SUMMARY
|
|
18
|
-
// LAST_CHANGE: [
|
|
18
|
+
// LAST_CHANGE: [C-PLUGIN-PEAK-HOURS - Registered the app_bottom peak-hours banner alongside the indicator and footer.]
|
|
19
19
|
// END_CHANGE_SUMMARY
|
|
20
20
|
import { ContextTuiPlugin } from "./tui/context/plugin.js";
|
|
21
21
|
import { registerAnalyticsIndicator } from "./tui/analytics/indicator.js";
|
|
22
22
|
import { registerBrandingFooter } from "./tui/branding/footer.js";
|
|
23
|
+
import { registerPeakHoursBanner } from "./tui/peak-hours/banner.js";
|
|
23
24
|
export { ContextTuiPlugin };
|
|
24
25
|
// START_BLOCK_TUI_MODULE
|
|
25
26
|
const plugin = {
|
|
@@ -38,6 +39,12 @@ const plugin = {
|
|
|
38
39
|
catch {
|
|
39
40
|
// Fail-soft: footer unavailable for this session.
|
|
40
41
|
}
|
|
42
|
+
try {
|
|
43
|
+
await registerPeakHoursBanner(api, options);
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
// Fail-soft: banner unavailable for this session.
|
|
47
|
+
}
|
|
41
48
|
},
|
|
42
49
|
};
|
|
43
50
|
// END_BLOCK_TUI_MODULE
|
package/dist/tui.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tui.js","sourceRoot":"","sources":["../src/tui.tsx"],"names":[],"mappings":"AAAA,oBAAoB;AACpB,iBAAiB;AACjB,wBAAwB;AACxB,
|
|
1
|
+
{"version":3,"file":"tui.js","sourceRoot":"","sources":["../src/tui.tsx"],"names":[],"mappings":"AAAA,oBAAoB;AACpB,iBAAiB;AACjB,wBAAwB;AACxB,sKAAsK;AACtK,mEAAmE;AACnE,oLAAoL;AACpL,qIAAqI;AACrI,iBAAiB;AACjB,sBAAsB;AACtB,sBAAsB;AACtB,EAAE;AACF,mBAAmB;AACnB,wIAAwI;AACxI,gFAAgF;AAChF,iBAAiB;AACjB,EAAE;AACF,uBAAuB;AACvB,yHAAyH;AACzH,qBAAqB;AAGrB,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AAC1E,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;AAErE,OAAO,EAAE,gBAAgB,EAAE,CAAC;AAE5B,yBAAyB;AACzB,MAAM,MAAM,GAAqC;IAC/C,EAAE,EAAE,cAAc;IAClB,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;QAChC,MAAM,gBAAgB,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;QAC3C,IAAI,CAAC;YACH,MAAM,0BAA0B,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QACjD,CAAC;QAAC,MAAM,CAAC;YACP,qDAAqD;QACvD,CAAC;QACD,IAAI,CAAC;YACH,sBAAsB,CAAC,GAAG,CAAC,CAAC;QAC9B,CAAC;QAAC,MAAM,CAAC;YACP,kDAAkD;QACpD,CAAC;QACD,IAAI,CAAC;YACH,MAAM,uBAAuB,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QAC9C,CAAC;QAAC,MAAM,CAAC;YACP,kDAAkD;QACpD,CAAC;IACH,CAAC;CACF,CAAC;AACF,uBAAuB;AAEvB,eAAe,MAAM,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@osovv/vv-opencode",
|
|
3
|
-
"version": "1.3.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.3.6-rc.0",
|
|
4
|
+
"description": "An opinionated agentic development layer for OpenCode — spec-first when it matters, review-driven execution, portable model roles, safer tools, and long-run safety.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
@@ -81,6 +81,10 @@
|
|
|
81
81
|
"./plugins/analytics": {
|
|
82
82
|
"types": "./dist/plugins/analytics/index.d.ts",
|
|
83
83
|
"import": "./dist/plugins/analytics/index.js"
|
|
84
|
+
},
|
|
85
|
+
"./plugins/peak-hours": {
|
|
86
|
+
"types": "./dist/plugins/peak-hours/index.d.ts",
|
|
87
|
+
"import": "./dist/plugins/peak-hours/index.js"
|
|
84
88
|
}
|
|
85
89
|
},
|
|
86
90
|
"scripts": {
|
|
@@ -93,7 +97,7 @@
|
|
|
93
97
|
"grace:check": "bun scripts/check-grace-markup.ts",
|
|
94
98
|
"test": "bun test",
|
|
95
99
|
"check": "bun run typecheck && bun run lint && bun run fmt:check && bun run grace:check && bun test",
|
|
96
|
-
"pack:check": "bun run build && bun -e \"const root = await import('./dist/index.js'); if (!('GuardianPlugin' in root)) throw new Error('dist root export missing GuardianPlugin'); if (!('HashlineEditPlugin' in root)) throw new Error('dist root export missing HashlineEditPlugin'); if (!('ModelRolesPlugin' in root)) throw new Error('dist root export missing ModelRolesPlugin'); if (!('SystemContextInjectionPlugin' in root)) throw new Error('dist root export missing SystemContextInjectionPlugin'); if (!('WorkflowPlugin' in root)) throw new Error('dist root export missing WorkflowPlugin'); if (!('SecretsRedactionPlugin' in root)) throw new Error('dist root export missing SecretsRedactionPlugin'); if (!('WebToolsPlugin' in root)) throw new Error('dist root export missing WebToolsPlugin'); if (!('AnalyticsPlugin' in root)) throw new Error('dist root export missing AnalyticsPlugin'); const tui = await import('./dist/tui.js'); if (!tui.default || typeof tui.default.tui !== 'function') throw new Error('dist TUI export missing default tui module'); await import('./dist/plugins/guardian/index.js'); await import('./dist/plugins/hashline-edit/index.js'); await import('./dist/plugins/model-roles/index.js'); await import('./dist/plugins/system-context-injection/index.js'); await import('./dist/plugins/workflow/index.js'); await import('./dist/plugins/secrets-redaction/index.js'); await import('./dist/plugins/web-tools/index.js'); await import('./dist/plugins/analytics/index.js')\" && npm pack --dry-run",
|
|
100
|
+
"pack:check": "bun run build && bun -e \"const root = await import('./dist/index.js'); if (!('GuardianPlugin' in root)) throw new Error('dist root export missing GuardianPlugin'); if (!('HashlineEditPlugin' in root)) throw new Error('dist root export missing HashlineEditPlugin'); if (!('ModelRolesPlugin' in root)) throw new Error('dist root export missing ModelRolesPlugin'); if (!('SystemContextInjectionPlugin' in root)) throw new Error('dist root export missing SystemContextInjectionPlugin'); if (!('WorkflowPlugin' in root)) throw new Error('dist root export missing WorkflowPlugin'); if (!('SecretsRedactionPlugin' in root)) throw new Error('dist root export missing SecretsRedactionPlugin'); if (!('WebToolsPlugin' in root)) throw new Error('dist root export missing WebToolsPlugin'); if (!('AnalyticsPlugin' in root)) throw new Error('dist root export missing AnalyticsPlugin'); if (!('PeakHoursPlugin' in root)) throw new Error('dist root export missing PeakHoursPlugin'); const tui = await import('./dist/tui.js'); if (!tui.default || typeof tui.default.tui !== 'function') throw new Error('dist TUI export missing default tui module'); await import('./dist/plugins/guardian/index.js'); await import('./dist/plugins/hashline-edit/index.js'); await import('./dist/plugins/model-roles/index.js'); await import('./dist/plugins/system-context-injection/index.js'); await import('./dist/plugins/workflow/index.js'); await import('./dist/plugins/secrets-redaction/index.js'); await import('./dist/plugins/web-tools/index.js'); await import('./dist/plugins/analytics/index.js'); await import('./dist/plugins/peak-hours/index.js')\" && npm pack --dry-run",
|
|
97
101
|
"tui:local": "bun scripts/tui-local.ts",
|
|
98
102
|
"release:check": "bun scripts/release-check.ts",
|
|
99
103
|
"release:bump": "bun scripts/release-bump.ts",
|