@theford/runly 0.0.0-stage → 0.20.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.
Files changed (128) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +157 -2
  3. package/dist/cli/client.d.ts +80 -0
  4. package/dist/cli/client.js +294 -0
  5. package/dist/cli/client.js.map +1 -0
  6. package/dist/cli/daemon-unit.d.ts +58 -0
  7. package/dist/cli/daemon-unit.js +289 -0
  8. package/dist/cli/daemon-unit.js.map +1 -0
  9. package/dist/cli/index.d.ts +2 -0
  10. package/dist/cli/index.js +1482 -0
  11. package/dist/cli/index.js.map +1 -0
  12. package/dist/cli/install.d.ts +9 -0
  13. package/dist/cli/install.js +53 -0
  14. package/dist/cli/install.js.map +1 -0
  15. package/dist/cli/logs.d.ts +43 -0
  16. package/dist/cli/logs.js +232 -0
  17. package/dist/cli/logs.js.map +1 -0
  18. package/dist/cli/tether.d.ts +3 -0
  19. package/dist/cli/tether.js +65 -0
  20. package/dist/cli/tether.js.map +1 -0
  21. package/dist/cli/watchdog.d.ts +1 -0
  22. package/dist/cli/watchdog.js +81 -0
  23. package/dist/cli/watchdog.js.map +1 -0
  24. package/dist/core/builds.d.ts +20 -0
  25. package/dist/core/builds.js +93 -0
  26. package/dist/core/builds.js.map +1 -0
  27. package/dist/core/caller-env.d.ts +17 -0
  28. package/dist/core/caller-env.js +77 -0
  29. package/dist/core/caller-env.js.map +1 -0
  30. package/dist/core/diagnostics.d.ts +68 -0
  31. package/dist/core/diagnostics.js +34 -0
  32. package/dist/core/diagnostics.js.map +1 -0
  33. package/dist/core/env-vars.d.ts +35 -0
  34. package/dist/core/env-vars.js +32 -0
  35. package/dist/core/env-vars.js.map +1 -0
  36. package/dist/core/events.d.ts +10 -0
  37. package/dist/core/events.js +42 -0
  38. package/dist/core/events.js.map +1 -0
  39. package/dist/core/exec.d.ts +22 -0
  40. package/dist/core/exec.js +84 -0
  41. package/dist/core/exec.js.map +1 -0
  42. package/dist/core/journal.d.ts +227 -0
  43. package/dist/core/journal.js +395 -0
  44. package/dist/core/journal.js.map +1 -0
  45. package/dist/core/logs.d.ts +56 -0
  46. package/dist/core/logs.js +259 -0
  47. package/dist/core/logs.js.map +1 -0
  48. package/dist/core/manifest.d.ts +292 -0
  49. package/dist/core/manifest.js +179 -0
  50. package/dist/core/manifest.js.map +1 -0
  51. package/dist/core/namespaces.d.ts +7 -0
  52. package/dist/core/namespaces.js +59 -0
  53. package/dist/core/namespaces.js.map +1 -0
  54. package/dist/core/paths.d.ts +31 -0
  55. package/dist/core/paths.js +65 -0
  56. package/dist/core/paths.js.map +1 -0
  57. package/dist/core/policy.d.ts +94 -0
  58. package/dist/core/policy.js +122 -0
  59. package/dist/core/policy.js.map +1 -0
  60. package/dist/core/ports.d.ts +52 -0
  61. package/dist/core/ports.js +94 -0
  62. package/dist/core/ports.js.map +1 -0
  63. package/dist/core/presets.d.ts +25 -0
  64. package/dist/core/presets.js +86 -0
  65. package/dist/core/presets.js.map +1 -0
  66. package/dist/core/procscan.d.ts +111 -0
  67. package/dist/core/procscan.js +342 -0
  68. package/dist/core/procscan.js.map +1 -0
  69. package/dist/core/retention.d.ts +97 -0
  70. package/dist/core/retention.js +322 -0
  71. package/dist/core/retention.js.map +1 -0
  72. package/dist/core/sleep.d.ts +51 -0
  73. package/dist/core/sleep.js +99 -0
  74. package/dist/core/sleep.js.map +1 -0
  75. package/dist/core/tree-ledger.d.ts +39 -0
  76. package/dist/core/tree-ledger.js +92 -0
  77. package/dist/core/tree-ledger.js.map +1 -0
  78. package/dist/core/types.d.ts +21 -0
  79. package/dist/core/types.js +6 -0
  80. package/dist/core/types.js.map +1 -0
  81. package/dist/core/units.d.ts +20 -0
  82. package/dist/core/units.js +69 -0
  83. package/dist/core/units.js.map +1 -0
  84. package/dist/core/upkeep.d.ts +90 -0
  85. package/dist/core/upkeep.js +176 -0
  86. package/dist/core/upkeep.js.map +1 -0
  87. package/dist/core/util.d.ts +46 -0
  88. package/dist/core/util.js +168 -0
  89. package/dist/core/util.js.map +1 -0
  90. package/dist/core/version.d.ts +39 -0
  91. package/dist/core/version.js +144 -0
  92. package/dist/core/version.js.map +1 -0
  93. package/dist/core/worktree.d.ts +51 -0
  94. package/dist/core/worktree.js +309 -0
  95. package/dist/core/worktree.js.map +1 -0
  96. package/dist/daemon/budget.d.ts +155 -0
  97. package/dist/daemon/budget.js +288 -0
  98. package/dist/daemon/budget.js.map +1 -0
  99. package/dist/daemon/election.d.ts +9 -0
  100. package/dist/daemon/election.js +140 -0
  101. package/dist/daemon/election.js.map +1 -0
  102. package/dist/daemon/engine.d.ts +1703 -0
  103. package/dist/daemon/engine.js +5305 -0
  104. package/dist/daemon/engine.js.map +1 -0
  105. package/dist/daemon/index.d.ts +2 -0
  106. package/dist/daemon/index.js +412 -0
  107. package/dist/daemon/index.js.map +1 -0
  108. package/dist/daemon/proxy.d.ts +108 -0
  109. package/dist/daemon/proxy.js +615 -0
  110. package/dist/daemon/proxy.js.map +1 -0
  111. package/dist/daemon/supervisor.d.ts +101 -0
  112. package/dist/daemon/supervisor.js +493 -0
  113. package/dist/daemon/supervisor.js.map +1 -0
  114. package/dist/drivers/appliances.d.ts +11 -0
  115. package/dist/drivers/appliances.js +174 -0
  116. package/dist/drivers/appliances.js.map +1 -0
  117. package/dist/drivers/datastores.d.ts +144 -0
  118. package/dist/drivers/datastores.js +775 -0
  119. package/dist/drivers/datastores.js.map +1 -0
  120. package/dist/drivers/preview.d.ts +69 -0
  121. package/dist/drivers/preview.js +605 -0
  122. package/dist/drivers/preview.js.map +1 -0
  123. package/dist/drivers/types.d.ts +70 -0
  124. package/dist/drivers/types.js +13 -0
  125. package/dist/drivers/types.js.map +1 -0
  126. package/package.json +63 -4
  127. package/schema/backlot.schema.json +549 -0
  128. package/schema/runly.schema.json +556 -0
