@osovv/vv-opencode 1.3.5 → 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.
@@ -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.1.0
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 branding footer.
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 branding footer.
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: [2026-08-19-cache-hit-rate-analytics - Registered the live cache indicator and vvoc version footer alongside /context.]
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,mJAAmJ;AACnJ,mEAAmE;AACnE,qJAAqJ;AACrJ,4GAA4G;AAC5G,iBAAiB;AACjB,sBAAsB;AACtB,sBAAsB;AACtB,EAAE;AACF,mBAAmB;AACnB,iHAAiH;AACjH,gFAAgF;AAChF,iBAAiB;AACjB,EAAE;AACF,uBAAuB;AACvB,yIAAyI;AACzI,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;AAElE,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;IACH,CAAC;CACF,CAAC;AACF,uBAAuB;AAEvB,eAAe,MAAM,CAAC"}
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,6 +1,6 @@
1
1
  {
2
2
  "name": "@osovv/vv-opencode",
3
- "version": "1.3.5",
3
+ "version": "1.3.6-rc.0",
4
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",
@@ -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",