@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
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Linux platform helpers — `systemd-inhibit`, `rtcwake`, and
|
|
3
|
+
* user-systemd unit-file generation.
|
|
4
|
+
*
|
|
5
|
+
* Like the macOS module, these wrap shell-outs and string-templating.
|
|
6
|
+
* The only side-effects are spawning subprocesses; nothing here writes
|
|
7
|
+
* a file. The `install` command places the unit files on disk.
|
|
8
|
+
*/
|
|
9
|
+
import { spawn } from "node:child_process";
|
|
10
|
+
/**
|
|
11
|
+
* Spawn `systemd-inhibit --what=idle` so the system stays awake.
|
|
12
|
+
* Returns a kill() function. If `systemd-inhibit` is not available,
|
|
13
|
+
* the returned kill() is a no-op.
|
|
14
|
+
*
|
|
15
|
+
* Note: many Linux desktops will honour this; headless servers may
|
|
16
|
+
* have no idle-sleep policy at all, in which case the inhibit is a
|
|
17
|
+
* functional no-op.
|
|
18
|
+
*/
|
|
19
|
+
export async function caffeinateWhilePending(durationSec) {
|
|
20
|
+
const seconds = Math.max(1, Math.floor(durationSec));
|
|
21
|
+
const args = [
|
|
22
|
+
"--what=idle",
|
|
23
|
+
"--why=Tidegap pending tasks",
|
|
24
|
+
"--mode=block",
|
|
25
|
+
"sleep",
|
|
26
|
+
String(seconds),
|
|
27
|
+
];
|
|
28
|
+
let child;
|
|
29
|
+
try {
|
|
30
|
+
child = spawn("systemd-inhibit", args, {
|
|
31
|
+
stdio: "ignore",
|
|
32
|
+
detached: false,
|
|
33
|
+
});
|
|
34
|
+
child.on("error", () => {
|
|
35
|
+
// systemd-inhibit missing — no-op.
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
// unavailable; return a no-op killer.
|
|
40
|
+
}
|
|
41
|
+
return () => {
|
|
42
|
+
if (child && child.exitCode === null && !child.killed) {
|
|
43
|
+
try {
|
|
44
|
+
child.kill("SIGTERM");
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
// ignore
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Build the exact `rtcwake -m no -t <epoch-seconds>` command for a
|
|
54
|
+
* given date. `-m no` tells rtcwake to *only* arm the RTC alarm without
|
|
55
|
+
* suspending the machine itself.
|
|
56
|
+
*/
|
|
57
|
+
export function rtcwakeCommand(at) {
|
|
58
|
+
const epoch = Math.floor(at.getTime() / 1000);
|
|
59
|
+
return `rtcwake -m no -t ${epoch}`;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Run `rtcwake -m no -t <epoch>`. Needs CAP_SYS_TIME / root. If we are
|
|
63
|
+
* euid 0 we run it directly; otherwise we try `sudo -n` (non-interactive
|
|
64
|
+
* — succeeds only if a sudoers rule pre-authorizes it without a password)
|
|
65
|
+
* and, on failure, hand the caller a non-ok result so it can print the
|
|
66
|
+
* exact sudoers one-liner.
|
|
67
|
+
*/
|
|
68
|
+
export async function rtcwakeScheduleWake(at) {
|
|
69
|
+
const command = rtcwakeCommand(at);
|
|
70
|
+
const uid = typeof process.getuid === "function" ? process.getuid() : -1;
|
|
71
|
+
const epoch = Math.floor(at.getTime() / 1000);
|
|
72
|
+
const bare = ["-m", "no", "-t", String(epoch)];
|
|
73
|
+
const [bin, args] = uid === 0
|
|
74
|
+
? ["rtcwake", bare]
|
|
75
|
+
: ["sudo", ["-n", "rtcwake", ...bare]];
|
|
76
|
+
return await new Promise((resolve) => {
|
|
77
|
+
const child = spawn(bin, args, {
|
|
78
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
79
|
+
});
|
|
80
|
+
let stderr = "";
|
|
81
|
+
child.stderr.on("data", (chunk) => {
|
|
82
|
+
stderr += chunk.toString();
|
|
83
|
+
});
|
|
84
|
+
child.on("error", (err) => {
|
|
85
|
+
resolve({ command, ok: false, stderr: err.message });
|
|
86
|
+
});
|
|
87
|
+
child.on("close", (code) => {
|
|
88
|
+
resolve({ command, ok: code === 0, stderr });
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Compatibility alias for the cross-platform `getPlatform` shim so
|
|
94
|
+
* callers can keep using one name regardless of OS.
|
|
95
|
+
*/
|
|
96
|
+
export const pmsetScheduleWake = rtcwakeScheduleWake;
|
|
97
|
+
/** Base name of the systemd user units (`.service` and `.timer`). */
|
|
98
|
+
export const SYSTEMD_UNIT = "tidegap-tick";
|
|
99
|
+
/** The 0.17 unit name, detected so `tidegap install` can print its cleanup. */
|
|
100
|
+
export const LEGACY_SYSTEMD_UNIT = "ebb-tick";
|
|
101
|
+
/**
|
|
102
|
+
* Render the `tidegap-tick.service` unit file. `Type=oneshot` because the
|
|
103
|
+
* service runs `tidegap tick --once` and exits; the companion timer is
|
|
104
|
+
* responsible for cadence. `EnvironmentFile=` references a user-owned
|
|
105
|
+
* env file (belt-and-braces: `tidegap tick` also loads it directly), so
|
|
106
|
+
* secrets never land in the service unit itself.
|
|
107
|
+
*/
|
|
108
|
+
export function systemdService(opts) {
|
|
109
|
+
const logPath = opts.logPath ?? `${homeDir()}/.tidegap/logs/tick.log`;
|
|
110
|
+
const launcher = opts.launcher && opts.launcher.length > 0
|
|
111
|
+
? opts.launcher
|
|
112
|
+
: [opts.ebbBinaryPath ?? "tidegap"];
|
|
113
|
+
const execStart = [...launcher, "tick", "--db", opts.dbPath, "--once"].join(" ");
|
|
114
|
+
const envLines = opts.env
|
|
115
|
+
? Object.entries(opts.env)
|
|
116
|
+
.map(([k, v]) => `Environment=${k}=${v}`)
|
|
117
|
+
.join("\n")
|
|
118
|
+
: "";
|
|
119
|
+
const envBlock = envLines ? `${envLines}\n` : "";
|
|
120
|
+
return `[Unit]
|
|
121
|
+
Description=Tidegap cron-tick drain
|
|
122
|
+
After=network.target
|
|
123
|
+
|
|
124
|
+
[Service]
|
|
125
|
+
Type=oneshot
|
|
126
|
+
ExecStart=${execStart}
|
|
127
|
+
EnvironmentFile=-%h/.config/tidegap/env
|
|
128
|
+
${envBlock}StandardOutput=append:${logPath}
|
|
129
|
+
StandardError=append:${logPath}
|
|
130
|
+
|
|
131
|
+
[Install]
|
|
132
|
+
WantedBy=default.target
|
|
133
|
+
`;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Render the `tidegap-tick.timer` unit file. Uses `OnUnitActiveSec=<n>s`
|
|
137
|
+
* so the cadence matches the launchd `StartInterval` — fires every N
|
|
138
|
+
* seconds regardless of wall-clock alignment. `OnBootSec=30s` covers
|
|
139
|
+
* the case where the user-session starts before the network does.
|
|
140
|
+
*/
|
|
141
|
+
export function systemdTimer(opts) {
|
|
142
|
+
const interval = Math.max(1, Math.floor(opts.tickIntervalSec));
|
|
143
|
+
return `[Unit]
|
|
144
|
+
Description=Run ${SYSTEMD_UNIT} every ${interval} seconds
|
|
145
|
+
|
|
146
|
+
[Timer]
|
|
147
|
+
OnBootSec=30s
|
|
148
|
+
OnUnitActiveSec=${interval}s
|
|
149
|
+
Unit=${SYSTEMD_UNIT}.service
|
|
150
|
+
|
|
151
|
+
[Install]
|
|
152
|
+
WantedBy=timers.target
|
|
153
|
+
`;
|
|
154
|
+
}
|
|
155
|
+
function homeDir() {
|
|
156
|
+
return process.env.HOME ?? "/tmp";
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=linux.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"linux.js","sourceRoot":"","sources":["../../src/platform/linux.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* macOS platform helpers — `caffeinate`, `pmset schedule wake`, and
|
|
3
|
+
* launchd plist generation.
|
|
4
|
+
*
|
|
5
|
+
* These wrap shell-outs and string-templating. The only side-effects are
|
|
6
|
+
* spawning subprocesses; nothing here writes a file. The `install`
|
|
7
|
+
* command is responsible for placing the plist on disk.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Spawn `caffeinate -i` so the system stays awake (idle-sleep is
|
|
11
|
+
* prevented; display can still sleep). Returns a kill() function. If
|
|
12
|
+
* caffeinate is not available (we're not on macOS), the returned kill()
|
|
13
|
+
* is a no-op.
|
|
14
|
+
*/
|
|
15
|
+
export declare function caffeinateWhilePending(durationSec: number): Promise<() => void>;
|
|
16
|
+
/**
|
|
17
|
+
* Format a Date as `MM/dd/yy HH:mm:ss` — the format `pmset schedule wake`
|
|
18
|
+
* expects. Times are interpreted in the local timezone by `pmset`.
|
|
19
|
+
*/
|
|
20
|
+
export declare function formatPmsetDate(d: Date): string;
|
|
21
|
+
/**
|
|
22
|
+
* Build the exact `pmset schedule wake "..."` command for a given date.
|
|
23
|
+
*/
|
|
24
|
+
export declare function pmsetCommand(at: Date): string;
|
|
25
|
+
/**
|
|
26
|
+
* Run `pmset schedule wake <at>`. `pmset` needs root. If we are euid 0
|
|
27
|
+
* we run it directly; otherwise we try `sudo -n` (non-interactive — it
|
|
28
|
+
* succeeds only if a sudoers rule pre-authorizes the command without a
|
|
29
|
+
* password) and, on failure, hand the caller a non-ok result so it can
|
|
30
|
+
* print the exact sudoers one-liner.
|
|
31
|
+
*/
|
|
32
|
+
export declare function pmsetScheduleWake(at: Date): Promise<{
|
|
33
|
+
command: string;
|
|
34
|
+
ok: boolean;
|
|
35
|
+
stderr: string;
|
|
36
|
+
}>;
|
|
37
|
+
/** launchd label of the tick agent; the plist file is `<label>.plist`. */
|
|
38
|
+
export declare const LAUNCHD_LABEL = "com.tidegap.tick";
|
|
39
|
+
/** The 0.17 label, detected so `tidegap install` can print its cleanup. */
|
|
40
|
+
export declare const LEGACY_LAUNCHD_LABEL = "com.ebb-ai.tick";
|
|
41
|
+
export interface LaunchdPlistOptions {
|
|
42
|
+
tickIntervalSec: number;
|
|
43
|
+
dbPath: string;
|
|
44
|
+
/**
|
|
45
|
+
* The argv[0..n] that invoke `tidegap`, resolved at install time. For a
|
|
46
|
+
* pinned node install this is `[process.execPath, realpath(argv[1])]`
|
|
47
|
+
* — the exact interpreter plus the real dist entry — which is immune
|
|
48
|
+
* to launchd's bare PATH and `#!/usr/bin/env node` shebangs. When the
|
|
49
|
+
* caller only has a single wrapper binary on PATH, pass a one-element
|
|
50
|
+
* array. Falls back to `ebbBinaryPath` (single element) if omitted.
|
|
51
|
+
*/
|
|
52
|
+
launcher?: string[];
|
|
53
|
+
/** Legacy single-binary launcher. Prefer `launcher`. */
|
|
54
|
+
ebbBinaryPath?: string;
|
|
55
|
+
/** Absolute path to write stdout/stderr logs. Defaults to ~/.tidegap/logs/tick.log. */
|
|
56
|
+
logPath?: string;
|
|
57
|
+
/** Optional env vars (e.g. ANTHROPIC_API_KEY) added to the plist. */
|
|
58
|
+
env?: Record<string, string>;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Generate a launchd plist that runs `tidegap tick` on a fixed interval.
|
|
62
|
+
*
|
|
63
|
+
* The plist intentionally uses `StartInterval` (not `StartCalendarInterval`)
|
|
64
|
+
* so the agent fires every N seconds regardless of wall-clock alignment.
|
|
65
|
+
* `RunAtLoad` means tasks queued before the user logs in still drain on
|
|
66
|
+
* first session.
|
|
67
|
+
*/
|
|
68
|
+
export declare function launchdPlist(opts: LaunchdPlistOptions): string;
|
|
69
|
+
//# sourceMappingURL=macos.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"macos.d.ts","sourceRoot":"","sources":["../../src/platform/macos.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC1C,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,MAAM,IAAI,CAAC,CAoBrB;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,IAAI,GAAG,MAAM,CAS/C;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,IAAI,GAAG,MAAM,CAE7C;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CACrC,EAAE,EAAE,IAAI,GACP,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAuB3D;AAED,0EAA0E;AAC1E,eAAO,MAAM,aAAa,qBAAqB,CAAC;AAChD,2EAA2E;AAC3E,eAAO,MAAM,oBAAoB,oBAAoB,CAAC;AAEtD,MAAM,WAAW,mBAAmB;IAClC,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,wDAAwD;IACxD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,uFAAuF;IACvF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qEAAqE;IACrE,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,mBAAmB,GAAG,MAAM,CA0C9D"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* macOS platform helpers — `caffeinate`, `pmset schedule wake`, and
|
|
3
|
+
* launchd plist generation.
|
|
4
|
+
*
|
|
5
|
+
* These wrap shell-outs and string-templating. The only side-effects are
|
|
6
|
+
* spawning subprocesses; nothing here writes a file. The `install`
|
|
7
|
+
* command is responsible for placing the plist on disk.
|
|
8
|
+
*/
|
|
9
|
+
import { spawn } from "node:child_process";
|
|
10
|
+
/**
|
|
11
|
+
* Spawn `caffeinate -i` so the system stays awake (idle-sleep is
|
|
12
|
+
* prevented; display can still sleep). Returns a kill() function. If
|
|
13
|
+
* caffeinate is not available (we're not on macOS), the returned kill()
|
|
14
|
+
* is a no-op.
|
|
15
|
+
*/
|
|
16
|
+
export async function caffeinateWhilePending(durationSec) {
|
|
17
|
+
const args = ["-i", "-t", String(Math.max(1, Math.floor(durationSec)))];
|
|
18
|
+
let child;
|
|
19
|
+
try {
|
|
20
|
+
child = spawn("caffeinate", args, { stdio: "ignore", detached: false });
|
|
21
|
+
child.on("error", () => {
|
|
22
|
+
// caffeinate missing — no-op.
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
// unavailable; return a no-op killer.
|
|
27
|
+
}
|
|
28
|
+
return () => {
|
|
29
|
+
if (child && child.exitCode === null && !child.killed) {
|
|
30
|
+
try {
|
|
31
|
+
child.kill("SIGTERM");
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
// ignore
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Format a Date as `MM/dd/yy HH:mm:ss` — the format `pmset schedule wake`
|
|
41
|
+
* expects. Times are interpreted in the local timezone by `pmset`.
|
|
42
|
+
*/
|
|
43
|
+
export function formatPmsetDate(d) {
|
|
44
|
+
const pad = (n) => String(n).padStart(2, "0");
|
|
45
|
+
const mm = pad(d.getMonth() + 1);
|
|
46
|
+
const dd = pad(d.getDate());
|
|
47
|
+
const yy = pad(d.getFullYear() % 100);
|
|
48
|
+
const hh = pad(d.getHours());
|
|
49
|
+
const mi = pad(d.getMinutes());
|
|
50
|
+
const ss = pad(d.getSeconds());
|
|
51
|
+
return `${mm}/${dd}/${yy} ${hh}:${mi}:${ss}`;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Build the exact `pmset schedule wake "..."` command for a given date.
|
|
55
|
+
*/
|
|
56
|
+
export function pmsetCommand(at) {
|
|
57
|
+
return `pmset schedule wake "${formatPmsetDate(at)}"`;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Run `pmset schedule wake <at>`. `pmset` needs root. If we are euid 0
|
|
61
|
+
* we run it directly; otherwise we try `sudo -n` (non-interactive — it
|
|
62
|
+
* succeeds only if a sudoers rule pre-authorizes the command without a
|
|
63
|
+
* password) and, on failure, hand the caller a non-ok result so it can
|
|
64
|
+
* print the exact sudoers one-liner.
|
|
65
|
+
*/
|
|
66
|
+
export async function pmsetScheduleWake(at) {
|
|
67
|
+
const command = pmsetCommand(at);
|
|
68
|
+
const uid = typeof process.getuid === "function" ? process.getuid() : -1;
|
|
69
|
+
const bare = ["schedule", "wake", formatPmsetDate(at)];
|
|
70
|
+
const [bin, args] = uid === 0
|
|
71
|
+
? ["pmset", bare]
|
|
72
|
+
: ["sudo", ["-n", "pmset", ...bare]];
|
|
73
|
+
return await new Promise((resolve) => {
|
|
74
|
+
const child = spawn(bin, args, {
|
|
75
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
76
|
+
});
|
|
77
|
+
let stderr = "";
|
|
78
|
+
child.stderr.on("data", (chunk) => {
|
|
79
|
+
stderr += chunk.toString();
|
|
80
|
+
});
|
|
81
|
+
child.on("error", (err) => {
|
|
82
|
+
resolve({ command, ok: false, stderr: err.message });
|
|
83
|
+
});
|
|
84
|
+
child.on("close", (code) => {
|
|
85
|
+
resolve({ command, ok: code === 0, stderr });
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
/** launchd label of the tick agent; the plist file is `<label>.plist`. */
|
|
90
|
+
export const LAUNCHD_LABEL = "com.tidegap.tick";
|
|
91
|
+
/** The 0.17 label, detected so `tidegap install` can print its cleanup. */
|
|
92
|
+
export const LEGACY_LAUNCHD_LABEL = "com.ebb-ai.tick";
|
|
93
|
+
/**
|
|
94
|
+
* Generate a launchd plist that runs `tidegap tick` on a fixed interval.
|
|
95
|
+
*
|
|
96
|
+
* The plist intentionally uses `StartInterval` (not `StartCalendarInterval`)
|
|
97
|
+
* so the agent fires every N seconds regardless of wall-clock alignment.
|
|
98
|
+
* `RunAtLoad` means tasks queued before the user logs in still drain on
|
|
99
|
+
* first session.
|
|
100
|
+
*/
|
|
101
|
+
export function launchdPlist(opts) {
|
|
102
|
+
const logPath = opts.logPath ?? `${homeDir()}/.tidegap/logs/tick.log`;
|
|
103
|
+
const launcher = opts.launcher && opts.launcher.length > 0
|
|
104
|
+
? opts.launcher
|
|
105
|
+
: [opts.ebbBinaryPath ?? "tidegap"];
|
|
106
|
+
const programArgs = [...launcher, "tick", "--db", opts.dbPath, "--once"];
|
|
107
|
+
const argBlock = programArgs
|
|
108
|
+
.map((a) => ` <string>${escapeXml(a)}</string>`)
|
|
109
|
+
.join("\n");
|
|
110
|
+
const envBlock = opts.env
|
|
111
|
+
? Object.entries(opts.env)
|
|
112
|
+
.map(([k, v]) => ` <key>${escapeXml(k)}</key>\n <string>${escapeXml(v)}</string>`)
|
|
113
|
+
.join("\n")
|
|
114
|
+
: "";
|
|
115
|
+
const envFragment = envBlock
|
|
116
|
+
? ` <key>EnvironmentVariables</key>\n <dict>\n${envBlock}\n </dict>\n`
|
|
117
|
+
: "";
|
|
118
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
119
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
120
|
+
<plist version="1.0">
|
|
121
|
+
<dict>
|
|
122
|
+
<key>Label</key>
|
|
123
|
+
<string>${LAUNCHD_LABEL}</string>
|
|
124
|
+
<key>ProgramArguments</key>
|
|
125
|
+
<array>
|
|
126
|
+
${argBlock}
|
|
127
|
+
</array>
|
|
128
|
+
<key>StartInterval</key>
|
|
129
|
+
<integer>${Math.max(1, Math.floor(opts.tickIntervalSec))}</integer>
|
|
130
|
+
<key>RunAtLoad</key>
|
|
131
|
+
<true/>
|
|
132
|
+
${envFragment} <key>StandardOutPath</key>
|
|
133
|
+
<string>${escapeXml(logPath)}</string>
|
|
134
|
+
<key>StandardErrorPath</key>
|
|
135
|
+
<string>${escapeXml(logPath)}</string>
|
|
136
|
+
</dict>
|
|
137
|
+
</plist>
|
|
138
|
+
`;
|
|
139
|
+
}
|
|
140
|
+
function homeDir() {
|
|
141
|
+
return process.env.HOME ?? "/tmp";
|
|
142
|
+
}
|
|
143
|
+
function escapeXml(s) {
|
|
144
|
+
return s
|
|
145
|
+
.replace(/&/g, "&")
|
|
146
|
+
.replace(/</g, "<")
|
|
147
|
+
.replace(/>/g, ">")
|
|
148
|
+
.replace(/"/g, """)
|
|
149
|
+
.replace(/'/g, "'");
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=macos.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"macos.js","sourceRoot":"","sources":["../../src/platform/macos.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Windows platform helpers.
|
|
3
|
+
*
|
|
4
|
+
* There is no automated daemon install on Windows: `tidegap install` does
|
|
5
|
+
* not register a Task Scheduler job or an nssm service for you. Instead
|
|
6
|
+
* it prints a ready-to-paste `schtasks` command, built from the real
|
|
7
|
+
* node interpreter + the resolved `tidegap` entry, that you run yourself
|
|
8
|
+
* from an elevated prompt. `caffeinate`/wake-event equivalents
|
|
9
|
+
* (SetThreadExecutionState, waitable timers) are not wired.
|
|
10
|
+
*/
|
|
11
|
+
export declare const TODO_NOTE: string;
|
|
12
|
+
export declare function caffeinateWhilePending(_durationSec: number): Promise<() => void>;
|
|
13
|
+
export declare function pmsetScheduleWake(_at: Date): Promise<{
|
|
14
|
+
command: string;
|
|
15
|
+
ok: boolean;
|
|
16
|
+
stderr: string;
|
|
17
|
+
}>;
|
|
18
|
+
/**
|
|
19
|
+
* Build a ready-to-paste `schtasks` command for running `tidegap tick`
|
|
20
|
+
* periodically. `launcher` is the resolved invocation
|
|
21
|
+
* (`[process.execPath, realpath(argv[1])]` for a pinned-node install),
|
|
22
|
+
* so the task runs the exact interpreter + entry rather than relying on
|
|
23
|
+
* a POSIX-style `/usr/local/bin/tidegap` path that never exists on Windows.
|
|
24
|
+
*/
|
|
25
|
+
export declare function schtasksTemplate(opts: {
|
|
26
|
+
launcher?: string[];
|
|
27
|
+
ebbBinaryPath?: string;
|
|
28
|
+
dbPath: string;
|
|
29
|
+
tickIntervalSec: number;
|
|
30
|
+
}): string;
|
|
31
|
+
//# sourceMappingURL=windows.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"windows.d.ts","sourceRoot":"","sources":["../../src/platform/windows.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,eAAO,MAAM,SAAS,QAGyC,CAAC;AAEhE,wBAAsB,sBAAsB,CAC1C,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,MAAM,IAAI,CAAC,CAQrB;AAED,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,IAAI,GACR,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAQ3D;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE;IACrC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,MAAM,CAAC;CACzB,GAAG,MAAM,CAmBT"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Windows platform helpers.
|
|
3
|
+
*
|
|
4
|
+
* There is no automated daemon install on Windows: `tidegap install` does
|
|
5
|
+
* not register a Task Scheduler job or an nssm service for you. Instead
|
|
6
|
+
* it prints a ready-to-paste `schtasks` command, built from the real
|
|
7
|
+
* node interpreter + the resolved `tidegap` entry, that you run yourself
|
|
8
|
+
* from an elevated prompt. `caffeinate`/wake-event equivalents
|
|
9
|
+
* (SetThreadExecutionState, waitable timers) are not wired.
|
|
10
|
+
*/
|
|
11
|
+
export const TODO_NOTE = "[tidegap/cli] Windows daemon install is not supported. " +
|
|
12
|
+
"Run `tidegap tick` under Task Scheduler or nssm manually — " +
|
|
13
|
+
"`tidegap install` prints a ready-to-paste schtasks command.";
|
|
14
|
+
export async function caffeinateWhilePending(_durationSec) {
|
|
15
|
+
// SetThreadExecutionState(ES_SYSTEM_REQUIRED) would be the equivalent
|
|
16
|
+
// here; not wired. Idle-sleep prevention is a no-op on Windows.
|
|
17
|
+
// eslint-disable-next-line no-console
|
|
18
|
+
console.warn(TODO_NOTE);
|
|
19
|
+
return () => {
|
|
20
|
+
// no-op
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
export async function pmsetScheduleWake(_at) {
|
|
24
|
+
// eslint-disable-next-line no-console
|
|
25
|
+
console.warn(TODO_NOTE);
|
|
26
|
+
return {
|
|
27
|
+
command: "",
|
|
28
|
+
ok: false,
|
|
29
|
+
stderr: "wake-event registration is not supported on Windows",
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Build a ready-to-paste `schtasks` command for running `tidegap tick`
|
|
34
|
+
* periodically. `launcher` is the resolved invocation
|
|
35
|
+
* (`[process.execPath, realpath(argv[1])]` for a pinned-node install),
|
|
36
|
+
* so the task runs the exact interpreter + entry rather than relying on
|
|
37
|
+
* a POSIX-style `/usr/local/bin/tidegap` path that never exists on Windows.
|
|
38
|
+
*/
|
|
39
|
+
export function schtasksTemplate(opts) {
|
|
40
|
+
const launcher = opts.launcher && opts.launcher.length > 0
|
|
41
|
+
? opts.launcher
|
|
42
|
+
: [opts.ebbBinaryPath ?? "tidegap"];
|
|
43
|
+
const quote = (s) => (/\s/.test(s) ? `\\"${s}\\"` : s);
|
|
44
|
+
const run = [...launcher, "tick", "--db", opts.dbPath, "--once"]
|
|
45
|
+
.map(quote)
|
|
46
|
+
.join(" ");
|
|
47
|
+
const everyMin = Math.max(1, Math.floor(opts.tickIntervalSec / 60));
|
|
48
|
+
return `Windows daemon install is not supported. Run \`tidegap tick\` yourself under
|
|
49
|
+
Task Scheduler or nssm. From an elevated PowerShell / CMD:
|
|
50
|
+
|
|
51
|
+
schtasks /create /TN "tidegap-tick" /TR "${run}" /SC MINUTE /MO ${everyMin} /F
|
|
52
|
+
|
|
53
|
+
Provide provider keys via %USERPROFILE%\\.config\\tidegap\\env (KEY=VALUE lines);
|
|
54
|
+
\`tidegap tick\` loads that file on startup. Wake-from-sleep events are not
|
|
55
|
+
supported on Windows.
|
|
56
|
+
`;
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=windows.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"windows.js","sourceRoot":"","sources":["../../src/platform/windows.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,MAAM,CAAC,MAAM,SAAS,GACpB,yDAAyD;IACzD,6DAA6D;IAC7D,6DAA6D,CAAC;AAEhE,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,YAAoB;IAEpB,sEAAsE;IACtE,gEAAgE;IAChE,sCAAsC;IACtC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACxB,OAAO,GAAG,EAAE;QACV,QAAQ;IACV,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,GAAS;IAET,sCAAsC;IACtC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACxB,OAAO;QACL,OAAO,EAAE,EAAE;QACX,EAAE,EAAE,KAAK;QACT,MAAM,EAAE,qDAAqD;KAC9D,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAKhC;IACC,MAAM,QAAQ,GACZ,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC;QACvC,CAAC,CAAC,IAAI,CAAC,QAAQ;QACf,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,IAAI,SAAS,CAAC,CAAC;IACxC,MAAM,KAAK,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/D,MAAM,GAAG,GAAG,CAAC,GAAG,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC;SAC7D,GAAG,CAAC,KAAK,CAAC;SACV,IAAI,CAAC,GAAG,CAAC,CAAC;IACb,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,eAAe,GAAG,EAAE,CAAC,CAAC,CAAC;IACpE,OAAO;;;6CAGoC,GAAG,oBAAoB,QAAQ;;;;;CAK3E,CAAC;AACF,CAAC"}
|
package/dist/ui/api.d.ts
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
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 { type GridFeed, type QuotaResetConfig, type Scheduler, type TaskStore } from "@tidegap/core";
|
|
13
|
+
import type { DaemonStatus } from "../platform/index.js";
|
|
14
|
+
import type { DispatcherControl } from "./dispatcher.js";
|
|
15
|
+
export interface ApiContext {
|
|
16
|
+
store: TaskStore;
|
|
17
|
+
dbPath: string;
|
|
18
|
+
feed: GridFeed;
|
|
19
|
+
defaultRegion: string;
|
|
20
|
+
/** Read per request so a config edit shows without a restart. */
|
|
21
|
+
quota: () => QuotaResetConfig;
|
|
22
|
+
daemonStatus: () => DaemonStatus;
|
|
23
|
+
now?: () => Date;
|
|
24
|
+
/** Write path (ui v2): a Scheduler with no adapters. Absent = read-only. */
|
|
25
|
+
scheduler?: Scheduler;
|
|
26
|
+
/** Start dispatcher and dispatcher state (ui v2). */
|
|
27
|
+
dispatcher?: DispatcherControl;
|
|
28
|
+
}
|
|
29
|
+
/** Longest reply text, in characters. */
|
|
30
|
+
export declare const REPLY_MAX_CHARS = 32000;
|
|
31
|
+
/**
|
|
32
|
+
* How each POST route treats its body (KTD9). `json`: the route reads a
|
|
33
|
+
* JSON object (Content-Type application/json required). `none`: no body.
|
|
34
|
+
*/
|
|
35
|
+
export declare function postBodyKind(pathname: string): "json" | "none" | undefined;
|
|
36
|
+
export interface ApiResponse {
|
|
37
|
+
status: number;
|
|
38
|
+
body?: unknown;
|
|
39
|
+
/** Task ids this request changed; the server pushes them to the stream. */
|
|
40
|
+
changedIds?: string[];
|
|
41
|
+
}
|
|
42
|
+
/** Most hours of forecast one request returns. */
|
|
43
|
+
export declare const MAX_FORECAST_HOURS = 72;
|
|
44
|
+
/**
|
|
45
|
+
* How long one forecast answer is reused. The page asks on every change
|
|
46
|
+
* event; without a cache each one would spend the grid provider's quota,
|
|
47
|
+
* which the tick needs for scheduling.
|
|
48
|
+
*/
|
|
49
|
+
export declare const FORECAST_CACHE_MS: number;
|
|
50
|
+
type Body = Record<string, unknown>;
|
|
51
|
+
/**
|
|
52
|
+
* Route one authenticated `/api/*` request (SSE is handled by the server).
|
|
53
|
+
* Returns 404 for an unknown path and 405 for a wrong method.
|
|
54
|
+
*/
|
|
55
|
+
export declare function handleApi(ctx: ApiContext, method: string, pathname: string, params: URLSearchParams,
|
|
56
|
+
/** Parsed JSON object of a body route (the server checked type and size). */
|
|
57
|
+
body?: Body): Promise<ApiResponse>;
|
|
58
|
+
export {};
|
|
59
|
+
//# sourceMappingURL=api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/ui/api.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAaL,KAAK,QAAQ,EACb,KAAK,gBAAgB,EAErB,KAAK,SAAS,EAGd,KAAK,SAAS,EACf,MAAM,eAAe,CAAC;AAUvB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEzD,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,SAAS,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,QAAQ,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,iEAAiE;IACjE,KAAK,EAAE,MAAM,gBAAgB,CAAC;IAC9B,YAAY,EAAE,MAAM,YAAY,CAAC;IACjC,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;IACjB,4EAA4E;IAC5E,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,qDAAqD;IACrD,UAAU,CAAC,EAAE,iBAAiB,CAAC;CAChC;AAED,yCAAyC;AACzC,eAAO,MAAM,eAAe,QAAS,CAAC;AAEtC;;;GAGG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,CAO1E;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,2EAA2E;IAC3E,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,kDAAkD;AAClD,eAAO,MAAM,kBAAkB,KAAK,CAAC;AAErC;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,QAAc,CAAC;AA2K7C,KAAK,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAyMpC;;;GAGG;AACH,wBAAsB,SAAS,CAC7B,GAAG,EAAE,UAAU,EACf,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,eAAe;AACvB,6EAA6E;AAC7E,IAAI,GAAE,IAAS,GACd,OAAO,CAAC,WAAW,CAAC,CA8CtB"}
|