pi-harness-runtime 0.9.15 → 0.9.16

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.
Files changed (101) hide show
  1. package/package.json +1 -1
  2. package/packages/autonomous-runtime/README.md +48 -0
  3. package/packages/autonomous-runtime/dist/inbox.d.ts +75 -0
  4. package/packages/autonomous-runtime/dist/inbox.d.ts.map +1 -0
  5. package/packages/autonomous-runtime/dist/inbox.js +212 -0
  6. package/packages/autonomous-runtime/dist/inbox.js.map +1 -0
  7. package/packages/autonomous-runtime/dist/index.d.ts +17 -0
  8. package/packages/autonomous-runtime/dist/index.d.ts.map +1 -0
  9. package/packages/autonomous-runtime/dist/index.js +17 -0
  10. package/packages/autonomous-runtime/dist/index.js.map +1 -0
  11. package/packages/autonomous-runtime/dist/lease.d.ts +78 -0
  12. package/packages/autonomous-runtime/dist/lease.d.ts.map +1 -0
  13. package/packages/autonomous-runtime/dist/lease.js +273 -0
  14. package/packages/autonomous-runtime/dist/lease.js.map +1 -0
  15. package/packages/autonomous-runtime/dist/types.d.ts +160 -0
  16. package/packages/autonomous-runtime/dist/types.d.ts.map +1 -0
  17. package/packages/autonomous-runtime/dist/types.js +31 -0
  18. package/packages/autonomous-runtime/dist/types.js.map +1 -0
  19. package/packages/autonomous-runtime/dist/worker.d.ts +63 -0
  20. package/packages/autonomous-runtime/dist/worker.d.ts.map +1 -0
  21. package/packages/autonomous-runtime/dist/worker.js +133 -0
  22. package/packages/autonomous-runtime/dist/worker.js.map +1 -0
  23. package/packages/autonomous-runtime/package.json +34 -0
  24. package/packages/autonomous-runtime/src/inbox.ts +266 -0
  25. package/packages/autonomous-runtime/src/index.ts +22 -0
  26. package/packages/autonomous-runtime/src/lease.ts +318 -0
  27. package/packages/autonomous-runtime/src/types.ts +257 -0
  28. package/packages/autonomous-runtime/test/autonomous-runtime.test.ts +194 -0
  29. package/packages/autonomous-runtime/test/inbox.test.mjs +266 -0
  30. package/packages/autonomous-runtime/test/inbox.test.ts +80 -0
  31. package/packages/autonomous-runtime/test/types.test.ts +68 -0
  32. package/packages/autonomous-runtime/tsconfig.json +22 -0
  33. package/packages/autonomous-runtime/tsconfig.tsbuildinfo +1 -0
  34. package/packages/privilege-broker/README.md +45 -0
  35. package/packages/privilege-broker/config/privileges.yaml.example +172 -0
  36. package/packages/privilege-broker/dist/approval.d.ts +23 -0
  37. package/packages/privilege-broker/dist/approval.d.ts.map +1 -0
  38. package/packages/privilege-broker/dist/approval.js +45 -0
  39. package/packages/privilege-broker/dist/approval.js.map +1 -0
  40. package/packages/privilege-broker/dist/audit.d.ts +38 -0
  41. package/packages/privilege-broker/dist/audit.d.ts.map +1 -0
  42. package/packages/privilege-broker/dist/audit.js +125 -0
  43. package/packages/privilege-broker/dist/audit.js.map +1 -0
  44. package/packages/privilege-broker/dist/executor.d.ts +25 -0
  45. package/packages/privilege-broker/dist/executor.d.ts.map +1 -0
  46. package/packages/privilege-broker/dist/executor.js +83 -0
  47. package/packages/privilege-broker/dist/executor.js.map +1 -0
  48. package/packages/privilege-broker/dist/index.d.ts +30 -0
  49. package/packages/privilege-broker/dist/index.d.ts.map +1 -0
  50. package/packages/privilege-broker/dist/index.js +5 -0
  51. package/packages/privilege-broker/dist/index.js.map +1 -0
  52. package/packages/privilege-broker/dist/registry.d.ts +15 -0
  53. package/packages/privilege-broker/dist/registry.d.ts.map +1 -0
  54. package/packages/privilege-broker/dist/registry.js +76 -0
  55. package/packages/privilege-broker/dist/registry.js.map +1 -0
  56. package/packages/privilege-broker/dist/types.d.ts +77 -0
  57. package/packages/privilege-broker/dist/types.d.ts.map +1 -0
  58. package/packages/privilege-broker/dist/types.js +11 -0
  59. package/packages/privilege-broker/dist/types.js.map +1 -0
  60. package/packages/privilege-broker/package.json +35 -0
  61. package/packages/privilege-broker/src/approval.ts +70 -0
  62. package/packages/privilege-broker/src/audit.ts +142 -0
  63. package/packages/privilege-broker/src/executor.ts +110 -0
  64. package/packages/privilege-broker/src/index.ts +46 -0
  65. package/packages/privilege-broker/src/registry.ts +98 -0
  66. package/packages/privilege-broker/src/types.ts +105 -0
  67. package/packages/privilege-broker/tsconfig.json +22 -0
  68. package/packages/privilege-broker/tsconfig.tsbuildinfo +1 -0
  69. package/packages/scheduler-adapter/README.md +36 -0
  70. package/packages/scheduler-adapter/dist/cron.d.ts +21 -0
  71. package/packages/scheduler-adapter/dist/cron.d.ts.map +1 -0
  72. package/packages/scheduler-adapter/dist/cron.js +116 -0
  73. package/packages/scheduler-adapter/dist/cron.js.map +1 -0
  74. package/packages/scheduler-adapter/dist/index.d.ts +9 -0
  75. package/packages/scheduler-adapter/dist/index.d.ts.map +1 -0
  76. package/packages/scheduler-adapter/dist/index.js +8 -0
  77. package/packages/scheduler-adapter/dist/index.js.map +1 -0
  78. package/packages/scheduler-adapter/dist/interface.d.ts +61 -0
  79. package/packages/scheduler-adapter/dist/interface.d.ts.map +1 -0
  80. package/packages/scheduler-adapter/dist/interface.js +2 -0
  81. package/packages/scheduler-adapter/dist/interface.js.map +1 -0
  82. package/packages/scheduler-adapter/dist/internal.d.ts +30 -0
  83. package/packages/scheduler-adapter/dist/internal.d.ts.map +1 -0
  84. package/packages/scheduler-adapter/dist/internal.js +82 -0
  85. package/packages/scheduler-adapter/dist/internal.js.map +1 -0
  86. package/packages/scheduler-adapter/dist/systemd.d.ts +31 -0
  87. package/packages/scheduler-adapter/dist/systemd.d.ts.map +1 -0
  88. package/packages/scheduler-adapter/dist/systemd.js +203 -0
  89. package/packages/scheduler-adapter/dist/systemd.js.map +1 -0
  90. package/packages/scheduler-adapter/package.json +32 -0
  91. package/packages/scheduler-adapter/src/cron.ts +123 -0
  92. package/packages/scheduler-adapter/src/index.ts +9 -0
  93. package/packages/scheduler-adapter/src/interface.ts +61 -0
  94. package/packages/scheduler-adapter/src/internal.ts +99 -0
  95. package/packages/scheduler-adapter/src/systemd.ts +221 -0
  96. package/packages/scheduler-adapter/tsconfig.json +22 -0
  97. package/packages/scheduler-adapter/tsconfig.tsbuildinfo +1 -0
  98. package/packages/types/dist/ai-providers.d.ts +0 -36
  99. package/packages/types/dist/ai-providers.d.ts.map +0 -1
  100. package/packages/types/dist/ai-providers.js +0 -66
  101. package/packages/types/dist/ai-providers.js.map +0 -1
