@descryy/runtime-controller 0.0.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 (61) hide show
  1. package/dist/capability-registry.d.ts +24 -0
  2. package/dist/capability-registry.d.ts.map +1 -0
  3. package/dist/capability-registry.js +42 -0
  4. package/dist/capability-registry.js.map +1 -0
  5. package/dist/collector-version.d.ts +10 -0
  6. package/dist/collector-version.d.ts.map +1 -0
  7. package/dist/collector-version.js +12 -0
  8. package/dist/collector-version.js.map +1 -0
  9. package/dist/container-sandbox.d.ts +188 -0
  10. package/dist/container-sandbox.d.ts.map +1 -0
  11. package/dist/container-sandbox.js +233 -0
  12. package/dist/container-sandbox.js.map +1 -0
  13. package/dist/controller.d.ts +162 -0
  14. package/dist/controller.d.ts.map +1 -0
  15. package/dist/controller.js +433 -0
  16. package/dist/controller.js.map +1 -0
  17. package/dist/dependency-version-check.d.ts +90 -0
  18. package/dist/dependency-version-check.d.ts.map +1 -0
  19. package/dist/dependency-version-check.js +121 -0
  20. package/dist/dependency-version-check.js.map +1 -0
  21. package/dist/env.d.ts +16 -0
  22. package/dist/env.d.ts.map +1 -0
  23. package/dist/env.js +18 -0
  24. package/dist/env.js.map +1 -0
  25. package/dist/environment-metadata.d.ts +23 -0
  26. package/dist/environment-metadata.d.ts.map +1 -0
  27. package/dist/environment-metadata.js +80 -0
  28. package/dist/environment-metadata.js.map +1 -0
  29. package/dist/environment-version-check.d.ts +83 -0
  30. package/dist/environment-version-check.d.ts.map +1 -0
  31. package/dist/environment-version-check.js +218 -0
  32. package/dist/environment-version-check.js.map +1 -0
  33. package/dist/execution-safety.d.ts +154 -0
  34. package/dist/execution-safety.d.ts.map +1 -0
  35. package/dist/execution-safety.js +194 -0
  36. package/dist/execution-safety.js.map +1 -0
  37. package/dist/index.d.ts +35 -0
  38. package/dist/index.d.ts.map +1 -0
  39. package/dist/index.js +14 -0
  40. package/dist/index.js.map +1 -0
  41. package/dist/orchestration.d.ts +70 -0
  42. package/dist/orchestration.d.ts.map +1 -0
  43. package/dist/orchestration.js +255 -0
  44. package/dist/orchestration.js.map +1 -0
  45. package/dist/process-collector.d.ts +34 -0
  46. package/dist/process-collector.d.ts.map +1 -0
  47. package/dist/process-collector.js +148 -0
  48. package/dist/process-collector.js.map +1 -0
  49. package/dist/process-manager.d.ts +133 -0
  50. package/dist/process-manager.d.ts.map +1 -0
  51. package/dist/process-manager.js +333 -0
  52. package/dist/process-manager.js.map +1 -0
  53. package/dist/readiness.d.ts +120 -0
  54. package/dist/readiness.d.ts.map +1 -0
  55. package/dist/readiness.js +179 -0
  56. package/dist/readiness.js.map +1 -0
  57. package/dist/sandbox.d.ts +139 -0
  58. package/dist/sandbox.d.ts.map +1 -0
  59. package/dist/sandbox.js +271 -0
  60. package/dist/sandbox.js.map +1 -0
  61. package/package.json +29 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAGjD,OAAO,EAAE,YAAY,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAa1F,OAAO,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAGtE,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAGtD,OAAO,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAGhE,OAAO,EAAE,0BAA0B,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAG5F,OAAO,EACL,uBAAuB,EACvB,mBAAmB,EACnB,uBAAuB,EACvB,kBAAkB,EAClB,sBAAsB,EACtB,2BAA2B,EAC3B,4BAA4B,EAC5B,4BAA4B,GAC7B,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EACL,6BAA6B,EAC7B,0BAA0B,EAC1B,8BAA8B,EAC9B,0BAA0B,EAC1B,YAAY,GACb,MAAM,cAAc,CAAC;AAGtB,OAAO,EACL,0BAA0B,EAC1B,sCAAsC,EACtC,mCAAmC,EACnC,uCAAuC,EACvC,qBAAqB,EACrB,qBAAqB,GACtB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,0BAA0B,EAAE,MAAM,2BAA2B,CAAC;AAGvE,OAAO,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAC;AAGxE,OAAO,EAAE,wBAAwB,EAAE,uBAAuB,EAAE,4BAA4B,EAAE,MAAM,gCAAgC,CAAC;AAajI,OAAO,EAAE,eAAe,EAAE,6BAA6B,EAAE,0BAA0B,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Turns a declarative `services` map (plan §6, RT-028) into a concrete
