@coool/opencode-adaptive 1.4.1 → 1.5.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/README.md +2 -1
- package/dist/adapters/opencode/index.d.ts +2 -0
- package/dist/adapters/opencode/index.js +2 -0
- package/dist/adapters/opencode/index.js.map +1 -1
- package/dist/adapters/opencode/process-ledger.d.ts +56 -0
- package/dist/adapters/opencode/process-ledger.js +143 -0
- package/dist/adapters/opencode/process-ledger.js.map +1 -0
- package/dist/adapters/opencode/session-ops.d.ts +2 -0
- package/dist/adapters/opencode/session-ops.js +15 -9
- package/dist/adapters/opencode/session-ops.js.map +1 -1
- package/dist/adapters/opencode/timer.d.ts +5 -0
- package/dist/adapters/opencode/timer.js +12 -0
- package/dist/adapters/opencode/timer.js.map +1 -0
- package/dist/execution/parking/index.d.ts +2 -1
- package/dist/execution/parking/index.js +2 -1
- package/dist/execution/parking/index.js.map +1 -1
- package/dist/execution/parking/wake.d.ts +52 -0
- package/dist/execution/parking/wake.js +95 -0
- package/dist/execution/parking/wake.js.map +1 -0
- package/dist/gui-experimental.cjs +3 -3
- package/dist/gui.d.ts +2 -2
- package/dist/gui.js +37 -3
- package/dist/gui.js.map +1 -1
- package/dist/index.js +33 -20
- package/dist/index.js.map +1 -1
- package/dist/rpc/status.d.ts +9 -0
- package/dist/rpc/status.js +1 -0
- package/dist/rpc/status.js.map +1 -1
- package/dist/state/parked-work/store.d.ts +5 -0
- package/dist/state/parked-work/store.js +24 -0
- package/dist/state/parked-work/store.js.map +1 -1
- package/dist/supervisor/supervisor.d.ts +2 -0
- package/dist/supervisor/supervisor.js +475 -106
- package/dist/supervisor/supervisor.js.map +1 -1
- package/dist/supervisor/types.d.ts +5 -0
- package/dist/supervisor/types.js.map +1 -1
- package/dist/tui.d.ts +13 -0
- package/dist/tui.js +62 -16
- package/dist/tui.js.map +1 -1
- package/dist/ui/flow/waiting.d.ts +11 -0
- package/dist/ui/flow/waiting.js +40 -0
- package/dist/ui/flow/waiting.js.map +1 -0
- package/dist/ui/gui/api.d.ts +2 -0
- package/dist/ui/gui/api.js +6 -2
- package/dist/ui/gui/api.js.map +1 -1
- package/package.json +1 -1
|
@@ -9,6 +9,7 @@ import type { ModelRef } from "../core/work-unit/types.js";
|
|
|
9
9
|
import type { SessionOpsSource } from "../adapters/opencode/session-ops.js";
|
|
10
10
|
import type { ModelSource } from "../adapters/opencode/inventory.js";
|
|
11
11
|
import type { StorageSource } from "../adapters/opencode/storage.js";
|
|
12
|
+
import type { ProcessLedger } from "../adapters/opencode/process-ledger.js";
|
|
12
13
|
/** The host session surface the supervisor actually uses. */
|
|
13
14
|
export interface SupervisorSessionSource extends SessionOpsSource {
|
|
14
15
|
get(input: {
|
|
@@ -44,6 +45,10 @@ export interface SupervisorOptions {
|
|
|
44
45
|
readonly storage: StorageSource;
|
|
45
46
|
/** Epoch-ms clock (injected so tests are deterministic). */
|
|
46
47
|
readonly clock: () => number;
|
|
48
|
+
/** One-shot timer for the parked-work wake; returns its cancel. */
|
|
49
|
+
readonly schedule: (callback: () => void, delayMs: number) => () => void;
|
|
50
|
+
/** What every plugin instance in the process shares (ADP-056). */
|
|
51
|
+
readonly ledger: ProcessLedger;
|
|
47
52
|
}
|
|
48
53
|
/** The Codex header sensor watches ChatGPT/Codex-backed resources. */
|
|
49
54
|
export declare const CODEX_PROVIDER_ID = "openai";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/supervisor/types.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/supervisor/types.ts"],"names":[],"mappings":"AAiDA,sEAAsE;AACtE,MAAM,CAAC,MAAM,iBAAiB,GAAG,QAAQ,CAAA","sourcesContent":["/**\n * Supervisor wiring types (ADP-029/031). Structural mirrors of the host\n * surfaces the supervisor consumes, so the supervisor never imports\n * `@opencode/plugin` (architecture rule: only the adapters touch the host\n * package) while the real host domains remain directly assignable — method\n * parameters are bivariant, so `ctx.session` satisfies the mirror.\n */\nimport type { ModelRef } from \"../core/work-unit/types.js\"\nimport type { SessionOpsSource } from \"../adapters/opencode/session-ops.js\"\nimport type { ModelSource } from \"../adapters/opencode/inventory.js\"\nimport type { StorageSource } from \"../adapters/opencode/storage.js\"\nimport type { ProcessLedger } from \"../adapters/opencode/process-ledger.js\"\n\n/** The host session surface the supervisor actually uses. */\nexport interface SupervisorSessionSource extends SessionOpsSource {\n get(input: { sessionID: string }): Promise<unknown>\n}\n\n/**\n * Structural mirror of the host `retry` hook input. The retry handler OWNS\n * `decision` — a veto assigns `{ retry: false }` (host hooks mutate their\n * inputs; callbacks never return replacements).\n */\nexport interface RetryHookInput {\n readonly sessionID: string\n readonly model: ModelRef\n readonly error: {\n readonly type: string\n readonly message: string\n readonly status?: number | undefined\n readonly retryAfterMs?: number | undefined\n }\n readonly attempt: number\n decision: { retry: false } | { retry: true; delay: number }\n}\n\n/** Everything the supervisor needs from the host. */\nexport interface SupervisorOptions {\n readonly session: SupervisorSessionSource\n readonly model: ModelSource\n readonly storage: StorageSource\n /** Epoch-ms clock (injected so tests are deterministic). */\n readonly clock: () => number\n /** One-shot timer for the parked-work wake; returns its cancel. */\n readonly schedule: (callback: () => void, delayMs: number) => () => void\n /** What every plugin instance in the process shares (ADP-056). */\n readonly ledger: ProcessLedger\n}\n\n/** The Codex header sensor watches ChatGPT/Codex-backed resources. */\nexport const CODEX_PROVIDER_ID = \"openai\"\n"]}
|
package/dist/tui.d.ts
CHANGED
|
@@ -11,5 +11,18 @@ export interface Chip {
|
|
|
11
11
|
* but calmer than full-brightness ANSI red, which reads as an error.
|
|
12
12
|
*/
|
|
13
13
|
export declare function chipFor(mode: OperatingMode): Chip;
|
|
14
|
+
/** A parked session's chip (ADP-024): amber like any pending state, with when it resumes. */
|
|
15
|
+
export declare function waitingChip(resumeAt: number | null, now: number): Chip;
|
|
16
|
+
/**
|
|
17
|
+
* The prompt footer chip for one session: parked work waiting for quota wins
|
|
18
|
+
* over the mode, then the session's override, then the global mode (ADP-054).
|
|
19
|
+
* `override` is undefined until fetched; null means "follows global".
|
|
20
|
+
*/
|
|
21
|
+
export declare function sessionChip(state: {
|
|
22
|
+
mode: OperatingMode | null;
|
|
23
|
+
override: OperatingMode | null | undefined;
|
|
24
|
+
resumeAt: number | null | undefined;
|
|
25
|
+
now: number;
|
|
26
|
+
}): Chip | null;
|
|
14
27
|
declare const _default: import("@opencode/plugin/tui/plugin").Definition;
|
|
15
28
|
export default _default;
|
package/dist/tui.js
CHANGED
|
@@ -14,12 +14,13 @@ import { jsx as _jsx, jsxs as _jsxs } from "@opentui/solid/jsx-runtime";
|
|
|
14
14
|
*/
|
|
15
15
|
import { define } from "@opencode/plugin/tui/plugin";
|
|
16
16
|
import { TextAttributes } from "@opentui/core";
|
|
17
|
-
import { createStore } from "solid-js/store";
|
|
17
|
+
import { createStore, reconcile } from "solid-js/store";
|
|
18
18
|
import { PLUGIN_ID } from "./plugin-id.js";
|
|
19
19
|
import { adaptiveRpc } from "./rpc/definition.js";
|
|
20
20
|
import { parseMode } from "./state/settings/index.js";
|
|
21
21
|
import { runAdaptive } from "./ui/flow/controller.js";
|
|
22
22
|
import { errorText } from "./ui/flow/options.js";
|
|
23
|
+
import { WAITING_POLL_MS, waitingLabel, waitingSessions } from "./ui/flow/waiting.js";
|
|
23
24
|
import { matchOptions } from "./ui/tui/search.js";
|
|
24
25
|
/**
|
|
25
26
|
* Label/color mapping for the footer chip. Pure so the mapping is testable
|
|
@@ -37,6 +38,21 @@ export function chipFor(mode) {
|
|
|
37
38
|
return { text: "Adaptive · off", fg: "#e57373" };
|
|
38
39
|
}
|
|
39
40
|
}
|
|
41
|
+
/** A parked session's chip (ADP-024): amber like any pending state, with when it resumes. */
|
|
42
|
+
export function waitingChip(resumeAt, now) {
|
|
43
|
+
return { text: `Adaptive · ${waitingLabel(resumeAt, now)}`, fg: "#e5c07b" };
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* The prompt footer chip for one session: parked work waiting for quota wins
|
|
47
|
+
* over the mode, then the session's override, then the global mode (ADP-054).
|
|
48
|
+
* `override` is undefined until fetched; null means "follows global".
|
|
49
|
+
*/
|
|
50
|
+
export function sessionChip(state) {
|
|
51
|
+
if (state.resumeAt !== undefined)
|
|
52
|
+
return waitingChip(state.resumeAt, state.now);
|
|
53
|
+
const mode = state.override ?? state.mode;
|
|
54
|
+
return mode === null ? null : chipFor(mode);
|
|
55
|
+
}
|
|
40
56
|
const BOOT_FETCH_RETRIES = 5;
|
|
41
57
|
const BOOT_FETCH_RETRY_MS = 2000;
|
|
42
58
|
export default define({
|
|
@@ -152,9 +168,10 @@ export default define({
|
|
|
152
168
|
],
|
|
153
169
|
}));
|
|
154
170
|
// Footer chip state: a reactive mirror of the server's operating mode,
|
|
155
|
-
// fetched once at boot and kept live via the settings-changed event,
|
|
156
|
-
//
|
|
157
|
-
|
|
171
|
+
// fetched once at boot and kept live via the settings-changed event, the
|
|
172
|
+
// per-session overrides seen so far (ADP-054), and the sessions parked
|
|
173
|
+
// until quota returns (ADP-024) with the clock they were read at.
|
|
174
|
+
const [chip, setChip] = createStore({ mode: null, sessions: {}, waiting: {}, now: Date.now() });
|
|
158
175
|
const fetchMode = async () => {
|
|
159
176
|
try {
|
|
160
177
|
const settings = await api.settings();
|
|
@@ -181,6 +198,27 @@ export default define({
|
|
|
181
198
|
setChip("sessions", sessionID, null);
|
|
182
199
|
}
|
|
183
200
|
};
|
|
201
|
+
/**
|
|
202
|
+
* Parked sessions come from the status snapshot. Work parks and resumes
|
|
203
|
+
* without any TUI action (a failed execution, the server's wake timer),
|
|
204
|
+
* so the chip polls; a failed read keeps the last known state.
|
|
205
|
+
*/
|
|
206
|
+
let waitingReads = 0;
|
|
207
|
+
const fetchWaiting = async () => {
|
|
208
|
+
// A poll and an event-driven read can overlap: only the latest lands.
|
|
209
|
+
waitingReads += 1;
|
|
210
|
+
const read = waitingReads;
|
|
211
|
+
try {
|
|
212
|
+
const sessions = waitingSessions(await api.status());
|
|
213
|
+
if (read !== waitingReads)
|
|
214
|
+
return;
|
|
215
|
+
setChip("waiting", reconcile(sessions));
|
|
216
|
+
setChip("now", Date.now());
|
|
217
|
+
}
|
|
218
|
+
catch {
|
|
219
|
+
// Keep the last known state until the next poll.
|
|
220
|
+
}
|
|
221
|
+
};
|
|
184
222
|
const bootFetch = async (retriesLeft) => {
|
|
185
223
|
if (await fetchMode())
|
|
186
224
|
return;
|
|
@@ -192,10 +230,9 @@ export default define({
|
|
|
192
230
|
setTimeout(() => void bootFetch(retriesLeft - 1), BOOT_FETCH_RETRY_MS);
|
|
193
231
|
}
|
|
194
232
|
};
|
|
195
|
-
const renderChip = (
|
|
196
|
-
if (
|
|
233
|
+
const renderChip = (entry) => {
|
|
234
|
+
if (entry === null)
|
|
197
235
|
return _jsx("text", {});
|
|
198
|
-
const entry = chipFor(mode);
|
|
199
236
|
// The accent-colored span cannot execute in-repo: the terminal renderer
|
|
200
237
|
// cannot start headless and jsdom's HTML parser mangles the intrinsic
|
|
201
238
|
// <text><span> template (null insert parent). The chipFor tests pin the
|
|
@@ -208,18 +245,21 @@ export default define({
|
|
|
208
245
|
};
|
|
209
246
|
const chipNode = (sessionID) => {
|
|
210
247
|
// On home (no session id) the chip shows the global mode; in a session
|
|
211
|
-
// it shows the session's EFFECTIVE mode (override ?? global).
|
|
248
|
+
// it shows the session's wait or EFFECTIVE mode (override ?? global).
|
|
212
249
|
if (sessionID === undefined)
|
|
213
|
-
return renderChip(chip.mode);
|
|
250
|
+
return renderChip(chip.mode === null ? null : chipFor(chip.mode));
|
|
214
251
|
const override = chip.sessions[sessionID];
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
252
|
+
// First render for this session: fetch the override; the store write
|
|
253
|
+
// re-renders this node with the fetched value. Until then the global
|
|
254
|
+
// mode is shown.
|
|
255
|
+
if (override === undefined)
|
|
219
256
|
void fetchSessionMode(sessionID);
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
257
|
+
return renderChip(sessionChip({
|
|
258
|
+
mode: chip.mode,
|
|
259
|
+
override,
|
|
260
|
+
resumeAt: chip.waiting[sessionID],
|
|
261
|
+
now: chip.now,
|
|
262
|
+
}));
|
|
223
263
|
};
|
|
224
264
|
// The home footer slot only exists on the home screen; sessions render
|
|
225
265
|
// the prompt footer — its slot input carries the open session's id, so
|
|
@@ -233,6 +273,8 @@ export default define({
|
|
|
233
273
|
];
|
|
234
274
|
const disposeWatch = client.events.on("settings-changed", () => {
|
|
235
275
|
void fetchMode();
|
|
276
|
+
// Only active sessions wait: a mode change can start or end a wait.
|
|
277
|
+
void fetchWaiting();
|
|
236
278
|
// A global mode change re-renders override-less sessions reactively;
|
|
237
279
|
// cached overrides are re-fetched so a stale mirror cannot stick.
|
|
238
280
|
for (const sessionID of Object.keys(chip.sessions)) {
|
|
@@ -245,13 +287,17 @@ export default define({
|
|
|
245
287
|
const sessionID = event.data.sessionID;
|
|
246
288
|
if (typeof sessionID === "string")
|
|
247
289
|
void fetchSessionMode(sessionID);
|
|
290
|
+
void fetchWaiting();
|
|
248
291
|
});
|
|
249
292
|
void bootFetch(BOOT_FETCH_RETRIES);
|
|
293
|
+
void fetchWaiting();
|
|
294
|
+
const waitingPoll = setInterval(() => void fetchWaiting(), WAITING_POLL_MS);
|
|
250
295
|
return () => {
|
|
251
296
|
for (const dispose of disposeSlots)
|
|
252
297
|
dispose();
|
|
253
298
|
disposeWatch();
|
|
254
299
|
disposeSessionWatch();
|
|
300
|
+
clearInterval(waitingPoll);
|
|
255
301
|
};
|
|
256
302
|
},
|
|
257
303
|
});
|
package/dist/tui.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tui.js","sourceRoot":"","sources":["../src/tui.tsx"],"names":[],"mappings":"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","sourcesContent":["/** @jsxImportSource @opentui/solid */\n// The pragma pins the JSX runtime for this file. The host compiles plugin\n// sources in a cache dir where its loader's tsconfig lookup finds nothing and\n// its default (react/jsx-runtime) fails to resolve there (empirical, sibling\n// @coool plugins); our own tsc build reads the same pragma, so dist/tui.js\n// imports @opentui/solid/jsx-runtime — the renderer the slot render runs on.\n/**\n * TUI entrypoint (ADP-033): registers the `/adaptive` slash command and\n * drives the dialog-based flows through typed RPC, plus the footer status\n * chip rendered through host UI slots. The TUI is a thin view — no local\n * settings state beyond the chip's reactive mode mirror; the server stays\n * the single source of truth. This file is the repo's one JSX surface.\n */\nimport { define } from \"@opencode/plugin/tui/plugin\"\nimport type { Context } from \"@opencode/plugin/tui/plugin\"\nimport { TextAttributes } from \"@opentui/core\"\nimport { createStore } from \"solid-js/store\"\nimport { PLUGIN_ID } from \"./plugin-id.js\"\nimport { adaptiveRpc } from \"./rpc/definition.js\"\nimport type { OperatingMode } from \"./core/scheduler/types.js\"\nimport { parseMode } from \"./state/settings/index.js\"\nimport { runAdaptive } from \"./ui/flow/controller.js\"\nimport type { AdaptiveApi, AdaptiveView } from \"./ui/flow/controller.js\"\nimport { errorText } from \"./ui/flow/options.js\"\nimport type { ModelSummary } from \"./ui/flow/tiers.js\"\nimport { matchOptions } from \"./ui/tui/search.js\"\n\n/** Footer chip appearance: label plus foreground color (null = theme default). */\nexport interface Chip {\n readonly text: string\n readonly fg: string | null\n}\n\n/**\n * Label/color mapping for the footer chip. Pure so the mapping is testable\n * without a JSX runtime: active is green (supervision engaged), observe is\n * the neutral default (visible but calm), off is a soft red — noticeable,\n * but calmer than full-brightness ANSI red, which reads as an error.\n */\nexport function chipFor(mode: OperatingMode): Chip {\n switch (mode) {\n case \"active\":\n return { text: \"Adaptive · active\", fg: \"green\" }\n case \"observe\":\n return { text: \"Adaptive · observe\", fg: null }\n case \"off\":\n return { text: \"Adaptive · off\", fg: \"#e57373\" }\n }\n}\n\nconst BOOT_FETCH_RETRIES = 5\nconst BOOT_FETCH_RETRY_MS = 2000\n\nexport default define({\n id: PLUGIN_ID,\n setup(context: Context) {\n const client = context.client.rpc(adaptiveRpc)\n // RPC handlers resolve per location: a location-less call never reaches a\n // project-local plugin's handlers (\"RPC is unavailable\", verified live in\n // the sibling @coool plugins), so every call carries the TUI's location.\n const at = () => ({ location: context.location })\n const api: AdaptiveApi = {\n settings: () => client[\"settings.get\"](undefined, at()),\n setSettings: (patch) => client[\"settings.set\"](patch, at()),\n status: () => client[\"status.get\"](undefined, at()),\n receipts: () => client[\"receipts.list\"](undefined, at()),\n sessionMode: (sessionID) =>\n client[\"session-mode.get\"]({ sessionID }, at()).then((out) => out.mode),\n setSessionMode: (sessionID, mode) => client[\"session-mode.set\"]({ sessionID, mode }, at()),\n tierRequest: (sessionID) =>\n client[\"tier-request.get\"]({ sessionID }, at()).then((out) => out.tier),\n setTierRequest: (sessionID, tier) => client[\"tier-request.set\"]({ sessionID, tier }, at()),\n }\n const view: AdaptiveView = {\n // A placeholder marks a searchable list (the model picker).\n select: (options) =>\n context.ui.dialog.select(\n options.placeholder === undefined ? options : { ...options, search: matchOptions },\n ),\n selectPaged: <Value,>(spec: {\n title: string\n options: readonly { title: string; value: Value }[]\n actions: readonly { title: string; value: string; bind: string }[]\n }) =>\n // Footer actions flip pages: triggering one closes the dialog and\n // resolves with the action instead of a pick; the controller loop\n // then reopens the browser at the new offset. The host resolves its\n // own select promise undefined on the clear() — resolving our\n // promise first-come means the action result wins.\n new Promise<{ picked: Value | undefined; action: string | undefined }>(\n (resolve, reject) => {\n void context.ui.dialog\n .select({\n title: spec.title,\n options: spec.options,\n actions: spec.actions.map((action) => ({\n bind: action.bind,\n title: action.title,\n selection: \"none\" as const,\n onTrigger: () => {\n context.ui.dialog.clear()\n resolve({ picked: undefined, action: action.value })\n },\n })),\n })\n .then((picked) => {\n resolve({ picked, action: undefined })\n }, reject)\n },\n ),\n confirm: (options) => context.ui.dialog.confirm(options),\n alert: (options) => context.ui.dialog.alert(options),\n table: (spec) =>\n // The host has no table dialog; a custom dialog render gives the\n // column grid its own layout. The default dialog size is too narrow\n // for the column grid (rows wrap mid-token), so the dialog is\n // widened to xlarge right after it opens. Escape closes the dialog\n // and fires onClose, which resolves the view promise.\n new Promise<void>((resolve) => {\n context.ui.dialog.show(\n () => (\n // Styled to match the host's own dialogs (bold title, dim esc\n // hint). The host dialog panel already insets the content, so\n // the box adds no top padding of its own; a blank spacer row\n // separates the title row from the table.\n <box style={{ flexDirection: \"column\", paddingBottom: 1, paddingX: 2 }}>\n <box style={{ flexDirection: \"row\", justifyContent: \"space-between\" }}>\n <text style={{ attributes: TextAttributes.BOLD }}>{spec.title}</text>\n <text style={{ attributes: TextAttributes.DIM }}>esc</text>\n </box>\n <text> </text>\n {spec.lines.map((line) => (\n <text>{line}</text>\n ))}\n </box>\n ),\n () => {\n resolve()\n },\n )\n context.ui.dialog.set({ size: \"xlarge\" })\n }),\n toast: (message, variant) => {\n context.ui.toast.show({ message, variant })\n },\n }\n // Real OpenCode models for the tier editor search (ADP-033); structural\n // summaries keep the view models free of client types.\n const models = (): readonly ModelSummary[] => {\n const list = context.data.location.model.list(context.location)\n return (list ?? []).map((info) => ({\n providerID: info.providerID,\n modelID: info.modelID,\n name: info.name,\n variants: info.variants.map((variant) => variant.id),\n }))\n }\n context.keymap.layer(() => ({\n // \"global\" opts out of input-mode scoping: the default (\"base\") binds\n // the commands to one OpenCode input mode, which kept the palette from\n // matching them (the sibling @coool plugins register the same way).\n mode: \"global\",\n commands: [\n {\n id: \"coool.adaptive.menu\",\n title: \"Adaptive\",\n group: \"Adaptive\",\n palette: true,\n // Surface the command in the palette's suggested row: discovery was\n // the reason users never found the menu at all.\n suggested: true,\n slash: { name: \"adaptive\" },\n run: () => {\n // Inside a session the flows steer that session's mode override\n // (ADP-054); on home they patch the global mode.\n const current = context.ui.router.current()\n const sessionID = current.type === \"session\" ? current.sessionID : undefined\n void runAdaptive({\n api,\n view,\n models,\n ...(sessionID !== undefined ? { sessionID } : {}),\n }).catch((error: unknown) => {\n view.toast(errorText(error), \"error\")\n })\n },\n },\n ],\n }))\n\n // Footer chip state: a reactive mirror of the server's operating mode,\n // fetched once at boot and kept live via the settings-changed event, plus\n // the per-session overrides seen so far (ADP-054).\n const [chip, setChip] = createStore<{\n mode: OperatingMode | null\n sessions: Record<string, OperatingMode | null>\n }>({ mode: null, sessions: {} })\n\n const fetchMode = async (): Promise<boolean> => {\n try {\n const settings = await api.settings()\n const mode = parseMode(settings.mode)\n if (mode !== undefined) setChip(\"mode\", mode)\n return true\n } catch {\n return false\n }\n }\n\n /**\n * One session's override, cached so the chip never re-fetches per render.\n * A fetch failure caches `null` (follow global): the chip stays correct\n * for override-less sessions, and a later `session-mode-changed` event\n * refreshes sessions that do carry an override.\n */\n const fetchSessionMode = async (sessionID: string): Promise<void> => {\n try {\n setChip(\"sessions\", sessionID, await api.sessionMode(sessionID))\n } catch {\n setChip(\"sessions\", sessionID, null)\n }\n }\n\n const bootFetch = async (retriesLeft: number): Promise<void> => {\n if (await fetchMode()) return\n // The server plugin may not be registered yet at TUI boot; retry\n // quietly. Bounded (unlike the sibling plugins' unbounded retry) so the\n // timer loop provably terminates: after the cap the chip stays hidden\n // until the next settings-changed event refreshes it.\n if (retriesLeft > 0) {\n setTimeout(() => void bootFetch(retriesLeft - 1), BOOT_FETCH_RETRY_MS)\n }\n }\n\n const renderChip = (mode: OperatingMode | null) => {\n if (mode === null) return <text></text>\n const entry = chipFor(mode)\n // The accent-colored span cannot execute in-repo: the terminal renderer\n // cannot start headless and jsdom's HTML parser mangles the intrinsic\n // <text><span> template (null insert parent). The chipFor tests pin the\n // color mapping; the chip render test pins the plain observe shape.\n /* v8 ignore start */\n if (entry.fg === null) return <text>{entry.text}</text>\n return (\n <text>\n <span style={{ fg: entry.fg }}>{entry.text}</span>\n </text>\n )\n /* v8 ignore stop */\n }\n const chipNode = (sessionID: string | undefined) => {\n // On home (no session id) the chip shows the global mode; in a session\n // it shows the session's EFFECTIVE mode (override ?? global).\n if (sessionID === undefined) return renderChip(chip.mode)\n const override = chip.sessions[sessionID]\n if (override === undefined) {\n // First render for this session: fetch the override; the store write\n // re-renders this node with the fetched value. Until then the global\n // mode is shown.\n void fetchSessionMode(sessionID)\n return renderChip(chip.mode)\n }\n return renderChip(override ?? chip.mode)\n }\n // The home footer slot only exists on the home screen; sessions render\n // the prompt footer — its slot input carries the open session's id, so\n // the chip there shows that session's effective mode (ADP-054).\n const disposeSlots = [\n context.ui.slot({ append: \"home.footer.status\", render: () => chipNode(undefined) }),\n context.ui.slot({\n append: \"prompt.footer.status\",\n render: (input) => chipNode(input.sessionID),\n }),\n ]\n\n const disposeWatch = client.events.on(\"settings-changed\", () => {\n void fetchMode()\n // A global mode change re-renders override-less sessions reactively;\n // cached overrides are re-fetched so a stale mirror cannot stick.\n for (const sessionID of Object.keys(chip.sessions)) {\n void fetchSessionMode(sessionID)\n }\n })\n const disposeSessionWatch = client.events.on(\"session-mode-changed\", (event) => {\n // The event data crosses the wire as an untyped record: a malformed\n // payload is ignored (fail-open) instead of steering a bogus session.\n const sessionID = event.data.sessionID\n if (typeof sessionID === \"string\") void fetchSessionMode(sessionID)\n })\n\n void bootFetch(BOOT_FETCH_RETRIES)\n\n return () => {\n for (const dispose of disposeSlots) dispose()\n disposeWatch()\n disposeSessionWatch()\n }\n },\n})\n"]}
|
|
1
|
+
{"version":3,"file":"tui.js","sourceRoot":"","sources":["../src/tui.tsx"],"names":[],"mappings":"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","sourcesContent":["/** @jsxImportSource @opentui/solid */\n// The pragma pins the JSX runtime for this file. The host compiles plugin\n// sources in a cache dir where its loader's tsconfig lookup finds nothing and\n// its default (react/jsx-runtime) fails to resolve there (empirical, sibling\n// @coool plugins); our own tsc build reads the same pragma, so dist/tui.js\n// imports @opentui/solid/jsx-runtime — the renderer the slot render runs on.\n/**\n * TUI entrypoint (ADP-033): registers the `/adaptive` slash command and\n * drives the dialog-based flows through typed RPC, plus the footer status\n * chip rendered through host UI slots. The TUI is a thin view — no local\n * settings state beyond the chip's reactive mode mirror; the server stays\n * the single source of truth. This file is the repo's one JSX surface.\n */\nimport { define } from \"@opencode/plugin/tui/plugin\"\nimport type { Context } from \"@opencode/plugin/tui/plugin\"\nimport { TextAttributes } from \"@opentui/core\"\nimport { createStore, reconcile } from \"solid-js/store\"\nimport { PLUGIN_ID } from \"./plugin-id.js\"\nimport { adaptiveRpc } from \"./rpc/definition.js\"\nimport type { OperatingMode } from \"./core/scheduler/types.js\"\nimport { parseMode } from \"./state/settings/index.js\"\nimport { runAdaptive } from \"./ui/flow/controller.js\"\nimport type { AdaptiveApi, AdaptiveView } from \"./ui/flow/controller.js\"\nimport { errorText } from \"./ui/flow/options.js\"\nimport type { ModelSummary } from \"./ui/flow/tiers.js\"\nimport { WAITING_POLL_MS, waitingLabel, waitingSessions } from \"./ui/flow/waiting.js\"\nimport { matchOptions } from \"./ui/tui/search.js\"\n\n/** Footer chip appearance: label plus foreground color (null = theme default). */\nexport interface Chip {\n readonly text: string\n readonly fg: string | null\n}\n\n/**\n * Label/color mapping for the footer chip. Pure so the mapping is testable\n * without a JSX runtime: active is green (supervision engaged), observe is\n * the neutral default (visible but calm), off is a soft red — noticeable,\n * but calmer than full-brightness ANSI red, which reads as an error.\n */\nexport function chipFor(mode: OperatingMode): Chip {\n switch (mode) {\n case \"active\":\n return { text: \"Adaptive · active\", fg: \"green\" }\n case \"observe\":\n return { text: \"Adaptive · observe\", fg: null }\n case \"off\":\n return { text: \"Adaptive · off\", fg: \"#e57373\" }\n }\n}\n\n/** A parked session's chip (ADP-024): amber like any pending state, with when it resumes. */\nexport function waitingChip(resumeAt: number | null, now: number): Chip {\n return { text: `Adaptive · ${waitingLabel(resumeAt, now)}`, fg: \"#e5c07b\" }\n}\n\n/**\n * The prompt footer chip for one session: parked work waiting for quota wins\n * over the mode, then the session's override, then the global mode (ADP-054).\n * `override` is undefined until fetched; null means \"follows global\".\n */\nexport function sessionChip(state: {\n mode: OperatingMode | null\n override: OperatingMode | null | undefined\n resumeAt: number | null | undefined\n now: number\n}): Chip | null {\n if (state.resumeAt !== undefined) return waitingChip(state.resumeAt, state.now)\n const mode = state.override ?? state.mode\n return mode === null ? null : chipFor(mode)\n}\n\nconst BOOT_FETCH_RETRIES = 5\nconst BOOT_FETCH_RETRY_MS = 2000\n\nexport default define({\n id: PLUGIN_ID,\n setup(context: Context) {\n const client = context.client.rpc(adaptiveRpc)\n // RPC handlers resolve per location: a location-less call never reaches a\n // project-local plugin's handlers (\"RPC is unavailable\", verified live in\n // the sibling @coool plugins), so every call carries the TUI's location.\n const at = () => ({ location: context.location })\n const api: AdaptiveApi = {\n settings: () => client[\"settings.get\"](undefined, at()),\n setSettings: (patch) => client[\"settings.set\"](patch, at()),\n status: () => client[\"status.get\"](undefined, at()),\n receipts: () => client[\"receipts.list\"](undefined, at()),\n sessionMode: (sessionID) =>\n client[\"session-mode.get\"]({ sessionID }, at()).then((out) => out.mode),\n setSessionMode: (sessionID, mode) => client[\"session-mode.set\"]({ sessionID, mode }, at()),\n tierRequest: (sessionID) =>\n client[\"tier-request.get\"]({ sessionID }, at()).then((out) => out.tier),\n setTierRequest: (sessionID, tier) => client[\"tier-request.set\"]({ sessionID, tier }, at()),\n }\n const view: AdaptiveView = {\n // A placeholder marks a searchable list (the model picker).\n select: (options) =>\n context.ui.dialog.select(\n options.placeholder === undefined ? options : { ...options, search: matchOptions },\n ),\n selectPaged: <Value,>(spec: {\n title: string\n options: readonly { title: string; value: Value }[]\n actions: readonly { title: string; value: string; bind: string }[]\n }) =>\n // Footer actions flip pages: triggering one closes the dialog and\n // resolves with the action instead of a pick; the controller loop\n // then reopens the browser at the new offset. The host resolves its\n // own select promise undefined on the clear() — resolving our\n // promise first-come means the action result wins.\n new Promise<{ picked: Value | undefined; action: string | undefined }>(\n (resolve, reject) => {\n void context.ui.dialog\n .select({\n title: spec.title,\n options: spec.options,\n actions: spec.actions.map((action) => ({\n bind: action.bind,\n title: action.title,\n selection: \"none\" as const,\n onTrigger: () => {\n context.ui.dialog.clear()\n resolve({ picked: undefined, action: action.value })\n },\n })),\n })\n .then((picked) => {\n resolve({ picked, action: undefined })\n }, reject)\n },\n ),\n confirm: (options) => context.ui.dialog.confirm(options),\n alert: (options) => context.ui.dialog.alert(options),\n table: (spec) =>\n // The host has no table dialog; a custom dialog render gives the\n // column grid its own layout. The default dialog size is too narrow\n // for the column grid (rows wrap mid-token), so the dialog is\n // widened to xlarge right after it opens. Escape closes the dialog\n // and fires onClose, which resolves the view promise.\n new Promise<void>((resolve) => {\n context.ui.dialog.show(\n () => (\n // Styled to match the host's own dialogs (bold title, dim esc\n // hint). The host dialog panel already insets the content, so\n // the box adds no top padding of its own; a blank spacer row\n // separates the title row from the table.\n <box style={{ flexDirection: \"column\", paddingBottom: 1, paddingX: 2 }}>\n <box style={{ flexDirection: \"row\", justifyContent: \"space-between\" }}>\n <text style={{ attributes: TextAttributes.BOLD }}>{spec.title}</text>\n <text style={{ attributes: TextAttributes.DIM }}>esc</text>\n </box>\n <text> </text>\n {spec.lines.map((line) => (\n <text>{line}</text>\n ))}\n </box>\n ),\n () => {\n resolve()\n },\n )\n context.ui.dialog.set({ size: \"xlarge\" })\n }),\n toast: (message, variant) => {\n context.ui.toast.show({ message, variant })\n },\n }\n // Real OpenCode models for the tier editor search (ADP-033); structural\n // summaries keep the view models free of client types.\n const models = (): readonly ModelSummary[] => {\n const list = context.data.location.model.list(context.location)\n return (list ?? []).map((info) => ({\n providerID: info.providerID,\n modelID: info.modelID,\n name: info.name,\n variants: info.variants.map((variant) => variant.id),\n }))\n }\n context.keymap.layer(() => ({\n // \"global\" opts out of input-mode scoping: the default (\"base\") binds\n // the commands to one OpenCode input mode, which kept the palette from\n // matching them (the sibling @coool plugins register the same way).\n mode: \"global\",\n commands: [\n {\n id: \"coool.adaptive.menu\",\n title: \"Adaptive\",\n group: \"Adaptive\",\n palette: true,\n // Surface the command in the palette's suggested row: discovery was\n // the reason users never found the menu at all.\n suggested: true,\n slash: { name: \"adaptive\" },\n run: () => {\n // Inside a session the flows steer that session's mode override\n // (ADP-054); on home they patch the global mode.\n const current = context.ui.router.current()\n const sessionID = current.type === \"session\" ? current.sessionID : undefined\n void runAdaptive({\n api,\n view,\n models,\n ...(sessionID !== undefined ? { sessionID } : {}),\n }).catch((error: unknown) => {\n view.toast(errorText(error), \"error\")\n })\n },\n },\n ],\n }))\n\n // Footer chip state: a reactive mirror of the server's operating mode,\n // fetched once at boot and kept live via the settings-changed event, the\n // per-session overrides seen so far (ADP-054), and the sessions parked\n // until quota returns (ADP-024) with the clock they were read at.\n const [chip, setChip] = createStore<{\n mode: OperatingMode | null\n sessions: Record<string, OperatingMode | null>\n waiting: Record<string, number | null>\n now: number\n }>({ mode: null, sessions: {}, waiting: {}, now: Date.now() })\n\n const fetchMode = async (): Promise<boolean> => {\n try {\n const settings = await api.settings()\n const mode = parseMode(settings.mode)\n if (mode !== undefined) setChip(\"mode\", mode)\n return true\n } catch {\n return false\n }\n }\n\n /**\n * One session's override, cached so the chip never re-fetches per render.\n * A fetch failure caches `null` (follow global): the chip stays correct\n * for override-less sessions, and a later `session-mode-changed` event\n * refreshes sessions that do carry an override.\n */\n const fetchSessionMode = async (sessionID: string): Promise<void> => {\n try {\n setChip(\"sessions\", sessionID, await api.sessionMode(sessionID))\n } catch {\n setChip(\"sessions\", sessionID, null)\n }\n }\n\n /**\n * Parked sessions come from the status snapshot. Work parks and resumes\n * without any TUI action (a failed execution, the server's wake timer),\n * so the chip polls; a failed read keeps the last known state.\n */\n let waitingReads = 0\n const fetchWaiting = async (): Promise<void> => {\n // A poll and an event-driven read can overlap: only the latest lands.\n waitingReads += 1\n const read = waitingReads\n try {\n const sessions = waitingSessions(await api.status())\n if (read !== waitingReads) return\n setChip(\"waiting\", reconcile(sessions))\n setChip(\"now\", Date.now())\n } catch {\n // Keep the last known state until the next poll.\n }\n }\n\n const bootFetch = async (retriesLeft: number): Promise<void> => {\n if (await fetchMode()) return\n // The server plugin may not be registered yet at TUI boot; retry\n // quietly. Bounded (unlike the sibling plugins' unbounded retry) so the\n // timer loop provably terminates: after the cap the chip stays hidden\n // until the next settings-changed event refreshes it.\n if (retriesLeft > 0) {\n setTimeout(() => void bootFetch(retriesLeft - 1), BOOT_FETCH_RETRY_MS)\n }\n }\n\n const renderChip = (entry: Chip | null) => {\n if (entry === null) return <text></text>\n // The accent-colored span cannot execute in-repo: the terminal renderer\n // cannot start headless and jsdom's HTML parser mangles the intrinsic\n // <text><span> template (null insert parent). The chipFor tests pin the\n // color mapping; the chip render test pins the plain observe shape.\n /* v8 ignore start */\n if (entry.fg === null) return <text>{entry.text}</text>\n return (\n <text>\n <span style={{ fg: entry.fg }}>{entry.text}</span>\n </text>\n )\n /* v8 ignore stop */\n }\n const chipNode = (sessionID: string | undefined) => {\n // On home (no session id) the chip shows the global mode; in a session\n // it shows the session's wait or EFFECTIVE mode (override ?? global).\n if (sessionID === undefined) return renderChip(chip.mode === null ? null : chipFor(chip.mode))\n const override = chip.sessions[sessionID]\n // First render for this session: fetch the override; the store write\n // re-renders this node with the fetched value. Until then the global\n // mode is shown.\n if (override === undefined) void fetchSessionMode(sessionID)\n return renderChip(\n sessionChip({\n mode: chip.mode,\n override,\n resumeAt: chip.waiting[sessionID],\n now: chip.now,\n }),\n )\n }\n // The home footer slot only exists on the home screen; sessions render\n // the prompt footer — its slot input carries the open session's id, so\n // the chip there shows that session's effective mode (ADP-054).\n const disposeSlots = [\n context.ui.slot({ append: \"home.footer.status\", render: () => chipNode(undefined) }),\n context.ui.slot({\n append: \"prompt.footer.status\",\n render: (input) => chipNode(input.sessionID),\n }),\n ]\n\n const disposeWatch = client.events.on(\"settings-changed\", () => {\n void fetchMode()\n // Only active sessions wait: a mode change can start or end a wait.\n void fetchWaiting()\n // A global mode change re-renders override-less sessions reactively;\n // cached overrides are re-fetched so a stale mirror cannot stick.\n for (const sessionID of Object.keys(chip.sessions)) {\n void fetchSessionMode(sessionID)\n }\n })\n const disposeSessionWatch = client.events.on(\"session-mode-changed\", (event) => {\n // The event data crosses the wire as an untyped record: a malformed\n // payload is ignored (fail-open) instead of steering a bogus session.\n const sessionID = event.data.sessionID\n if (typeof sessionID === \"string\") void fetchSessionMode(sessionID)\n void fetchWaiting()\n })\n\n void bootFetch(BOOT_FETCH_RETRIES)\n void fetchWaiting()\n const waitingPoll = setInterval(() => void fetchWaiting(), WAITING_POLL_MS)\n\n return () => {\n for (const dispose of disposeSlots) dispose()\n disposeWatch()\n disposeSessionWatch()\n clearInterval(waitingPoll)\n }\n },\n})\n"]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { StatusSnapshot } from "../../rpc/status.js";
|
|
2
|
+
/** How often a view re-reads parked sessions: wakes land at second granularity, a few seconds' lag is fine. */
|
|
3
|
+
export declare const WAITING_POLL_MS = 10000;
|
|
4
|
+
/** Parked sessions by id, mapped to when their tier is next expected to be usable (null = unknown). */
|
|
5
|
+
export declare function waitingSessions(snapshot: StatusSnapshot): Record<string, number | null>;
|
|
6
|
+
/**
|
|
7
|
+
* Short human text for a parked session (ADP-024): "waiting · resumes 18:42". Weekly limits reset days away, so
|
|
8
|
+
* a later day gains its weekday, and beyond a week its date. Local fields, not the locale formatter, keep the
|
|
9
|
+
* text identical across hosts.
|
|
10
|
+
*/
|
|
11
|
+
export declare function waitingLabel(resumeAt: number | null, now: number): string;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/** How often a view re-reads parked sessions: wakes land at second granularity, a few seconds' lag is fine. */
|
|
2
|
+
export const WAITING_POLL_MS = 10_000;
|
|
3
|
+
const DAY_MS = 24 * 60 * 60_000;
|
|
4
|
+
const WEEK_DAYS = 6;
|
|
5
|
+
/** Parked sessions by id, mapped to when their tier is next expected to be usable (null = unknown). */
|
|
6
|
+
export function waitingSessions(snapshot) {
|
|
7
|
+
const sessions = {};
|
|
8
|
+
for (const entry of snapshot.waiting)
|
|
9
|
+
sessions[entry.sessionID] = entry.resumeAt;
|
|
10
|
+
return sessions;
|
|
11
|
+
}
|
|
12
|
+
function startOfDay(at) {
|
|
13
|
+
const date = new Date(at);
|
|
14
|
+
return new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime();
|
|
15
|
+
}
|
|
16
|
+
function clock(date) {
|
|
17
|
+
return `${String(date.getHours()).padStart(2, "0")}:${String(date.getMinutes()).padStart(2, "0")}`;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Short human text for a parked session (ADP-024): "waiting · resumes 18:42". Weekly limits reset days away, so
|
|
21
|
+
* a later day gains its weekday, and beyond a week its date. Local fields, not the locale formatter, keep the
|
|
22
|
+
* text identical across hosts.
|
|
23
|
+
*/
|
|
24
|
+
export function waitingLabel(resumeAt, now) {
|
|
25
|
+
if (resumeAt === null)
|
|
26
|
+
return "waiting";
|
|
27
|
+
if (resumeAt <= now)
|
|
28
|
+
return "waiting · resuming";
|
|
29
|
+
const date = new Date(resumeAt);
|
|
30
|
+
// Calendar days, not elapsed time: 01:00 tomorrow is "Sun 01:00" even when it is only two hours away.
|
|
31
|
+
const days = Math.round((startOfDay(resumeAt) - startOfDay(now)) / DAY_MS);
|
|
32
|
+
if (days === 0)
|
|
33
|
+
return `waiting · resumes ${clock(date)}`;
|
|
34
|
+
// toDateString is spec-fixed ("Sat Nov 07 2026"), unlike toLocaleString.
|
|
35
|
+
const day = date.toDateString();
|
|
36
|
+
if (days <= WEEK_DAYS)
|
|
37
|
+
return `waiting · resumes ${day.slice(0, 3)} ${clock(date)}`;
|
|
38
|
+
return `waiting · resumes ${day.slice(4, 7)} ${String(date.getDate())} ${clock(date)}`;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=waiting.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"waiting.js","sourceRoot":"","sources":["../../../src/ui/flow/waiting.ts"],"names":[],"mappings":"AAEA,+GAA+G;AAC/G,MAAM,CAAC,MAAM,eAAe,GAAG,MAAM,CAAA;AAErC,MAAM,MAAM,GAAG,EAAE,GAAG,EAAE,GAAG,MAAM,CAAA;AAC/B,MAAM,SAAS,GAAG,CAAC,CAAA;AAEnB,uGAAuG;AACvG,MAAM,UAAU,eAAe,CAAC,QAAwB;IACtD,MAAM,QAAQ,GAAkC,EAAE,CAAA;IAClD,KAAK,MAAM,KAAK,IAAI,QAAQ,CAAC,OAAO;QAAE,QAAQ,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAA;IAChF,OAAO,QAAQ,CAAA;AACjB,CAAC;AAED,SAAS,UAAU,CAAC,EAAU;IAC5B,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,EAAE,CAAC,CAAA;IACzB,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,IAAI,CAAC,QAAQ,EAAE,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAA;AAChF,CAAC;AAED,SAAS,KAAK,CAAC,IAAU;IACvB,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAA;AACpG,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,QAAuB,EAAE,GAAW;IAC/D,IAAI,QAAQ,KAAK,IAAI;QAAE,OAAO,SAAS,CAAA;IACvC,IAAI,QAAQ,IAAI,GAAG;QAAE,OAAO,oBAAoB,CAAA;IAChD,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAA;IAC/B,sGAAsG;IACtG,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,CAAA;IAC1E,IAAI,IAAI,KAAK,CAAC;QAAE,OAAO,qBAAqB,KAAK,CAAC,IAAI,CAAC,EAAE,CAAA;IACzD,yEAAyE;IACzE,MAAM,GAAG,GAAG,IAAI,CAAC,YAAY,EAAE,CAAA;IAC/B,IAAI,IAAI,IAAI,SAAS;QAAE,OAAO,qBAAqB,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,EAAE,CAAA;IACnF,OAAO,qBAAqB,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,EAAE,CAAA;AACxF,CAAC","sourcesContent":["import type { StatusSnapshot } from \"../../rpc/status.js\"\n\n/** How often a view re-reads parked sessions: wakes land at second granularity, a few seconds' lag is fine. */\nexport const WAITING_POLL_MS = 10_000\n\nconst DAY_MS = 24 * 60 * 60_000\nconst WEEK_DAYS = 6\n\n/** Parked sessions by id, mapped to when their tier is next expected to be usable (null = unknown). */\nexport function waitingSessions(snapshot: StatusSnapshot): Record<string, number | null> {\n const sessions: Record<string, number | null> = {}\n for (const entry of snapshot.waiting) sessions[entry.sessionID] = entry.resumeAt\n return sessions\n}\n\nfunction startOfDay(at: number): number {\n const date = new Date(at)\n return new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime()\n}\n\nfunction clock(date: Date): string {\n return `${String(date.getHours()).padStart(2, \"0\")}:${String(date.getMinutes()).padStart(2, \"0\")}`\n}\n\n/**\n * Short human text for a parked session (ADP-024): \"waiting · resumes 18:42\". Weekly limits reset days away, so\n * a later day gains its weekday, and beyond a week its date. Local fields, not the locale formatter, keep the\n * text identical across hosts.\n */\nexport function waitingLabel(resumeAt: number | null, now: number): string {\n if (resumeAt === null) return \"waiting\"\n if (resumeAt <= now) return \"waiting · resuming\"\n const date = new Date(resumeAt)\n // Calendar days, not elapsed time: 01:00 tomorrow is \"Sun 01:00\" even when it is only two hours away.\n const days = Math.round((startOfDay(resumeAt) - startOfDay(now)) / DAY_MS)\n if (days === 0) return `waiting · resumes ${clock(date)}`\n // toDateString is spec-fixed (\"Sat Nov 07 2026\"), unlike toLocaleString.\n const day = date.toDateString()\n if (days <= WEEK_DAYS) return `waiting · resumes ${day.slice(0, 3)} ${clock(date)}`\n return `waiting · resumes ${day.slice(4, 7)} ${String(date.getDate())} ${clock(date)}`\n}\n"]}
|
package/dist/ui/gui/api.d.ts
CHANGED
|
@@ -9,6 +9,8 @@ import type { StatusSnapshot } from "../../rpc.js";
|
|
|
9
9
|
*/
|
|
10
10
|
export interface GuiApi {
|
|
11
11
|
status(): Promise<StatusSnapshot | undefined>;
|
|
12
|
+
/** Waiting sessions by id, each with when it resumes (`null`: unknown). */
|
|
13
|
+
waiting(): Promise<Record<string, number | null> | undefined>;
|
|
12
14
|
receipts(): Promise<Receipt[] | undefined>;
|
|
13
15
|
update(patch: SettingsPatch): Promise<boolean>;
|
|
14
16
|
/** Calls back whenever settings change on the server. Returns the unsubscribe function. */
|
package/dist/ui/gui/api.js
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
|
+
import { waitingSessions } from "../flow/waiting.js";
|
|
1
2
|
import { adaptiveRpc } from "../../rpc.js";
|
|
2
3
|
export function adaptiveGuiApi(client, at) {
|
|
3
4
|
const rpc = client.rpc(adaptiveRpc);
|
|
5
|
+
const unreachable = () => undefined;
|
|
4
6
|
return {
|
|
5
|
-
status: () => rpc["status.get"](undefined, at()).catch(
|
|
6
|
-
|
|
7
|
+
status: () => rpc["status.get"](undefined, at()).catch(unreachable),
|
|
8
|
+
// A snapshot from a server older than waiting sessions has none to read.
|
|
9
|
+
waiting: () => rpc["status.get"](undefined, at()).then(waitingSessions).catch(unreachable),
|
|
10
|
+
receipts: () => rpc["receipts.list"](undefined, at()).catch(unreachable),
|
|
7
11
|
update: async (patch) => {
|
|
8
12
|
try {
|
|
9
13
|
const result = await rpc["settings.set"](patch, at());
|
package/dist/ui/gui/api.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../../src/ui/gui/api.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../../src/ui/gui/api.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAkB1C,MAAM,UAAU,cAAc,CAC5B,MAAsB,EACtB,EAA8C;IAE9C,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;IACnC,MAAM,WAAW,GAAG,GAAc,EAAE,CAAC,SAAS,CAAA;IAC9C,OAAO;QACL,MAAM,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,SAAS,EAAE,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC;QACnE,yEAAyE;QACzE,OAAO,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,SAAS,EAAE,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC;QAC1F,QAAQ,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,SAAS,EAAE,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC;QACxE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;YACtB,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,cAAc,CAAC,CAAC,KAAK,EAAE,EAAE,EAAE,CAAC,CAAA;gBACrD,OAAO,MAAM,CAAC,EAAE,CAAA;YAClB,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,KAAK,CAAA;YACd,CAAC;QACH,CAAC;QACD,aAAa,EAAE,CAAC,QAAQ,EAAE,EAAE,CAC1B,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,kBAAkB,EAAE,GAAG,EAAE;YACrC,QAAQ,EAAE,CAAA;QACZ,CAAC,CAAC;KACL,CAAA;AACH,CAAC","sourcesContent":["import type { OpenCodeClient } from \"@opencode/client/promise\"\n\nimport type { SettingsPatch } from \"../../state/settings/index.js\"\nimport type { Receipt } from \"../../state/receipts/index.js\"\nimport { waitingSessions } from \"../flow/waiting.js\"\nimport { adaptiveRpc } from \"../../rpc.js\"\nimport type { StatusSnapshot } from \"../../rpc.js\"\n\n/**\n * Thin typed-RPC adapter for the GUI surface (ADP-034). Every call resolves to `undefined` (reads) or `false`\n * (writes) when the server is unreachable, so the page can render an explicit disconnected state instead of\n * throwing. `at` supplies the per-call location (see `rpcLocation`). The server stays the single source of truth (ADP-036): the GUI holds no local settings state.\n */\nexport interface GuiApi {\n status(): Promise<StatusSnapshot | undefined>\n /** Waiting sessions by id, each with when it resumes (`null`: unknown). */\n waiting(): Promise<Record<string, number | null> | undefined>\n receipts(): Promise<Receipt[] | undefined>\n update(patch: SettingsPatch): Promise<boolean>\n /** Calls back whenever settings change on the server. Returns the unsubscribe function. */\n watchSettings(onChange: () => void): () => void\n}\n\nexport function adaptiveGuiApi(\n client: OpenCodeClient,\n at: () => { location?: { directory: string } },\n): GuiApi {\n const rpc = client.rpc(adaptiveRpc)\n const unreachable = (): undefined => undefined\n return {\n status: () => rpc[\"status.get\"](undefined, at()).catch(unreachable),\n // A snapshot from a server older than waiting sessions has none to read.\n waiting: () => rpc[\"status.get\"](undefined, at()).then(waitingSessions).catch(unreachable),\n receipts: () => rpc[\"receipts.list\"](undefined, at()).catch(unreachable),\n update: async (patch) => {\n try {\n const result = await rpc[\"settings.set\"](patch, at())\n return result.ok\n } catch {\n return false\n }\n },\n watchSettings: (onChange) =>\n rpc.events.on(\"settings-changed\", () => {\n onChange()\n }),\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coool/opencode-adaptive",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "Execution supervisor plugin for OpenCode v2: capability-tier routing, structured-evidence escalation, horizontal failure recovery, and resource health tracking.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|