remote-pi-app 0.7.1
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 +21 -0
- package/README.md +675 -0
- package/dist/actions/handlers.d.ts +138 -0
- package/dist/actions/handlers.js +189 -0
- package/dist/actions/handlers.js.map +1 -0
- package/dist/actions/registry.d.ts +39 -0
- package/dist/actions/registry.js +58 -0
- package/dist/actions/registry.js.map +1 -0
- package/dist/bin/supervisord.d.ts +2 -0
- package/dist/bin/supervisord.js +86 -0
- package/dist/bin/supervisord.js.map +1 -0
- package/dist/config.d.ts +62 -0
- package/dist/config.js +115 -0
- package/dist/config.js.map +1 -0
- package/dist/daemon/client.d.ts +20 -0
- package/dist/daemon/client.js +131 -0
- package/dist/daemon/client.js.map +1 -0
- package/dist/daemon/control_protocol.d.ts +176 -0
- package/dist/daemon/control_protocol.js +63 -0
- package/dist/daemon/control_protocol.js.map +1 -0
- package/dist/daemon/cron_log.d.ts +45 -0
- package/dist/daemon/cron_log.js +72 -0
- package/dist/daemon/cron_log.js.map +1 -0
- package/dist/daemon/cron_registry.d.ts +80 -0
- package/dist/daemon/cron_registry.js +194 -0
- package/dist/daemon/cron_registry.js.map +1 -0
- package/dist/daemon/id.d.ts +24 -0
- package/dist/daemon/id.js +36 -0
- package/dist/daemon/id.js.map +1 -0
- package/dist/daemon/install.d.ts +170 -0
- package/dist/daemon/install.js +547 -0
- package/dist/daemon/install.js.map +1 -0
- package/dist/daemon/registry.d.ts +63 -0
- package/dist/daemon/registry.js +153 -0
- package/dist/daemon/registry.js.map +1 -0
- package/dist/daemon/rpc_child.d.ts +194 -0
- package/dist/daemon/rpc_child.js +389 -0
- package/dist/daemon/rpc_child.js.map +1 -0
- package/dist/daemon/supervisor.d.ts +93 -0
- package/dist/daemon/supervisor.js +596 -0
- package/dist/daemon/supervisor.js.map +1 -0
- package/dist/extension_ui_bridge.d.ts +26 -0
- package/dist/extension_ui_bridge.js +341 -0
- package/dist/extension_ui_bridge.js.map +1 -0
- package/dist/index.d.ts +213 -0
- package/dist/index.js +5090 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/mesh_result.d.ts +10 -0
- package/dist/mcp/mesh_result.js +42 -0
- package/dist/mcp/mesh_result.js.map +1 -0
- package/dist/mcp/mesh_server.d.ts +16 -0
- package/dist/mcp/mesh_server.js +327 -0
- package/dist/mcp/mesh_server.js.map +1 -0
- package/dist/mesh/canonical.d.ts +30 -0
- package/dist/mesh/canonical.js +61 -0
- package/dist/mesh/canonical.js.map +1 -0
- package/dist/mesh/client.d.ts +18 -0
- package/dist/mesh/client.js +125 -0
- package/dist/mesh/client.js.map +1 -0
- package/dist/mesh/encoding.d.ts +38 -0
- package/dist/mesh/encoding.js +216 -0
- package/dist/mesh/encoding.js.map +1 -0
- package/dist/mesh/self_revoke.d.ts +73 -0
- package/dist/mesh/self_revoke.js +401 -0
- package/dist/mesh/self_revoke.js.map +1 -0
- package/dist/mesh/siblings.d.ts +49 -0
- package/dist/mesh/siblings.js +159 -0
- package/dist/mesh/siblings.js.map +1 -0
- package/dist/mesh/types.d.ts +34 -0
- package/dist/mesh/types.js +11 -0
- package/dist/mesh/types.js.map +1 -0
- package/dist/mesh/verify.d.ts +17 -0
- package/dist/mesh/verify.js +86 -0
- package/dist/mesh/verify.js.map +1 -0
- package/dist/pairing/crypto.d.ts +8 -0
- package/dist/pairing/crypto.js +22 -0
- package/dist/pairing/crypto.js.map +1 -0
- package/dist/pairing/qr.d.ts +59 -0
- package/dist/pairing/qr.js +125 -0
- package/dist/pairing/qr.js.map +1 -0
- package/dist/pairing/storage.d.ts +120 -0
- package/dist/pairing/storage.js +604 -0
- package/dist/pairing/storage.js.map +1 -0
- package/dist/protocol/codec.d.ts +7 -0
- package/dist/protocol/codec.js +53 -0
- package/dist/protocol/codec.js.map +1 -0
- package/dist/protocol/types.d.ts +432 -0
- package/dist/protocol/types.js +2 -0
- package/dist/protocol/types.js.map +1 -0
- package/dist/rooms.d.ts +29 -0
- package/dist/rooms.js +57 -0
- package/dist/rooms.js.map +1 -0
- package/dist/session/bridge.d.ts +37 -0
- package/dist/session/bridge.js +130 -0
- package/dist/session/bridge.js.map +1 -0
- package/dist/session/broker.d.ts +189 -0
- package/dist/session/broker.js +507 -0
- package/dist/session/broker.js.map +1 -0
- package/dist/session/broker_remote.d.ts +74 -0
- package/dist/session/broker_remote.js +583 -0
- package/dist/session/broker_remote.js.map +1 -0
- package/dist/session/cwd_lock.d.ts +33 -0
- package/dist/session/cwd_lock.js +126 -0
- package/dist/session/cwd_lock.js.map +1 -0
- package/dist/session/envelope.d.ts +33 -0
- package/dist/session/envelope.js +117 -0
- package/dist/session/envelope.js.map +1 -0
- package/dist/session/global_config.d.ts +33 -0
- package/dist/session/global_config.js +73 -0
- package/dist/session/global_config.js.map +1 -0
- package/dist/session/ipc.d.ts +27 -0
- package/dist/session/ipc.js +22 -0
- package/dist/session/ipc.js.map +1 -0
- package/dist/session/leader_election.d.ts +32 -0
- package/dist/session/leader_election.js +106 -0
- package/dist/session/leader_election.js.map +1 -0
- package/dist/session/local_config.d.ts +55 -0
- package/dist/session/local_config.js +157 -0
- package/dist/session/local_config.js.map +1 -0
- package/dist/session/mesh_node.d.ts +116 -0
- package/dist/session/mesh_node.js +573 -0
- package/dist/session/mesh_node.js.map +1 -0
- package/dist/session/peer.d.ts +139 -0
- package/dist/session/peer.js +451 -0
- package/dist/session/peer.js.map +1 -0
- package/dist/session/peer_inventory.d.ts +13 -0
- package/dist/session/peer_inventory.js +48 -0
- package/dist/session/peer_inventory.js.map +1 -0
- package/dist/session/peer_limits.d.ts +9 -0
- package/dist/session/peer_limits.js +21 -0
- package/dist/session/peer_limits.js.map +1 -0
- package/dist/session/setup_wizard.d.ts +39 -0
- package/dist/session/setup_wizard.js +63 -0
- package/dist/session/setup_wizard.js.map +1 -0
- package/dist/session/tools.d.ts +24 -0
- package/dist/session/tools.js +252 -0
- package/dist/session/tools.js.map +1 -0
- package/dist/session/wizard.d.ts +13 -0
- package/dist/session/wizard.js +20 -0
- package/dist/session/wizard.js.map +1 -0
- package/dist/transport/peer_channel.d.ts +37 -0
- package/dist/transport/peer_channel.js +98 -0
- package/dist/transport/peer_channel.js.map +1 -0
- package/dist/transport/pi_forward_client.d.ts +29 -0
- package/dist/transport/pi_forward_client.js +62 -0
- package/dist/transport/pi_forward_client.js.map +1 -0
- package/dist/transport/relay_client.d.ts +91 -0
- package/dist/transport/relay_client.js +206 -0
- package/dist/transport/relay_client.js.map +1 -0
- package/dist/ui/footer.d.ts +32 -0
- package/dist/ui/footer.js +34 -0
- package/dist/ui/footer.js.map +1 -0
- package/docs/daemon.md +289 -0
- package/package.json +90 -0
- package/service-templates/launchd.plist.template +35 -0
- package/service-templates/systemd.service.template +19 -0
- package/service-templates/task-launcher.vbs.template +10 -0
- package/service-templates/task-scheduler.xml.template +38 -0
- package/skills/agent-network/SKILL.md +310 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cron registry: scheduled prompts for daemons, persisted at
|
|
3
|
+
* `~/.pi/remote/cron.json`. Mirrors `registry.ts` (`daemons.json`) — tolerant
|
|
4
|
+
* load (missing/corrupt → empty), atomic-ish full-file save.
|
|
5
|
+
*
|
|
6
|
+
* Each job targets a daemon by its `daemon_id` (the 8-hex id from
|
|
7
|
+
* `daemonIdForCwd`) and fires `prompt` on `schedule` (a cron expression, run
|
|
8
|
+
* by croner in the supervisor). The scheduler engine + `fireJob` live in
|
|
9
|
+
* `supervisor.ts`; this module only owns persistence + schedule validation.
|
|
10
|
+
*
|
|
11
|
+
* Plan/39. Decisions B (croner), C (min-interval 60s), E (audit via cron_log).
|
|
12
|
+
*/
|
|
13
|
+
/** Minimum allowed interval between two consecutive runs of a schedule. */
|
|
14
|
+
export declare const MIN_INTERVAL_MS = 60000;
|
|
15
|
+
/** A scheduled prompt. */
|
|
16
|
+
export interface CronJob {
|
|
17
|
+
/** `j_<hex>` — random, stable across restarts. */
|
|
18
|
+
id: string;
|
|
19
|
+
/** Target daemon id (`daemonIdForCwd`). */
|
|
20
|
+
daemon_id: string;
|
|
21
|
+
/** Cron expression (croner syntax; optional 6th seconds field supported). */
|
|
22
|
+
schedule: string;
|
|
23
|
+
/** IANA timezone for the schedule (e.g. "America/Sao_Paulo"). */
|
|
24
|
+
tz?: string;
|
|
25
|
+
/** Prompt text injected into the daemon when the job fires. */
|
|
26
|
+
prompt: string;
|
|
27
|
+
enabled: boolean;
|
|
28
|
+
/** Skip the fire when the daemon is mid-turn (default true). */
|
|
29
|
+
skip_if_busy: boolean;
|
|
30
|
+
/** Start the daemon if it's down, then fire (default false). */
|
|
31
|
+
wake: boolean;
|
|
32
|
+
/** On supervisor start, run once if the previous scheduled run was missed
|
|
33
|
+
* while it was down (default false; at most 1×). */
|
|
34
|
+
catchup: boolean;
|
|
35
|
+
created_at: string;
|
|
36
|
+
last_run?: string;
|
|
37
|
+
/** Last fire result — see cron_log `result` values. Shortcut for `cron list`. */
|
|
38
|
+
last_status?: string;
|
|
39
|
+
}
|
|
40
|
+
export interface CronRegistry {
|
|
41
|
+
jobs: CronJob[];
|
|
42
|
+
}
|
|
43
|
+
/** Test/diag-only: the on-disk path. */
|
|
44
|
+
export declare function cronRegistryPath(): string;
|
|
45
|
+
/** Reads the registry; returns empty on missing/corrupt file. */
|
|
46
|
+
export declare function loadCronRegistry(): CronRegistry;
|
|
47
|
+
export declare function saveCronRegistry(reg: CronRegistry): void;
|
|
48
|
+
export declare function listJobs(): CronJob[];
|
|
49
|
+
export declare function getJob(id: string): CronJob | undefined;
|
|
50
|
+
/** Fields a caller supplies when creating a job. Flags default sensibly. */
|
|
51
|
+
export interface NewJobInput {
|
|
52
|
+
daemon_id: string;
|
|
53
|
+
schedule: string;
|
|
54
|
+
prompt: string;
|
|
55
|
+
tz?: string;
|
|
56
|
+
skip_if_busy?: boolean;
|
|
57
|
+
wake?: boolean;
|
|
58
|
+
catchup?: boolean;
|
|
59
|
+
}
|
|
60
|
+
/** Adds a job with a fresh `j_<hex>` id. Pure persistence — call
|
|
61
|
+
* `validateSchedule` first at the op/CLI boundary. */
|
|
62
|
+
export declare function addJob(input: NewJobInput): CronJob;
|
|
63
|
+
export declare function removeJob(id: string): boolean;
|
|
64
|
+
export declare function setJobEnabled(id: string, enabled: boolean): boolean;
|
|
65
|
+
/** Records the outcome of a fire on the job (the `cron list` shortcut). */
|
|
66
|
+
export declare function recordRun(id: string, at: string, status: string): void;
|
|
67
|
+
export interface ScheduleValidation {
|
|
68
|
+
ok: boolean;
|
|
69
|
+
error?: string;
|
|
70
|
+
/** Interval (ms) between the next two runs, when computable. */
|
|
71
|
+
intervalMs?: number;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Validates a cron expression via croner and enforces the ≥60s min-interval
|
|
75
|
+
* (decision C — guards against pileup + token burn). Returns `ok:false` with a
|
|
76
|
+
* user-facing message on a bad expression or a too-frequent schedule.
|
|
77
|
+
*/
|
|
78
|
+
export declare function validateSchedule(schedule: string, tz?: string): ScheduleValidation;
|
|
79
|
+
/** Returns the next scheduled run for a job, or null. Used by `cron list`. */
|
|
80
|
+
export declare function nextRunFor(job: CronJob): Date | null;
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { randomBytes } from "node:crypto";
|
|
4
|
+
import { dirname, join } from "node:path";
|
|
5
|
+
import { Cron } from "croner";
|
|
6
|
+
/**
|
|
7
|
+
* Cron registry: scheduled prompts for daemons, persisted at
|
|
8
|
+
* `~/.pi/remote/cron.json`. Mirrors `registry.ts` (`daemons.json`) — tolerant
|
|
9
|
+
* load (missing/corrupt → empty), atomic-ish full-file save.
|
|
10
|
+
*
|
|
11
|
+
* Each job targets a daemon by its `daemon_id` (the 8-hex id from
|
|
12
|
+
* `daemonIdForCwd`) and fires `prompt` on `schedule` (a cron expression, run
|
|
13
|
+
* by croner in the supervisor). The scheduler engine + `fireJob` live in
|
|
14
|
+
* `supervisor.ts`; this module only owns persistence + schedule validation.
|
|
15
|
+
*
|
|
16
|
+
* Plan/39. Decisions B (croner), C (min-interval 60s), E (audit via cron_log).
|
|
17
|
+
*/
|
|
18
|
+
/** Minimum allowed interval between two consecutive runs of a schedule. */
|
|
19
|
+
export const MIN_INTERVAL_MS = 60_000;
|
|
20
|
+
function cronPath() {
|
|
21
|
+
const root = process.env["REMOTE_PI_HOME"] || homedir();
|
|
22
|
+
return join(root, ".pi", "remote", "cron.json");
|
|
23
|
+
}
|
|
24
|
+
/** Test/diag-only: the on-disk path. */
|
|
25
|
+
export function cronRegistryPath() {
|
|
26
|
+
return cronPath();
|
|
27
|
+
}
|
|
28
|
+
/** Reads the registry; returns empty on missing/corrupt file. */
|
|
29
|
+
export function loadCronRegistry() {
|
|
30
|
+
if (!existsSync(cronPath()))
|
|
31
|
+
return { jobs: [] };
|
|
32
|
+
try {
|
|
33
|
+
const parsed = JSON.parse(readFileSync(cronPath(), "utf8"));
|
|
34
|
+
if (!parsed || typeof parsed !== "object")
|
|
35
|
+
return { jobs: [] };
|
|
36
|
+
const arr = parsed.jobs;
|
|
37
|
+
if (!Array.isArray(arr))
|
|
38
|
+
return { jobs: [] };
|
|
39
|
+
const jobs = [];
|
|
40
|
+
for (const item of arr) {
|
|
41
|
+
const job = _coerceJob(item);
|
|
42
|
+
if (job)
|
|
43
|
+
jobs.push(job);
|
|
44
|
+
}
|
|
45
|
+
return { jobs };
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return { jobs: [] };
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
export function saveCronRegistry(reg) {
|
|
52
|
+
mkdirSync(dirname(cronPath()), { recursive: true });
|
|
53
|
+
writeFileSync(cronPath(), JSON.stringify(reg, null, 2) + "\n");
|
|
54
|
+
}
|
|
55
|
+
export function listJobs() {
|
|
56
|
+
return loadCronRegistry().jobs;
|
|
57
|
+
}
|
|
58
|
+
export function getJob(id) {
|
|
59
|
+
return loadCronRegistry().jobs.find((j) => j.id === id);
|
|
60
|
+
}
|
|
61
|
+
/** Adds a job with a fresh `j_<hex>` id. Pure persistence — call
|
|
62
|
+
* `validateSchedule` first at the op/CLI boundary. */
|
|
63
|
+
export function addJob(input) {
|
|
64
|
+
const reg = loadCronRegistry();
|
|
65
|
+
const job = {
|
|
66
|
+
id: _freshId(reg.jobs),
|
|
67
|
+
daemon_id: input.daemon_id,
|
|
68
|
+
schedule: input.schedule,
|
|
69
|
+
prompt: input.prompt,
|
|
70
|
+
enabled: true,
|
|
71
|
+
skip_if_busy: input.skip_if_busy ?? true,
|
|
72
|
+
wake: input.wake ?? false,
|
|
73
|
+
catchup: input.catchup ?? false,
|
|
74
|
+
created_at: new Date().toISOString(),
|
|
75
|
+
};
|
|
76
|
+
if (input.tz)
|
|
77
|
+
job.tz = input.tz;
|
|
78
|
+
reg.jobs.push(job);
|
|
79
|
+
saveCronRegistry(reg);
|
|
80
|
+
return job;
|
|
81
|
+
}
|
|
82
|
+
export function removeJob(id) {
|
|
83
|
+
const reg = loadCronRegistry();
|
|
84
|
+
const idx = reg.jobs.findIndex((j) => j.id === id);
|
|
85
|
+
if (idx === -1)
|
|
86
|
+
return false;
|
|
87
|
+
reg.jobs.splice(idx, 1);
|
|
88
|
+
saveCronRegistry(reg);
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
export function setJobEnabled(id, enabled) {
|
|
92
|
+
const reg = loadCronRegistry();
|
|
93
|
+
const job = reg.jobs.find((j) => j.id === id);
|
|
94
|
+
if (!job)
|
|
95
|
+
return false;
|
|
96
|
+
job.enabled = enabled;
|
|
97
|
+
saveCronRegistry(reg);
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
100
|
+
/** Records the outcome of a fire on the job (the `cron list` shortcut). */
|
|
101
|
+
export function recordRun(id, at, status) {
|
|
102
|
+
const reg = loadCronRegistry();
|
|
103
|
+
const job = reg.jobs.find((j) => j.id === id);
|
|
104
|
+
if (!job)
|
|
105
|
+
return;
|
|
106
|
+
job.last_run = at;
|
|
107
|
+
job.last_status = status;
|
|
108
|
+
saveCronRegistry(reg);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Validates a cron expression via croner and enforces the ≥60s min-interval
|
|
112
|
+
* (decision C — guards against pileup + token burn). Returns `ok:false` with a
|
|
113
|
+
* user-facing message on a bad expression or a too-frequent schedule.
|
|
114
|
+
*/
|
|
115
|
+
export function validateSchedule(schedule, tz) {
|
|
116
|
+
let cron;
|
|
117
|
+
try {
|
|
118
|
+
cron = new Cron(schedule, tz ? { timezone: tz } : {});
|
|
119
|
+
}
|
|
120
|
+
catch (e) {
|
|
121
|
+
return { ok: false, error: `invalid cron expression: ${e.message}` };
|
|
122
|
+
}
|
|
123
|
+
try {
|
|
124
|
+
const n1 = cron.nextRun();
|
|
125
|
+
const n2 = n1 ? cron.nextRun(n1) : null;
|
|
126
|
+
if (!n1 || !n2)
|
|
127
|
+
return { ok: false, error: "schedule has no upcoming runs" };
|
|
128
|
+
const intervalMs = n2.getTime() - n1.getTime();
|
|
129
|
+
if (intervalMs < MIN_INTERVAL_MS) {
|
|
130
|
+
return {
|
|
131
|
+
ok: false,
|
|
132
|
+
intervalMs,
|
|
133
|
+
error: `schedule too frequent: ~${Math.round(intervalMs / 1000)}s between runs (minimum is 60s)`,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
return { ok: true, intervalMs };
|
|
137
|
+
}
|
|
138
|
+
finally {
|
|
139
|
+
cron.stop();
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
/** Returns the next scheduled run for a job, or null. Used by `cron list`. */
|
|
143
|
+
export function nextRunFor(job) {
|
|
144
|
+
try {
|
|
145
|
+
const cron = new Cron(job.schedule, job.tz ? { timezone: job.tz } : {});
|
|
146
|
+
const n = cron.nextRun();
|
|
147
|
+
cron.stop();
|
|
148
|
+
return n;
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
// ── internals ───────────────────────────────────────────────────────────────
|
|
155
|
+
function _freshId(existing) {
|
|
156
|
+
for (let i = 0; i < 1000; i++) {
|
|
157
|
+
const id = `j_${randomBytes(4).toString("hex")}`;
|
|
158
|
+
if (!existing.some((j) => j.id === id))
|
|
159
|
+
return id;
|
|
160
|
+
}
|
|
161
|
+
throw new Error("cron id space exhausted");
|
|
162
|
+
}
|
|
163
|
+
function _coerceJob(item) {
|
|
164
|
+
if (!item || typeof item !== "object")
|
|
165
|
+
return null;
|
|
166
|
+
const o = item;
|
|
167
|
+
if (typeof o["id"] !== "string")
|
|
168
|
+
return null;
|
|
169
|
+
if (typeof o["daemon_id"] !== "string")
|
|
170
|
+
return null;
|
|
171
|
+
if (typeof o["schedule"] !== "string")
|
|
172
|
+
return null;
|
|
173
|
+
if (typeof o["prompt"] !== "string")
|
|
174
|
+
return null;
|
|
175
|
+
const job = {
|
|
176
|
+
id: o["id"],
|
|
177
|
+
daemon_id: o["daemon_id"],
|
|
178
|
+
schedule: o["schedule"],
|
|
179
|
+
prompt: o["prompt"],
|
|
180
|
+
enabled: o["enabled"] !== false,
|
|
181
|
+
skip_if_busy: o["skip_if_busy"] !== false,
|
|
182
|
+
wake: o["wake"] === true,
|
|
183
|
+
catchup: o["catchup"] === true,
|
|
184
|
+
created_at: typeof o["created_at"] === "string" ? o["created_at"] : new Date(0).toISOString(),
|
|
185
|
+
};
|
|
186
|
+
if (typeof o["tz"] === "string")
|
|
187
|
+
job.tz = o["tz"];
|
|
188
|
+
if (typeof o["last_run"] === "string")
|
|
189
|
+
job.last_run = o["last_run"];
|
|
190
|
+
if (typeof o["last_status"] === "string")
|
|
191
|
+
job.last_status = o["last_status"];
|
|
192
|
+
return job;
|
|
193
|
+
}
|
|
194
|
+
//# sourceMappingURL=cron_registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cron_registry.js","sourceRoot":"","sources":["../../src/daemon/cron_registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stable 8-character hex id for a daemon, derived from the cwd it manages.
|
|
3
|
+
*
|
|
4
|
+
* Derivation: `sha256(realpath(cwd))` truncated to 8 hex chars (32 bits ≈
|
|
5
|
+
* 4 billion). Collision risk is negligible at fleet sizes a single user
|
|
6
|
+
* will ever have (<1000 daemons), and 8 hex characters are short enough
|
|
7
|
+
* to type on the CLI (`/remote-pi send a1b2c3d4 "..."`).
|
|
8
|
+
*
|
|
9
|
+
* Same scheme as `roomIdForCwd` in `src/rooms.ts` — but we use hex
|
|
10
|
+
* instead of base64url so the id has no `_`/`-` (cleaner double-click
|
|
11
|
+
* selection in terminals).
|
|
12
|
+
*
|
|
13
|
+
* Symlinks resolve to a single canonical id via `realpath`, so
|
|
14
|
+
* `/Users/x/Movies` and `/Users/x/link-to-Movies` map to the same daemon.
|
|
15
|
+
* Falls back to the raw path when realpath fails (cwd doesn't exist —
|
|
16
|
+
* shouldn't happen in production but covers test sandboxes).
|
|
17
|
+
*
|
|
18
|
+
* plan/41 audit (2026-06-08): this stays **per-cwd** (no name axis). The
|
|
19
|
+
* multiagent-per-folder model (plan/38/41) applies to the App↔Pi room and the
|
|
20
|
+
* mesh address; a *supervisor daemon* is **one per cwd** by design — the
|
|
21
|
+
* registry keys exactly one entry per cwd (`registry.ts`), so a daemon id never
|
|
22
|
+
* needs the name to disambiguate. Decision: leave `daemonIdForCwd` cwd-only.
|
|
23
|
+
*/
|
|
24
|
+
export declare function daemonIdForCwd(cwd: string): string;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { realpathSync } from "node:fs";
|
|
3
|
+
/**
|
|
4
|
+
* Stable 8-character hex id for a daemon, derived from the cwd it manages.
|
|
5
|
+
*
|
|
6
|
+
* Derivation: `sha256(realpath(cwd))` truncated to 8 hex chars (32 bits ≈
|
|
7
|
+
* 4 billion). Collision risk is negligible at fleet sizes a single user
|
|
8
|
+
* will ever have (<1000 daemons), and 8 hex characters are short enough
|
|
9
|
+
* to type on the CLI (`/remote-pi send a1b2c3d4 "..."`).
|
|
10
|
+
*
|
|
11
|
+
* Same scheme as `roomIdForCwd` in `src/rooms.ts` — but we use hex
|
|
12
|
+
* instead of base64url so the id has no `_`/`-` (cleaner double-click
|
|
13
|
+
* selection in terminals).
|
|
14
|
+
*
|
|
15
|
+
* Symlinks resolve to a single canonical id via `realpath`, so
|
|
16
|
+
* `/Users/x/Movies` and `/Users/x/link-to-Movies` map to the same daemon.
|
|
17
|
+
* Falls back to the raw path when realpath fails (cwd doesn't exist —
|
|
18
|
+
* shouldn't happen in production but covers test sandboxes).
|
|
19
|
+
*
|
|
20
|
+
* plan/41 audit (2026-06-08): this stays **per-cwd** (no name axis). The
|
|
21
|
+
* multiagent-per-folder model (plan/38/41) applies to the App↔Pi room and the
|
|
22
|
+
* mesh address; a *supervisor daemon* is **one per cwd** by design — the
|
|
23
|
+
* registry keys exactly one entry per cwd (`registry.ts`), so a daemon id never
|
|
24
|
+
* needs the name to disambiguate. Decision: leave `daemonIdForCwd` cwd-only.
|
|
25
|
+
*/
|
|
26
|
+
export function daemonIdForCwd(cwd) {
|
|
27
|
+
let target;
|
|
28
|
+
try {
|
|
29
|
+
target = realpathSync(cwd);
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
target = cwd;
|
|
33
|
+
}
|
|
34
|
+
return createHash("sha256").update(target).digest("hex").slice(0, 8);
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=id.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"id.js","sourceRoot":"","sources":["../../src/daemon/id.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,UAAU,cAAc,CAAC,GAAW;IACxC,IAAI,MAAc,CAAC;IACnB,IAAI,CAAC;QACH,MAAM,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,GAAG,GAAG,CAAC;IACf,CAAC;IACD,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AACvE,CAAC"}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generates and activates a system service for `pi-supervisord` so the
|
|
3
|
+
* daemon fleet survives reboots (plan/26 W3).
|
|
4
|
+
*
|
|
5
|
+
* Platform support:
|
|
6
|
+
* - **macOS**: writes `~/Library/LaunchAgents/dev.remotepi.supervisord.plist`
|
|
7
|
+
* and runs `launchctl bootstrap gui/<uid> <plist>` (modern API) with a
|
|
8
|
+
* fallback to `launchctl load` for older macOS.
|
|
9
|
+
* - **Linux**: writes `~/.config/systemd/user/remote-pi-supervisord.service`
|
|
10
|
+
* and runs `systemctl --user daemon-reload && systemctl --user enable
|
|
11
|
+
* --now remote-pi-supervisord.service`.
|
|
12
|
+
*
|
|
13
|
+
* Uninstall reverses both. Idempotent — re-running install over an existing
|
|
14
|
+
* unit refreshes it (paths could have changed if user moved node_modules).
|
|
15
|
+
*
|
|
16
|
+
* **What does NOT happen here**: the actual `npm install -g remote-pi` step.
|
|
17
|
+
* The user has to make the supervisor bin reachable on disk before install
|
|
18
|
+
* can wire up the service. The `findSupervisorScript` resolver detects
|
|
19
|
+
* common cases (npm global, pnpm global, local dev clone) and yields a
|
|
20
|
+
* clear error otherwise.
|
|
21
|
+
*/
|
|
22
|
+
export type SupervisorPlatform = "macos" | "linux" | "windows" | "unsupported";
|
|
23
|
+
export declare function detectPlatform(): SupervisorPlatform;
|
|
24
|
+
/**
|
|
25
|
+
* Absolute path to the supervisor's compiled entry. We resolve from
|
|
26
|
+
* `import.meta.url` (this file's location) since wherever the daemon
|
|
27
|
+
* module lives, `bin/supervisord.js` is a sibling of `daemon/` under
|
|
28
|
+
* `dist/`.
|
|
29
|
+
*
|
|
30
|
+
* After build: `dist/daemon/install.js` → `dist/bin/supervisord.js`.
|
|
31
|
+
* In dev (`tsx`): same path resolution still lands inside `src/`, which
|
|
32
|
+
* isn't directly runnable by `node` — dev install isn't expected.
|
|
33
|
+
*/
|
|
34
|
+
export declare function findSupervisorScript(): string;
|
|
35
|
+
/**
|
|
36
|
+
* Absolute path to the extension's CLI entry (`dist/index.js`). This is
|
|
37
|
+
* the file we symlink to `~/.local/bin/remote-pi` so the user can run
|
|
38
|
+
* `remote-pi <subcommand>` from any shell after installing the extension
|
|
39
|
+
* through Pi (`pi install npm:remote-pi`).
|
|
40
|
+
*
|
|
41
|
+
* Same resolution strategy as `findSupervisorScript`: from
|
|
42
|
+
* `dist/daemon/install.js` → `dist/index.js`.
|
|
43
|
+
*/
|
|
44
|
+
export declare function findRemotePiScript(): string;
|
|
45
|
+
export declare function findNodeBinary(): string;
|
|
46
|
+
export declare function findTemplate(name: "systemd" | "launchd" | "taskscheduler" | "vbs-launcher"): string;
|
|
47
|
+
export declare function systemdUnitPath(): string;
|
|
48
|
+
export declare function launchdPlistPath(): string;
|
|
49
|
+
export declare const LAUNCHD_LABEL = "dev.remotepi.supervisord";
|
|
50
|
+
/** systemd --user unit name (with `.service`) for the supervisor. */
|
|
51
|
+
export declare const SYSTEMD_UNIT = "remote-pi-supervisord.service";
|
|
52
|
+
/** Windows Task Scheduler task name (plan/40). */
|
|
53
|
+
export declare const WINDOWS_TASK_NAME = "RemotePiSupervisor";
|
|
54
|
+
/** Path of the rendered Task Scheduler XML (input to `schtasks /Create /XML`). */
|
|
55
|
+
export declare function taskXmlPath(): string;
|
|
56
|
+
/**
|
|
57
|
+
* Path of the rendered VBScript launcher the Task Scheduler action invokes
|
|
58
|
+
* via `wscript.exe` (plan/40, Windows). Launching node through this hidden
|
|
59
|
+
* wrapper is what keeps the supervisor from flashing a console window.
|
|
60
|
+
*/
|
|
61
|
+
export declare function vbsLauncherPath(): string;
|
|
62
|
+
/**
|
|
63
|
+
* Combined stdout/stderr log for the Windows supervisor. The Task Scheduler
|
|
64
|
+
* launches it hidden via wscript, so without this redirect its output (and the
|
|
65
|
+
* forwarded daemon-child stderr) would vanish — mirrors launchd/systemd, which
|
|
66
|
+
* already log to `~/.pi/remote/supervisord.log`.
|
|
67
|
+
*/
|
|
68
|
+
export declare function supervisordLogPath(): string;
|
|
69
|
+
export interface RenderVars {
|
|
70
|
+
node: string;
|
|
71
|
+
supervisor: string;
|
|
72
|
+
home: string;
|
|
73
|
+
user: string;
|
|
74
|
+
/** PATH inherited so `pi --mode rpc` resolves the same way it does
|
|
75
|
+
* interactively. We snapshot `process.env.PATH` at install time. */
|
|
76
|
+
path: string;
|
|
77
|
+
/** Windows only: absolute path of the VBScript launcher the Task Scheduler
|
|
78
|
+
* action runs via `wscript.exe`. Empty on POSIX (templates ignore `{VBS}`). */
|
|
79
|
+
vbs: string;
|
|
80
|
+
/** Windows only: combined stdout/stderr log the hidden supervisor appends to.
|
|
81
|
+
* Empty on POSIX (templates ignore `{LOG}`). */
|
|
82
|
+
logPath: string;
|
|
83
|
+
}
|
|
84
|
+
export declare function defaultRenderVars(): RenderVars;
|
|
85
|
+
/** Replace `{NODE}` / `{SUPERVISOR}` / `{USER}` / `{HOME}` / `{PATH}` / `{VBS}` / `{LOG}`. */
|
|
86
|
+
export declare function renderTemplate(template: string, vars: RenderVars): string;
|
|
87
|
+
export interface InstallResult {
|
|
88
|
+
platform: SupervisorPlatform;
|
|
89
|
+
unitPath: string;
|
|
90
|
+
/** Lines describing each step taken — surfaced to the user via notify. */
|
|
91
|
+
log: string[];
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Writes the unit/plist, runs the platform's activation command. Throws
|
|
95
|
+
* on unsupported OS or when the supervisor script isn't found.
|
|
96
|
+
*
|
|
97
|
+
* Idempotent: re-running re-writes the unit (paths could have changed)
|
|
98
|
+
* and re-activates via the platform tool's idempotent flag.
|
|
99
|
+
*/
|
|
100
|
+
export declare function installService(vars?: RenderVars): InstallResult;
|
|
101
|
+
export interface UninstallResult {
|
|
102
|
+
platform: SupervisorPlatform;
|
|
103
|
+
unitPath: string;
|
|
104
|
+
removed: boolean;
|
|
105
|
+
log: string[];
|
|
106
|
+
}
|
|
107
|
+
export declare function uninstallService(): UninstallResult;
|
|
108
|
+
/**
|
|
109
|
+
* Build the batch script run elevated. Each command line redirects its output
|
|
110
|
+
* to `logFile` so the (separate, elevated) process's output can be read back by
|
|
111
|
+
* the parent. Control-flow lines (`if`/`exit`/`rem`/`@`) run bare — redirecting
|
|
112
|
+
* them would swallow the exit code. Pure + exported for tests.
|
|
113
|
+
*/
|
|
114
|
+
export declare function buildElevatedCmd(lines: string[], logFile: string): string;
|
|
115
|
+
export interface LinkBinariesResult {
|
|
116
|
+
/** `~/.local/bin/`. The two symlinks land here. */
|
|
117
|
+
binDir: string;
|
|
118
|
+
/** Paths of the two symlinks we created/refreshed. */
|
|
119
|
+
links: Array<{
|
|
120
|
+
name: string;
|
|
121
|
+
path: string;
|
|
122
|
+
target: string;
|
|
123
|
+
}>;
|
|
124
|
+
/** True when `binDir` is already on `$PATH`. False → caller surfaces the
|
|
125
|
+
* "add this line to your shell rc" hint to the user. */
|
|
126
|
+
onPath: boolean;
|
|
127
|
+
log: string[];
|
|
128
|
+
}
|
|
129
|
+
export declare function userLocalBinDir(home?: string): string;
|
|
130
|
+
/**
|
|
131
|
+
* Check whether `dir` is on `process.env.PATH`. Tolerates trailing
|
|
132
|
+
* slashes and relative entries (which we treat as not matching — `~/.local/bin`
|
|
133
|
+
* is always absolute on our end).
|
|
134
|
+
*/
|
|
135
|
+
export declare function isOnPath(dir: string, envPath?: string): boolean;
|
|
136
|
+
/**
|
|
137
|
+
* Create (or refresh) the `remote-pi` + `pi-supervisord` symlinks in
|
|
138
|
+
* `~/.local/bin/`. Idempotent — replaces stale links pointing at old
|
|
139
|
+
* extension paths (Pi can reinstall the extension to a different hash dir
|
|
140
|
+
* on upgrades, so this MUST overwrite).
|
|
141
|
+
*
|
|
142
|
+
* Returns `onPath: false` when `~/.local/bin` isn't in the user's `$PATH`.
|
|
143
|
+
* The caller is responsible for surfacing the shell-rc instruction —
|
|
144
|
+
* we don't edit the user's shell config files automatically.
|
|
145
|
+
*/
|
|
146
|
+
export declare function linkCliBinaries(home?: string, paths?: {
|
|
147
|
+
remotePi?: string;
|
|
148
|
+
supervisord?: string;
|
|
149
|
+
}, opts?: {
|
|
150
|
+
node?: string;
|
|
151
|
+
mutatePath?: boolean;
|
|
152
|
+
}): LinkBinariesResult;
|
|
153
|
+
/** A Windows `.cmd` shim that forwards all args to `node "<target>"`. Pure. */
|
|
154
|
+
export declare function buildCmdShim(node: string, target: string): string;
|
|
155
|
+
/**
|
|
156
|
+
* Remove the symlinks `linkCliBinaries` created. Idempotent — missing
|
|
157
|
+
* links are a no-op. Returns whether each link was actually present so
|
|
158
|
+
* the caller can render a useful summary. Targets (the extension files)
|
|
159
|
+
* are NOT touched here — they live outside this dir and belong to Pi.
|
|
160
|
+
*/
|
|
161
|
+
export interface UnlinkBinariesResult {
|
|
162
|
+
binDir: string;
|
|
163
|
+
removed: Array<{
|
|
164
|
+
name: string;
|
|
165
|
+
path: string;
|
|
166
|
+
existed: boolean;
|
|
167
|
+
}>;
|
|
168
|
+
log: string[];
|
|
169
|
+
}
|
|
170
|
+
export declare function unlinkCliBinaries(home?: string): UnlinkBinariesResult;
|