3
+ * spawn order for `ExecutionController.run()` (RT-032). Everything here is
4
+ * pure and side-effect-free — validated and ordered before anything is
5
+ * spawned, so a bad reference is refused atomically rather than discovered
6
+ * mid-sequence with some services already running.
7
+ *
8
+ * Start order and port injection are **declared in configuration, never
9
+ * inferred** — the same "ask, don't guess" discipline RT-023 already
10
+ * applied to browser script-URL roots. A `${name.port}` reference alone
11
+ * does not create an ordering guarantee; `name` must also appear in the
12
+ * referencing service's own `dependsOn`, or validation refuses.
13
+ */
14
+ import type { ServiceConfiguration } from "@descryy/runtime-contracts";
15
+ export type ServicesValidation = {
16
+ readonly valid: true;
17
+ readonly order: readonly string[];
18
+ } | {
19
+ readonly valid: false;
20
+ readonly reason: string;
21
+ };
22
+ /**
23
+ * Validates a `services` map and returns a valid topological spawn order.
24
+ * Three checks, all before anything is spawned:
25
+ * 1. every `dependsOn` entry names a real key in `services`;
26
+ * 2. the `dependsOn` graph has no cycle (a start order must exist);
27
+ * 3. every `${name}.port` placeholder referenced in a service's own `env`
28
+ * has `name` in that same service's `dependsOn` — the placeholder does
29
+ * not itself create the ordering guarantee it depends on.
30
+ */
31
+ export declare function validateServicesConfiguration(services: Readonly<Record<string, ServiceConfiguration>>): ServicesValidation;
32
+ /**
33
+ * Replaces every `${name}.port` in `env`'s values with the resolved port
34
+ * for `name`. Assumes `validateServicesConfiguration` already confirmed
35
+ * every referenced name is a declared dependency that the caller resolves
36
+ * earlier in the same spawn order — a reference this function can't
37
+ * resolve is left untouched rather than silently dropped, so a caller that
38
+ * skipped validation sees an obviously-wrong literal `${...}` instead of a
39
+ * silently empty substitution.
40
+ */
41
+ export declare function substitutePortPlaceholders(env: Readonly<Record<string, string>> | undefined, resolvedPorts: ReadonlyMap<string, number>): Record<string, string>;
42
+ export type CommandTokenization = {
43
+ readonly ok: true;
44
+ readonly command: string;
45
+ readonly args: readonly string[];
46
+ } | {
47
+ readonly ok: false;
48
+ readonly reason: string;
49
+ };
50
+ /**
51
+ * POSIX-style tokenizer for `ServiceConfiguration.command`: single quotes
52
+ * (literal throughout), double quotes (with `\` escaping `"` and `\`), and
53
+ * backslash escapes outside quotes. `spawnProcess` takes `command`/`args`
54
+ * separately while configuration carries one string (plan §6's YAML shape),
55
+ * so something has to split it, and doing that by whitespace alone breaks
56
+ * every path with a space in it — `"C:\Program Files\node.exe"` and
57
+ * `python3 -c "import app; app.main()"` both tokenized wrong before.
58
+ *
59
+ * **Refuses rather than guesses** on an unterminated quote, a trailing
60
+ * backslash, or an unquoted shell operator. Each of those has no correct
61
+ * interpretation without a shell, and returning a plausible tokenization
62
+ * for input that cannot mean what it says is how a configuration error
63
+ * arrives disguised as an application failure.
64
+ *
65
+ * Globs and `~` are *not* refused: they pass through literally, which is
66
+ * exactly what happens with no shell, and unlike the operators above they
67
+ * are frequently intended literally.
68
+ */
69
+ export declare function tokenizeCommand(raw: string): CommandTokenization;
70
+ //# sourceMappingURL=orchestration.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orchestration.d.ts","sourceRoot":"","sources":["../src/orchestration.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAiBvE,MAAM,MAAM,kBAAkB,GAC1B;IAAE,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GAC3D;IAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvD;;;;;;;;GAQG;AACH,wBAAgB,6BAA6B,CAC3C,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC,GACvD,kBAAkB,CA+DpB;AAkCD;;;;;;;;GAQG;AACH,wBAAgB,0BAA0B,CACxC,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,SAAS,EACjD,aAAa,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,GACzC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CASxB;AAED,MAAM,MAAM,mBAAmB,GAC3B;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GACjF;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAkBpD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,mBAAmB,CA8EhE"}
@@ -0,0 +1,255 @@
1
+ /**
2
+ * Turns a declarative `services` map (plan §6, RT-028) into a concrete
3
+ * spawn order for `ExecutionController.run()` (RT-032). Everything here is
4
+ * pure and side-effect-free — validated and ordered before anything is
5
+ * spawned, so a bad reference is refused atomically rather than discovered
6
+ * mid-sequence with some services already running.
7
+ *
8
+ * Start order and port injection are **declared in configuration, never
9
+ * inferred** — the same "ask, don't guess" discipline RT-023 already
10
+ * applied to browser script-URL roots. A `${name.port}` reference alone
11
+ * does not create an ordering guarantee; `name` must also appear in the
12
+ * referencing service's own `dependsOn`, or validation refuses.
13
+ */
14
+ /**
15
+ * Bounded at `{1,256}`, not `+`, since RT-070's own regex audit (prompted by
16
+ * RT-069's ReDoS finding in `evidence-store/redaction.ts`) named this exact
17
+ * shape: an unbounded character class immediately followed by a required
18
+ * literal (`.port}`) that can be absent from the input. On a long string
19
+ * with `${` but no closing `.port}`, an unbounded class here would
20
+ * backtrack once per starting position -- O(n^2). `service.env` values are
21
+ * developer-authored configuration, not runtime/adversarial data, which is
22
+ * why this was flagged low-risk rather than urgent -- but the shape is
23
+ * identical to the one that DID become a real denial-of-service on a
24
+ * different input source the same day, and 256 characters is far more than
25
+ * any real service or dependency name needs.
26
+ */
27
+ const PORT_PLACEHOLDER = /\$\{([^}]{1,256})\.port\}/g;
28
+ /**
29
+ * Validates a `services` map and returns a valid topological spawn order.
30
+ * Three checks, all before anything is spawned:
31
+ * 1. every `dependsOn` entry names a real key in `services`;
32
+ * 2. the `dependsOn` graph has no cycle (a start order must exist);
33
+ * 3. every `${name}.port` placeholder referenced in a service's own `env`
34
+ * has `name` in that same service's `dependsOn` — the placeholder does
35
+ * not itself create the ordering guarantee it depends on.
36
+ */
37
+ export function validateServicesConfiguration(services) {
38
+ const names = Object.keys(services);
39
+ for (const name of names) {
40
+ for (const dep of services[name]?.dependsOn ?? []) {
41
+ if (!(dep in services)) {
42
+ return { valid: false, reason: `service "${name}" depends on "${dep}", which is not in services` };
43
+ }
44
+ }
45
+ }
46
+ const orderResult = topologicalOrder(services, names);
47
+ if (!orderResult.valid) {
48
+ return orderResult;
49
+ }
50
+ for (const name of names) {
51
+ const declared = new Set(services[name]?.dependsOn ?? []);
52
+ for (const value of Object.values(services[name]?.env ?? {})) {
53
+ for (const match of value.matchAll(PORT_PLACEHOLDER)) {
54
+ const referenced = match[1];
55
+ if (referenced !== undefined && !declared.has(referenced)) {
56
+ return {
57
+ valid: false,
58
+ reason: `service "${name}" references "\${${referenced}.port}" in env but does not declare "${referenced}" in dependsOn`,
59
+ };
60
+ }
61
+ }
62
+ }
63
+ }
64
+ // Fourth check, and like the other three it runs before anything is
65
+ // spawned: exactly one of `command`/`attach` per service (RT-attach-mode-
66
+ // service-configuration). Neither means nothing tells `run()` how to
67
+ // start this service; both means an ambiguous configuration nothing here
68
+ // should silently pick a side on.
69
+ for (const name of names) {
70
+ const service = services[name];
71
+ const hasCommand = service?.command !== undefined;
72
+ const hasAttach = service?.attach !== undefined;
73
+ if (hasCommand === hasAttach) {
74
+ return {
75
+ valid: false,
76
+ reason: `service "${name}" must declare exactly one of "command" (spawn) or "attach" (attach to an already-running process), not ${hasCommand ? "both" : "neither"}`,
77
+ };
78
+ }
79
+ }
80
+ // Fifth check, same atomic-refusal placement. A command that cannot be
81
+ // tokenized is a configuration error, and discovering it mid-sequence
82
+ // would mean refusing service 3 after services 1 and 2 are already
83
+ // running — recoverable via rollback, but needlessly: nothing about this
84
+ // check needs a process to exist.
85
+ for (const name of names) {
86
+ const command = services[name]?.command;
87
+ if (command === undefined)
88
+ continue;
89
+ const tokenized = tokenizeCommand(command);
90
+ if (!tokenized.ok) {
91
+ return { valid: false, reason: `service "${name}": ${tokenized.reason}` };
92
+ }
93
+ }
94
+ return orderResult;
95
+ }
96
+ function topologicalOrder(services, names) {
97
+ const order = [];
98
+ const visited = new Set();
99
+ const visiting = new Set();
100
+ function visit(name) {
101
+ if (visited.has(name))
102
+ return null;
103
+ if (visiting.has(name))
104
+ return `cycle detected in dependsOn involving "${name}"`;
105
+ visiting.add(name);
106
+ for (const dep of services[name]?.dependsOn ?? []) {
107
+ const err = visit(dep);
108
+ if (err !== null)
109
+ return err;
110
+ }
111
+ visiting.delete(name);
112
+ visited.add(name);
113
+ order.push(name);
114
+ return null;
115
+ }
116
+ for (const name of names) {
117
+ const err = visit(name);
118
+ if (err !== null) {
119
+ return { valid: false, reason: err };
120
+ }
121
+ }
122
+ return { valid: true, order };
123
+ }
124
+ /**
125
+ * Replaces every `${name}.port` in `env`'s values with the resolved port
126
+ * for `name`. Assumes `validateServicesConfiguration` already confirmed
127
+ * every referenced name is a declared dependency that the caller resolves
128
+ * earlier in the same spawn order — a reference this function can't
129
+ * resolve is left untouched rather than silently dropped, so a caller that
130
+ * skipped validation sees an obviously-wrong literal `${...}` instead of a
131
+ * silently empty substitution.
132
+ */
133
+ export function substitutePortPlaceholders(env, resolvedPorts) {
134
+ const result = {};
135
+ for (const [key, value] of Object.entries(env ?? {})) {
136
+ result[key] = value.replace(PORT_PLACEHOLDER, (literal, name) => {
137
+ const port = resolvedPorts.get(name);
138
+ return port === undefined ? literal : String(port);
139
+ });
140
+ }
141
+ return result;
142
+ }
143
+ /**
144
+ * Shell operators that only mean anything to a shell. `spawnProcess` uses
145
+ * `child_process.spawn` **without** one, deliberately — no implicit shell
146
+ * means no injection surface and no expansion nobody asked for. So a
147
+ * command containing these was never going to behave as written: it would
148
+ * be handed to the program as a literal argument.
149
+ *
150
+ * Refusing is the honest answer. The previous whitespace split passed
151
+ * `node server.mjs > out.log` through as three arguments to `node`, which
152
+ * starts a process that fails in a way pointing at the application rather
153
+ * than at its own configuration. Someone who genuinely wants a shell can
154
+ * say so — `sh -c "..."` tokenizes fine, since the operators are then
155
+ * inside quotes where they belong.
156
+ */
157
+ const SHELL_OPERATORS = new Set(["|", "&", ";", "<", ">", "`", "$"]);
158
+ /**
159
+ * POSIX-style tokenizer for `ServiceConfiguration.command`: single quotes
160
+ * (literal throughout), double quotes (with `\` escaping `"` and `\`), and
161
+ * backslash escapes outside quotes. `spawnProcess` takes `command`/`args`
162
+ * separately while configuration carries one string (plan §6's YAML shape),
163
+ * so something has to split it, and doing that by whitespace alone breaks
164
+ * every path with a space in it — `"C:\Program Files\node.exe"` and
165
+ * `python3 -c "import app; app.main()"` both tokenized wrong before.
166
+ *
167
+ * **Refuses rather than guesses** on an unterminated quote, a trailing
168
+ * backslash, or an unquoted shell operator. Each of those has no correct
169
+ * interpretation without a shell, and returning a plausible tokenization
170
+ * for input that cannot mean what it says is how a configuration error
171
+ * arrives disguised as an application failure.
172
+ *
173
+ * Globs and `~` are *not* refused: they pass through literally, which is
174
+ * exactly what happens with no shell, and unlike the operators above they
175
+ * are frequently intended literally.
176
+ */
177
+ export function tokenizeCommand(raw) {
178
+ const tokens = [];
179
+ let current = "";
180
+ let started = false; // distinguishes an empty quoted token ('') from no token
181
+ let quote = null;
182
+ for (let i = 0; i < raw.length; i++) {
183
+ const char = raw[i];
184
+ if (quote === "'") {
185
+ if (char === "'")
186
+ quote = null;
187
+ else
188
+ current += char;
189
+ continue;
190
+ }
191
+ if (quote === '"') {
192
+ if (char === "\\") {
193
+ const next = raw[i + 1];
194
+ if (next === undefined)
195
+ return { ok: false, reason: 'command ends with a trailing backslash inside a double-quoted string, which escapes nothing' };
196
+ // Only `"` and `\` are escapable inside double quotes; anything
197
+ // else keeps the backslash, as a shell would.
198
+ if (next === '"' || next === "\\") {
199
+ current += next;
200
+ i++;
201
+ }
202
+ else {
203
+ current += char;
204
+ }
205
+ continue;
206
+ }
207
+ if (char === '"')
208
+ quote = null;
209
+ else
210
+ current += char;
211
+ continue;
212
+ }
213
+ if (char === "'" || char === '"') {
214
+ quote = char;
215
+ started = true;
216
+ continue;
217
+ }
218
+ if (char === "\\") {
219
+ const next = raw[i + 1];
220
+ if (next === undefined)
221
+ return { ok: false, reason: "command ends with a trailing backslash, which escapes nothing" };
222
+ current += next;
223
+ started = true;
224
+ i++;
225
+ continue;
226
+ }
227
+ if (SHELL_OPERATORS.has(char)) {
228
+ return {
229
+ ok: false,
230
+ reason: `command contains the shell operator "${char}" outside quotes, but processes are spawned without a shell — ` +
231
+ `it would be passed to the program as a literal argument rather than interpreted. ` +
232
+ `Use an explicit shell (sh -c "...") if that is what you meant.`,
233
+ };
234
+ }
235
+ if (/\s/.test(char)) {
236
+ if (started) {
237
+ tokens.push(current);
238
+ current = "";
239
+ started = false;
240
+ }
241
+ continue;
242
+ }
243
+ current += char;
244
+ started = true;
245
+ }
246
+ if (quote !== null)
247
+ return { ok: false, reason: `command has an unterminated ${quote === '"' ? "double" : "single"} quote` };
248
+ if (started)
249
+ tokens.push(current);
250
+ const [head, ...rest] = tokens;
251
+ if (head === undefined || head === "")
252
+ return { ok: false, reason: "command is empty" };
253
+ return { ok: true, command: head, args: rest };
254
+ }
255
+ //# sourceMappingURL=orchestration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orchestration.js","sourceRoot":"","sources":["../src/orchestration.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * `ProcessCollector`: turns `ProcessLifecycleEvent` (`controller.ts`) into
3
+ * `PROCESS_STARTED` / `PROCESS_READY` / `PROCESS_EXITED` Evidence.
4
+ *
5
+ * `backend-observation/collector.ts` named this a non-goal of `LogCollector`
6
+ * — "whether it becomes Evidence at all is an orchestration-layer question"
7
+ * — and it stayed unbuilt long enough that all three event types were
8
+ * declared in `contracts/src/runtime-event.ts` and emitted by nothing
9
+ * (RUNTIME-CHECKLIST.md §3). This is that orchestration-layer answer: a
10
+ * plain translator with no lifecycle logic of its own. `ExecutionController`
11
+ * decides *when* each transition happens (spawn, readiness settling either
12
+ * way, reap) and calls `RunOptions.onProcessLifecycleEvent` at exactly
13
+ * those moments; this collector's only job is turning one of those calls
14
+ * into one `context.emit()` call. It does not spawn anything, does not
15
+ * decide readiness, and does not know why a process exited — only that it
16
+ * did, and what `ProcessHandle` says about it.
17
+ *
18
+ * **Wiring order is load-bearing.** `start(context)` must be called before
19
+ * `RunOptions.onProcessLifecycleEvent` can fire — i.e. before
20
+ * `ExecutionController.run()` is called with this collector's
21
+ * `handleLifecycleEvent` wired in. `handleLifecycleEvent` throws rather
22
+ * than silently dropping an event if that order is violated: a lost
23
+ * PROCESS_STARTED reads to everything downstream as "this process was
24
+ * never observed," which is a worse and quieter failure than a thrown
25
+ * error at the exact call site that got the order wrong.
26
+ */
27
+ import type { Collector } from "@descryy/runtime-contracts";
28
+ import type { ProcessLifecycleEvent } from "./controller.ts";
29
+ export interface ProcessCollector extends Collector {
30
+ /** Wire as `RunOptions.onProcessLifecycleEvent` — see the module doc for the ordering this depends on. */
31
+ handleLifecycleEvent(event: ProcessLifecycleEvent): void;
32
+ }
33
+ export declare function createProcessCollector(): ProcessCollector;
34
+ //# sourceMappingURL=process-collector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"process-collector.d.ts","sourceRoot":"","sources":["../src/process-collector.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAmF,MAAM,4BAA4B,CAAC;AAC7I,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAG7D,MAAM,WAAW,gBAAiB,SAAQ,SAAS;IACjD,0GAA0G;IAC1G,oBAAoB,CAAC,KAAK,EAAE,qBAAqB,GAAG,IAAI,CAAC;CAC1D;AA4ED,wBAAgB,sBAAsB,IAAI,gBAAgB,CAuDzD"}
@@ -0,0 +1,148 @@
1
+ /**
2
+ * `ProcessCollector`: turns `ProcessLifecycleEvent` (`controller.ts`) into
3
+ * `PROCESS_STARTED` / `PROCESS_READY` / `PROCESS_EXITED` Evidence.
4
+ *
5
+ * `backend-observation/collector.ts` named this a non-goal of `LogCollector`
6
+ * — "whether it becomes Evidence at all is an orchestration-layer question"
7
+ * — and it stayed unbuilt long enough that all three event types were
8
+ * declared in `contracts/src/runtime-event.ts` and emitted by nothing
9
+ * (RUNTIME-CHECKLIST.md §3). This is that orchestration-layer answer: a
10
+ * plain translator with no lifecycle logic of its own. `ExecutionController`
11
+ * decides *when* each transition happens (spawn, readiness settling either
12
+ * way, reap) and calls `RunOptions.onProcessLifecycleEvent` at exactly
13
+ * those moments; this collector's only job is turning one of those calls
14
+ * into one `context.emit()` call. It does not spawn anything, does not
15
+ * decide readiness, and does not know why a process exited — only that it
16
+ * did, and what `ProcessHandle` says about it.
17
+ *
18
+ * **Wiring order is load-bearing.** `start(context)` must be called before
19
+ * `RunOptions.onProcessLifecycleEvent` can fire — i.e. before
20
+ * `ExecutionController.run()` is called with this collector's
21
+ * `handleLifecycleEvent` wired in. `handleLifecycleEvent` throws rather
22
+ * than silently dropping an event if that order is violated: a lost
23
+ * PROCESS_STARTED reads to everything downstream as "this process was
24
+ * never observed," which is a worse and quieter failure than a thrown
25
+ * error at the exact call site that got the order wrong.
26
+ */
27
+ import { COLLECTOR_VERSION } from "./collector-version.js";
28
+ /**
29
+ * All seven `CollectorCapabilities` fields describe DOM/console/network/
30
+ * backend-log/trace/source-mapping/stack-capture observation — none of them
31
+ * is "process lifecycle observation," which is the one thing this collector
32
+ * actually does. There is no eighth field to report it as available in.
33
+ * Reported `unavailable` on all seven, each with its own honest reason,
34
+ * rather than inventing a field this package doesn't own (`contracts` is
35
+ * outside this lane's boundary this round — flagged to the peer rather than
36
+ * changed unilaterally). A collector that is doing its one real job while
37
+ * `capabilities()` shows nothing but `unavailable` is itself a disclosed
38
+ * gap in the capability model, not a bug in this file.
39
+ */
40
+ function computeCapabilities() {
41
+ const reason = "ProcessCollector observes process lifecycle (started/ready/exited) only — the capability model has no field for that yet.";
42
+ const status = { availability: "unavailable", reason };
43
+ return {
44
+ domObservation: status,
45
+ consoleObservation: status,
46
+ networkObservation: status,
47
+ backendLogAccess: status,
48
+ distributedTrace: status,
49
+ sourceMapping: status,
50
+ stackCapture: status,
51
+ processLifecycle: { availability: "available", reason: null },
52
+ databaseObservation: status,
53
+ externalServiceObservation: status,
54
+ };
55
+ }
56
+ function eventTypeOf(kind) {
57
+ switch (kind) {
58
+ case "process-started":
59
+ return "PROCESS_STARTED";
60
+ case "process-ready":
61
+ case "process-ready-failed":
62
+ return "PROCESS_READY";
63
+ case "process-exited":
64
+ return "PROCESS_EXITED";
65
+ }
66
+ }
67
+ /**
68
+ * `process-ready-failed` still becomes a `PROCESS_READY`-typed Evidence
69
+ * item — the vocabulary has no separate "readiness failed" type, and
70
+ * inventing one here would be a runtime-event vocabulary change made
71
+ * unilaterally in a collector, the wrong layer for it. The failure is not
72
+ * lost: `payload.ready` is `false` and `payload.readiness` carries the full
73
+ * `ReadinessResult` (mechanism attempted, elapsed time, reason), so a
74
+ * reader distinguishes "became ready" from "readiness failed" from the
75
+ * payload, not the event type — the same shape `ServiceStartResult`
76
+ * already uses (`succeeded: boolean` alongside a `stage`), not a new one.
77
+ */
78
+ function payloadOf(event) {
79
+ switch (event.kind) {
80
+ case "process-started":
81
+ return { processId: event.handle.processId, serviceName: event.serviceName, pid: event.handle.pid, command: event.handle.command, startedAt: event.handle.startedAt };
82
+ case "process-ready":
83
+ case "process-ready-failed":
84
+ return { processId: event.handle.processId, serviceName: event.serviceName, ready: event.readiness.ready, readiness: event.readiness };
85
+ case "process-exited":
86
+ // `phase` is what lets a reader tell "crashed on boot" from
87
+ // "finished/was stopped after running successfully" — see
88
+ // `ProcessLifecycleEvent`'s own doc comment in controller.ts.
89
+ return {
90
+ processId: event.handle.processId,
91
+ serviceName: event.serviceName,
92
+ exitCode: event.handle.exitCode,
93
+ signal: event.handle.signal,
94
+ exitedAt: event.handle.exitedAt,
95
+ phase: event.phase,
96
+ };
97
+ }
98
+ }
99
+ export function createProcessCollector() {
100
+ const capabilities = computeCapabilities();
101
+ let context = null;
102
+ return {
103
+ collectorId: "process-collector",
104
+ start(ctx) {
105
+ context = ctx;
106
+ return Promise.resolve({ available: true });
107
+ },
108
+ stop() {
109
+ // Idempotent per the Collector contract; nothing held to release —
110
+ // this collector owns no process, socket, or file handle of its own,
111
+ // only a reference to the context it emits through.
112
+ context = null;
113
+ return Promise.resolve();
114
+ },
115
+ capabilities() {
116
+ return capabilities;
117
+ },
118
+ handleLifecycleEvent(event) {
119
+ if (context === null) {
120
+ throw new Error(`ProcessCollector.handleLifecycleEvent("${event.kind}") called before start() — ` +
121
+ `wire handleLifecycleEvent as RunOptions.onProcessLifecycleEvent only after start() has resolved, ` +
122
+ `or this event (and everything downstream of it) is silently unobserved rather than loudly wrong.`);
123
+ }
124
+ context.emit({
125
+ timestamp: new Date().toISOString(),
126
+ source: event.kind === "process-exited" ? "process-exit" : "backend-process",
127
+ service: event.serviceName,
128
+ process: event.handle.processId,
129
+ eventType: eventTypeOf(event.kind),
130
+ payload: payloadOf(event),
131
+ traceId: null,
132
+ requestId: null,
133
+ correlationId: null,
134
+ graphNodeId: null,
135
+ sourceLocation: null,
136
+ stackTrace: null,
137
+ // A direct observation of our own orchestration state (we spawned
138
+ // it, we polled its readiness, we reaped it) — never inferred or
139
+ // guessed, same basis LogCollector already uses for its own
140
+ // verbatim-capture confidence of 1.
141
+ confidence: 1,
142
+ redactionStatus: "pending-redaction",
143
+ collectorVersion: COLLECTOR_VERSION,
144
+ });
145
+ },
146
+ };
147
+ }
148
+ //# sourceMappingURL=process-collector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"process-collector.js","sourceRoot":"","sources":["../src/process-collector.ts"],"names":[],"mappings":"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"}