@@ -0,0 +1,116 @@
1
+ /**
2
+ * Cron Scheduler Adapter — RFC-0101 §6
3
+ *
4
+ * Writes crontab entries for scheduled tasks.
5
+ * Entries are managed via a marker block so unschedule() is clean.
6
+ */
7
+ import { execSync } from "node:child_process";
8
+ import { writeFileSync, unlinkSync } from "node:fs";
9
+ import { tmpdir } from "node:os";
10
+ import { join } from "node:path";
11
+ export class CronAdapter {
12
+ name = "cron";
13
+ runtimeBin;
14
+ constructor(options = {}) {
15
+ this.runtimeBin = options.runtimeBin ?? "/usr/local/bin/pi-harness-runtime";
16
+ }
17
+ async install() {
18
+ // Idempotent — verify cron is available
19
+ try {
20
+ execSync("crontab -l >/dev/null 2>&1", { stdio: "pipe" });
21
+ }
22
+ catch {
23
+ // No existing crontab — that's fine
24
+ }
25
+ }
26
+ async schedule(task) {
27
+ const cronExpr = this._toCronExpr(task);
28
+ const marker = `# PI-HARNESS-RUNTIME: ${task.id}`;
29
+ const line = `${cronExpr} ${this.runtimeBin} run-scheduled --task-id ${task.id}`;
30
+ const existing = this._getCrontab();
31
+ // Remove any existing entry for this task
32
+ const cleaned = existing.filter((l) => !l.includes(`PI-HARNESS-RUNTIME: ${task.id}`));
33
+ const updated = [...cleaned, marker, line].join("\n") + "\n";
34
+ this._setCrontab(updated);
35
+ }
36
+ async unschedule(taskId) {
37
+ const existing = this._getCrontab();
38
+ const cleaned = existing.filter((l) => !l.includes(`PI-HARNESS-RUNTIME: ${taskId}`));
39
+ if (cleaned.length === 0) {
40
+ try {
41
+ execSync("crontab -r 2>/dev/null", { stdio: "pipe" });
42
+ }
43
+ catch {
44
+ // No crontab to remove — that's fine
45
+ }
46
+ }
47
+ else {
48
+ this._setCrontab(cleaned.join("\n") + "\n");
49
+ }
50
+ }
51
+ async listScheduled() {
52
+ const lines = this._getCrontab();
53
+ return lines
54
+ .filter((l) => l.includes("PI-HARNESS-RUNTIME: "))
55
+ .map((l) => {
56
+ const match = l.match(/PI-HARNESS-RUNTIME: ([\w-]+)/);
57
+ return {
58
+ id: match?.[1] ?? "unknown",
59
+ taskTemplate: {},
60
+ schedule: { kind: "cron", expression: "" },
61
+ enabled: true,
62
+ };
63
+ });
64
+ }
65
+ async healthCheck() {
66
+ try {
67
+ execSync("crontab -l >/dev/null 2>&1", { stdio: "pipe" });
68
+ return { healthy: true };
69
+ }
70
+ catch {
71
+ return { healthy: false, error: "crontab not accessible" };
72
+ }
73
+ }
74
+ _getCrontab() {
75
+ try {
76
+ const out = execSync("crontab -l 2>/dev/null", { encoding: "utf8" });
77
+ return out.split("\n").filter((l) => l.trim());
78
+ }
79
+ catch {
80
+ return [];
81
+ }
82
+ }
83
+ _setCrontab(content) {
84
+ const tmpFile = join(tmpdir(), `pi-harness-cron-${Date.now()}.tmp`);
85
+ try {
86
+ writeFileSync(tmpFile, content);
87
+ execSync(`crontab "${tmpFile}"`, { stdio: "pipe" });
88
+ }
89
+ finally {
90
+ try {
91
+ unlinkSync(tmpFile);
92
+ }
93
+ catch {
94
+ /* ignore */
95
+ }
96
+ }
97
+ }
98
+ _toCronExpr(task) {
99
+ if (task.schedule.kind === "cron")
100
+ return task.schedule.expression;
101
+ if (task.schedule.kind === "interval") {
102
+ const ms = task.schedule.intervalMs;
103
+ const minutes = Math.round(ms / 60_000);
104
+ if (minutes < 60)
105
+ return `*/${minutes} * * * *`;
106
+ const hours = Math.round(ms / 3_600_000);
107
+ return `${minutes % 60} */${hours} * * *`;
108
+ }
109
+ if (task.schedule.kind === "once") {
110
+ const d = new Date(task.schedule.at);
111
+ return `${d.getUTCMinutes()} ${d.getUTCHours()} ${d.getUTCDate()} ${d.getUTCMonth() + 1} *`;
112
+ }
113
+ return "* * * * *";
114
+ }
115
+ }
116
+ //# sourceMappingURL=cron.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cron.js","sourceRoot":"","sources":["../src/cron.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Scheduler Adapter Package — Barrel
3
+ * RFC-0101 §6
4
+ */
5
+ export type { SchedulerAdapter, ScheduledTask } from "./interface.js";
6
+ export { CronAdapter } from "./cron.js";
7
+ export { SystemdAdapter } from "./systemd.js";
8
+ export { InternalAdapter } from "./internal.js";
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,YAAY,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACtE,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Scheduler Adapter Package — Barrel
3
+ * RFC-0101 §6
4
+ */
5
+ export { CronAdapter } from "./cron.js";
6
+ export { SystemdAdapter } from "./systemd.js";
7
+ export { InternalAdapter } from "./internal.js";
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Scheduler Adapter — Common Interface
3
+ * RFC-0101 §6
4
+ *
5
+ * All scheduler adapters implement this interface.
6
+ * The runtime selects an adapter at install time and uses it for all scheduled tasks.
7
+ */
8
+ export type ScheduledTask = {
9
+ id: string;
10
+ taskTemplate: Record<string, unknown>;
11
+ schedule: {
12
+ kind: "cron";
13
+ expression: string;
14
+ } | {
15
+ kind: "interval";
16
+ intervalMs: number;
17
+ } | {
18
+ kind: "once";
19
+ at: string;
20
+ };
21
+ enabled: boolean;
22
+ lastFiredAt?: string;
23
+ nextFireAt?: string;
24
+ };
25
+ /**
26
+ * Supported scheduler adapter backends.
27
+ * Set at install time; can be changed via config.
28
+ */
29
+ export type SchedulerAdapterKind = "systemd" | "cron" | "launchd" | "internal";
30
+ export interface SchedulerAdapter {
31
+ /** Human-readable name. */
32
+ readonly name: SchedulerAdapterKind;
33
+ /**
34
+ * Install the scheduler adapter.
35
+ * Idempotent — re-running does not duplicate units.
36
+ * @throws if installation fails (e.g. no systemd on this system)
37
+ */
38
+ install(): Promise<void>;
39
+ /**
40
+ * Schedule a task. Installs the timer/unit if not yet installed.
41
+ * @param task The scheduled task to materialise
42
+ */
43
+ schedule(task: ScheduledTask): Promise<void>;
44
+ /**
45
+ * Remove a scheduled task.
46
+ * @param taskId The id of the task to unschedule
47
+ */
48
+ unschedule(taskId: string): Promise<void>;
49
+ /**
50
+ * List all scheduled tasks currently installed by this adapter.
51
+ */
52
+ listScheduled(): Promise<ScheduledTask[]>;
53
+ /**
54
+ * Check if the adapter is healthy (e.g. systemd is running).
55
+ */
56
+ healthCheck(): Promise<{
57
+ healthy: boolean;
58
+ error?: string;
59
+ }>;
60
+ }
61
+ //# sourceMappingURL=interface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../src/interface.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,MAAM,MAAM,aAAa,GAAG;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC,QAAQ,EACL;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,GACpC;QAAE,IAAI,EAAE,UAAU,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,GACxC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,oBAAoB,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,GAAG,UAAU,CAAC;AAE/E,MAAM,WAAW,gBAAgB;IAChC,2BAA2B;IAC3B,QAAQ,CAAC,IAAI,EAAE,oBAAoB,CAAC;IAEpC;;;;OAIG;IACH,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEzB;;;OAGG;IACH,QAAQ,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE7C;;;OAGG;IACH,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE1C;;OAEG;IACH,aAAa,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC,CAAC;IAE1C;;OAEG;IACH,WAAW,IAAI,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC7D"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=interface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interface.js","sourceRoot":"","sources":["../src/interface.ts"],"names":[],"mappings":""}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Scheduler Adapter — Internal (In-Process) Backend
3
+ * RFC-0101 §6
4
+ *
5
+ * Uses in-process setTimeout / setInterval for scheduling.
6
+ * Useful for testing, local development, and environments where
7
+ * systemd/cron are not available.
8
+ */
9
+ import type { SchedulerAdapter, ScheduledTask } from "./interface.js";
10
+ export declare class InternalAdapter implements SchedulerAdapter {
11
+ readonly name: "internal";
12
+ private tasks;
13
+ private handlers;
14
+ install(): Promise<void>;
15
+ healthCheck(): Promise<{
16
+ healthy: boolean;
17
+ error?: string;
18
+ }>;
19
+ /**
20
+ * Register a task handler before scheduling.
21
+ * The adapter calls `handler(task)` when the task fires.
22
+ */
23
+ setHandler(handler: (task: ScheduledTask) => unknown): void;
24
+ schedule(task: ScheduledTask): Promise<void>;
25
+ unschedule(taskId: string): Promise<void>;
26
+ listScheduled(): Promise<ScheduledTask[]>;
27
+ /** Fire a task immediately (useful for testing). */
28
+ fireNow(taskId: string): void;
29
+ }
30
+ //# sourceMappingURL=internal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"internal.d.ts","sourceRoot":"","sources":["../src/internal.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAQtE,qBAAa,eAAgB,YAAW,gBAAgB;IACvD,QAAQ,CAAC,IAAI,EAAG,UAAU,CAAU;IAEpC,OAAO,CAAC,KAAK,CAAmC;IAChD,OAAO,CAAC,QAAQ,CAAuD;IAEjE,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAE7B;IAEK,WAAW,IAAI,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAEjE;IAED;;;OAGG;IACH,UAAU,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,OAAO,GAAG,IAAI,CAE1D;IAEK,QAAQ,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAsCjD;IAEK,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAM9C;IAEK,aAAa,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC,CAE9C;IAED,oDAAoD;IACpD,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAK5B;CACD"}
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Scheduler Adapter — Internal (In-Process) Backend
3
+ * RFC-0101 §6
4
+ *
5
+ * Uses in-process setTimeout / setInterval for scheduling.
6
+ * Useful for testing, local development, and environments where
7
+ * systemd/cron are not available.
8
+ */
9
+ export class InternalAdapter {
10
+ name = "internal";
11
+ tasks = new Map();
12
+ handlers = new Map();
13
+ async install() {
14
+ // Nothing to install for in-process scheduling
15
+ }
16
+ async healthCheck() {
17
+ return { healthy: true };
18
+ }
19
+ /**
20
+ * Register a task handler before scheduling.
21
+ * The adapter calls `handler(task)` when the task fires.
22
+ */
23
+ setHandler(handler) {
24
+ this.handlers.set("default", handler);
25
+ }
26
+ async schedule(task) {
27
+ if (this.tasks.has(task.id)) {
28
+ await this.unschedule(task.id);
29
+ }
30
+ const handler = this.handlers.get("default");
31
+ if (!handler) {
32
+ throw new Error("[InternalAdapter] No task handler registered. Call setHandler() first.");
33
+ }
34
+ if (!task.enabled)
35
+ return; // skip disabled tasks
36
+ let delayMs;
37
+ if (task.schedule.kind === "once") {
38
+ delayMs = new Date(task.schedule.at).getTime() - Date.now();
39
+ }
40
+ else if (task.schedule.kind === "interval") {
41
+ delayMs = task.schedule.intervalMs;
42
+ }
43
+ else {
44
+ // cron — resolve to next occurrence (simplified: 1h from now)
45
+ delayMs = 3_600_000;
46
+ }
47
+ if (delayMs <= 0)
48
+ delayMs = 1000;
49
+ const tick = () => {
50
+ const t = this.tasks.get(task.id);
51
+ if (!t)
52
+ return;
53
+ handler(task);
54
+ // Re-schedule if interval
55
+ if (task.schedule.kind === "interval") {
56
+ t.timerId = setTimeout(tick, task.schedule.intervalMs);
57
+ }
58
+ };
59
+ const timerId = setTimeout(tick, delayMs);
60
+ this.tasks.set(task.id, { task, timerId, createdAt: new Date() });
61
+ }
62
+ async unschedule(taskId) {
63
+ const t = this.tasks.get(taskId);
64
+ if (t) {
65
+ clearTimeout(t.timerId);
66
+ this.tasks.delete(taskId);
67
+ }
68
+ }
69
+ async listScheduled() {
70
+ return Array.from(this.tasks.values()).map((t) => t.task);
71
+ }
72
+ /** Fire a task immediately (useful for testing). */
73
+ fireNow(taskId) {
74
+ const t = this.tasks.get(taskId);
75
+ if (!t)
76
+ return;
77
+ const handler = this.handlers.get("default");
78
+ if (handler)
79
+ handler(t.task);
80
+ }
81
+ }
82
+ //# sourceMappingURL=internal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"internal.js","sourceRoot":"","sources":["../src/internal.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Scheduler Adapter — systemd Backend
3
+ * RFC-0101 §6
4
+ *
5
+ * Uses systemd user timers as the scheduling backend.
6
+ * Each scheduled task becomes a .timer + .service unit pair.
7
+ * Works on any Linux system with systemd (no root required for user units).
8
+ */
9
+ import type { SchedulerAdapter, ScheduledTask } from "./interface.js";
10
+ /**
11
+ * Install systemd user units (runs `systemctl --user`).
12
+ * Must call this once before scheduling.
13
+ */
14
+ export declare class SystemdAdapter implements SchedulerAdapter {
15
+ readonly name: "systemd";
16
+ /** Per-task unit files live in ~/.config/systemd/user/ */
17
+ private readonly unitDir;
18
+ private installed;
19
+ constructor(unitDir?: string);
20
+ install(): Promise<void>;
21
+ schedule(task: ScheduledTask): Promise<void>;
22
+ unschedule(taskId: string): Promise<void>;
23
+ listScheduled(): Promise<ScheduledTask[]>;
24
+ /** Convert a schedule to a systemd.timer OnCalendar or OnUnitActiveSec line. */
25
+ private _toTimerLine;
26
+ healthCheck(): Promise<{
27
+ healthy: boolean;
28
+ error?: string;
29
+ }>;
30
+ }
31
+ //# sourceMappingURL=systemd.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"systemd.d.ts","sourceRoot":"","sources":["../src/systemd.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAItE;;;GAGG;AACH,qBAAa,cAAe,YAAW,gBAAgB;IACtD,QAAQ,CAAC,IAAI,EAAG,SAAS,CAAU;IACnC,0DAA0D;IAC1D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,SAAS,CAAS;IAE1B,YAAY,OAAO,CAAC,EAAE,MAAM,EAE3B;IAEK,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CA0B7B;IAEK,QAAQ,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CA8DjD;IAEK,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA6B9C;IAEK,aAAa,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC,CA8B9C;IAED,gFAAgF;IAChF,OAAO,CAAC,YAAY;IAuBd,WAAW,IAAI,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CASjE;CACD"}
@@ -0,0 +1,203 @@
1
+ /**
2
+ * Scheduler Adapter — systemd Backend
3
+ * RFC-0101 §6
4
+ *
5
+ * Uses systemd user timers as the scheduling backend.
6
+ * Each scheduled task becomes a .timer + .service unit pair.
7
+ * Works on any Linux system with systemd (no root required for user units).
8
+ */
9
+ import { execSync } from "node:child_process";
10
+ import { existsSync, mkdirSync, writeFileSync, unlinkSync } from "node:fs";
11
+ import { join } from "node:path";
12
+ import { homedir } from "node:os";
13
+ // ScheduledTask duplicated here — see interface.ts for details.
14
+ /**
15
+ * Install systemd user units (runs `systemctl --user`).
16
+ * Must call this once before scheduling.
17
+ */
18
+ export class SystemdAdapter {
19
+ name = "systemd";
20
+ /** Per-task unit files live in ~/.config/systemd/user/ */
21
+ unitDir;
22
+ installed = false;
23
+ constructor(unitDir) {
24
+ this.unitDir = unitDir ?? join(homedir(), ".config", "systemd", "user");
25
+ }
26
+ async install() {
27
+ // Verify systemd user mode is available
28
+ try {
29
+ execSync("systemctl --user show-environment >/dev/null 2>&1", {
30
+ stdio: "pipe",
31
+ });
32
+ }
33
+ catch {
34
+ throw new Error("[SystemdAdapter] systemd user mode is not available. " +
35
+ "Ensure systemd is running and $SYSTEMD_RUNTIME_DIRECTORY is set.");
36
+ }
37
+ // Ensure unit directory exists
38
+ if (!existsSync(this.unitDir)) {
39
+ mkdirSync(this.unitDir, { recursive: true });
40
+ }
41
+ // Reload systemd to pick up new units
42
+ try {
43
+ execSync("systemctl --user daemon-reload", { stdio: "pipe" });
44
+ }
45
+ catch {
46
+ throw new Error("[SystemdAdapter] Failed to reload systemd daemon");
47
+ }
48
+ this.installed = true;
49
+ }
50
+ async schedule(task) {
51
+ if (!this.installed)
52
+ await this.install();
53
+ const id = task.id.replace(/[^a-zA-Z0-9_-]/g, "-");
54
+ const base = `pi-runtime-${id}`;
55
+ const servicePath = join(this.unitDir, `${base}.service`);
56
+ const timerPath = join(this.unitDir, `${base}.timer`);
57
+ const scriptPath = join(this.unitDir, `${base}.sh`);
58
+ // Build the run script
59
+ const runScript = [
60
+ "#!/usr/bin/env bash",
61
+ `# Generated by pi-harness-runtime — ${new Date().toISOString()}`,
62
+ "",
63
+ `PI_HARNESS_TASK_ID="${task.id}" \\`,
64
+ `PI_HARNESS_WORKER_ID="$(hostname)-$(id -u)" \\`,
65
+ `PI_HARNESS_RUNTIME_ROOT="${process.env.PI_HARNESS_RUNTIME_ROOT ?? join(homedir(), ".pi", "harness")}" \\`,
66
+ `exec "${process.env.PI_HARNESS_RUNTIME_ROOT}/bin/run-task.sh" \\`,
67
+ ` --task-id "${task.id}" \\`,
68
+ ` --worker-id "$PI_HARNESS_WORKER_ID"`,
69
+ ].join("\n");
70
+ // Write script
71
+ writeFileSync(scriptPath, runScript, { mode: 0o755 });
72
+ // Service unit: runs the script
73
+ const service = [
74
+ "[Unit]",
75
+ "Description=pi-harness-runtime task: ${task.id}",
76
+ "[Service]",
77
+ `ExecStart=${scriptPath}`,
78
+ "Type=oneshot",
79
+ "Environment=SYSTEMD_EXEC_PID=$$",
80
+ "[Install]",
81
+ "WantedBy=default.target",
82
+ ].join("\n");
83
+ // Timer unit: schedules the service
84
+ const timerContent = [
85
+ "[Unit]",
86
+ `Description=pi-harness-runtime schedule: ${task.id}`,
87
+ "[Timer]",
88
+ this._toTimerLine(task.schedule),
89
+ "Persistent=true",
90
+ "[Install]",
91
+ "WantedBy=timers.target",
92
+ ].join("\n");
93
+ writeFileSync(servicePath, service);
94
+ writeFileSync(timerPath, timerContent);
95
+ // Reload and enable
96
+ try {
97
+ execSync("systemctl --user daemon-reload", { stdio: "pipe" });
98
+ execSync(`systemctl --user enable ${base}.timer`, { stdio: "pipe" });
99
+ execSync(`systemctl --user start ${base}.timer`, { stdio: "pipe" });
100
+ }
101
+ catch (e) {
102
+ const err = e;
103
+ throw new Error(`[SystemdAdapter] Failed to enable/start ${base}.timer: ${err?.message ?? String(e)}`);
104
+ }
105
+ }
106
+ async unschedule(taskId) {
107
+ const id = taskId.replace(/[^a-zA-Z0-9_-]/g, "-");
108
+ const base = `pi-runtime-${id}`;
109
+ const servicePath = join(this.unitDir, `${base}.service`);
110
+ const timerPath = join(this.unitDir, `${base}.timer`);
111
+ const scriptPath = join(this.unitDir, `${base}.sh`);
112
+ // Stop and disable
113
+ try {
114
+ execSync(`systemctl --user stop ${base}.timer`, { stdio: "pipe" });
115
+ execSync(`systemctl --user disable ${base}.timer`, { stdio: "pipe" });
116
+ }
117
+ catch {
118
+ // Ignore if not running
119
+ }
120
+ // Remove files
121
+ for (const p of [servicePath, timerPath, scriptPath]) {
122
+ try {
123
+ if (existsSync(p))
124
+ unlinkSync(p);
125
+ }
126
+ catch {
127
+ // Ignore cleanup errors
128
+ }
129
+ }
130
+ try {
131
+ execSync("systemctl --user daemon-reload", { stdio: "pipe" });
132
+ }
133
+ catch {
134
+ // Ignore
135
+ }
136
+ }
137
+ async listScheduled() {
138
+ try {
139
+ const out = execSync("systemctl --user list-timers --all --no-legend --output json 2>/dev/null | grep pi-runtime- || true", { encoding: "utf8" });
140
+ if (!out.trim())
141
+ return [];
142
+ let timers = [];
143
+ try {
144
+ timers = JSON.parse(out.trim());
145
+ }
146
+ catch {
147
+ return [];
148
+ }
149
+ return timers
150
+ .filter((t) => t.Unit?.startsWith("pi-runtime-"))
151
+ .map((t) => {
152
+ const id = (t.Unit ?? "").replace(/^pi-runtime-(.+)\.timer$/, "$1");
153
+ return {
154
+ id,
155
+ taskTemplate: {},
156
+ schedule: { kind: "interval", intervalMs: 0 },
157
+ enabled: true,
158
+ };
159
+ });
160
+ }
161
+ catch {
162
+ return [];
163
+ }
164
+ }
165
+ /** Convert a schedule to a systemd.timer OnCalendar or OnUnitActiveSec line. */
166
+ _toTimerLine(schedule) {
167
+ if (schedule.kind === "cron") {
168
+ // Convert cron to systemd calendar format
169
+ const parts = schedule.expression.trim().split(/\s+/);
170
+ if (parts.length >= 5) {
171
+ const [min, hour, dom, month] = parts;
172
+ return `OnCalendar=${dom}.${month}.* ${hour}:${min.padStart(2, "0")}`;
173
+ }
174
+ return `OnCalendar=${schedule.expression}`;
175
+ }
176
+ if (schedule.kind === "interval") {
177
+ const sec = Math.round(schedule.intervalMs / 1000);
178
+ if (sec >= 86400)
179
+ return `OnUnitActiveSec=${Math.round(sec / 86400)}d`;
180
+ if (sec >= 3600)
181
+ return `OnUnitActiveSec=${Math.round(sec / 3600)}h`;
182
+ if (sec >= 60)
183
+ return `OnUnitActiveSec=${Math.round(sec / 60)}min`;
184
+ return `OnUnitActiveSec=${sec}s`;
185
+ }
186
+ if (schedule.kind === "once") {
187
+ return `OnCalendar=${new Date(schedule.at).toISOString().split("T").join(" ")}`;
188
+ }
189
+ return "OnUnitActiveSec=1h"; // fallback
190
+ }
191
+ async healthCheck() {
192
+ try {
193
+ execSync("systemctl --user show-environment >/dev/null 2>&1", {
194
+ stdio: "pipe",
195
+ });
196
+ return { healthy: true };
197
+ }
198
+ catch {
199
+ return { healthy: false, error: "systemd user mode not available" };
200
+ }
201
+ }
202
+ }
203
+ //# sourceMappingURL=systemd.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"systemd.js","sourceRoot":"","sources":["../src/systemd.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "@pi/scheduler-adapter",
3
+ "version": "0.9.15",
4
+ "description": "Scheduler Adapter — cron, systemd, launchd, internal adapters for autonomous runtime (RFC-0101 §6)",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.js",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.js",
11
+ "types": "./dist/index.js"
12
+ }
13
+ },
14
+ "scripts": {
15
+ "build": "tsc",
16
+ "test": "bun test",
17
+ "clean": "rm -rf dist"
18
+ },
19
+ "keywords": [
20
+ "scheduler",
21
+ "cron",
22
+ "systemd",
23
+ "launchd",
24
+ "rfc-0101"
25
+ ],
26
+ "author": "",
27
+ "license": "MIT",
28
+ "devDependencies": {
29
+ "@types/node": "^20.11.0",
30
+ "typescript": "^7.0.2"
31
+ }
32
+ }