@tidegap/cli 0.0.0-stage → 0.18.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/LICENSE +201 -0
- package/README.md +125 -2
- package/dist/commands/env-file.d.ts +53 -0
- package/dist/commands/env-file.d.ts.map +1 -0
- package/dist/commands/env-file.js +127 -0
- package/dist/commands/env-file.js.map +1 -0
- package/dist/commands/install.d.ts +84 -0
- package/dist/commands/install.d.ts.map +1 -0
- package/dist/commands/install.js +299 -0
- package/dist/commands/install.js.map +1 -0
- package/dist/commands/queue.d.ts +139 -0
- package/dist/commands/queue.d.ts.map +1 -0
- package/dist/commands/queue.js +491 -0
- package/dist/commands/queue.js.map +1 -0
- package/dist/commands/receipts.d.ts +15 -0
- package/dist/commands/receipts.d.ts.map +1 -0
- package/dist/commands/receipts.js +70 -0
- package/dist/commands/receipts.js.map +1 -0
- package/dist/commands/register-wake.d.ts +21 -0
- package/dist/commands/register-wake.d.ts.map +1 -0
- package/dist/commands/register-wake.js +76 -0
- package/dist/commands/register-wake.js.map +1 -0
- package/dist/commands/stats.d.ts +31 -0
- package/dist/commands/stats.d.ts.map +1 -0
- package/dist/commands/stats.js +165 -0
- package/dist/commands/stats.js.map +1 -0
- package/dist/commands/tick.d.ts +73 -0
- package/dist/commands/tick.d.ts.map +1 -0
- package/dist/commands/tick.js +294 -0
- package/dist/commands/tick.js.map +1 -0
- package/dist/commands/ui.d.ts +25 -0
- package/dist/commands/ui.d.ts.map +1 -0
- package/dist/commands/ui.js +83 -0
- package/dist/commands/ui.js.map +1 -0
- package/dist/commands/verify.d.ts +32 -0
- package/dist/commands/verify.d.ts.map +1 -0
- package/dist/commands/verify.js +135 -0
- package/dist/commands/verify.js.map +1 -0
- package/dist/env.d.ts +55 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +90 -0
- package/dist/env.js.map +1 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +351 -0
- package/dist/index.js.map +1 -0
- package/dist/platform/index.d.ts +30 -0
- package/dist/platform/index.d.ts.map +1 -0
- package/dist/platform/index.js +66 -0
- package/dist/platform/index.js.map +1 -0
- package/dist/platform/linux.d.ts +81 -0
- package/dist/platform/linux.d.ts.map +1 -0
- package/dist/platform/linux.js +158 -0
- package/dist/platform/linux.js.map +1 -0
- package/dist/platform/macos.d.ts +69 -0
- package/dist/platform/macos.d.ts.map +1 -0
- package/dist/platform/macos.js +151 -0
- package/dist/platform/macos.js.map +1 -0
- package/dist/platform/windows.d.ts +31 -0
- package/dist/platform/windows.d.ts.map +1 -0
- package/dist/platform/windows.js +58 -0
- package/dist/platform/windows.js.map +1 -0
- package/dist/ui/api.d.ts +59 -0
- package/dist/ui/api.d.ts.map +1 -0
- package/dist/ui/api.js +459 -0
- package/dist/ui/api.js.map +1 -0
- package/dist/ui/dispatcher.d.ts +84 -0
- package/dist/ui/dispatcher.d.ts.map +1 -0
- package/dist/ui/dispatcher.js +150 -0
- package/dist/ui/dispatcher.js.map +1 -0
- package/dist/ui/events.d.ts +27 -0
- package/dist/ui/events.d.ts.map +1 -0
- package/dist/ui/events.js +85 -0
- package/dist/ui/events.js.map +1 -0
- package/dist/ui/server.d.ts +69 -0
- package/dist/ui/server.d.ts.map +1 -0
- package/dist/ui/server.js +258 -0
- package/dist/ui/server.js.map +1 -0
- package/package.json +54 -3
- package/ui/agenda.js +256 -0
- package/ui/api.js +111 -0
- package/ui/app.css +707 -0
- package/ui/app.js +597 -0
- package/ui/detail.js +431 -0
- package/ui/dialog.js +279 -0
- package/ui/dnd.js +131 -0
- package/ui/dom.js +255 -0
- package/ui/index.html +37 -0
- package/ui/journal.js +207 -0
- package/ui/keys.js +92 -0
- package/ui/row.js +153 -0
- package/ui/state.js +412 -0
- package/ui/timeline.js +202 -0
- package/ui/toast.js +69 -0
- package/ui/tokens.css +106 -0
- package/ui/views.js +31 -0
package/dist/ui/api.js
ADDED
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON API handlers for `tidegap ui`. Reads go through the `TaskStore`. Writes
|
|
3
|
+
* (ui v2) go through `ctx.scheduler`, a `Scheduler` built with NO adapters:
|
|
4
|
+
* cancel, reschedule, run now and reply only write the ledger, with a
|
|
5
|
+
* compare-and-set, and the dispatcher (`tidegap tick` or the OpenClaw loop)
|
|
6
|
+
* runs the task. Nothing here dispatches a provider call. A refused action
|
|
7
|
+
* returns 409 with the core's one-line rule, never a stack or a path.
|
|
8
|
+
*
|
|
9
|
+
* Task strings are untrusted (prompts and model output). They leave here as
|
|
10
|
+
* JSON values; the page renders them with `textContent` only.
|
|
11
|
+
*/
|
|
12
|
+
import { deadlineKindLabel, InvalidDeadlineError, LAST_TICK_META_KEY, nextQuotaReset, resolveQuotaDeadline, resumeCommand, TaskActionError, taskActions, taskHistory, taskPrompt, taskResultText, } from "@tidegap/core";
|
|
13
|
+
import { rawPayload, sortSeries, taskSummary, VALID_KINDS, VALID_STATUSES, withoutRaw, } from "../commands/queue.js";
|
|
14
|
+
/** Longest reply text, in characters. */
|
|
15
|
+
export const REPLY_MAX_CHARS = 32_000;
|
|
16
|
+
/**
|
|
17
|
+
* How each POST route treats its body (KTD9). `json`: the route reads a
|
|
18
|
+
* JSON object (Content-Type application/json required). `none`: no body.
|
|
19
|
+
*/
|
|
20
|
+
export function postBodyKind(pathname) {
|
|
21
|
+
const route = pathname.split("/").filter(Boolean).slice(1);
|
|
22
|
+
if (route.length === 2 && route[0] === "dispatcher" && route[1] === "start")
|
|
23
|
+
return "none";
|
|
24
|
+
if (route.length !== 3 || route[0] !== "tasks")
|
|
25
|
+
return undefined;
|
|
26
|
+
if (route[2] === "cancel" || route[2] === "reschedule" || route[2] === "reply")
|
|
27
|
+
return "json";
|
|
28
|
+
if (route[2] === "read" || route[2] === "unread" || route[2] === "run-now")
|
|
29
|
+
return "none";
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
/** Most hours of forecast one request returns. */
|
|
33
|
+
export const MAX_FORECAST_HOURS = 72;
|
|
34
|
+
/**
|
|
35
|
+
* How long one forecast answer is reused. The page asks on every change
|
|
36
|
+
* event; without a cache each one would spend the grid provider's quota,
|
|
37
|
+
* which the tick needs for scheduling.
|
|
38
|
+
*/
|
|
39
|
+
export const FORECAST_CACHE_MS = 10 * 60_000;
|
|
40
|
+
const forecastCache = new WeakMap();
|
|
41
|
+
const REGION_RE = /^[A-Za-z0-9_-]{1,64}$/;
|
|
42
|
+
function error(status, message) {
|
|
43
|
+
return { status, body: { error: message } };
|
|
44
|
+
}
|
|
45
|
+
function listSummary(r) {
|
|
46
|
+
return {
|
|
47
|
+
...taskSummary(r),
|
|
48
|
+
parent_task_id: r.parentTaskId ?? null,
|
|
49
|
+
estimated_carbon_g: r.estimatedCarbonGCo2 ?? null,
|
|
50
|
+
// What the task cost (receipt) or is expected to cost (schedule time).
|
|
51
|
+
carbon_g: r.receipt?.actualCarbonGCo2 ?? r.estimatedCarbonGCo2 ?? null,
|
|
52
|
+
intensity_g_per_kwh: r.receipt?.intensityGCo2PerKwh ?? null,
|
|
53
|
+
actions: taskActions(r),
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
const MAX_LIST_LIMIT = 1000;
|
|
57
|
+
function listTasks(ctx, params) {
|
|
58
|
+
const statuses = (params.get("status") ?? "")
|
|
59
|
+
.split(",")
|
|
60
|
+
.map((s) => s.trim())
|
|
61
|
+
.filter(Boolean);
|
|
62
|
+
for (const s of statuses) {
|
|
63
|
+
if (!VALID_STATUSES.has(s))
|
|
64
|
+
return error(400, `unknown status ${s}`);
|
|
65
|
+
}
|
|
66
|
+
const kind = params.get("kind") ?? undefined;
|
|
67
|
+
if (kind !== undefined && !VALID_KINDS.has(kind)) {
|
|
68
|
+
return error(400, `unknown kind ${kind}`);
|
|
69
|
+
}
|
|
70
|
+
const unread = params.get("unread") === "1" || params.get("unread") === "true";
|
|
71
|
+
const series = params.get("series") ?? undefined;
|
|
72
|
+
const rawLimit = params.get("limit");
|
|
73
|
+
const limit = rawLimit === null ? undefined : Number(rawLimit);
|
|
74
|
+
if (limit !== undefined && (!Number.isInteger(limit) || limit < 1 || limit > MAX_LIST_LIMIT)) {
|
|
75
|
+
return error(400, `limit must be an integer from 1 to ${MAX_LIST_LIMIT}`);
|
|
76
|
+
}
|
|
77
|
+
const base = {
|
|
78
|
+
...(kind ? { deadlineKind: kind } : {}),
|
|
79
|
+
...(unread ? { unread: true } : {}),
|
|
80
|
+
...(series ? { seriesId: series } : {}),
|
|
81
|
+
};
|
|
82
|
+
let rows = statuses.length === 0
|
|
83
|
+
? ctx.store.list(base)
|
|
84
|
+
: statuses.flatMap((status) => ctx.store.list({ ...base, status: status }));
|
|
85
|
+
if (series)
|
|
86
|
+
rows = sortSeries(rows);
|
|
87
|
+
// `limit` keeps the newest rows by enqueue time; the order stays as listed.
|
|
88
|
+
if (limit !== undefined && rows.length > limit) {
|
|
89
|
+
const keep = new Set([...rows]
|
|
90
|
+
.sort((a, b) => b.enqueuedAt.localeCompare(a.enqueuedAt))
|
|
91
|
+
.slice(0, limit)
|
|
92
|
+
.map((r) => r.taskId));
|
|
93
|
+
rows = rows.filter((r) => keep.has(r.taskId));
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
status: 200,
|
|
97
|
+
body: {
|
|
98
|
+
last_tick_at: ctx.store.getMeta(LAST_TICK_META_KEY) ?? null,
|
|
99
|
+
tasks: rows.map(listSummary),
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
function taskDetail(ctx, taskId) {
|
|
104
|
+
const r = ctx.store.get(taskId);
|
|
105
|
+
if (!r)
|
|
106
|
+
return error(404, "task not found");
|
|
107
|
+
const quota = ctx.quota();
|
|
108
|
+
const schedule = r.deadlineKind === "quota_reset" ? quota[r.quotaProvider ?? ""] : undefined;
|
|
109
|
+
return {
|
|
110
|
+
status: 200,
|
|
111
|
+
body: {
|
|
112
|
+
...listSummary(r),
|
|
113
|
+
enqueued_at: r.enqueuedAt,
|
|
114
|
+
origin_cwd: r.originCwd ?? null,
|
|
115
|
+
origin_session_id: r.originSessionId ?? null,
|
|
116
|
+
resume_command: resumeCommand(r) ?? null,
|
|
117
|
+
parent: parentSummary(ctx, r),
|
|
118
|
+
children: ctx.store
|
|
119
|
+
.list()
|
|
120
|
+
.filter((c) => c.parentTaskId === r.taskId)
|
|
121
|
+
.map(listSummary),
|
|
122
|
+
series: r.seriesId ? seriesInfo(ctx, r.seriesId) : null,
|
|
123
|
+
deadline_label: deadlineKindLabel(r, quota),
|
|
124
|
+
quota_margin_h: schedule?.marginH ?? null,
|
|
125
|
+
prompt: taskPrompt(r) ?? null,
|
|
126
|
+
history: taskHistory(r),
|
|
127
|
+
result_text: taskResultText(r) ?? null,
|
|
128
|
+
result: withoutRaw(r.result) ?? null,
|
|
129
|
+
error: r.error ?? null,
|
|
130
|
+
receipt: r.receipt ?? null,
|
|
131
|
+
routing: r.receipt?.routing ?? r.routingDecision ?? null,
|
|
132
|
+
raw: rawPayload(r) ?? null,
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
function parentSummary(ctx, r) {
|
|
137
|
+
if (!r.parentTaskId)
|
|
138
|
+
return null;
|
|
139
|
+
const p = ctx.store.get(r.parentTaskId);
|
|
140
|
+
return p ? listSummary(p) : { task_id: r.parentTaskId, missing: true };
|
|
141
|
+
}
|
|
142
|
+
const DAY_MS = 86_400_000;
|
|
143
|
+
/**
|
|
144
|
+
* Up to `count` deadlines after `fromMs` for a series rule: whole periods
|
|
145
|
+
* for daily/weekly; the label's next resets minus margin for quota_reset
|
|
146
|
+
* (+7 days without a config). Empty for an ended series.
|
|
147
|
+
*/
|
|
148
|
+
function projectDeadlines(rule, fromMs, label, quota, count) {
|
|
149
|
+
const out = [];
|
|
150
|
+
const schedule = rule === "quota_reset" && label ? quota[label] : undefined;
|
|
151
|
+
let t = fromMs;
|
|
152
|
+
for (let i = 0; i < count; i++) {
|
|
153
|
+
if (rule === "daily")
|
|
154
|
+
t += DAY_MS;
|
|
155
|
+
else if (rule === "weekly")
|
|
156
|
+
t += 7 * DAY_MS;
|
|
157
|
+
else if (rule === "quota_reset") {
|
|
158
|
+
t = schedule ? resolveQuotaDeadline(schedule, new Date(t + 60_000)).deadline.getTime() : t + 7 * DAY_MS;
|
|
159
|
+
}
|
|
160
|
+
else
|
|
161
|
+
break;
|
|
162
|
+
out.push(new Date(t).toISOString());
|
|
163
|
+
}
|
|
164
|
+
return out;
|
|
165
|
+
}
|
|
166
|
+
function seriesInfo(ctx, seriesId) {
|
|
167
|
+
const rows = sortSeries(ctx.store.list({ seriesId }));
|
|
168
|
+
if (rows.length === 0)
|
|
169
|
+
return null;
|
|
170
|
+
const last = rows[rows.length - 1];
|
|
171
|
+
const rule = last.repeat ?? "none";
|
|
172
|
+
const label = [...rows].reverse().find((r) => r.quotaProvider)?.quotaProvider;
|
|
173
|
+
const lastDeadline = last.deadline ? Date.parse(last.deadline) : Number.NaN;
|
|
174
|
+
return {
|
|
175
|
+
series_id: seriesId,
|
|
176
|
+
repeat: rule,
|
|
177
|
+
ended: rule === "none",
|
|
178
|
+
occurrences: rows.length,
|
|
179
|
+
next_deadlines: Number.isFinite(lastDeadline)
|
|
180
|
+
? projectDeadlines(rule, lastDeadline, label, ctx.quota(), 8)
|
|
181
|
+
: [],
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
function seriesDetail(ctx, seriesId) {
|
|
185
|
+
const info = seriesInfo(ctx, seriesId);
|
|
186
|
+
if (!info)
|
|
187
|
+
return error(404, "series not found");
|
|
188
|
+
return {
|
|
189
|
+
status: 200,
|
|
190
|
+
body: {
|
|
191
|
+
...info,
|
|
192
|
+
occurrences: sortSeries(ctx.store.list({ seriesId })).map(listSummary),
|
|
193
|
+
},
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
function onlyKeys(body, allowed) {
|
|
197
|
+
const extra = Object.keys(body).filter((k) => !allowed.includes(k));
|
|
198
|
+
return extra.length > 0 ? `unknown field ${extra[0]}` : undefined;
|
|
199
|
+
}
|
|
200
|
+
/** An ISO instant from the body, or the 400 message when it is not one. */
|
|
201
|
+
function instant(value, name) {
|
|
202
|
+
if (typeof value !== "string" || value.length === 0 || value.length > 64) {
|
|
203
|
+
return `${name} must be an ISO-8601 string`;
|
|
204
|
+
}
|
|
205
|
+
const d = new Date(value);
|
|
206
|
+
return Number.isNaN(d.getTime()) ? `${name} is not an ISO-8601 instant` : d;
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Run one write through the action scheduler: 404 for an unknown task,
|
|
210
|
+
* 409 with the core's rule when the task's state or input refuses it, 500
|
|
211
|
+
* with a generic body for any other error.
|
|
212
|
+
*/
|
|
213
|
+
async function act(ctx, taskId, run, status = 200) {
|
|
214
|
+
if (!ctx.scheduler)
|
|
215
|
+
return error(405, "this server is read-only");
|
|
216
|
+
if (!ctx.store.get(taskId))
|
|
217
|
+
return error(404, "task not found");
|
|
218
|
+
let out;
|
|
219
|
+
try {
|
|
220
|
+
out = await run(ctx.scheduler);
|
|
221
|
+
}
|
|
222
|
+
catch (err) {
|
|
223
|
+
// Only a refusal carries a rule safe to show; anything else is internal
|
|
224
|
+
// and gets a generic body (no exception text, no path).
|
|
225
|
+
if (err instanceof TaskActionError || err instanceof InvalidDeadlineError) {
|
|
226
|
+
return error(409, oneLine(err));
|
|
227
|
+
}
|
|
228
|
+
return error(500, "action failed");
|
|
229
|
+
}
|
|
230
|
+
const fresh = ctx.store.get(out.taskId) ?? out;
|
|
231
|
+
const changed = out.taskId === taskId ? [taskId] : [taskId, out.taskId];
|
|
232
|
+
return { status, body: listSummary(fresh), changedIds: changed };
|
|
233
|
+
}
|
|
234
|
+
/** The core's message on one line, without anything after a newline. */
|
|
235
|
+
function oneLine(err) {
|
|
236
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
237
|
+
return msg.split("\n")[0].slice(0, 300);
|
|
238
|
+
}
|
|
239
|
+
function cancelAction(ctx, taskId, body) {
|
|
240
|
+
const bad = onlyKeys(body, ["series"]);
|
|
241
|
+
if (bad)
|
|
242
|
+
return error(400, bad);
|
|
243
|
+
if (body.series !== undefined && typeof body.series !== "boolean") {
|
|
244
|
+
return error(400, "series must be a boolean");
|
|
245
|
+
}
|
|
246
|
+
return act(ctx, taskId, (s) => {
|
|
247
|
+
// The core cancel is idempotent; the API reports a finished task as a
|
|
248
|
+
// refused action (409), so a second click says what happened.
|
|
249
|
+
const current = ctx.store.get(taskId);
|
|
250
|
+
if (!taskActions(current).cancel) {
|
|
251
|
+
throw new TaskActionError(`cancel: task ${taskId} is ${current.status}; only pending tasks can be cancelled`);
|
|
252
|
+
}
|
|
253
|
+
return s.cancelTask(taskId, { series: body.series === true });
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
function rescheduleAction(ctx, taskId, body) {
|
|
257
|
+
const bad = onlyKeys(body, ["deadline", "at", "day_start", "day_end"]);
|
|
258
|
+
if (bad)
|
|
259
|
+
return error(400, bad);
|
|
260
|
+
const has = (k) => body[k] !== undefined;
|
|
261
|
+
const shapes = [has("deadline"), has("at"), has("day_start") || has("day_end")].filter(Boolean);
|
|
262
|
+
if (shapes.length !== 1) {
|
|
263
|
+
return error(400, "pass exactly one of {deadline}, {at} or {day_start, day_end}");
|
|
264
|
+
}
|
|
265
|
+
const now = (ctx.now?.() ?? new Date()).getTime();
|
|
266
|
+
let target;
|
|
267
|
+
if (has("deadline") || has("at")) {
|
|
268
|
+
const key = has("deadline") ? "deadline" : "at";
|
|
269
|
+
const d = instant(body[key], key);
|
|
270
|
+
if (typeof d === "string")
|
|
271
|
+
return error(400, d);
|
|
272
|
+
if (d.getTime() < now - 5_000)
|
|
273
|
+
return error(400, `${key} is in the past`);
|
|
274
|
+
target = key === "deadline" ? { deadline: d } : { at: d };
|
|
275
|
+
}
|
|
276
|
+
else {
|
|
277
|
+
const start = instant(body.day_start, "day_start");
|
|
278
|
+
if (typeof start === "string")
|
|
279
|
+
return error(400, start);
|
|
280
|
+
const end = instant(body.day_end, "day_end");
|
|
281
|
+
if (typeof end === "string")
|
|
282
|
+
return error(400, end);
|
|
283
|
+
const span = end.getTime() - start.getTime();
|
|
284
|
+
if (span < 3_600_000 || span > 25 * 3_600_000)
|
|
285
|
+
return error(400, "a day must span 1 to 25 hours");
|
|
286
|
+
if (end.getTime() < now)
|
|
287
|
+
return error(400, "day_end is in the past");
|
|
288
|
+
target = { dayStart: start, dayEnd: end };
|
|
289
|
+
}
|
|
290
|
+
return act(ctx, taskId, (s) => s.rescheduleTask(taskId, target));
|
|
291
|
+
}
|
|
292
|
+
function replyAction(ctx, taskId, body) {
|
|
293
|
+
const bad = onlyKeys(body, ["text", "deadline"]);
|
|
294
|
+
if (bad)
|
|
295
|
+
return error(400, bad);
|
|
296
|
+
if (typeof body.text !== "string" || body.text.trim().length === 0 || body.text.length > REPLY_MAX_CHARS) {
|
|
297
|
+
return error(400, `text must be 1 to ${REPLY_MAX_CHARS} characters`);
|
|
298
|
+
}
|
|
299
|
+
let deadline;
|
|
300
|
+
if (body.deadline !== undefined) {
|
|
301
|
+
const d = instant(body.deadline, "deadline");
|
|
302
|
+
if (typeof d === "string")
|
|
303
|
+
return error(400, d);
|
|
304
|
+
deadline = d;
|
|
305
|
+
}
|
|
306
|
+
const text = body.text;
|
|
307
|
+
return act(ctx, taskId, (s) => s.replyToTask(taskId, text, deadline ? { deadline } : {}), 201);
|
|
308
|
+
}
|
|
309
|
+
function startDispatcher(ctx) {
|
|
310
|
+
if (!ctx.dispatcher)
|
|
311
|
+
return error(404, "not found");
|
|
312
|
+
try {
|
|
313
|
+
const res = ctx.dispatcher.start();
|
|
314
|
+
if (!res.ok && res.reason === "ui_child") {
|
|
315
|
+
return { status: 409, body: { error: "a dispatcher started from this page is running", ...res.meta } };
|
|
316
|
+
}
|
|
317
|
+
if (!res.ok) {
|
|
318
|
+
return {
|
|
319
|
+
status: 409,
|
|
320
|
+
body: { error: "a dispatcher is already ticking this ledger", last_tick_at: res.last_tick_at },
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
return { status: 201, body: res.meta };
|
|
324
|
+
}
|
|
325
|
+
catch {
|
|
326
|
+
// The spawn error can name paths; the page needs only the fact.
|
|
327
|
+
return error(500, "could not start the dispatcher");
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
function setRead(ctx, taskId, read) {
|
|
331
|
+
const r = ctx.store.get(taskId);
|
|
332
|
+
if (!r)
|
|
333
|
+
return error(404, "task not found");
|
|
334
|
+
if (r.status !== "completed" && r.status !== "failed") {
|
|
335
|
+
return error(409, "only a completed or failed task has a read marker");
|
|
336
|
+
}
|
|
337
|
+
if (read)
|
|
338
|
+
ctx.store.markRead(taskId, ctx.now?.() ?? new Date());
|
|
339
|
+
else
|
|
340
|
+
ctx.store.markUnread(taskId);
|
|
341
|
+
return { status: 204, changedIds: [taskId] };
|
|
342
|
+
}
|
|
343
|
+
async function forecast(ctx, params) {
|
|
344
|
+
const region = params.get("region") || ctx.defaultRegion;
|
|
345
|
+
if (!REGION_RE.test(region))
|
|
346
|
+
return error(400, "invalid region");
|
|
347
|
+
const rawHours = Number(params.get("hours") ?? 24);
|
|
348
|
+
const hours = Math.min(MAX_FORECAST_HOURS, Math.max(1, Number.isFinite(rawHours) ? Math.ceil(rawHours) : 24));
|
|
349
|
+
const now = (ctx.now?.() ?? new Date()).getTime();
|
|
350
|
+
let cache = forecastCache.get(ctx);
|
|
351
|
+
if (!cache)
|
|
352
|
+
forecastCache.set(ctx, (cache = new Map()));
|
|
353
|
+
const key = `${region}|${hours}`;
|
|
354
|
+
const hit = cache.get(key);
|
|
355
|
+
if (hit && now - hit.at < FORECAST_CACHE_MS)
|
|
356
|
+
return { status: 200, body: hit.body };
|
|
357
|
+
try {
|
|
358
|
+
const f = await ctx.feed.fetchForecast(region, hours);
|
|
359
|
+
for (const [k, v] of cache)
|
|
360
|
+
if (now - v.at >= FORECAST_CACHE_MS)
|
|
361
|
+
cache.delete(k);
|
|
362
|
+
const body = {
|
|
363
|
+
region: f.region,
|
|
364
|
+
source: f.source,
|
|
365
|
+
generated_at: f.generatedAt,
|
|
366
|
+
points: f.entries.slice(0, hours).map((e) => ({
|
|
367
|
+
t: e.datetime,
|
|
368
|
+
g: e.carbonIntensityGCo2PerKwh,
|
|
369
|
+
band: e.band,
|
|
370
|
+
})),
|
|
371
|
+
};
|
|
372
|
+
cache.set(key, { at: now, body });
|
|
373
|
+
return { status: 200, body };
|
|
374
|
+
}
|
|
375
|
+
catch {
|
|
376
|
+
// The provider error can name a URL or key; the page needs only the fact.
|
|
377
|
+
return error(502, "forecast unavailable");
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
function status(ctx) {
|
|
381
|
+
const now = ctx.now?.() ?? new Date();
|
|
382
|
+
const quota = ctx.quota();
|
|
383
|
+
return {
|
|
384
|
+
status: 200,
|
|
385
|
+
body: {
|
|
386
|
+
daemon: ctx.daemonStatus(),
|
|
387
|
+
db_path: ctx.dbPath,
|
|
388
|
+
default_region: ctx.defaultRegion,
|
|
389
|
+
last_tick_at: ctx.store.getMeta(LAST_TICK_META_KEY) ?? null,
|
|
390
|
+
dispatcher: ctx.dispatcher?.state() ?? null,
|
|
391
|
+
quota: Object.entries(quota).map(([label, s]) => ({
|
|
392
|
+
label,
|
|
393
|
+
next_reset: nextQuotaReset(s, now).toISOString(),
|
|
394
|
+
margin_h: s.marginH,
|
|
395
|
+
})),
|
|
396
|
+
},
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* Route one authenticated `/api/*` request (SSE is handled by the server).
|
|
401
|
+
* Returns 404 for an unknown path and 405 for a wrong method.
|
|
402
|
+
*/
|
|
403
|
+
export async function handleApi(ctx, method, pathname, params,
|
|
404
|
+
/** Parsed JSON object of a body route (the server checked type and size). */
|
|
405
|
+
body = {}) {
|
|
406
|
+
const parts = pathname.split("/").filter(Boolean); // ["api", ...]
|
|
407
|
+
const route = parts.slice(1);
|
|
408
|
+
const get = method === "GET";
|
|
409
|
+
if (route.length === 1 && route[0] === "tasks")
|
|
410
|
+
return get ? listTasks(ctx, params) : error(405, "method not allowed");
|
|
411
|
+
if (route.length === 1 && route[0] === "forecast")
|
|
412
|
+
return get ? forecast(ctx, params) : error(405, "method not allowed");
|
|
413
|
+
if (route.length === 1 && route[0] === "status")
|
|
414
|
+
return get ? status(ctx) : error(405, "method not allowed");
|
|
415
|
+
if (route.length === 2 && route[0] === "dispatcher" && route[1] === "start") {
|
|
416
|
+
return method === "POST" ? startDispatcher(ctx) : error(405, "method not allowed");
|
|
417
|
+
}
|
|
418
|
+
if (route.length === 2 && route[0] === "series") {
|
|
419
|
+
if (!get)
|
|
420
|
+
return error(405, "method not allowed");
|
|
421
|
+
let seriesId;
|
|
422
|
+
try {
|
|
423
|
+
seriesId = decodeURIComponent(route[1]);
|
|
424
|
+
}
|
|
425
|
+
catch {
|
|
426
|
+
return error(400, "bad series id");
|
|
427
|
+
}
|
|
428
|
+
return seriesDetail(ctx, seriesId);
|
|
429
|
+
}
|
|
430
|
+
if (route[0] === "tasks" && route.length >= 2) {
|
|
431
|
+
let taskId;
|
|
432
|
+
try {
|
|
433
|
+
taskId = decodeURIComponent(route[1]);
|
|
434
|
+
}
|
|
435
|
+
catch {
|
|
436
|
+
return error(400, "bad task id");
|
|
437
|
+
}
|
|
438
|
+
if (route.length === 2)
|
|
439
|
+
return get ? taskDetail(ctx, taskId) : error(405, "method not allowed");
|
|
440
|
+
if (route.length === 3 && (route[2] === "read" || route[2] === "unread")) {
|
|
441
|
+
return method === "POST" ? setRead(ctx, taskId, route[2] === "read") : error(405, "method not allowed");
|
|
442
|
+
}
|
|
443
|
+
if (route.length === 3) {
|
|
444
|
+
const post = method === "POST";
|
|
445
|
+
switch (route[2]) {
|
|
446
|
+
case "cancel":
|
|
447
|
+
return post ? cancelAction(ctx, taskId, body) : error(405, "method not allowed");
|
|
448
|
+
case "reschedule":
|
|
449
|
+
return post ? rescheduleAction(ctx, taskId, body) : error(405, "method not allowed");
|
|
450
|
+
case "reply":
|
|
451
|
+
return post ? replyAction(ctx, taskId, body) : error(405, "method not allowed");
|
|
452
|
+
case "run-now":
|
|
453
|
+
return post ? act(ctx, taskId, (s) => s.runNow(taskId)) : error(405, "method not allowed");
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
return error(404, "not found");
|
|
458
|
+
}
|
|
459
|
+
//# sourceMappingURL=api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/ui/api.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dispatcher state and "Start dispatcher" for `tidegap ui` (ui v2, KTD13).
|
|
3
|
+
*
|
|
4
|
+
* The UI server never dispatches a task. When no dispatcher has run lately,
|
|
5
|
+
* the page can ask the server to start one: the same `tidegap` binary the
|
|
6
|
+
* install step resolves, spawned detached as `tidegap tick --daemon --interval
|
|
7
|
+
* 60 --db <ledger>`, with stdout and stderr appended to
|
|
8
|
+
* `~/.tidegap/logs/ui-tick.log` (directory 0700, file 0600). The child's
|
|
9
|
+
* pid, log path and start time are kept in ledger meta `ui_dispatcher`. A
|
|
10
|
+
* start is refused (409) while that child is alive or while any other
|
|
11
|
+
* ticker ticked within two intervals. The user stops it with `kill <pid>`.
|
|
12
|
+
*
|
|
13
|
+
* State: `running` when the UI-started child is alive (its pid exists and it
|
|
14
|
+
* started or ticked recently, so a recycled pid is not trusted) or a tick ran within
|
|
15
|
+
* two intervals (300 s when the daemon is installed, else 60 s); `stale`
|
|
16
|
+
* when a tick ran before that; `never` when no tick was ever recorded.
|
|
17
|
+
*/
|
|
18
|
+
import { type TaskStore } from "@tidegap/core";
|
|
19
|
+
import type { DaemonStatus } from "../platform/index.js";
|
|
20
|
+
export declare const UI_DISPATCHER_META_KEY = "ui_dispatcher";
|
|
21
|
+
/** Tick interval of a dispatcher started from the page, in seconds. */
|
|
22
|
+
export declare const UI_DISPATCHER_INTERVAL_S = 60;
|
|
23
|
+
/** Interval of the installed daemon (`tidegap install` default), in seconds. */
|
|
24
|
+
export declare const DAEMON_INTERVAL_S = 300;
|
|
25
|
+
export interface DispatcherMeta {
|
|
26
|
+
pid: number;
|
|
27
|
+
log: string;
|
|
28
|
+
started_at: string;
|
|
29
|
+
}
|
|
30
|
+
/** Start `argv` detached with output appended to `logPath`; returns the pid. */
|
|
31
|
+
export type Spawner = (argv: string[], logPath: string) => number;
|
|
32
|
+
export interface DispatcherOptions {
|
|
33
|
+
/** The `tidegap` launcher (`[node, script]` or `[binary]`), from `resolveLauncher`. */
|
|
34
|
+
launcher: string[];
|
|
35
|
+
dbPath: string;
|
|
36
|
+
/** Default `~/.tidegap/logs`. */
|
|
37
|
+
logDir?: string;
|
|
38
|
+
spawn?: Spawner;
|
|
39
|
+
isAlive?: (pid: number) => boolean;
|
|
40
|
+
daemonStatus: () => DaemonStatus;
|
|
41
|
+
now?: () => Date;
|
|
42
|
+
}
|
|
43
|
+
export interface DispatcherState {
|
|
44
|
+
state: "running" | "stale" | "never";
|
|
45
|
+
last_tick_at: string | null;
|
|
46
|
+
interval_s: number;
|
|
47
|
+
ui_child: {
|
|
48
|
+
pid: number;
|
|
49
|
+
log: string;
|
|
50
|
+
started_at: string;
|
|
51
|
+
alive: boolean;
|
|
52
|
+
} | null;
|
|
53
|
+
}
|
|
54
|
+
export declare function defaultLogDir(): string;
|
|
55
|
+
/** True when a process with `pid` exists (EPERM still means it exists). */
|
|
56
|
+
export declare function pidAlive(pid: number): boolean;
|
|
57
|
+
export declare const defaultSpawner: Spawner;
|
|
58
|
+
export declare class DispatcherControl {
|
|
59
|
+
private readonly store;
|
|
60
|
+
private readonly opts;
|
|
61
|
+
constructor(store: TaskStore, opts: DispatcherOptions);
|
|
62
|
+
private meta;
|
|
63
|
+
private alive;
|
|
64
|
+
state(): DispatcherState;
|
|
65
|
+
/**
|
|
66
|
+
* Spawn the dispatcher. Refused (`ok: false`) when the child started from
|
|
67
|
+
* the page is alive (`ui_child`), or when another ticker (the installed
|
|
68
|
+
* daemon, an `tidegap tick` loop, OpenClaw) ticked recently (`ticking`): a
|
|
69
|
+
* second ticker would only race the first.
|
|
70
|
+
*/
|
|
71
|
+
start(): {
|
|
72
|
+
ok: true;
|
|
73
|
+
meta: DispatcherMeta;
|
|
74
|
+
} | {
|
|
75
|
+
ok: false;
|
|
76
|
+
reason: "ui_child";
|
|
77
|
+
meta: DispatcherMeta;
|
|
78
|
+
} | {
|
|
79
|
+
ok: false;
|
|
80
|
+
reason: "ticking";
|
|
81
|
+
last_tick_at: string | null;
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=dispatcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dispatcher.d.ts","sourceRoot":"","sources":["../../src/ui/dispatcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAMH,OAAO,EAA0C,KAAK,SAAS,EAAE,MAAM,eAAe,CAAC;AAEvF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEzD,eAAO,MAAM,sBAAsB,kBAAkB,CAAC;AACtD,uEAAuE;AACvE,eAAO,MAAM,wBAAwB,KAAK,CAAC;AAC3C,gFAAgF;AAChF,eAAO,MAAM,iBAAiB,MAAM,CAAC;AAErC,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,gFAAgF;AAChF,MAAM,MAAM,OAAO,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC;AAElE,MAAM,WAAW,iBAAiB;IAChC,uFAAuF;IACvF,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,iCAAiC;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;IACnC,YAAY,EAAE,MAAM,YAAY,CAAC;IACjC,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,SAAS,GAAG,OAAO,GAAG,OAAO,CAAC;IACrC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;CACnF;AAED,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED,2EAA2E;AAC3E,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAO7C;AAED,eAAO,MAAM,cAAc,EAAE,OAkB5B,CAAC;AAEF,qBAAa,iBAAiB;IAE1B,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,IAAI;gBADJ,KAAK,EAAE,SAAS,EAChB,IAAI,EAAE,iBAAiB;IAG1C,OAAO,CAAC,IAAI;IAcZ,OAAO,CAAC,KAAK;IAIb,KAAK,IAAI,eAAe;IAwBxB;;;;;OAKG;IACH,KAAK,IACD;QAAE,EAAE,EAAE,IAAI,CAAC;QAAC,IAAI,EAAE,cAAc,CAAA;KAAE,GAClC;QAAE,EAAE,EAAE,KAAK,CAAC;QAAC,MAAM,EAAE,UAAU,CAAC;QAAC,IAAI,EAAE,cAAc,CAAA;KAAE,GACvD;QAAE,EAAE,EAAE,KAAK,CAAC;QAAC,MAAM,EAAE,SAAS,CAAC;QAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE;CAmClE"}
|