@@ -0,0 +1,259 @@
1
+ /**
2
+ * Service logs on disk (decision 0038).
3
+ *
4
+ * Every line a service writes is stored with the time it arrived —
5
+ * `<ISO-8601> <line>` — so `runly logs` can interleave several services in
6
+ * order and answer `--since`. Each process start writes a marker line, which
7
+ * is what `--since up` (this process's output only) finds. A file is capped
8
+ * (BACKLOT_LOG_CAP_BYTES, default 20 MB) and rotated once: past the cap it
9
+ * becomes `<name>.log.1`, replacing the previous rotation. Logs live in the
10
+ * environment's private directory, so they survive idle stops and daemon
11
+ * restarts and go with the environment.
12
+ *
13
+ * Build and upkeep output of the last `up` are kept apart, in
14
+ * `<service>.build.log` and `upkeep.build.log`, replaced by each new build.
15
+ */
16
+ import { appendFileSync, closeSync, existsSync, openSync, readSync, renameSync, statSync, writeFileSync } from 'node:fs';
17
+ import { join } from 'node:path';
18
+ import { policy } from './policy.js';
19
+ export const START_MARKER = '-- runly:';
20
+ const STAMP = /^(\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d(?:\.\d+)?Z) (.*)$/;
21
+ /** A stamped start marker line, as it is on disk. */
22
+ const MARKER_LINE = /^\S+Z -- runly:/;
23
+ export const logFileOf = (dir, service) => join(dir, `${service}.log`);
24
+ export const buildLogOf = (dir, service) => join(dir, `${service}.build.log`);
25
+ export const UPKEEP_LOG = 'upkeep';
26
+ /** The marker written when a service process starts; `--since up` reads from the last one. */
27
+ export function startMarker(service, pid, reason) {
28
+ return `${START_MARKER} ${service} started${pid ? ` (pid ${pid})` : ''}${reason ? ` — ${reason}` : ''} --`;
29
+ }
30
+ /**
31
+ * Appends time-stamped lines to one service's log. Output arrives in chunks
32
+ * from two streams; each stream keeps its own partial line, so a line is
33
+ * stamped once, when it completes, and stdout and stderr never splice into
34
+ * one line.
35
+ */
36
+ export class LogWriter {
37
+ file;
38
+ cap;
39
+ size = -1;
40
+ partial = new Map();
41
+ constructor(file, cap = policy().logCapBytes) {
42
+ this.file = file;
43
+ this.cap = cap;
44
+ }
45
+ /** A whole line from runly itself (a start marker). */
46
+ line(text) {
47
+ this.flushAll();
48
+ this.append(`${new Date().toISOString()} ${text}\n`);
49
+ }
50
+ /** A chunk of output from `stream` ('out'/'err'). */
51
+ write(stream, chunk) {
52
+ if (!chunk)
53
+ return;
54
+ const text = (this.partial.get(stream) ?? '') + chunk;
55
+ const nl = text.lastIndexOf('\n');
56
+ if (nl < 0) {
57
+ // Bounded: a process that never prints a newline must not grow memory.
58
+ if (text.length > 64_000) {
59
+ this.partial.delete(stream);
60
+ this.append(`${new Date().toISOString()} ${text}\n`);
61
+ }
62
+ else
63
+ this.partial.set(stream, text);
64
+ return;
65
+ }
66
+ this.partial.set(stream, text.slice(nl + 1));
67
+ const stamp = new Date().toISOString();
68
+ const lines = text.slice(0, nl).split('\n');
69
+ this.append(lines.map((l) => `${stamp} ${l}\n`).join(''));
70
+ }
71
+ /** The stream ended: whatever is left of its last line is written. */
72
+ end(stream) {
73
+ const rest = this.partial.get(stream);
74
+ this.partial.delete(stream);
75
+ if (rest)
76
+ this.append(`${new Date().toISOString()} ${rest}\n`);
77
+ }
78
+ flushAll() {
79
+ for (const s of [...this.partial.keys()])
80
+ this.end(s);
81
+ }
82
+ append(data) {
83
+ try {
84
+ if (this.size < 0)
85
+ this.size = existsSync(this.file) ? statSync(this.file).size : 0;
86
+ if (this.size + data.length > this.cap && this.size > 0) {
87
+ renameSync(this.file, `${this.file}.1`);
88
+ this.size = 0;
89
+ }
90
+ appendFileSync(this.file, data);
91
+ this.size += Buffer.byteLength(data);
92
+ }
93
+ catch {
94
+ /* log dir gone mid-teardown */
95
+ }
96
+ }
97
+ }
98
+ /** Rotate a log past the cap (the retention sweep's backstop for a writer that never rotated). */
99
+ export function rotateIfOver(file, cap) {
100
+ try {
101
+ if (statSync(file).size <= cap)
102
+ return false;
103
+ renameSync(file, `${file}.1`);
104
+ return true;
105
+ }
106
+ catch {
107
+ return false;
108
+ }
109
+ }
110
+ /**
111
+ * Read the tail of a file (bounded), so a 20 MB log is never one string
112
+ * twice. `end` stops at that offset (what a follower will read from), so a
113
+ * line appended meanwhile is read once, by the follower.
114
+ */
115
+ function readTail(file, maxBytes, end) {
116
+ try {
117
+ const size = Math.min(statSync(file).size, end ?? Infinity);
118
+ const len = Math.min(size, maxBytes);
119
+ const fd = openSync(file, 'r');
120
+ try {
121
+ const buf = Buffer.alloc(len);
122
+ readSync(fd, buf, 0, len, size - len);
123
+ const text = buf.toString('utf8');
124
+ // A cut-off first line is dropped rather than shown half.
125
+ return len < size ? text.slice(text.indexOf('\n') + 1) : text;
126
+ }
127
+ finally {
128
+ closeSync(fd);
129
+ }
130
+ }
131
+ catch {
132
+ return '';
133
+ }
134
+ }
135
+ function parseInto(out, text, service, last) {
136
+ for (const raw of text.split('\n')) {
137
+ if (raw === '')
138
+ continue;
139
+ const m = STAMP.exec(raw);
140
+ if (m) {
141
+ last = Date.parse(m[1]);
142
+ out.push({ service, at: last, text: m[2], marker: m[2].startsWith(START_MARKER) });
143
+ }
144
+ else {
145
+ out.push({ service, at: last, text: raw, marker: false });
146
+ }
147
+ }
148
+ return last;
149
+ }
150
+ /** Parse one log (its rotation first, then the live file up to `end`) into lines. */
151
+ export function readLog(file, service, maxBytes = 64 * 1024 * 1024, end) {
152
+ const out = [];
153
+ let last = NaN;
154
+ for (const f of [`${file}.1`, file]) {
155
+ const text = readTail(f, maxBytes, f === file ? end : undefined);
156
+ if (text)
157
+ last = parseInto(out, text, service, last);
158
+ }
159
+ return out;
160
+ }
161
+ /**
162
+ * The last lines of one log — at least `want` that are not start markers, or
163
+ * all there are — read BACKWARDS from `end` in growing chunks, into the
164
+ * rotation only when the live file runs out. `logs --lines 40` on a 20 MB log
165
+ * used to parse both whole files to print 40 lines.
166
+ */
167
+ export function readLastLines(file, service, want, end) {
168
+ const content = (text) => text.split('\n').filter((l) => l !== '' && !MARKER_LINE.test(l)).length;
169
+ const chunks = [];
170
+ let have = 0;
171
+ for (const f of [file, `${file}.1`]) {
172
+ if (have >= want)
173
+ break;
174
+ let fd;
175
+ let size;
176
+ try {
177
+ size = Math.min(statSync(f).size, f === file ? (end ?? Infinity) : Infinity);
178
+ fd = openSync(f, 'r');
179
+ }
180
+ catch {
181
+ continue;
182
+ }
183
+ try {
184
+ let pos = size;
185
+ let held = Buffer.alloc(0);
186
+ let step = 64 * 1024;
187
+ let text = '';
188
+ while (pos > 0) {
189
+ const len = Math.min(step, pos);
190
+ pos -= len;
191
+ const buf = Buffer.alloc(len);
192
+ readSync(fd, buf, 0, len, pos);
193
+ held = Buffer.concat([buf, held]);
194
+ step *= 2;
195
+ if (pos === 0) {
196
+ text = held.toString('utf8');
197
+ break;
198
+ }
199
+ // Whole lines only: what follows the first newline of what is held.
200
+ const nl = held.indexOf(0x0a);
201
+ if (nl < 0)
202
+ continue;
203
+ const whole = held.subarray(nl + 1).toString('utf8');
204
+ if (have + content(whole) >= want) {
205
+ text = whole;
206
+ break;
207
+ }
208
+ }
209
+ have += content(text);
210
+ chunks.unshift(text);
211
+ }
212
+ finally {
213
+ closeSync(fd);
214
+ }
215
+ }
216
+ const out = [];
217
+ let last = NaN;
218
+ for (const text of chunks)
219
+ last = parseInto(out, text, service, last);
220
+ return out;
221
+ }
222
+ /** Mark every line before the last start marker as `prior` (an earlier process's). */
223
+ export function markPrior(lines) {
224
+ let lastMarker = -1;
225
+ for (let i = lines.length - 1; i >= 0; i--) {
226
+ if (lines[i].marker) {
227
+ lastMarker = i;
228
+ break;
229
+ }
230
+ }
231
+ return lines.map((l, i) => (i < lastMarker ? { ...l, prior: true } : l));
232
+ }
233
+ /** Only the lines of the CURRENT process: from the last start marker on. */
234
+ export function sinceLastStart(lines) {
235
+ for (let i = lines.length - 1; i >= 0; i--)
236
+ if (lines[i].marker)
237
+ return lines.slice(i);
238
+ return lines;
239
+ }
240
+ /** Interleave several services' lines by time (stable within one service). */
241
+ export function interleave(groups) {
242
+ const all = groups.flatMap((g, gi) => g.map((l, i) => ({ l, gi, i })));
243
+ all.sort((a, b) => {
244
+ const ta = Number.isNaN(a.l.at) ? -Infinity : a.l.at;
245
+ const tb = Number.isNaN(b.l.at) ? -Infinity : b.l.at;
246
+ return ta - tb || (a.gi === b.gi ? a.i - b.i : a.gi - b.gi);
247
+ });
248
+ return all.map((x) => x.l);
249
+ }
250
+ /** Start a build log afresh for this build. */
251
+ export function beginBuildLog(file, header) {
252
+ try {
253
+ writeFileSync(file, `${new Date().toISOString()} ${START_MARKER} ${header} --\n`);
254
+ }
255
+ catch {
256
+ /* no log dir (warm without an environment) */
257
+ }
258
+ }
259
+ //# sourceMappingURL=logs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logs.js","sourceRoot":"","sources":["../../src/core/logs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,292 @@
1
+ export interface ReadySpec {
2
+ http?: string;
3
+ log?: string;
4
+ cmd?: string;
5
+ timeout?: number;
6
+ }
7
+ /**
8
+ * What a service (or an appliance) costs the box, for the server-wide load
9
+ * budget (decision 0036). `memory` is a size (`600M`, `2G`, or bytes), `cpu`
10
+ * a number of cores. `build` is what its build costs while it runs. Anything
11
+ * left out is a conservative default, and `runly plan` says so.
12
+ */
13
+ export interface ResourceSpec {
14
+ memory?: string | number;
15
+ cpu?: number;
16
+ build?: {
17
+ memory?: string | number;
18
+ cpu?: number;
19
+ };
20
+ }
21
+ /**
22
+ * A build step. The string form runs on every `up` that starts or keeps the
23
+ * service. The object form adds `when:` — globs of the files the build reads;
24
+ * when none of the matched files changed (path, size, mtime) since the last
25
+ * SUCCESSFUL build of this service in this worktree, the build is skipped
26
+ * (decision 0038).
27
+ */
28
+ export type BuildSpec = string | {
29
+ run: string;
30
+ when?: string[];
31
+ serial?: boolean;
32
+ };
33
+ /**
34
+ * What a build produces. String/array form: globs compared by path, size and
35
+ * mtime. Object form: `compare: content` hashes the files instead, so a build
36
+ * that rewrites identical files does not restart the service (decision 0038).
37
+ */
38
+ export type OutputsSpec = string | string[] | {
39
+ paths: string[];
40
+ compare?: 'stat' | 'content';
41
+ };
42
+ /** The build line and its `when:` globs, whichever form the manifest used. */
43
+ export declare function buildOf(spec: {
44
+ build?: BuildSpec;
45
+ }): {
46
+ run: string;
47
+ when?: string[];
48
+ serial?: boolean;
49
+ } | undefined;
50
+ /** The output globs and how they are compared, whichever form the manifest used. */
51
+ export declare function outputsOf(spec: {
52
+ outputs?: OutputsSpec;
53
+ }): {
54
+ paths: string[];
55
+ compare: 'stat' | 'content';
56
+ };
57
+ export interface ServiceSpec {
58
+ run: string;
59
+ build?: BuildSpec;
60
+ /**
61
+ * How long this service may sit with no client bytes through its public
62
+ * port and no runly verb on its environment before it is stopped (decision
63
+ * 0035). A duration (`90s`, `10m`, `2h`), seconds as a number, or `never`.
64
+ * Default: BACKLOT_SERVICE_IDLE_MS (10 minutes).
65
+ */
66
+ idle?: string | number;
67
+ resources?: ResourceSpec;
68
+ /** Accepted and ignored since decision 0032 (`--watch` was removed). */
69
+ watch_run?: string;
70
+ /** Accepted and ignored since decision 0032: a service without `build:` keeps running on `up` anyway. */
71
+ hot_reload?: boolean;
72
+ /**
73
+ * Globs (relative to the stack root) of what this service's `build:`
74
+ * produces. Snapshotted (path, size, mtime) around the build on every `up`;
75
+ * the service is restarted only when they changed. Without it, a service
76
+ * with a build is restarted after every build (decision 0032).
77
+ */
78
+ outputs?: OutputsSpec;
79
+ cwd?: string;
80
+ port?: string;
81
+ env?: Record<string, string>;
82
+ /** Allowlisted inputs supplied by the caller, retained only in lease memory. */
83
+ env_from?: Record<string, 'required' | 'optional'>;
84
+ ready?: ReadySpec;
85
+ fatal_logs?: string;
86
+ depends_on?: string[];
87
+ }
88
+ export interface DatastoreSpec {
89
+ driver: 'sqlite' | 'postgres' | 'mssql' | 'mysql' | 'redis';
90
+ server?: 'external';
91
+ probe?: string;
92
+ url?: string;
93
+ create?: string;
94
+ drop?: string;
95
+ template_restore?: string;
96
+ presets?: string[];
97
+ /** One preset name; the pre-0.13 `{run, session}` split is accepted and read as one value (session, then run). */
98
+ default_preset?: string | {
99
+ run?: string;
100
+ session?: string;
101
+ };
102
+ template?: boolean;
103
+ ephemeral?: boolean;
104
+ /**
105
+ * Never provisioned for an environment (decision 0039): it exists only as
106
+ * the source of `runly db new|with` copies. Its template is baked on the
107
+ * first copy and reused by the next. No service may template it, `ctx`
108
+ * does not list it, and `up --preset` / `reset-data` cannot name it.
109
+ */
110
+ copies_only?: boolean;
111
+ /**
112
+ * Share this datastore's templates with every worktree of the same manifest
113
+ * name on this daemon (decision 0044). Default true; it applies only to a
114
+ * content-keyed template (an `@rebake-template` rule names the datastore).
115
+ * Set false when the baked content depends on the worktree beyond its
116
+ * trigger files (an absolute path written into the data, say).
117
+ */
118
+ share_templates?: boolean;
119
+ /**
120
+ * Repo command printing the namespaces ({{ns}} values) of this datastore
121
+ * that exist on its server, one per line. Only `runly pool doctor` reads it:
122
+ * a listed name that matches runly's naming and no journal row references is
123
+ * an orphan, and `--fix` drops it with `drop:` (decision 0037).
124
+ */
125
+ list?: string;
126
+ }
127
+ export interface ApplianceSpec {
128
+ /** host:port whose reachability IS the appliance's identity. */
129
+ probe: string;
130
+ /** Daemonizing command run once (machine-wide) when the probe fails. */
131
+ start?: string;
132
+ /** Command for the explicit stop verb; never run automatically. */
133
+ stop?: string;
134
+ /** Optional readiness gate polled after TCP accepts (exit 0 = ready). */
135
+ ready?: string;
136
+ /** Seconds to wait after start for probe+ready. Default 60. */
137
+ timeout?: number;
138
+ /** What it costs while running, counted against the load budget when runly would start it (decision 0036). */
139
+ resources?: ResourceSpec;
140
+ }
141
+ export interface UpkeepRule {
142
+ when: string;
143
+ run: string;
144
+ /** Hard process-group deadline in seconds; default 300, global override wins. */
145
+ timeout?: number;
146
+ /**
147
+ * Paths (relative to the stack root) the rule's command leaves behind — an
148
+ * install's `node_modules/.modules.yaml`, a generated client's directory. A
149
+ * rule whose trigger is unchanged runs again when any of them is missing
150
+ * (a `git clean -fdx` removed it). A rule without `outputs:` is forgotten by
151
+ * `runly destroy` instead, so the next `up` after a pool reset runs it.
152
+ */
153
+ outputs?: string | string[];
154
+ }
155
+ /** A rule's declared `outputs:` as a list (empty when it declares none). */
156
+ export declare const upkeepOutputs: (rule: {
157
+ outputs?: string | string[];
158
+ }) => string[];
159
+ /**
160
+ * A seeded, dev-grade login the stack advertises to consumers. `role` names the
161
+ * `{{role}}` an `auth.token` hook would take; `description` says what the login is
162
+ * FOR, so a consumer picks the right one without reading the seed.
163
+ */
164
+ export interface Login {
165
+ user: string;
166
+ password: string;
167
+ role?: string;
168
+ description?: string;
169
+ }
170
+ /**
171
+ * `auth.logins` accepts a single login (the original form) or a list. The list's
172
+ * FIRST entry is the primary one — see `normalizeLogins`.
173
+ */
174
+ export type LoginsSpec = Login | Login[];
175
+ /**
176
+ * One shape for consumers regardless of which form the manifest used: `[]` when no
177
+ * login is declared, otherwise every declared login in order. A single-object
178
+ * manifest yields exactly one entry, so callers never branch on the manifest form.
179
+ */
180
+ export declare function normalizeLogins(spec: LoginsSpec | undefined): Login[];
181
+ export interface PreviewSpec {
182
+ /**
183
+ * When true, `runly preview` is refused (work-error). Stacks with fixed dev
184
+ * credentials or a known signing key must set this.
185
+ */
186
+ forbidden?: boolean;
187
+ /**
188
+ * Named preview publisher adapter (default: cloudflare-quick). Known:
189
+ * `cloudflare-quick`, `cloudflare-named`, `tailscale` (tailnet-only HTTPS via
190
+ * `tailscale serve`, decision 0031).
191
+ */
192
+ publisher?: string;
193
+ /**
194
+ * Zone a naming publisher publishes under, e.g. `example.dev`. Required by
195
+ * `cloudflare-named`; meaningless to `cloudflare-quick`, which is handed its
196
+ * hostname by Cloudflare.
197
+ */
198
+ domain?: string;
199
+ /**
200
+ * What makes a hostname this environment's own.
201
+ *
202
+ * A naming publisher derives `<service>-<prefix>.<domain>`, so two
203
+ * environments sharing a prefix want the same name — and the second one takes
204
+ * it from the first. The manifest is the wrong place to make that unique: a
205
+ * pooled stack has several environments and one manifest. Left unset, the
206
+ * environment id supplies the prefix, which is unique by construction. Set it
207
+ * only to pin a name a human has to remember, and only where one environment
208
+ * of this stack runs at a time.
209
+ */
210
+ prefix?: string;
211
+ /**
212
+ * The HTTPS port on this machine's tailnet name that the `tailscale` publisher
213
+ * serves on (`https://<machine>.<tailnet>.ts.net:<port>`). Unset means a port
214
+ * derived from the environment id and service, stable for the environment's
215
+ * lifetime and moved past any port this machine already serves. Pin it only
216
+ * for an address a human has to remember, and only where one environment of
217
+ * this stack publishes at a time — a second publish of a pinned port is
218
+ * refused rather than taken over. Ignored by the Cloudflare publishers.
219
+ */
220
+ https_port?: number;
221
+ }
222
+ export interface Manifest {
223
+ name: string;
224
+ services: Record<string, ServiceSpec>;
225
+ preview?: PreviewSpec;
226
+ appliances?: Record<string, ApplianceSpec>;
227
+ datastores?: Record<string, DatastoreSpec>;
228
+ /**
229
+ * How one `up` runs its builds: `parallel` (default) in depends_on waves,
230
+ * the builds of one wave at once; `serial` one at a time in manifest order.
231
+ */
232
+ builds?: 'parallel' | 'serial';
233
+ /** Build/install output in the worktree: never an upkeep trigger (decision 0032). */
234
+ caches?: string[];
235
+ /** `include`: git-ignored files an upkeep `when:` glob may still match. `keep` is accepted and ignored (decision 0032). */
236
+ sync?: {
237
+ keep?: string[];
238
+ include?: string[];
239
+ };
240
+ /** Accepted and ignored since decision 0032 (it served `runly run`). */
241
+ outputs?: string[];
242
+ upkeep?: UpkeepRule[];
243
+ auth?: {
244
+ logins?: LoginsSpec;
245
+ token?: string;
246
+ };
247
+ /**
248
+ * Accepted and ignored since decision 0032: `runly run` was removed. Repo
249
+ * scripts read `runly ctx --env` instead. A manifest that still declares it
250
+ * loads, with a one-line deprecation warning (`manifestDeprecations`).
251
+ */
252
+ checks?: Record<string, unknown>;
253
+ }
254
+ /**
255
+ * One-line warnings for manifest sections runly accepts but no longer acts on.
256
+ * The CLI prints them to stderr; the manifest still loads.
257
+ */
258
+ export declare function manifestDeprecations(manifest: Manifest, file?: string): string[];
259
+ export interface Stack {
260
+ manifest: Manifest;
261
+ /** Directory containing the manifest — the worktree environments run in (decision 0032). */
262
+ root: string;
263
+ /** Stable identity: pools are keyed by this. */
264
+ id: string;
265
+ /** The manifest's file name as found (runly.yml, backlot.yml or stack.yaml), for messages. */
266
+ file?: string;
267
+ }
268
+ /** The manifest's file name for a message: the one actually loaded. */
269
+ export declare const manifestFileOf: (stack?: {
270
+ file?: string;
271
+ }) => string;
272
+ /** Walk upward from cwd to the nearest manifest. */
273
+ /** runly.yml is canonical; backlot.yml and stack.yaml stay accepted so
274
+ * existing consumers survive the upgrade. When several exist, runly.yml wins —
275
+ * a rename, not a coin toss. */
276
+ export declare const MANIFEST_NAMES: readonly ["runly.yml", "backlot.yml", "stack.yaml"];
277
+ export declare function canonicalDirectory(from: string): string;
278
+ export declare function stackIdentity(name: string, root: string): string;
279
+ export declare function findStackRoot(from: string): string;
280
+ /**
281
+ * Find, read and validate the manifest from `from` upward. `validate: false`
282
+ * skips the schema check — only for a CLI-side read whose result the daemon
283
+ * re-reads and validates before acting on it (the deprecation warnings).
284
+ */
285
+ export declare function loadStack(from: string, opts?: {
286
+ validate?: boolean;
287
+ }): Stack;
288
+ /** The datastores an environment provisions: every declared one except `copies_only` (decision 0039). */
289
+ export declare function envDatastoreNames(manifest: Manifest): string[];
290
+ /** The declared default preset, if any — one value, whichever form the manifest used. */
291
+ export declare function declaredDefaultPreset(ds: DatastoreSpec): string | undefined;
292
+ export declare function defaultPreset(ds: DatastoreSpec): string;